Skip to content

Commit 2e52eab

Browse files
authored
Merge pull request #4622 from nextcloud/backport/4598/manualBackportTooManyRequestsException
manual backport of PR #4598 (TooManyRequestsException)
2 parents 237b6fa + 36f4c4f commit 2e52eab

File tree

9 files changed

+71
-73
lines changed

9 files changed

+71
-73
lines changed

app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ class OutcomingTextMessageViewHolder(itemView: View) :
180180
).first()
181181
}
182182

183-
parentChatMessage!!.activeUser = message.activeUser
183+
parentChatMessage.activeUser = message.activeUser
184184
parentChatMessage.imageUrl?.let {
185185
binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
186186
binding.messageQuote.quotedMessageImage.load(it) {
@@ -207,7 +207,6 @@ class OutcomingTextMessageViewHolder(itemView: View) :
207207
viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
208208

209209
binding.messageQuote.quotedChatMessageView.setOnClickListener {
210-
val chatActivity = commonMessageInterface as ChatActivity
211210
chatActivity.jumpToQuotedMessage(parentChatMessage)
212211
}
213212
} catch (e: Exception) {

app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ import kotlinx.coroutines.CoroutineScope
191191
import kotlinx.coroutines.Dispatchers
192192
import kotlinx.coroutines.delay
193193
import kotlinx.coroutines.flow.collect
194-
import kotlinx.coroutines.flow.first
195194
import kotlinx.coroutines.flow.onEach
196195
import kotlinx.coroutines.launch
197196
import kotlinx.coroutines.withContext
@@ -428,7 +427,7 @@ class ChatActivity :
428427

429428
this.lifecycleScope.launch {
430429
delay(DELAY_TO_SHOW_PROGRESS_BAR)
431-
if (adapter?.isEmpty == true && networkMonitor.isOnline.first()) {
430+
if (adapter?.isEmpty == true && networkMonitor.isOnline.value) {
432431
binding.progressBar.visibility = View.VISIBLE
433432
}
434433
}
@@ -923,7 +922,7 @@ class ChatActivity :
923922
chatViewModel.getGeneralUIFlow.onEach { key ->
924923
when (key) {
925924
NO_OFFLINE_MESSAGES_FOUND -> {
926-
if (networkMonitor.isOnline.first().not()) {
925+
if (networkMonitor.isOnline.value.not()) {
927926
binding.offline.root.visibility = View.VISIBLE
928927
}
929928
}

app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessageJson
2626
import com.nextcloud.talk.models.json.chat.ChatOverall
2727
import com.nextcloud.talk.utils.bundle.BundleKeys
2828
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
29-
import com.nextcloud.talk.utils.preferences.AppPreferences
3029
import io.reactivex.android.schedulers.AndroidSchedulers
3130
import io.reactivex.schedulers.Schedulers
3231
import kotlinx.coroutines.CoroutineScope
@@ -45,8 +44,7 @@ class OfflineFirstChatRepository @Inject constructor(
4544
private val chatDao: ChatMessagesDao,
4645
private val chatBlocksDao: ChatBlocksDao,
4746
private val network: ChatNetworkDataSource,
48-
private val datastore: AppPreferences,
49-
private val monitor: NetworkMonitor,
47+
private val networkMonitor: NetworkMonitor,
5048
private val userProvider: CurrentUserProviderNew
5149
) : ChatMessageRepository {
5250

@@ -71,8 +69,7 @@ class OfflineFirstChatRepository @Inject constructor(
7169
>
7270
> = MutableSharedFlow()
7371

74-
override val updateMessageFlow:
75-
Flow<ChatMessage>
72+
override val updateMessageFlow: Flow<ChatMessage>
7673
get() = _updateMessageFlow
7774

7875
private val _updateMessageFlow:
@@ -85,8 +82,7 @@ class OfflineFirstChatRepository @Inject constructor(
8582
private val _lastCommonReadFlow:
8683
MutableSharedFlow<Int> = MutableSharedFlow()
8784

88-
override val lastReadMessageFlow:
89-
Flow<Int>
85+
override val lastReadMessageFlow: Flow<Int>
9086
get() = _lastReadMessageFlow
9187

9288
private val _lastReadMessageFlow:
@@ -278,7 +274,7 @@ class OfflineFirstChatRepository @Inject constructor(
278274
var showUnreadMessagesMarker = true
279275

280276
while (true) {
281-
if (!monitor.isOnline.first() || itIsPaused) {
277+
if (!networkMonitor.isOnline.value || itIsPaused) {
282278
Thread.sleep(HALF_SECOND)
283279
} else {
284280
// sync database with server
@@ -469,7 +465,7 @@ class OfflineFirstChatRepository @Inject constructor(
469465
}
470466

471467
private suspend fun sync(bundle: Bundle): List<ChatMessageEntity>? {
472-
if (!monitor.isOnline.first()) {
468+
if (!networkMonitor.isOnline.value) {
473469
Log.d(TAG, "Device is offline, can't load chat messages from server")
474470
return null
475471
}

app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ import io.reactivex.disposables.Disposable
138138
import io.reactivex.schedulers.Schedulers
139139
import io.reactivex.subjects.BehaviorSubject
140140
import kotlinx.coroutines.flow.collect
141-
import kotlinx.coroutines.flow.first
142141
import kotlinx.coroutines.flow.onEach
143142
import kotlinx.coroutines.launch
144143
import org.apache.commons.lang3.builder.CompareToBuilder
@@ -1359,7 +1358,7 @@ class ConversationsListActivity :
13591358

13601359
override fun onItemLongClick(position: Int) {
13611360
this.lifecycleScope.launch {
1362-
if (showShareToScreen || !networkMonitor.isOnline.first()) {
1361+
if (showShareToScreen || !networkMonitor.isOnline.value) {
13631362
Log.d(TAG, "sharing to multiple rooms not yet implemented. onItemLongClick is ignored.")
13641363
} else {
13651364
val clickedItem: Any? = adapter!!.getItem(position)

app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ package com.nextcloud.talk.conversationlist.data.network
1010

1111
import android.util.Log
1212
import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
13-
import com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository
1413
import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository
1514
import com.nextcloud.talk.data.database.dao.ConversationsDao
1615
import com.nextcloud.talk.data.database.mappers.asEntity
@@ -40,7 +39,7 @@ class OfflineFirstConversationsRepository @Inject constructor(
4039
private val dao: ConversationsDao,
4140
private val network: ConversationsNetworkDataSource,
4241
private val chatNetworkDataSource: ChatNetworkDataSource,
43-
private val monitor: NetworkMonitor,
42+
private val networkMonitor: NetworkMonitor,
4443
private val currentUserProviderNew: CurrentUserProviderNew
4544
) : OfflineConversationsRepository {
4645
override val roomListFlow: Flow<List<ConversationModel>>
@@ -59,7 +58,7 @@ class OfflineFirstConversationsRepository @Inject constructor(
5958
val initialConversationModels = getListOfConversations(user.id!!)
6059
_roomListFlow.emit(initialConversationModels)
6160

62-
if (monitor.isOnline.first()) {
61+
if (networkMonitor.isOnline.value) {
6362
val conversationEntitiesFromSync = getRoomsFromServer()
6463
if (!conversationEntitiesFromSync.isNullOrEmpty()) {
6564
val conversationModelsFromSync = conversationEntitiesFromSync.map(ConversationEntity::asModel)
@@ -106,8 +105,8 @@ class OfflineFirstConversationsRepository @Inject constructor(
106105
private suspend fun getRoomsFromServer(): List<ConversationEntity>? {
107106
var conversationsFromSync: List<ConversationEntity>? = null
108107

109-
if (!monitor.isOnline.first()) {
110-
Log.d(OfflineFirstChatRepository.TAG, "Device is offline, can't load conversations from server")
108+
if (!networkMonitor.isOnline.value) {
109+
Log.d(TAG, "Device is offline, can't load conversations from server")
111110
return null
112111
}
113112

app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ import com.nextcloud.talk.translate.repositories.TranslateRepositoryImpl
6161
import com.nextcloud.talk.users.UserManager
6262
import com.nextcloud.talk.utils.DateUtils
6363
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
64-
import com.nextcloud.talk.utils.preferences.AppPreferences
6564
import dagger.Module
6665
import dagger.Provides
6766
import okhttp3.OkHttpClient
@@ -180,15 +179,13 @@ class RepositoryModule {
180179
chatMessagesDao: ChatMessagesDao,
181180
chatBlocksDao: ChatBlocksDao,
182181
dataSource: ChatNetworkDataSource,
183-
appPreferences: AppPreferences,
184182
networkMonitor: NetworkMonitor,
185183
userProvider: CurrentUserProviderNew
186184
): ChatMessageRepository {
187185
return OfflineFirstChatRepository(
188186
chatMessagesDao,
189187
chatBlocksDao,
190188
dataSource,
191-
appPreferences,
192189
networkMonitor,
193190
userProvider
194191
)

app/src/main/java/com/nextcloud/talk/data/network/NetworkMonitor.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
* Nextcloud Talk - Android Client
33
*
44
* SPDX-FileCopyrightText: 2024 Julius Linus <[email protected]>
5+
* SPDX-FileCopyrightText: 2024 Marcel Hibbe <[email protected]>
56
* SPDX-License-Identifier: GPL-3.0-or-later
67
*/
78

89
package com.nextcloud.talk.data.network
910

1011
import androidx.lifecycle.LiveData
11-
import kotlinx.coroutines.flow.Flow
12+
import kotlinx.coroutines.flow.StateFlow
1213

1314
/**
1415
* Utility for reporting app connectivity status.
@@ -17,7 +18,7 @@ interface NetworkMonitor {
1718
/**
1819
* Returns the device's current connectivity status.
1920
*/
20-
val isOnline: Flow<Boolean>
21+
val isOnline: StateFlow<Boolean>
2122

2223
/**
2324
* Returns the device's current connectivity status as LiveData for better interop with Java code.

app/src/main/java/com/nextcloud/talk/data/network/NetworkMonitorImpl.kt

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Nextcloud Talk - Android Client
33
*
44
* SPDX-FileCopyrightText: 2024 Julius Linus <[email protected]>
5+
* SPDX-FileCopyrightText: 2024 Marcel Hibbe <[email protected]>
56
* SPDX-License-Identifier: GPL-3.0-or-later
67
*/
78

@@ -11,67 +12,75 @@ import android.content.Context
1112
import android.net.ConnectivityManager
1213
import android.net.Network
1314
import android.net.NetworkCapabilities
14-
import android.net.NetworkRequest.Builder
15+
import android.util.Log
1516
import androidx.core.content.getSystemService
1617
import androidx.lifecycle.LiveData
1718
import androidx.lifecycle.asLiveData
19+
import kotlinx.coroutines.CoroutineScope
1820
import kotlinx.coroutines.Dispatchers
1921
import kotlinx.coroutines.channels.awaitClose
20-
import kotlinx.coroutines.flow.Flow
22+
import kotlinx.coroutines.flow.SharingStarted
23+
import kotlinx.coroutines.flow.StateFlow
2124
import kotlinx.coroutines.flow.callbackFlow
22-
import kotlinx.coroutines.flow.conflate
23-
import kotlinx.coroutines.flow.distinctUntilChanged
24-
import kotlinx.coroutines.flow.flowOn
25+
import kotlinx.coroutines.flow.stateIn
2526
import javax.inject.Inject
2627
import javax.inject.Singleton
2728

2829
@Singleton
2930
class NetworkMonitorImpl @Inject constructor(
3031
private val context: Context
3132
) : NetworkMonitor {
33+
34+
private val connectivityManager = context.getSystemService<ConnectivityManager>()!!
35+
3236
override val isOnlineLiveData: LiveData<Boolean>
3337
get() = isOnline.asLiveData()
3438

35-
override val isOnline: Flow<Boolean> = callbackFlow {
36-
val connectivityManager = context.getSystemService<ConnectivityManager>()
37-
if (connectivityManager == null) {
38-
channel.trySend(false)
39-
channel.close()
40-
return@callbackFlow
41-
}
42-
43-
val networkRequest = Builder()
44-
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
45-
.build()
39+
override val isOnline: StateFlow<Boolean> get() = _isOnline
4640

47-
val networkCallback = object : ConnectivityManager.NetworkCallback() {
48-
private val networks = mutableSetOf<Network>()
41+
private val _isOnline: StateFlow<Boolean> = callbackFlow {
42+
val callback = object : ConnectivityManager.NetworkCallback() {
43+
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
44+
super.onCapabilitiesChanged(network, networkCapabilities)
45+
val connected = networkCapabilities.hasCapability(
46+
NetworkCapabilities.NET_CAPABILITY_VALIDATED
47+
)
48+
trySend(connected)
49+
Log.d(TAG, "Network status changed: $connected")
50+
}
4951

50-
override fun onAvailable(network: Network) {
51-
networks += network
52-
channel.trySend(true)
52+
override fun onUnavailable() {
53+
super.onUnavailable()
54+
trySend(false)
55+
Log.d(TAG, "Network status: onUnavailable")
5356
}
5457

5558
override fun onLost(network: Network) {
56-
networks -= network
57-
channel.trySend(networks.isNotEmpty())
59+
super.onLost(network)
60+
trySend(false)
61+
Log.d(TAG, "Network status: onLost")
5862
}
59-
}
6063

61-
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
64+
override fun onAvailable(network: Network) {
65+
super.onAvailable(network)
66+
trySend(true)
67+
Log.d(TAG, "Network status: onAvailable")
68+
}
69+
}
6270

63-
channel.trySend(connectivityManager.isCurrentlyConnected())
71+
connectivityManager.registerDefaultNetworkCallback(callback)
6472

6573
awaitClose {
66-
connectivityManager.unregisterNetworkCallback(networkCallback)
74+
connectivityManager.unregisterNetworkCallback(callback)
6775
}
68-
}
69-
.distinctUntilChanged()
70-
.flowOn(Dispatchers.IO)
71-
.conflate()
76+
}.stateIn(
77+
CoroutineScope(Dispatchers.IO),
78+
SharingStarted.WhileSubscribed(COROUTINE_TIMEOUT),
79+
false
80+
)
7281

73-
private fun ConnectivityManager.isCurrentlyConnected() =
74-
activeNetwork
75-
?.let(::getNetworkCapabilities)
76-
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false
82+
companion object {
83+
private val TAG = NetworkMonitorImpl::class.java.simpleName
84+
private const val COROUTINE_TIMEOUT = 5000L
85+
}
7786
}

app/src/main/java/com/nextcloud/talk/ui/dialog/MessageActionsDialog.kt

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ import io.reactivex.Observer
5151
import io.reactivex.android.schedulers.AndroidSchedulers
5252
import io.reactivex.disposables.Disposable
5353
import io.reactivex.schedulers.Schedulers
54-
import kotlinx.coroutines.flow.first
5554
import kotlinx.coroutines.launch
5655
import java.util.Date
5756
import javax.inject.Inject
@@ -134,7 +133,7 @@ class MessageActionsDialog(
134133
initMenuAddToNote(
135134
!message.isDeleted &&
136135
!ConversationUtils.isNoteToSelfConversation(currentConversation) &&
137-
networkMonitor.isOnline.first(),
136+
networkMonitor.isOnline.value,
138137
state.roomToken
139138
)
140139
}
@@ -147,16 +146,16 @@ class MessageActionsDialog(
147146
}
148147
}
149148

150-
initMenuItems()
149+
initMenuItems(networkMonitor.isOnline.value)
151150
}
152151

153-
private fun initMenuItems() {
152+
private fun initMenuItems(isOnline: Boolean) {
154153
this.lifecycleScope.launch {
155154
initMenuItemTranslate(
156155
!message.isDeleted &&
157156
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
158157
CapabilitiesUtil.isTranslationsSupported(spreedCapabilities) &&
159-
networkMonitor.isOnline.first()
158+
isOnline
160159
)
161160
initMenuEditorDetails(message.lastEditTimestamp!! != 0L && !message.isDeleted)
162161
initMenuReplyToMessage(message.replyable && hasChatPermission)
@@ -165,30 +164,30 @@ class MessageActionsDialog(
165164
hasUserId(user) &&
166165
hasUserActorId(message) &&
167166
currentConversation?.type != ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
168-
networkMonitor.isOnline.first()
167+
isOnline
169168
)
170169
initMenuEditMessage(isMessageEditable)
171-
initMenuDeleteMessage(showMessageDeletionButton && networkMonitor.isOnline.first())
170+
initMenuDeleteMessage(showMessageDeletionButton && isOnline)
172171
initMenuForwardMessage(
173172
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
174173
!(message.isDeletedCommentMessage || message.isDeleted) &&
175-
networkMonitor.isOnline.first()
174+
isOnline
176175
)
177176
initMenuRemindMessage(
178177
!message.isDeleted &&
179178
hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.REMIND_ME_LATER) &&
180179
currentConversation!!.remoteServer.isNullOrEmpty() &&
181-
networkMonitor.isOnline.first()
180+
isOnline
182181
)
183182
initMenuMarkAsUnread(
184183
message.previousMessageId > NO_PREVIOUS_MESSAGE_ID &&
185184
ChatMessage.MessageType.SYSTEM_MESSAGE != message.getCalculateMessageType() &&
186-
networkMonitor.isOnline.first()
185+
isOnline
187186
)
188-
initMenuShare(messageHasFileAttachment || messageHasRegularText && networkMonitor.isOnline.first())
187+
initMenuShare(messageHasFileAttachment || messageHasRegularText && isOnline)
189188
initMenuItemOpenNcApp(
190189
ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE == message.getCalculateMessageType() &&
191-
networkMonitor.isOnline.first()
190+
isOnline
192191
)
193192
initMenuItemSave(message.getCalculateMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE)
194193
}

0 commit comments

Comments
 (0)