mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 03:59:35 +01:00
manual backport of PR #4598 (TooManyRequestsException)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
237b6fafac
commit
36f4c4f497
@ -180,7 +180,7 @@ class OutcomingTextMessageViewHolder(itemView: View) :
|
||||
).first()
|
||||
}
|
||||
|
||||
parentChatMessage!!.activeUser = message.activeUser
|
||||
parentChatMessage.activeUser = message.activeUser
|
||||
parentChatMessage.imageUrl?.let {
|
||||
binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
|
||||
binding.messageQuote.quotedMessageImage.load(it) {
|
||||
@ -207,7 +207,6 @@ class OutcomingTextMessageViewHolder(itemView: View) :
|
||||
viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
|
||||
|
||||
binding.messageQuote.quotedChatMessageView.setOnClickListener {
|
||||
val chatActivity = commonMessageInterface as ChatActivity
|
||||
chatActivity.jumpToQuotedMessage(parentChatMessage)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -191,7 +191,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -428,7 +427,7 @@ class ChatActivity :
|
||||
|
||||
this.lifecycleScope.launch {
|
||||
delay(DELAY_TO_SHOW_PROGRESS_BAR)
|
||||
if (adapter?.isEmpty == true && networkMonitor.isOnline.first()) {
|
||||
if (adapter?.isEmpty == true && networkMonitor.isOnline.value) {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
@ -923,7 +922,7 @@ class ChatActivity :
|
||||
chatViewModel.getGeneralUIFlow.onEach { key ->
|
||||
when (key) {
|
||||
NO_OFFLINE_MESSAGES_FOUND -> {
|
||||
if (networkMonitor.isOnline.first().not()) {
|
||||
if (networkMonitor.isOnline.value.not()) {
|
||||
binding.offline.root.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessageJson
|
||||
import com.nextcloud.talk.models.json.chat.ChatOverall
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -45,8 +44,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
private val chatDao: ChatMessagesDao,
|
||||
private val chatBlocksDao: ChatBlocksDao,
|
||||
private val network: ChatNetworkDataSource,
|
||||
private val datastore: AppPreferences,
|
||||
private val monitor: NetworkMonitor,
|
||||
private val networkMonitor: NetworkMonitor,
|
||||
private val userProvider: CurrentUserProviderNew
|
||||
) : ChatMessageRepository {
|
||||
|
||||
@ -71,8 +69,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
>
|
||||
> = MutableSharedFlow()
|
||||
|
||||
override val updateMessageFlow:
|
||||
Flow<ChatMessage>
|
||||
override val updateMessageFlow: Flow<ChatMessage>
|
||||
get() = _updateMessageFlow
|
||||
|
||||
private val _updateMessageFlow:
|
||||
@ -85,8 +82,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
private val _lastCommonReadFlow:
|
||||
MutableSharedFlow<Int> = MutableSharedFlow()
|
||||
|
||||
override val lastReadMessageFlow:
|
||||
Flow<Int>
|
||||
override val lastReadMessageFlow: Flow<Int>
|
||||
get() = _lastReadMessageFlow
|
||||
|
||||
private val _lastReadMessageFlow:
|
||||
@ -278,7 +274,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
var showUnreadMessagesMarker = true
|
||||
|
||||
while (true) {
|
||||
if (!monitor.isOnline.first() || itIsPaused) {
|
||||
if (!networkMonitor.isOnline.value || itIsPaused) {
|
||||
Thread.sleep(HALF_SECOND)
|
||||
} else {
|
||||
// sync database with server
|
||||
@ -469,7 +465,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
}
|
||||
|
||||
private suspend fun sync(bundle: Bundle): List<ChatMessageEntity>? {
|
||||
if (!monitor.isOnline.first()) {
|
||||
if (!networkMonitor.isOnline.value) {
|
||||
Log.d(TAG, "Device is offline, can't load chat messages from server")
|
||||
return null
|
||||
}
|
||||
|
@ -138,7 +138,6 @@ import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder
|
||||
@ -1359,7 +1358,7 @@ class ConversationsListActivity :
|
||||
|
||||
override fun onItemLongClick(position: Int) {
|
||||
this.lifecycleScope.launch {
|
||||
if (showShareToScreen || !networkMonitor.isOnline.first()) {
|
||||
if (showShareToScreen || !networkMonitor.isOnline.value) {
|
||||
Log.d(TAG, "sharing to multiple rooms not yet implemented. onItemLongClick is ignored.")
|
||||
} else {
|
||||
val clickedItem: Any? = adapter!!.getItem(position)
|
||||
|
@ -10,7 +10,6 @@ package com.nextcloud.talk.conversationlist.data.network
|
||||
|
||||
import android.util.Log
|
||||
import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
|
||||
import com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository
|
||||
import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository
|
||||
import com.nextcloud.talk.data.database.dao.ConversationsDao
|
||||
import com.nextcloud.talk.data.database.mappers.asEntity
|
||||
@ -40,7 +39,7 @@ class OfflineFirstConversationsRepository @Inject constructor(
|
||||
private val dao: ConversationsDao,
|
||||
private val network: ConversationsNetworkDataSource,
|
||||
private val chatNetworkDataSource: ChatNetworkDataSource,
|
||||
private val monitor: NetworkMonitor,
|
||||
private val networkMonitor: NetworkMonitor,
|
||||
private val currentUserProviderNew: CurrentUserProviderNew
|
||||
) : OfflineConversationsRepository {
|
||||
override val roomListFlow: Flow<List<ConversationModel>>
|
||||
@ -59,7 +58,7 @@ class OfflineFirstConversationsRepository @Inject constructor(
|
||||
val initialConversationModels = getListOfConversations(user.id!!)
|
||||
_roomListFlow.emit(initialConversationModels)
|
||||
|
||||
if (monitor.isOnline.first()) {
|
||||
if (networkMonitor.isOnline.value) {
|
||||
val conversationEntitiesFromSync = getRoomsFromServer()
|
||||
if (!conversationEntitiesFromSync.isNullOrEmpty()) {
|
||||
val conversationModelsFromSync = conversationEntitiesFromSync.map(ConversationEntity::asModel)
|
||||
@ -106,8 +105,8 @@ class OfflineFirstConversationsRepository @Inject constructor(
|
||||
private suspend fun getRoomsFromServer(): List<ConversationEntity>? {
|
||||
var conversationsFromSync: List<ConversationEntity>? = null
|
||||
|
||||
if (!monitor.isOnline.first()) {
|
||||
Log.d(OfflineFirstChatRepository.TAG, "Device is offline, can't load conversations from server")
|
||||
if (!networkMonitor.isOnline.value) {
|
||||
Log.d(TAG, "Device is offline, can't load conversations from server")
|
||||
return null
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,6 @@ import com.nextcloud.talk.translate.repositories.TranslateRepositoryImpl
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.DateUtils
|
||||
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import okhttp3.OkHttpClient
|
||||
@ -180,7 +179,6 @@ class RepositoryModule {
|
||||
chatMessagesDao: ChatMessagesDao,
|
||||
chatBlocksDao: ChatBlocksDao,
|
||||
dataSource: ChatNetworkDataSource,
|
||||
appPreferences: AppPreferences,
|
||||
networkMonitor: NetworkMonitor,
|
||||
userProvider: CurrentUserProviderNew
|
||||
): ChatMessageRepository {
|
||||
@ -188,7 +186,6 @@ class RepositoryModule {
|
||||
chatMessagesDao,
|
||||
chatBlocksDao,
|
||||
dataSource,
|
||||
appPreferences,
|
||||
networkMonitor,
|
||||
userProvider
|
||||
)
|
||||
|
@ -2,13 +2,14 @@
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Julius Linus <juliuslinus1@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2024 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.data.network
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Utility for reporting app connectivity status.
|
||||
@ -17,7 +18,7 @@ interface NetworkMonitor {
|
||||
/**
|
||||
* Returns the device's current connectivity status.
|
||||
*/
|
||||
val isOnline: Flow<Boolean>
|
||||
val isOnline: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Returns the device's current connectivity status as LiveData for better interop with Java code.
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Julius Linus <juliuslinus1@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2024 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
@ -11,17 +12,17 @@ import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest.Builder
|
||||
import android.util.Log
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ -29,49 +30,57 @@ import javax.inject.Singleton
|
||||
class NetworkMonitorImpl @Inject constructor(
|
||||
private val context: Context
|
||||
) : NetworkMonitor {
|
||||
|
||||
private val connectivityManager = context.getSystemService<ConnectivityManager>()!!
|
||||
|
||||
override val isOnlineLiveData: LiveData<Boolean>
|
||||
get() = isOnline.asLiveData()
|
||||
|
||||
override val isOnline: Flow<Boolean> = callbackFlow {
|
||||
val connectivityManager = context.getSystemService<ConnectivityManager>()
|
||||
if (connectivityManager == null) {
|
||||
channel.trySend(false)
|
||||
channel.close()
|
||||
return@callbackFlow
|
||||
}
|
||||
override val isOnline: StateFlow<Boolean> get() = _isOnline
|
||||
|
||||
val networkRequest = Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.build()
|
||||
private val _isOnline: StateFlow<Boolean> = callbackFlow {
|
||||
val callback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||
super.onCapabilitiesChanged(network, networkCapabilities)
|
||||
val connected = networkCapabilities.hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||
)
|
||||
trySend(connected)
|
||||
Log.d(TAG, "Network status changed: $connected")
|
||||
}
|
||||
|
||||
val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
private val networks = mutableSetOf<Network>()
|
||||
|
||||
override fun onAvailable(network: Network) {
|
||||
networks += network
|
||||
channel.trySend(true)
|
||||
override fun onUnavailable() {
|
||||
super.onUnavailable()
|
||||
trySend(false)
|
||||
Log.d(TAG, "Network status: onUnavailable")
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
networks -= network
|
||||
channel.trySend(networks.isNotEmpty())
|
||||
super.onLost(network)
|
||||
trySend(false)
|
||||
Log.d(TAG, "Network status: onLost")
|
||||
}
|
||||
|
||||
override fun onAvailable(network: Network) {
|
||||
super.onAvailable(network)
|
||||
trySend(true)
|
||||
Log.d(TAG, "Network status: onAvailable")
|
||||
}
|
||||
}
|
||||
|
||||
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
|
||||
|
||||
channel.trySend(connectivityManager.isCurrentlyConnected())
|
||||
connectivityManager.registerDefaultNetworkCallback(callback)
|
||||
|
||||
awaitClose {
|
||||
connectivityManager.unregisterNetworkCallback(networkCallback)
|
||||
connectivityManager.unregisterNetworkCallback(callback)
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.flowOn(Dispatchers.IO)
|
||||
.conflate()
|
||||
}.stateIn(
|
||||
CoroutineScope(Dispatchers.IO),
|
||||
SharingStarted.WhileSubscribed(COROUTINE_TIMEOUT),
|
||||
false
|
||||
)
|
||||
|
||||
private fun ConnectivityManager.isCurrentlyConnected() =
|
||||
activeNetwork
|
||||
?.let(::getNetworkCapabilities)
|
||||
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false
|
||||
companion object {
|
||||
private val TAG = NetworkMonitorImpl::class.java.simpleName
|
||||
private const val COROUTINE_TIMEOUT = 5000L
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ import io.reactivex.Observer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
@ -134,7 +133,7 @@ class MessageActionsDialog(
|
||||
initMenuAddToNote(
|
||||
!message.isDeleted &&
|
||||
!ConversationUtils.isNoteToSelfConversation(currentConversation) &&
|
||||
networkMonitor.isOnline.first(),
|
||||
networkMonitor.isOnline.value,
|
||||
state.roomToken
|
||||
)
|
||||
}
|
||||
@ -147,16 +146,16 @@ class MessageActionsDialog(
|
||||
}
|
||||
}
|
||||
|
||||
initMenuItems()
|
||||
initMenuItems(networkMonitor.isOnline.value)
|
||||
}
|
||||
|
||||
private fun initMenuItems() {
|
||||
private fun initMenuItems(isOnline: Boolean) {
|
||||
this.lifecycleScope.launch {
|
||||
initMenuItemTranslate(
|
||||
!message.isDeleted &&
|
||||
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
|
||||
CapabilitiesUtil.isTranslationsSupported(spreedCapabilities) &&
|
||||
networkMonitor.isOnline.first()
|
||||
isOnline
|
||||
)
|
||||
initMenuEditorDetails(message.lastEditTimestamp!! != 0L && !message.isDeleted)
|
||||
initMenuReplyToMessage(message.replyable && hasChatPermission)
|
||||
@ -165,30 +164,30 @@ class MessageActionsDialog(
|
||||
hasUserId(user) &&
|
||||
hasUserActorId(message) &&
|
||||
currentConversation?.type != ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
|
||||
networkMonitor.isOnline.first()
|
||||
isOnline
|
||||
)
|
||||
initMenuEditMessage(isMessageEditable)
|
||||
initMenuDeleteMessage(showMessageDeletionButton && networkMonitor.isOnline.first())
|
||||
initMenuDeleteMessage(showMessageDeletionButton && isOnline)
|
||||
initMenuForwardMessage(
|
||||
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
|
||||
!(message.isDeletedCommentMessage || message.isDeleted) &&
|
||||
networkMonitor.isOnline.first()
|
||||
isOnline
|
||||
)
|
||||
initMenuRemindMessage(
|
||||
!message.isDeleted &&
|
||||
hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.REMIND_ME_LATER) &&
|
||||
currentConversation!!.remoteServer.isNullOrEmpty() &&
|
||||
networkMonitor.isOnline.first()
|
||||
isOnline
|
||||
)
|
||||
initMenuMarkAsUnread(
|
||||
message.previousMessageId > NO_PREVIOUS_MESSAGE_ID &&
|
||||
ChatMessage.MessageType.SYSTEM_MESSAGE != message.getCalculateMessageType() &&
|
||||
networkMonitor.isOnline.first()
|
||||
isOnline
|
||||
)
|
||||
initMenuShare(messageHasFileAttachment || messageHasRegularText && networkMonitor.isOnline.first())
|
||||
initMenuShare(messageHasFileAttachment || messageHasRegularText && isOnline)
|
||||
initMenuItemOpenNcApp(
|
||||
ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE == message.getCalculateMessageType() &&
|
||||
networkMonitor.isOnline.first()
|
||||
isOnline
|
||||
)
|
||||
initMenuItemSave(message.getCalculateMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user