Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,4 @@ freeline_project_description.json

/gradle/verification-keyring.gpg
/.claude/settings.local.json
/.artifacts/
25 changes: 0 additions & 25 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ import com.nextcloud.talk.events.ProximitySensorEvent
import com.nextcloud.talk.events.WebSocketCommunicationEvent
import com.nextcloud.talk.models.ExternalSignalingServer
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.models.domain.ConversationModel.Companion.checkIfVoiceRoom
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomOverall
Expand All @@ -117,6 +116,7 @@ import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.CapabilitiesUtil
import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability
import com.nextcloud.talk.utils.CapabilitiesUtil.isCallRecordingAvailable
import com.nextcloud.talk.utils.ConversationUtils.checkIfVoiceRoom
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
import com.nextcloud.talk.utils.ReceiverFlag
import com.nextcloud.talk.utils.SpreedFeatures
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import com.nextcloud.talk.models.json.chatprobeattachmentfolder.ProbeConversatio
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.hovercard.HoverCardOverall
import com.nextcloud.talk.models.json.invitation.InvitationOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
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.hovercard.HoverCardOverall
import com.nextcloud.talk.models.json.reactions.ReactionsOverall
import com.nextcloud.talk.models.json.status.StatusOverall
import com.nextcloud.talk.models.json.status.predefined.PredefinedStatusOverall
Expand All @@ -46,6 +46,7 @@ import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.Field
import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.Header
Expand Down Expand Up @@ -82,6 +83,14 @@ interface NcApiCoroutines {
@QueryMap options: Map<String, String>?
): RoomOverall

@FormUrlEncoded
@POST
suspend fun createRoomForm(
@Header("Authorization") authorization: String?,
@Url url: String?,
@FieldMap options: Map<String, String>?
): RoomOverall

@POST
suspend fun createRoomWithBody(
@Header("Authorization") authorization: String?,
Expand Down
12 changes: 8 additions & 4 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
import com.nextcloud.talk.location.LocationPickerActivity
import com.nextcloud.talk.models.ExternalSignalingServer
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.models.domain.ConversationModel.Companion.checkIfVoiceRoom
import com.nextcloud.talk.models.json.capabilities.SpreedCapability
import com.nextcloud.talk.models.json.chat.ChatMessageJson
import com.nextcloud.talk.models.json.conversations.ConversationEnums
Expand Down Expand Up @@ -175,6 +174,7 @@ import com.nextcloud.talk.utils.CapabilitiesUtil.retentionOfClassifiedRoom
import com.nextcloud.talk.utils.CapabilitiesUtil.retentionOfSIPRoom
import com.nextcloud.talk.utils.ContactUtils
import com.nextcloud.talk.utils.ConversationUtils
import com.nextcloud.talk.utils.ConversationUtils.checkIfVoiceRoom
import com.nextcloud.talk.utils.DateConstants
import com.nextcloud.talk.utils.DateUtils
import com.nextcloud.talk.utils.DisplayUtils
Expand Down Expand Up @@ -1989,7 +1989,8 @@ class ChatActivity :
!isChatThread() &&
!ConversationUtils.isNoteToSelfConversation(conversation) &&
!isReadOnlyConversation() &&
!shouldShowLobby()
!shouldShowLobby() &&
!ConversationUtils.isChannel(conversation, spreedCapabilities)

private fun isSearchAvailable(capabilitiesReady: Boolean, conversation: ConversationModel?): Boolean =
capabilitiesReady &&
Expand Down Expand Up @@ -2267,8 +2268,11 @@ class ChatActivity :
}

private fun checkShowMessageInputView() {
val permissions = participantPermissionsFlow.value
val isChannel = ConversationUtils.isChannel(currentConversation, spreedCapabilities)

if (isReadOnlyConversation() ||
participantPermissionsFlow.value?.hasChatPermission() == false
(permissions?.hasChatPermission() == false && (!isChannel || permissions.hasReactPermission() == false))
) {
binding.fragmentContainerActivityChat.visibility = View.GONE
} else {
Expand Down Expand Up @@ -2815,7 +2819,7 @@ class ChatActivity :
)
}

public override fun onDestroy() {
override fun onDestroy() {
super.onDestroy()
logConversationInfos("onDestroy")

Expand Down
35 changes: 31 additions & 4 deletions app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.CapabilitiesUtil
import com.nextcloud.talk.utils.CharPolicy
import com.nextcloud.talk.utils.ConversationUtils
import com.nextcloud.talk.utils.DateUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.EmojiTextInputEditText
Expand Down Expand Up @@ -173,6 +174,12 @@ class MessageInputFragment : Fragment() {
val threadTitle = text.toString()
chatActivity.chatViewModel.messageDraft.threadTitle = threadTitle
}

viewLifecycleOwner.lifecycleScope.launch {
chatActivity.participantPermissionsFlow.collect {
handleButtonsVisibility()
}
}
}

@Suppress("LongMethod")
Expand All @@ -186,6 +193,7 @@ class MessageInputFragment : Fragment() {
initVoiceRecordButton()
initThreadHandling()
updateScheduledMessagesAvailability(hasScheduledMessages)
setReactionsOnly(state.spreedCapabilities)
}

is ChatViewModel.GetCapabilitiesInitialLoadState -> {
Expand All @@ -195,6 +203,7 @@ class MessageInputFragment : Fragment() {
initThreadHandling()
updateScheduledMessagesAvailability(hasScheduledMessages)
restoreState()
setReactionsOnly(state.spreedCapabilities)
}

else -> {}
Expand Down Expand Up @@ -330,6 +339,17 @@ class MessageInputFragment : Fragment() {
}
}

private fun setReactionsOnly(spreedCapabilities: SpreedCapability) {
val isReactionOnly = isReactionOnlyMode(spreedCapabilities)
if (isReactionOnly) {
binding.fragmentMessageInputView.setVisible(false)
binding.reactionOnlyAffordance.setVisible(true)
} else {
binding.fragmentMessageInputView.setVisible(true)
binding.reactionOnlyAffordance.setVisible(false)
}
}

private fun handleUI(isOnline: Boolean, connectionGained: Boolean) {
if (isOnline) {
if (connectionGained) {
Expand Down Expand Up @@ -694,16 +714,16 @@ class MessageInputFragment : Fragment() {
}
}

fun View.setVisible(isVisible: Boolean) {
visibility = if (isVisible) View.VISIBLE else View.GONE
}

private fun handleButtonsVisibility() {
if (!this::binding.isInitialized) {
Log.w(TAG, "binding not initialized in handleButtonsVisibility")
return
}

fun View.setVisible(isVisible: Boolean) {
visibility = if (isVisible) View.VISIBLE else View.GONE
}

val isEditModeActive = binding.fragmentEditView.editMessageView.isVisible
val isThreadCreateModeActive = binding.fragmentCreateThreadView.createThreadView.isVisible
val inputContainsText = binding.fragmentMessageInputView.messageInput.text.isNotEmpty()
Expand Down Expand Up @@ -1214,6 +1234,13 @@ class MessageInputFragment : Fragment() {
return jsonId != null
}

private fun isReactionOnlyMode(spreedCapabilities: SpreedCapability): Boolean {
val conversation = chatActivity.currentConversation
val permissions = chatActivity.participantPermissionsFlow.value
val isChannel = ConversationUtils.isChannel(conversation, spreedCapabilities)
return isChannel && permissions?.hasChatPermission() == false && permissions.hasReactPermission() == true
}

companion object {
fun newInstance() = MessageInputFragment()
private val TAG: String = MessageInputFragment::class.java.simpleName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ internal fun buildMessageActionsState(
val messageIsEditable = hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.EDIT_MESSAGES) &&
(messageHasRegularText || messageHasCaptions) &&
!isOlderThanTwentyFourHours &&
isUserAllowedByPrivileges
isUserAllowedByPrivileges &&
hasChatPermission
val isMessageEditable = isNoTimeLimitOnNoteToSelf || messageIsEditable || isMessageBotOneToOne

val hasDeleteMessagesUnlimitedCapability =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.nextcloud.talk.conversationlist.DirectShareHelper
import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository
import com.nextcloud.talk.conversationlist.data.network.OfflineFirstConversationsRepository
import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel.Companion.FOLLOWED_THREADS_EXIST
import com.nextcloud.talk.dagger.modules.ApplicationScope
import com.nextcloud.talk.data.database.mappers.toDomainModel
import com.nextcloud.talk.data.database.model.ChatMessageEntity
import com.nextcloud.talk.data.user.model.User
Expand Down Expand Up @@ -80,7 +81,6 @@ import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import com.nextcloud.talk.dagger.modules.ApplicationScope
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -493,6 +493,11 @@ class ChatViewModel @AssistedInject constructor(
replay = 1
)

private val isChannelFlow: Flow<Boolean> =
combine(conversationAndUserFlow, spreedCapabilities) { (conversation, _), capabilities ->
ConversationUtils.isChannel(conversation, capabilities)
}.distinctUntilChanged()

// ------------------------------
// Messages
// ------------------------------
Expand Down Expand Up @@ -528,10 +533,10 @@ class ChatViewModel @AssistedInject constructor(
.distinctUntilChanged()
.mapToChatMessages(user.userId!!)
}
}
.map { messages ->
messages.let(::handleSystemMessages)
.let(::handleThreadMessages)
.combine(isChannelFlow) { messages, isChannel ->
handleSystemMessages(messages, isChannel)
.let(::handleThreadMessages)
}
}
.distinctUntilChanged()

Expand Down Expand Up @@ -1364,7 +1369,11 @@ class ChatViewModel @AssistedInject constructor(
}
Log.d(TAG, "fetchNewMessagesWithRetry: no new messages after $POST_UPLOAD_FETCH_MAX_ATTEMPTS attempts")
}
private fun handleSystemMessages(chatMessageList: List<ChatMessage>): List<ChatMessage> {
private fun handleSystemMessages(chatMessageList: List<ChatMessage>, isChannel: Boolean): List<ChatMessage> {
if (isChannel) {
return chatMessageList.filter { !it.isSystemMessage }
}

fun shouldRemoveMessage(currentMessage: MutableMap.MutableEntry<Int, ChatMessage>): Boolean =
isInfoMessageAboutDeletion(currentMessage) ||
isReactionsMessage(currentMessage) ||
Expand Down
Loading
Loading