mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-08 13:29:49 +01:00
add option to create thread
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
fd10937d68
commit
db62bd051d
@ -19,6 +19,7 @@ import com.nextcloud.talk.models.json.participants.TalkBan
|
||||
import com.nextcloud.talk.models.json.participants.TalkBanOverall
|
||||
import com.nextcloud.talk.models.json.profile.ProfileOverall
|
||||
import com.nextcloud.talk.models.json.testNotification.TestNotificationOverall
|
||||
import com.nextcloud.talk.models.json.threads.ThreadOverall
|
||||
import com.nextcloud.talk.models.json.userAbsence.UserAbsenceOverall
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
@ -285,4 +286,7 @@ interface NcApiCoroutines {
|
||||
|
||||
@DELETE
|
||||
suspend fun unbindRoom(@Header("Authorization") authorization: String, @Url url: String): GenericOverall
|
||||
|
||||
@POST
|
||||
suspend fun createThread(@Header("Authorization") authorization: String, @Url url: String): ThreadOverall
|
||||
}
|
||||
|
@ -4141,6 +4141,36 @@ class ChatActivity :
|
||||
}
|
||||
}
|
||||
|
||||
fun createThread(chatMessage: ChatMessage) {
|
||||
chatViewModel.createThread(
|
||||
credentials = conversationUser!!.getCredentials(),
|
||||
url = ApiUtils.getUrlForThread(
|
||||
version = chatApiVersion,
|
||||
baseUrl = conversationUser!!.baseUrl!!,
|
||||
token = roomToken,
|
||||
threadId = chatMessage.jsonMessageId
|
||||
)
|
||||
)
|
||||
|
||||
this.lifecycleScope.launch {
|
||||
chatViewModel.threadCreationState.collect { uiState ->
|
||||
when (uiState) {
|
||||
ChatViewModel.ThreadCreationUiState.None -> {
|
||||
}
|
||||
|
||||
is ChatViewModel.ThreadCreationUiState.Error -> {
|
||||
Log.e(TAG, "Error when creating thread")
|
||||
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
is ChatViewModel.ThreadCreationUiState.Success -> {
|
||||
openThread(chatMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun joinAudioCall() {
|
||||
startACall(true, false)
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.opengraph.Reference
|
||||
import com.nextcloud.talk.models.json.reminder.Reminder
|
||||
import com.nextcloud.talk.models.json.threads.ThreadOverall
|
||||
import com.nextcloud.talk.models.json.userAbsence.UserAbsenceOverall
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.Response
|
||||
@ -65,6 +66,7 @@ interface ChatNetworkDataSource {
|
||||
fun pullChatMessages(credentials: String, url: String, fieldMap: HashMap<String, Int>): Observable<Response<*>>
|
||||
fun deleteChatMessage(credentials: String, url: String): Observable<ChatOverallSingleMessage>
|
||||
fun createRoom(credentials: String, url: String, map: Map<String, String>): Observable<RoomOverall>
|
||||
suspend fun createThread(credentials: String, url: String): ThreadOverall
|
||||
fun setChatReadMarker(credentials: String, url: String, previousMessageId: Int): Observable<GenericOverall>
|
||||
suspend fun editChatMessage(credentials: String, url: String, text: String): ChatOverallSingleMessage
|
||||
suspend fun getOutOfOfficeStatusForUser(credentials: String, baseUrl: String, userId: String): UserAbsenceOverall
|
||||
|
@ -17,6 +17,7 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.opengraph.Reference
|
||||
import com.nextcloud.talk.models.json.reminder.Reminder
|
||||
import com.nextcloud.talk.models.json.threads.ThreadOverall
|
||||
import com.nextcloud.talk.models.json.userAbsence.UserAbsenceOverall
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.message.SendMessageUtils
|
||||
@ -174,6 +175,9 @@ class RetrofitChatNetwork(
|
||||
it
|
||||
}
|
||||
|
||||
override suspend fun createThread(credentials: String, url: String): ThreadOverall =
|
||||
ncApiCoroutines.createThread(credentials, url)
|
||||
|
||||
override fun setChatReadMarker(
|
||||
credentials: String,
|
||||
url: String,
|
||||
|
@ -37,6 +37,7 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.opengraph.Reference
|
||||
import com.nextcloud.talk.models.json.reminder.Reminder
|
||||
import com.nextcloud.talk.models.json.threads.ThreadInfo
|
||||
import com.nextcloud.talk.models.json.userAbsence.UserAbsenceData
|
||||
import com.nextcloud.talk.repositories.reactions.ReactionsRepository
|
||||
import com.nextcloud.talk.ui.PlaybackSpeed
|
||||
@ -51,6 +52,8 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
@ -158,6 +161,9 @@ class ChatViewModel @Inject constructor(
|
||||
val getContextChatMessages: LiveData<List<ChatMessageJson>>
|
||||
get() = _getContextChatMessages
|
||||
|
||||
private val _threadCreationState = MutableStateFlow<ThreadCreationUiState>(ThreadCreationUiState.None)
|
||||
val threadCreationState: StateFlow<ThreadCreationUiState> = _threadCreationState
|
||||
|
||||
val getOpenGraph: LiveData<Reference>
|
||||
get() = _getOpenGraph
|
||||
private val _getOpenGraph: MutableLiveData<Reference> = MutableLiveData()
|
||||
@ -424,6 +430,13 @@ class ChatViewModel @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun createThread(credentials: String, url: String) {
|
||||
viewModelScope.launch {
|
||||
val thread = chatNetworkDataSource.createThread(credentials, url)
|
||||
_threadCreationState.value = ThreadCreationUiState.Success(thread.ocs?.data)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMessages(withCredentials: String, withUrl: String) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(BundleKeys.KEY_CHAT_URL, withUrl)
|
||||
@ -873,4 +886,10 @@ class ChatViewModel @Inject constructor(
|
||||
data class Success(val statusCode: Int) : UnbindRoomUiState()
|
||||
data class Error(val message: String) : UnbindRoomUiState()
|
||||
}
|
||||
|
||||
sealed class ThreadCreationUiState {
|
||||
data object None : ThreadCreationUiState()
|
||||
data class Success(val thread: ThreadInfo?) : ThreadCreationUiState()
|
||||
data class Error(val message: String) : ThreadCreationUiState()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.threads
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonObject
|
||||
data class Thread(
|
||||
@JsonField(name = ["id"])
|
||||
var id: Int = 0,
|
||||
|
||||
@JsonField(name = ["roomId"])
|
||||
var roomId: Int = 0,
|
||||
|
||||
@JsonField(name = ["lastMessageId"])
|
||||
var lastMessageId: Int = 0,
|
||||
|
||||
@JsonField(name = ["numReplies"])
|
||||
var numReplies: Int = 0
|
||||
) : Parcelable
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.threads
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonObject
|
||||
data class ThreadAttendee(
|
||||
@JsonField(name = ["notificationLevel"])
|
||||
var notificationLevel: Int = 0,
|
||||
|
||||
@JsonField(name = ["lastReadMessage"])
|
||||
var lastReadMessage: Int = 0,
|
||||
|
||||
@JsonField(name = ["lastMentionMessage"])
|
||||
var lastMentionMessage: Int = 0,
|
||||
|
||||
@JsonField(name = ["lastMentionDirect"])
|
||||
var lastMentionDirect: Int = 0,
|
||||
|
||||
@JsonField(name = ["readPrivacy"])
|
||||
var readPrivacy: Int = 0
|
||||
) : Parcelable
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.threads
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessageJson
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonObject
|
||||
data class ThreadInfo(
|
||||
@JsonField(name = ["thread"])
|
||||
var thread: Thread? = null,
|
||||
|
||||
@JsonField(name = ["attendee"])
|
||||
var attendee: ThreadAttendee? = null,
|
||||
|
||||
@JsonField(name = ["first"])
|
||||
var first: ChatMessageJson? = null,
|
||||
|
||||
@JsonField(name = ["last"])
|
||||
var last: ChatMessageJson? = null
|
||||
) : Parcelable
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.threads
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import com.nextcloud.talk.models.json.generic.GenericMeta
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonObject
|
||||
data class ThreadOCS(
|
||||
@JsonField(name = ["meta"])
|
||||
var meta: GenericMeta?,
|
||||
@JsonField(name = ["data"])
|
||||
var data: ThreadInfo? = null
|
||||
) : Parcelable {
|
||||
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
|
||||
constructor() : this(null, null)
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.threads
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonObject
|
||||
data class ThreadOverall(
|
||||
@JsonField(name = ["ocs"])
|
||||
var ocs: ThreadOCS? = null
|
||||
) : Parcelable {
|
||||
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
|
||||
constructor() : this(null)
|
||||
}
|
@ -144,6 +144,7 @@ class MessageActionsDialog(
|
||||
currentConversation?.type != ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
|
||||
isOnline
|
||||
)
|
||||
initMenuReplyInThread(true) // TODO: set visibility
|
||||
initMenuOpenThread(message.isThread && chatActivity.threadId == null)
|
||||
initMenuEditMessage(isMessageEditable)
|
||||
initMenuDeleteMessage(showMessageDeletionButton && isOnline)
|
||||
@ -412,6 +413,17 @@ class MessageActionsDialog(
|
||||
dialogMessageActionsBinding.menuReplyPrivately.visibility = getVisibility(visible)
|
||||
}
|
||||
|
||||
private fun initMenuReplyInThread(visible: Boolean) {
|
||||
if (visible) {
|
||||
dialogMessageActionsBinding.menuReplyInThread.setOnClickListener {
|
||||
chatActivity.createThread(message)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
dialogMessageActionsBinding.menuReplyInThread.visibility = getVisibility(visible)
|
||||
}
|
||||
|
||||
private fun initMenuOpenThread(visible: Boolean) {
|
||||
if (visible) {
|
||||
dialogMessageActionsBinding.menuOpenThread.setOnClickListener {
|
||||
|
@ -641,4 +641,12 @@ object ApiUtils {
|
||||
fun getUrlForProfile(baseUrl: String, userId: String): String {
|
||||
return "$baseUrl$OCS_API_VERSION/profile/$userId"
|
||||
}
|
||||
|
||||
fun getUrlForThreads(version: Int, baseUrl: String?, token: String): String {
|
||||
return getUrlForApi(version, baseUrl) + "/chat/" + token + "/threads"
|
||||
}
|
||||
|
||||
fun getUrlForThread(version: Int, baseUrl: String?, token: String, threadId: Int): String {
|
||||
return getUrlForThreads(version, baseUrl, token) + "/$threadId"
|
||||
}
|
||||
}
|
||||
|
@ -282,6 +282,39 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/menu_reply_in_thread"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/menu_icon_reply_in_thread"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:paddingStart="@dimen/standard_padding"
|
||||
android:paddingEnd="@dimen/zero"
|
||||
android:src="@drawable/outline_thread_unread_24"
|
||||
app:tint="@color/high_emphasis_menu_icon" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/menu_text_reply_in_thread"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:paddingStart="@dimen/standard_double_padding"
|
||||
android:paddingEnd="@dimen/standard_padding"
|
||||
android:text="@string/reply_in_thread"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/high_emphasis_text"
|
||||
android:textSize="@dimen/bottom_sheet_text_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/menu_open_thread"
|
||||
android:layout_width="match_parent"
|
||||
|
Loading…
Reference in New Issue
Block a user