Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,11 @@ class ChatActivity :
var myFirstMessage: CharSequence? = null
private var isLeavingRoom: Boolean = false

// The room is only joined while the chat is resumed, as onPause leaves it. A join requested in between
// (e.g. by a GetCapabilitiesInitialLoadState re-emitted after the leave reset it) is deferred until onResume.
private var isChatResumed: Boolean = false
private var isJoinRoomPending: Boolean = false

private var lastHandledHighlightNonce: Long? = null
private var pendingHighlightedMessageId: Long? = null
private var lastNoMoreResultsToastTime: Long = 0L
Expand Down Expand Up @@ -2089,6 +2094,8 @@ class ChatActivity :

logConversationInfos("onResume")

isChatResumed = true

pullChatMessagesPending = false

// reset in case a previously started leave failed (success already resets this in leaveRoomObserver)
Expand All @@ -2104,6 +2111,11 @@ class ChatActivity :
binding.let { viewThemeUtils.material.themeFAB(it.voiceRecordingLock) }

updateToolbarState()

if (isJoinRoomPending) {
isJoinRoomPending = false
joinRoomWithPassword()
}
}

private fun setupChatToolbarView() {
Expand Down Expand Up @@ -2942,6 +2954,8 @@ class ChatActivity :

logConversationInfos("onPause")

isChatResumed = false

eventBus.unregister(this)

webSocketInstance?.getSignalingMessageReceiver()?.removeListener(localParticipantMessageListener)
Expand All @@ -2958,6 +2972,10 @@ class ChatActivity :
Log.d(TAG, "not leaving room (leave already in progress)")
} else if (validSessionId()) {
leaveRoom(null)
} else if (chatViewModel.requestLeaveAfterJoin()) {
Log.d(TAG, "join in progress -> leaving room once it completes")
isJoinRoomPending = true
ApplicationWideCurrentRoomHolder.getInstance().clear()
} else {
Log.d(TAG, "not leaving room (validSessionId is false)")
ApplicationWideCurrentRoomHolder.getInstance().clear()
Expand Down Expand Up @@ -3016,6 +3034,12 @@ class ChatActivity :
}

private fun joinRoomWithPassword() {
if (!isChatResumed) {
Log.d(TAG, "joinRoomWithPassword - chat is not resumed, deferring join until onResume")
isJoinRoomPending = true
return
}

// if ApplicationWideCurrentRoomHolder contains a session (because a call is active), then keep the sessionId
if (ApplicationWideCurrentRoomHolder.getInstance().isCurrentRoom(
currentConversation!!.token,
Expand Down Expand Up @@ -3052,6 +3076,8 @@ class ChatActivity :
webSocketInstance?.joinRoomWithRoomTokenAndSession("", sessionIdAfterRoomJoined)
}
sessionIdAfterRoomJoined = "0"
// rejoin on the next resume, even if no conversation update re-emits GetCapabilitiesInitialLoadState
isJoinRoomPending = true

// FIXME Fix API checking with guests?
val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4, 1))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,12 @@ class ChatViewModel @AssistedInject constructor(
lateinit var currentLifeCycleFlag: LifeCycleFlag
val disposableSet = mutableSetOf<Disposable>()

// A join request is not disposed when the chat is paused: the server may already have created the session,
// so if the chat was left in the meantime it is left again once the join completes (see [requestLeaveAfterJoin]).
var isJoinRoomInFlight: Boolean = false
private set
private var isLeaveAfterJoinRequested: Boolean = false

var messageDraft: MessageDraft = MessageDraft()
var hiddenUpcomingEvent: String? = null
lateinit var participantPermissions: ParticipantPermissions
Expand Down Expand Up @@ -1861,12 +1867,47 @@ class ChatViewModel @AssistedInject constructor(
}

fun joinRoom(user: User, token: String, roomPassword: String) {
if (isJoinRoomInFlight) {
// the chat was resumed again before the running join completed, so it keeps the joined session
Log.d(TAG, "joinRoom - join already in progress, not leaving the room after it")
isLeaveAfterJoinRequested = false
return
}
isJoinRoomInFlight = true
isLeaveAfterJoinRequested = false
_joinRoomViewState.value = JoinRoomStartState
chatNetworkDataSource.joinRoom(user, token, roomPassword)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.retry(JOIN_ROOM_RETRY_COUNT)
?.subscribe(JoinRoomObserver())
?.subscribe(JoinRoomObserver(user, token))
}

/**
* Requests leaving the room as soon as the running join request completes, instead of reporting the join.
* Returns false if no join request is running.
*/
fun requestLeaveAfterJoin(): Boolean {
if (!isJoinRoomInFlight) {
return false
}
isLeaveAfterJoinRequested = true
return true
}

@Suppress("Detekt.TooGenericExceptionCaught")
private fun leaveRoomAfterJoin(user: User, token: String) {
val credentials = ApiUtils.getCredentials(user.username, user.token) ?: return
val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, 1))
val url = ApiUtils.getUrlForParticipantsActive(apiVersion, user.baseUrl!!, token)
appScope.launch {
try {
val result = chatNetworkDataSource.leaveRoom(credentials, url)
Log.d(TAG, "leaveRoomAfterJoin completed with OCS status: ${result.ocs?.meta?.statusCode}")
} catch (e: Exception) {
Log.e(TAG, "leaveRoomAfterJoin - ERROR", e)
}
}
}

fun setReminder(user: User, roomToken: String, messageId: String, timestamp: Int, chatApiVersion: Int) {
Expand Down Expand Up @@ -2542,17 +2583,26 @@ class ChatViewModel @AssistedInject constructor(
return chatRepository.getMessage(messageId, bundle)
}

inner class JoinRoomObserver : Observer<ConversationModel> {
inner class JoinRoomObserver(private val user: User, private val token: String) : Observer<ConversationModel> {
override fun onSubscribe(d: Disposable) {
disposableSet.add(d)
// not added to disposableSet, see isJoinRoomInFlight
}

override fun onNext(conversationModel: ConversationModel) {
isJoinRoomInFlight = false
if (isLeaveAfterJoinRequested) {
isLeaveAfterJoinRequested = false
Log.d(TAG, "joinRoom completed after the chat was left -> leaving the room again")
leaveRoomAfterJoin(user, token)
return
}
_joinRoomViewState.value = JoinRoomSuccessState(conversationModel)
}

override fun onError(e: Throwable) {
Log.e(TAG, "Error when joining room")
isJoinRoomInFlight = false
isLeaveAfterJoinRequested = false
_joinRoomViewState.value = JoinRoomErrorState
}

Expand Down
Loading