From 9b6aa486396c3117b6dd24114f670a097fd394f1 Mon Sep 17 00:00:00 2001 From: Chumva Date: Wed, 5 Dec 2018 17:52:26 +0200 Subject: [PATCH] Add ability to share location to contacts --- .../net/osmand/telegram/TelegramSettings.kt | 82 ++++++++--- .../osmand/telegram/helpers/TelegramHelper.kt | 75 ++++++++++ .../osmand/telegram/ui/LiveNowTabFragment.kt | 4 + .../net/osmand/telegram/ui/MainActivity.kt | 6 + .../telegram/ui/MyLocationTabFragment.kt | 138 +++++++++++++----- .../telegram/ui/SetTimeDialogFragment.kt | 104 ++++++++++--- 6 files changed, 334 insertions(+), 75 deletions(-) diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt index a2cb3e34ef..8b0575bf1b 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt @@ -44,8 +44,8 @@ private val LOC_HISTORY_VALUES_SEC = listOf( ) private const val SEND_MY_LOC_DEFAULT_INDEX = 6 -private const val STALE_LOC_DEFAULT_INDEX = 4 -private const val LOC_HISTORY_DEFAULT_INDEX = 2 +private const val STALE_LOC_DEFAULT_INDEX = 0 +private const val LOC_HISTORY_DEFAULT_INDEX = 7 private const val SETTINGS_NAME = "osmand_telegram_settings" @@ -113,6 +113,15 @@ class TelegramSettings(private val app: TelegramApplication) { fun isSharingLocationToChat(chatId: Long) = shareChatsInfo.containsKey(chatId) + fun isSharingLocationToUser(userId: Int): Boolean { + shareChatsInfo.forEach { (_, shareInfo: ShareChatInfo) -> + if (shareInfo.userId == userId) { + return true + } + } + return false + } + fun hasAnyChatToShowOnMap() = !hiddenOnMapChats.containsAll(getLiveNowChats()) fun isShowingChatOnMap(chatId: Long) = !hiddenOnMapChats.contains(chatId) @@ -132,35 +141,33 @@ class TelegramSettings(private val app: TelegramApplication) { addActiveTime: Long = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0] ) { if (share) { - val lp: Long = when { - livePeriod < TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC -> TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong() - else -> livePeriod - } var shareChatInfo = shareChatsInfo[chatId] if (shareChatInfo == null) { shareChatInfo = ShareChatInfo() } - val currentTime = System.currentTimeMillis() / 1000 - val user = app.telegramHelper.getCurrentUser() - if (user != null && currentSharingMode != user.id.toString() && shareChatInfo.start == -1L) { - shareChatInfo.shouldSendViaBotMessage = true + val chat = app.telegramHelper.getChat(chatId) + if (chat != null && (chat.type is TdApi.ChatTypePrivate || chat.type is TdApi.ChatTypeSecret)) { + shareChatInfo.userId = app.telegramHelper.getUserIdFromChatType(chat.type) } - shareChatInfo.chatId = chatId - shareChatInfo.start = currentTime - if (shareChatInfo.livePeriod == -1L) { - shareChatInfo.livePeriod = lp - } - shareChatInfo.userSetLivePeriod = lp - shareChatInfo.userSetLivePeriodStart = currentTime - shareChatInfo.currentMessageLimit = currentTime + Math.min(lp, TelegramHelper.MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong()) - shareChatInfo.additionalActiveTime = addActiveTime + updateChatShareInfo(shareChatInfo, livePeriod, addActiveTime) shareChatsInfo[chatId] = shareChatInfo } else { shareChatsInfo.remove(chatId) } } + fun shareLocationToUser( + userId: Int, + livePeriod: Long = DEFAULT_VISIBLE_TIME_SECONDS, + addActiveTime: Long = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0] + ) { + val shareChatInfo = ShareChatInfo() + shareChatInfo.userId = userId + updateChatShareInfo(shareChatInfo, livePeriod, addActiveTime) + app.telegramHelper.createPrivateChatWithUser(userId, shareChatInfo, shareChatsInfo) + } + fun updateShareDevices(list: List) { shareDevices = list.toHashSet() } @@ -235,10 +242,12 @@ class TelegramSettings(private val app: TelegramApplication) { fun updateShareInfo(message: TdApi.Message) { val shareChatInfo = shareChatsInfo[message.chatId] val content = message.content - if (shareChatInfo != null && content is TdApi.MessageLocation) { + if (shareChatInfo != null) { shareChatInfo.currentMessageId = message.id - shareChatInfo.lastSuccessfulLocation = LatLon(content.location.latitude, content.location.longitude) - shareChatInfo.lastSuccessfulSendTimeMs = Math.max(message.editDate, message.date) * 1000L + if (content is TdApi.MessageLocation) { + shareChatInfo.lastSuccessfulLocation = LatLon(content.location.latitude, content.location.longitude) + shareChatInfo.lastSuccessfulSendTimeMs = Math.max(message.editDate, message.date) * 1000L + } } } @@ -271,6 +280,31 @@ class TelegramSettings(private val app: TelegramApplication) { } } + private fun updateChatShareInfo( + shareChatInfo: ShareChatInfo, + livePeriod: Long = DEFAULT_VISIBLE_TIME_SECONDS, + addActiveTime: Long = ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0] + ) { + val lp: Long = when { + livePeriod < TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC -> TelegramHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong() + else -> livePeriod + } + val currentTime = System.currentTimeMillis() / 1000 + val user = app.telegramHelper.getCurrentUser() + if (user != null && currentSharingMode != user.id.toString() && shareChatInfo.start == -1L) { + shareChatInfo.shouldSendViaBotMessage = true + } + + shareChatInfo.start = currentTime + if (shareChatInfo.livePeriod == -1L) { + shareChatInfo.livePeriod = lp + } + shareChatInfo.userSetLivePeriod = lp + shareChatInfo.userSetLivePeriodStart = currentTime + shareChatInfo.currentMessageLimit = currentTime + Math.min(lp, TelegramHelper.MAX_LOCATION_MESSAGE_LIVE_PERIOD_SEC.toLong()) + shareChatInfo.additionalActiveTime = addActiveTime + } + private fun getNewSharingStatusHistoryItem(): SharingStatus { return SharingStatus().apply { statusChangeTime = System.currentTimeMillis() @@ -472,6 +506,7 @@ class TelegramSettings(private val app: TelegramApplication) { shareChatsInfo.forEach { (chatId, chatInfo) -> val obj = JSONObject() obj.put(ShareChatInfo.CHAT_ID_KEY, chatId) + obj.put(ShareChatInfo.USER_ID_KEY, chatInfo.userId) obj.put(ShareChatInfo.START_KEY, chatInfo.start) obj.put(ShareChatInfo.LIVE_PERIOD_KEY, chatInfo.livePeriod) obj.put(ShareChatInfo.LIMIT_KEY, chatInfo.currentMessageLimit) @@ -493,6 +528,7 @@ class TelegramSettings(private val app: TelegramApplication) { val obj = json.getJSONObject(i) val shareInfo = ShareChatInfo().apply { chatId = obj.optLong(ShareChatInfo.CHAT_ID_KEY) + userId = obj.optInt(ShareChatInfo.USER_ID_KEY) start = obj.optLong(ShareChatInfo.START_KEY) livePeriod = obj.optLong(ShareChatInfo.LIVE_PERIOD_KEY) currentMessageLimit = obj.optLong(ShareChatInfo.LIMIT_KEY) @@ -738,6 +774,7 @@ class TelegramSettings(private val app: TelegramApplication) { class ShareChatInfo { var chatId = -1L + var userId = -1 var start = -1L var livePeriod = -1L var currentMessageLimit = -1L @@ -767,6 +804,7 @@ class TelegramSettings(private val app: TelegramApplication) { companion object { internal const val CHAT_ID_KEY = "chatId" + internal const val USER_ID_KEY = "userId" internal const val START_KEY = "start" internal const val LIVE_PERIOD_KEY = "livePeriod" internal const val LIMIT_KEY = "limit" diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt index 0d3091f700..142fac8c83 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt @@ -68,6 +68,7 @@ class TelegramHelper private constructor() { var lastTelegramUpdateTime: Int = 0 private val users = ConcurrentHashMap() + private val contacts = ConcurrentHashMap() private val basicGroups = ConcurrentHashMap() private val supergroups = ConcurrentHashMap() private val secretChats = ConcurrentHashMap() @@ -141,6 +142,8 @@ class TelegramHelper private constructor() { fun getChatListIds() = getChatList().map { it.chatId } + fun getContacts() = contacts + fun getChatIds() = chats.keys().toList() fun getChat(id: Long) = chats[id] @@ -237,6 +240,7 @@ class TelegramHelper private constructor() { fun onTelegramChatsRead() fun onTelegramChatsChanged() fun onTelegramChatChanged(chat: TdApi.Chat) + fun onTelegramChatCreated(chat: TdApi.Chat) fun onTelegramUserChanged(user: TdApi.User) fun onTelegramError(code: Int, message: String) } @@ -561,6 +565,73 @@ class TelegramHelper private constructor() { } } + private fun requestContacts(){ + client?.send(TdApi.GetContacts()) { obj -> + when (obj.constructor) { + TdApi.Error.CONSTRUCTOR -> { + val error = obj as TdApi.Error + if (error.code != IGNORED_ERROR_CODE) { + listener?.onTelegramError(error.code, error.message) + } + } + TdApi.Users.CONSTRUCTOR -> { + val usersIds = obj as TdApi.Users + usersIds.userIds.forEach { + requestUser(it) + } + } + } + } + } + + private fun requestUser(id: Int) { + client?.send(TdApi.GetUser(id)) { obj -> + when (obj.constructor) { + TdApi.Error.CONSTRUCTOR -> { + val error = obj as TdApi.Error + if (error.code != IGNORED_ERROR_CODE) { + listener?.onTelegramError(error.code, error.message) + } + } + TdApi.User.CONSTRUCTOR -> { + val user = obj as TdApi.User + contacts[user.id] = user + if (!hasLocalUserPhoto(user) && hasRemoteUserPhoto(user)) { + requestUserPhoto(user) + } + } + } + } + } + + fun createPrivateChatWithUser( + userId: Int, + shareInfo: TelegramSettings.ShareChatInfo, + shareChatsInfo: ConcurrentHashMap + ) { + client?.send(TdApi.CreatePrivateChat(userId, false)) { obj -> + when (obj.constructor) { + TdApi.Error.CONSTRUCTOR -> { + val error = obj as TdApi.Error + needRefreshActiveLiveLocationMessages = true + if (error.code == MESSAGE_CANNOT_BE_EDITED_ERROR_CODE) { + shareInfo.shouldDeletePreviousMessage = true + } else if (error.code != IGNORED_ERROR_CODE) { + shareInfo.hasSharingError = true + outgoingMessagesListeners.forEach { + it.onSendLiveLocationError(error.code, error.message) + } + } + } + TdApi.Chat.CONSTRUCTOR -> { + shareInfo.chatId = (obj as TdApi.Chat).id + shareChatsInfo[shareInfo.chatId] = shareInfo + listener?.onTelegramChatCreated(obj) + } + } + } + } + fun loadMessage(chatId: Long, messageId: Long) { requestMessage(chatId, messageId, this@TelegramHelper::addNewMessage) } @@ -896,6 +967,7 @@ class TelegramHelper private constructor() { if (haveAuthorization) { requestChats(true) requestCurrentUser() + requestContacts() } } val newAuthState = getTelegramAuthorizationState() @@ -1085,6 +1157,9 @@ class TelegramHelper private constructor() { val updateUser = obj as TdApi.UpdateUser val user = updateUser.user users[updateUser.user.id] = user + if (user.outgoingLink is TdApi.LinkStateIsContact) { + contacts[user.id] = user + } if (isOsmAndBot(user.id)) { osmandBot = user } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt index 382f8a4be8..f962a1f3f8 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt @@ -171,6 +171,10 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage updateList() } + override fun onTelegramChatCreated(chat: TdApi.Chat) { + updateList() + } + override fun onTelegramUserChanged(user: TdApi.User) { updateList() } diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt index d3a84743d8..0ac6356a0b 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt @@ -254,6 +254,12 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene } } + override fun onTelegramChatCreated(chat: TdApi.Chat) { + runOnUi { + listeners.forEach { it.get()?.onTelegramChatCreated(chat) } + } + } + override fun onTelegramUserChanged(user: TdApi.User) { val photoPath = telegramHelper.getUserPhotoPath(user) if (photoPath != null) { diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt index 91fbb97f1e..58fdf0e6d0 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt @@ -28,6 +28,7 @@ import net.osmand.telegram.utils.OsmandFormatter import org.drinkless.td.libcore.telegram.TdApi private const val SELECTED_CHATS_KEY = "selected_chats" +private const val SELECTED_CHATS_USERS = "selected_users" private const val SHARE_LOCATION_CHAT = 1 private const val DEFAULT_CHAT = 0 @@ -71,6 +72,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { private lateinit var appBarOutlineProvider: ViewOutlineProvider private val selectedChats = HashSet() + private val selectedUsers = HashSet() private var actionButtonsListener: ActionButtonsListener? = null @@ -97,9 +99,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener { savedInstanceState?.apply { selectedChats.addAll(getLongArray(SELECTED_CHATS_KEY).toSet()) - if (selectedChats.isNotEmpty()) { - actionButtonsListener?.switchButtonsVisibility(true) - } + selectedUsers.addAll(getLongArray(SELECTED_CHATS_USERS).toSet()) + actionButtonsListener?.switchButtonsVisibility((selectedUsers.isNotEmpty() || selectedChats.isNotEmpty())) } val mainView = inflater.inflate(R.layout.fragment_my_location_tab, container, false) @@ -191,7 +192,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { mainView.findViewById(R.id.stop_all_sharing_row).setOnClickListener { fragmentManager?.also { fm -> - DisableSharingBottomSheet.showInstance(fm, this, adapter.chats.size) + DisableSharingBottomSheet.showInstance(fm, this, adapter.items.size) } } @@ -274,7 +275,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { TelegramHelper.TelegramAuthorizationState.LOGGING_OUT, TelegramHelper.TelegramAuthorizationState.CLOSED, TelegramHelper.TelegramAuthorizationState.UNKNOWN -> { - adapter.chats = mutableListOf() + adapter.items = mutableListOf() } else -> Unit } @@ -292,6 +293,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { updateContent() } + override fun onTelegramChatCreated(chat: TdApi.Chat) { + sharingMode = settings.hasAnyChatToShareLocation() + updateContent() + } + override fun onTelegramUserChanged(user: TdApi.User) { if (user.id == telegramHelper.getCurrentUser()?.id) { updateCurrentUserPhoto() @@ -303,9 +309,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } fun onPrimaryBtnClick() { - if (selectedChats.isNotEmpty()) { + if (selectedChats.isNotEmpty() || selectedUsers.isNotEmpty()) { val fm = fragmentManager ?: return - SetTimeDialogFragment.showInstance(fm, selectedChats, this) + SetTimeDialogFragment.showInstance(fm, selectedChats, selectedUsers, this) } } @@ -351,6 +357,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { private fun clearSelection() { selectedChats.clear() + selectedUsers.clear() adapter.notifyDataSetChanged() actionButtonsListener?.switchButtonsVisibility(false) } @@ -453,8 +460,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } private fun updateList() { - val chats: MutableList = mutableListOf() + val items: MutableList = mutableListOf() val currentUser = telegramHelper.getCurrentUser() + val contacts = telegramHelper.getContacts() val chatList = if (sharingMode) { settings.getShareLocationChats() } else { @@ -470,30 +478,56 @@ class MyLocationTabFragment : Fragment(), TelegramListener { continue } } - chats.add(chat) + items.add(chat) + } + } + if (!sharingMode) { + for (user in contacts.values) { + if ((!sharingMode && settings.isSharingLocationToUser(user.id)) || user.id == currentUser?.id) { + continue + } + items.add(user) } } if (sharingMode && settings.hasAnyChatToShareLocation()) { - adapter.chats = sortAdapterItems(chats) + adapter.items = sortAdapterItems(items) } else { - adapter.chats = chats + adapter.items = items } } - private fun sortAdapterItems(list: MutableList): MutableList { - list.sortWith(Comparator { o1, o2 -> o1.title.compareTo(o2.title) }) + private fun sortAdapterItems(list: MutableList): MutableList { + list.sortWith(Comparator { o1, o2 -> + val title1 = when (o1) { + is TdApi.Chat -> o1.title + is TdApi.User -> TelegramUiHelper.getUserName(o1) + else -> "" + } + val title2 = when (o2) { + is TdApi.Chat -> o2.title + is TdApi.User -> TelegramUiHelper.getUserName(o2) + else -> "" + } + title1.compareTo(title2) + }) return list } inner class MyLocationListAdapter : RecyclerView.Adapter() { - var chats = mutableListOf() + var items = mutableListOf() set(value) { field = value notifyDataSetChanged() } override fun getItemViewType(position: Int): Int { - return if (settings.isSharingLocationToChat(chats[position].id) && sharingMode) { + val item = items[position] + val id = when (item) { + is TdApi.Chat -> item.id + is TdApi.User -> item.id.toLong() + else -> -1 + } + return if (settings.isSharingLocationToChat(id) && sharingMode) { SHARE_LOCATION_CHAT } else { DEFAULT_CHAT @@ -518,14 +552,34 @@ class MyLocationTabFragment : Fragment(), TelegramListener { @SuppressLint("SetTextI18n") override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { - val chat = chats[position] - val lastItem = position == itemCount - 1 - val placeholderId = if (telegramHelper.isGroup(chat)) R.drawable.img_group_picture else R.drawable.img_user_picture - val live = settings.isSharingLocationToChat(chat.id) - val shareInfo = settings.getChatsShareInfo()[chat.id] + val item = items[position] + val isChat = item is TdApi.Chat + val itemId = if (isChat) { + (item as TdApi.Chat).id + } else { + (item as TdApi.User).id.toLong() + } - TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false) - holder.title?.text = chat.title + 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 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) + + val title = when (item) { + is TdApi.Chat -> item.title + is TdApi.User -> TelegramUiHelper.getUserName(item) + else -> null + } + + holder.title?.text = title if (holder is ChatViewHolder) { holder.description?.visibility = View.GONE @@ -535,21 +589,33 @@ class MyLocationTabFragment : Fragment(), TelegramListener { holder.checkBox?.apply { visibility = View.VISIBLE setOnCheckedChangeListener(null) - isChecked = selectedChats.contains(chat.id) + isChecked = if (isChat) { + selectedChats.contains(itemId) + } else { + selectedUsers.contains(itemId) + } setOnCheckedChangeListener { _, isChecked -> if (isChecked) { - selectedChats.add(chat.id) + if (isChat) { + selectedChats.add(itemId) + } else { + selectedUsers.add(itemId) + } } else { - selectedChats.remove(chat.id) + if (isChat) { + selectedChats.remove(itemId) + } else { + selectedUsers.remove(itemId) + } } - actionButtonsListener?.switchButtonsVisibility(selectedChats.isNotEmpty()) + actionButtonsListener?.switchButtonsVisibility(selectedChats.isNotEmpty() || selectedUsers.isNotEmpty()) } } } holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE holder.itemView.setOnClickListener { if (live) { - settings.shareLocationToChat(chat.id, false) + settings.shareLocationToChat(itemId, false) shareLocationHelper.stopSharingLocation() notifyItemChanged(position) } else { @@ -563,11 +629,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { isChecked = live setOnCheckedChangeListener { _, isChecked -> if (!isChecked) { - settings.shareLocationToChat(chat.id, false) + settings.shareLocationToChat(itemId, false) if (shareInfo != null) { telegramHelper.stopSendingLiveLocationToChat(shareInfo) } - removeItem(chat) + removeItem(item) } } } @@ -591,7 +657,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener { val expireTime = shareInfo?.getChatLiveMessageExpireTime() ?: 0 val newLivePeriod = expireTime + (shareInfo?.additionalActiveTime ?: ADDITIONAL_ACTIVE_TIME_VALUES_SEC[0]) val nextAdditionalActiveTime = shareInfo?.getNextAdditionalActiveTime() ?: ADDITIONAL_ACTIVE_TIME_VALUES_SEC[1] - settings.shareLocationToChat(chat.id, true, newLivePeriod, nextAdditionalActiveTime) + if (isChat) { + settings.shareLocationToChat(itemId, true, newLivePeriod, nextAdditionalActiveTime) + } else { + settings.shareLocationToUser(itemId.toInt(), newLivePeriod, nextAdditionalActiveTime) + } notifyItemChanged(position) } } @@ -616,9 +686,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener { private fun getStopSharingVisibility(expiresIn: Long) = if (expiresIn > 0) View.VISIBLE else View.INVISIBLE - private fun removeItem(chat: TdApi.Chat) { - chats.remove(chat) - if (chats.isEmpty()) { + private fun removeItem(chat: TdApi.Object) { + items.remove(chat) + if (items.isEmpty()) { sharingMode = false updateContent() shareLocationHelper.stopSharingLocation() @@ -627,7 +697,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener { } } - override fun getItemCount() = chats.size + override fun getItemCount() = items.size abstract inner class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view) { val icon: ImageView? = view.findViewById(R.id.icon) diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt index c7d49771fe..48616165db 100644 --- a/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt +++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/SetTimeDialogFragment.kt @@ -14,8 +14,8 @@ import android.widget.TextView import net.osmand.Location import net.osmand.data.LatLon import net.osmand.telegram.R -import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener import net.osmand.telegram.TelegramLocationProvider.TelegramCompassListener +import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener import net.osmand.telegram.helpers.ShareLocationHelper import net.osmand.telegram.helpers.TelegramUiHelper import net.osmand.telegram.ui.SetTimeDialogFragment.SetTimeListAdapter.ChatViewHolder @@ -36,6 +36,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te private lateinit var timeForAllValue: TextView private val chatLivePeriods = HashMap() + private val userLivePeriods = HashMap() private var location: Location? = null private var heading: Float? = null @@ -90,6 +91,9 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te chatLivePeriods.forEach { (chatId, livePeriod) -> settings.shareLocationToChat(chatId, true, livePeriod) } + userLivePeriods.forEach { (userId, livePeriod) -> + settings.shareLocationToUser(userId.toInt(), livePeriod) + } app.shareLocationHelper.startSharingLocation() targetFragment?.also { it.onActivityResult(targetRequestCode, LOCATION_SHARED_REQUEST_CODE, null) @@ -121,7 +125,13 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te chats.add(id) chats.add(livePeriod) } + val users = mutableListOf() + for ((id, livePeriod) in userLivePeriods) { + users.add(id) + users.add(livePeriod) + } outState.putLongArray(CHATS_KEY, chats.toLongArray()) + outState.putLongArray(USERS_KEY, users.toLongArray()) } override fun updateLocation(location: Location?) { @@ -167,17 +177,27 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te private fun readFromBundle(bundle: Bundle?) { chatLivePeriods.clear() + userLivePeriods.clear() bundle?.getLongArray(CHATS_KEY)?.also { for (i in 0 until it.size step 2) { val livePeriod = settings.getChatLivePeriod(it[i]) chatLivePeriods[it[i]] = livePeriod ?: it[i + 1] } } + bundle?.getLongArray(USERS_KEY)?.also { + for (j in 0 until it.size step 2) { + val livePeriod = settings.getChatLivePeriod(it[j]) + userLivePeriods[it[j]] = livePeriod ?: it[j + 1] + } + } } private fun getTimeForAll(useDefValue: Boolean = false): Long { val returnVal = if (useDefValue) DEFAULT_VISIBLE_TIME_SECONDS else NO_VALUE - val iterator = chatLivePeriods.values.iterator() + val allTime = mutableListOf() + allTime.addAll(chatLivePeriods.values) + allTime.addAll(userLivePeriods.values) + val iterator = allTime.iterator() if (!iterator.hasNext()) { return returnVal } @@ -202,7 +222,7 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te } } - private fun selectDuration(id: Long? = null) { + private fun selectDuration(id: Long? = null, isChat: Boolean = true) { val timeForAll = getTimeForAll(true) val defSeconds = if (id == null) timeForAll else chatLivePeriods[id] ?: timeForAll val (defHours, defMinutes) = secondsToHoursAndMinutes(defSeconds) @@ -213,11 +233,18 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te TimeUnit.MINUTES.toSeconds(minutes.toLong()) if (seconds >= ShareLocationHelper.MIN_LOCATION_MESSAGE_LIVE_PERIOD_SEC) { if (id != null) { - chatLivePeriods[id] = seconds + if (isChat) { + chatLivePeriods[id] = seconds + } else { + userLivePeriods[id] = seconds + } } else { chatLivePeriods.keys.forEach { chatLivePeriods[it] = seconds } + userLivePeriods.keys.forEach { + userLivePeriods[it] = seconds + } } updateTimeForAllRow() adapter.notifyDataSetChanged() @@ -242,17 +269,19 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te } private fun updateList() { - val chats: MutableList = mutableListOf() + val items: MutableList = mutableListOf() telegramHelper.getChatList().filter { chatLivePeriods.keys.contains(it.chatId) } .forEach { orderedChat -> - telegramHelper.getChat(orderedChat.chatId)?.also { chats.add(it) } + telegramHelper.getChat(orderedChat.chatId)?.also { items.add(it) } } - adapter.chats = chats + telegramHelper.getContacts().values.filter { userLivePeriods.keys.contains(it.id.toLong()) } + .forEach { user -> items.add(user) } + adapter.items = items } inner class SetTimeListAdapter : RecyclerView.Adapter() { - var chats: List = emptyList() + var items: List = emptyList() set(value) { field = value notifyDataSetChanged() @@ -265,18 +294,38 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te } override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { - val chat = chats[position] - val placeholderId = if (telegramHelper.isGroup(chat)) R.drawable.img_group_picture else R.drawable.img_user_picture + val item = items[position] + val isChat = item is TdApi.Chat + val itemId = if (isChat) { + (item as TdApi.Chat).id + } else { + (item as TdApi.User).id.toLong() + } - TelegramUiHelper.setupPhoto(app, holder.icon, chat.photo?.small?.local?.path, placeholderId, false) - holder.title?.text = chat.title + val placeholderId = if (isChat && telegramHelper.isGroup((item as TdApi.Chat))) R.drawable.img_group_picture else R.drawable.img_user_picture - if (telegramHelper.isGroup(chat)) { + val photoPath = when (item) { + 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) + + val title = when (item) { + is TdApi.Chat -> item.title + is TdApi.User -> TelegramUiHelper.getUserName(item) + else -> null + } + + holder.title?.text = title + + if (isChat && telegramHelper.isGroup((item as TdApi.Chat))) { holder.locationViewContainer?.visibility = View.GONE holder.description?.visibility = View.VISIBLE holder.description?.text = getString(R.string.shared_string_group) } else { - val message = telegramHelper.getChatMessages(chat.id).firstOrNull() + val message = telegramHelper.getChatMessages(itemId).firstOrNull() val content = message?.content if (message != null && content is TdApi.MessageLocation && (location != null && content.location != null)) { val lastUpdated = telegramHelper.getLastUpdatedTime(message) @@ -301,15 +350,19 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te holder.textInArea?.apply { visibility = View.VISIBLE - chatLivePeriods[chat.id]?.also { text = formatLivePeriod(it) } + if (isChat) { + chatLivePeriods[itemId]?.also { text = formatLivePeriod(it) } + } else { + userLivePeriods[itemId]?.also { text = formatLivePeriod(it) } + } } holder.bottomShadow?.visibility = View.GONE holder.itemView.setOnClickListener { - selectDuration(chat.id) + selectDuration(itemId, isChat) } } - override fun getItemCount() = chats.size + override fun getItemCount() = items.size inner class ChatViewHolder(val view: View) : RecyclerView.ViewHolder(view) { val icon: ImageView? = view.findViewById(R.id.icon) @@ -329,18 +382,31 @@ class SetTimeDialogFragment : BaseDialogFragment(), TelegramLocationListener, Te private const val TAG = "SetTimeDialogFragment" private const val CHATS_KEY = "chats_key" + private const val USERS_KEY = "users_key" private const val DEFAULT_VISIBLE_TIME_SECONDS = 60 * 60L // 1 hour private const val NO_VALUE = -1L - fun showInstance(fm: FragmentManager, chatIds: Set, target: Fragment): Boolean { + fun showInstance(fm: FragmentManager, chatIds: Set, usersIds: Set, target: Fragment): Boolean { return try { val chats = mutableListOf() for (id in chatIds) { chats.add(id) chats.add(DEFAULT_VISIBLE_TIME_SECONDS) } + val users = mutableListOf() + for (id in usersIds) { + users.add(id) + users.add(DEFAULT_VISIBLE_TIME_SECONDS) + } SetTimeDialogFragment().apply { - arguments = Bundle().apply { putLongArray(CHATS_KEY, chats.toLongArray()) } + arguments = Bundle().apply { + if (chats.isNotEmpty()) { + putLongArray(CHATS_KEY, chats.toLongArray()) + } + if (users.isNotEmpty()) { + putLongArray(USERS_KEY, users.toLongArray()) + } + } setTargetFragment(target, LOCATION_SHARED_REQUEST_CODE) show(fm, TAG) }