Skip to content
Open
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
33 changes: 28 additions & 5 deletions app/src/main/kotlin/com/wire/android/ui/common/AttachmentButton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,42 @@ import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography

@Composable
fun AttachmentButton(@DrawableRes icon: Int, labelStyle: TextStyle, modifier: Modifier = Modifier, text: String = "", onClick: () -> Unit) {
fun AttachmentButton(
@DrawableRes icon: Int,
labelStyle: TextStyle,
modifier: Modifier = Modifier,
text: String = "",
enabled: Boolean = true,
onClick: () -> Unit,
) {
val buttonBackgroundColor = if (enabled) {
MaterialTheme.wireColorScheme.primaryButtonEnabled
} else {
MaterialTheme.wireColorScheme.primaryButtonDisabled
}
val buttonContentColor = if (enabled) {
MaterialTheme.wireColorScheme.onPrimaryButtonEnabled
} else {
MaterialTheme.wireColorScheme.onPrimaryButtonDisabled
}
val labelColor = if (enabled) {
MaterialTheme.wireColorScheme.onBackground
} else {
MaterialTheme.wireColorScheme.secondaryText
}

Column(
modifier = modifier
.padding(dimensions().spacing4x)
.clip(RoundedCornerShape(size = MaterialTheme.wireDimensions.buttonSmallCornerSize))
.clickable { onClick() }
.clickable(enabled = enabled) { onClick() }
.padding(dimensions().spacing8x),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(dimensions().attachmentButtonSize)
.background(MaterialTheme.wireColorScheme.primaryButtonEnabled, CircleShape)
.background(buttonBackgroundColor, CircleShape)
.padding(dimensions().spacing2x)
) {
Image(
Expand All @@ -70,7 +93,7 @@ fun AttachmentButton(@DrawableRes icon: Int, labelStyle: TextStyle, modifier: Mo
modifier = Modifier
.padding(dimensions().spacing8x)
.align(Alignment.Center),
colorFilter = ColorFilter.tint(MaterialTheme.wireColorScheme.onPrimaryButtonEnabled)
colorFilter = ColorFilter.tint(buttonContentColor)
)
}
VerticalSpace.x4()
Expand All @@ -80,7 +103,7 @@ fun AttachmentButton(@DrawableRes icon: Int, labelStyle: TextStyle, modifier: Mo
maxLines = 2,
textAlign = TextAlign.Center,
style = labelStyle,
color = MaterialTheme.wireColorScheme.onBackground,
color = labelColor,
)
Spacer(modifier = Modifier.weight(1F))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.wire.kalium.logic.data.id.MessageId

data class MessageComposerViewState(
val isFileSharingEnabled: Boolean = true,
val areAttachmentOptionsEnabled: Boolean = true,
val interactionAvailability: InteractionAvailability = InteractionAvailability.ENABLED,
val mentionSearchResult: List<Contact> = listOf(),
val mentionSearchQuery: String = String.EMPTY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,46 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.ramcosta.composedestinations.generated.app.navArgs
import com.wire.android.datastore.GlobalDataStore
import com.wire.android.mapper.ContactMapper
import com.wire.android.ui.home.conversations.ConversationNavArgs
import com.wire.android.ui.home.conversations.InvalidLinkDialogState
import com.wire.android.ui.home.conversations.MessageComposerViewState
import com.wire.android.ui.home.conversations.VisitLinkDialogState
import com.wire.android.ui.home.conversations.model.UIMessage
import com.ramcosta.composedestinations.generated.app.navArgs
import com.wire.android.util.EMPTY
import com.wire.android.util.FileManager
import com.wire.android.util.dispatchers.DispatcherProvider
import com.wire.kalium.logic.configuration.FileSharingStatus
import com.wire.kalium.logic.data.asset.KaliumFileSystem
import com.wire.kalium.logic.data.conversation.Conversation.TypingIndicatorMode
import com.wire.kalium.logic.data.conversation.ConversationDetails
import com.wire.kalium.logic.data.conversation.InteractionAvailability
import com.wire.kalium.logic.data.id.QualifiedID
import com.wire.kalium.logic.data.message.SelfDeletionTimer
import com.wire.kalium.logic.data.user.OtherUser
import com.wire.kalium.logic.data.user.SelfUser
import com.wire.kalium.logic.feature.call.usecase.ObserveEstablishedCallsUseCase
import com.wire.kalium.logic.feature.conversation.IsInteractionAvailableResult
import com.wire.kalium.logic.feature.conversation.MarkConversationAsReadLocallyUseCase
import com.wire.kalium.logic.feature.conversation.MembersToMentionUseCase
import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseCase
import com.wire.kalium.logic.feature.conversation.ObserveConversationInteractionAvailabilityUseCase
import com.wire.kalium.logic.feature.conversation.MarkConversationAsReadLocallyUseCase
import com.wire.kalium.logic.feature.conversation.SendTypingEventUseCase
import com.wire.kalium.logic.feature.conversation.UpdateConversationReadDateUseCase
import com.wire.kalium.logic.feature.message.ephemeral.EnqueueMessageSelfDeletionUseCase
import com.wire.kalium.logic.feature.selfDeletingMessages.PersistNewSelfDeletionTimerUseCase
import com.wire.kalium.logic.feature.session.CurrentSessionFlowUseCase
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import com.wire.kalium.logic.feature.user.IsFileSharingEnabledUseCase
import com.wire.kalium.logic.feature.user.ObserveSelfUserUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
Expand All @@ -74,6 +80,8 @@ class MessageComposerViewModel @Inject constructor(
val savedStateHandle: SavedStateHandle,
private val dispatchers: DispatcherProvider,
private val isFileSharingEnabled: IsFileSharingEnabledUseCase,
private val observeConversationDetails: ObserveConversationDetailsUseCase,
private val observeSelfUser: ObserveSelfUserUseCase,
private val observeConversationInteractionAvailability: ObserveConversationInteractionAvailabilityUseCase,
private val updateConversationReadDate: UpdateConversationReadDateUseCase,
private val markConversationAsReadLocally: MarkConversationAsReadLocallyUseCase,
Expand Down Expand Up @@ -116,6 +124,7 @@ class MessageComposerViewModel @Inject constructor(
initTempWritableImageUri()
observeIsTypingAvailable()
setFileSharingStatus()
observeAttachmentOptionsAvailability()
getEnterToSendState()
observeCallState()
}
Expand Down Expand Up @@ -199,6 +208,38 @@ class MessageComposerViewModel @Inject constructor(
}
}

private fun observeAttachmentOptionsAvailability() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not aware of this "Viewers profile" feature but it seems like this does not allow uploading to user from other team. This is a clear business logic and must be placed into kalium use case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we disable attachment options, should we also disable sharing files into this conversation from other apps?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be better to to add a real restriction on the logic level to make sure we do not depend on the enabled/disabled button states.
Enable/disable buttons will only visualize the restriction.

viewModelScope.launch {

combine(
observeSelfUser().distinctUntilChanged(),
observeConversationDetails(conversationId)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observing all conversations details just for reading two fields (wireCell and teamId) is probably an overkill.
Also this may update frequently causing UI updates.

.filterIsInstance<ObserveConversationDetailsUseCase.Result.Success>()
.map { it.conversationDetails }
.distinctUntilChanged(),
) { selfUser, conversationDetails ->
canUseAttachmentOptions(
selfUser = selfUser,
conversationDetails = conversationDetails,
)
}.collectLatest { areAttachmentOptionsEnabled ->
messageComposerViewState.value = messageComposerViewState.value.copy(
areAttachmentOptionsEnabled = areAttachmentOptionsEnabled
)
}
}
}

private fun canUseAttachmentOptions(
selfUser: SelfUser,
conversationDetails: ConversationDetails,
): Boolean {
val isCellsConversation = (conversationDetails as? ConversationDetails.Group)?.wireCell != null
val isConversationOwnedBySelfTeam = conversationDetails.conversation.teamId == selfUser.teamId

return !(isCellsConversation && !isConversationOwnedBySelfTeam)
}

fun updateConversationReadDate(utcISO: String) {
val instant = Instant.parse(utcISO)
lastReadInstant = instant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ fun AdditionalOptionsMenu(
isEditing: Boolean,
isMentionActive: Boolean,
isFileSharingEnabled: Boolean,
areAttachmentOptionsEnabled: Boolean,
onAdditionalOptionsMenuClicked: () -> Unit,
onMentionButtonClicked: (() -> Unit),
onPingOptionClicked: () -> Unit,
Expand Down Expand Up @@ -75,7 +76,8 @@ fun AdditionalOptionsMenu(
onRichEditingButtonClicked = onRichEditingButtonClicked,
onPingClicked = onPingOptionClicked,
onDrawingModeClicked = onDrawingModeClicked,
isFileSharingEnabled = isFileSharingEnabled
isFileSharingEnabled = isFileSharingEnabled,
areAttachmentOptionsEnabled = areAttachmentOptionsEnabled,
)
}

Expand All @@ -94,6 +96,7 @@ fun AdditionalOptionsMenu(
@Composable
fun AdditionalOptionSubMenu(
isFileSharingEnabled: Boolean,
areAttachmentOptionsEnabled: Boolean,
optionsVisible: Boolean,
onPermissionPermanentlyDenied: (type: ConversationActionPermissionType) -> Unit,
onLocationPickerClicked: () -> Unit,
Expand All @@ -115,6 +118,7 @@ fun AdditionalOptionSubMenu(
tempWritableImageUri = tempWritableImageUri,
tempWritableVideoUri = tempWritableVideoUri,
isFileSharingEnabled = isFileSharingEnabled,
areAttachmentOptionsEnabled = areAttachmentOptionsEnabled,
onRecordAudioMessageClicked = onRecordAudioMessageClicked,
onLocationPickerClicked = onLocationPickerClicked,
onPermissionPermanentlyDenied = onPermissionPermanentlyDenied,
Expand All @@ -139,6 +143,7 @@ fun AttachmentAndAdditionalOptionsMenuItems(
attachmentsVisible: Boolean,
isMentionActive: Boolean,
isFileSharingEnabled: Boolean,
areAttachmentOptionsEnabled: Boolean,
onMentionButtonClicked: () -> Unit,
onSelfDeletionOptionButtonClicked: (SelfDeletionTimer) -> Unit,
modifier: Modifier = Modifier,
Expand All @@ -163,7 +168,8 @@ fun AttachmentAndAdditionalOptionsMenuItems(
onGifButtonClicked = onGifButtonClicked,
onRichEditingButtonClicked = onRichEditingButtonClicked,
onDrawingModeClicked = onDrawingModeClicked,
isFileSharingEnabled = isFileSharingEnabled
isFileSharingEnabled = isFileSharingEnabled,
areAttachmentOptionsEnabled = areAttachmentOptionsEnabled,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
tempWritableImageUri: Uri?,
tempWritableVideoUri: Uri?,
isFileSharingEnabled: Boolean,
areAttachmentOptionsEnabled: Boolean,
onLocationPickerClicked: () -> Unit,
onPermissionPermanentlyDenied: (type: ConversationActionPermissionType) -> Unit,
modifier: Modifier = Modifier,
Expand All @@ -80,6 +81,7 @@

val attachmentOptions = buildAttachmentOptionItems(
isFileSharingEnabled = isFileSharingEnabled,
areAttachmentOptionsEnabled = areAttachmentOptionsEnabled,
tempWritableImageUri = tempWritableImageUri,
tempWritableVideoUri = tempWritableVideoUri,
onImagesPicked = onImagesPicked,
Expand Down Expand Up @@ -163,7 +165,8 @@
icon = option.icon,
labelStyle = labelStyle,
modifier = Modifier.scale(animatedScale),
text = stringResource(option.text)
text = stringResource(option.text),
enabled = option.isEnabled,
) { option.onClick() }
}
}
Expand Down Expand Up @@ -278,6 +281,7 @@
@Composable
private fun buildAttachmentOptionItems(
isFileSharingEnabled: Boolean,
areAttachmentOptionsEnabled: Boolean,
tempWritableImageUri: Uri?,
tempWritableVideoUri: Uri?,
onImagesPicked: (List<Uri>) -> Unit,
Expand Down Expand Up @@ -311,39 +315,44 @@
with(localFeatureVisibilityFlags) {
add(
AttachmentOptionItem(
isFileSharingEnabled,
R.string.attachment_share_file,
R.drawable.ic_attach_file
shouldShow = isFileSharingEnabled,
isEnabled = areAttachmentOptionsEnabled,
text = R.string.attachment_share_file,
icon = R.drawable.ic_attach_file,
) { fileFlow.launch() }
)
add(
AttachmentOptionItem(
isFileSharingEnabled,
R.string.attachment_share_image,
R.drawable.ic_gallery
shouldShow = isFileSharingEnabled,
isEnabled = areAttachmentOptionsEnabled,
text = R.string.attachment_share_image,
icon = R.drawable.ic_gallery,
) { galleryFlow.launch() }
)
add(
AttachmentOptionItem(
isFileSharingEnabled,
R.string.attachment_take_photo,
R.drawable.ic_camera
shouldShow = isFileSharingEnabled,
isEnabled = areAttachmentOptionsEnabled,
text = R.string.attachment_take_photo,
icon = R.drawable.ic_camera,
) { takePictureFlow?.launch() }
)
add(
AttachmentOptionItem(
isFileSharingEnabled,
R.string.attachment_record_video,
R.drawable.ic_video
shouldShow = isFileSharingEnabled,
isEnabled = areAttachmentOptionsEnabled,
text = R.string.attachment_record_video,
icon = R.drawable.ic_video,
) { captureVideoFlow?.launch() }
)
if (AudioMessagesIcon) {
add(
AttachmentOptionItem(
isFileSharingEnabled,
R.string.attachment_voice_message,
R.drawable.ic_mic_on,
onRecordAudioMessageClicked
shouldShow = isFileSharingEnabled,
isEnabled = areAttachmentOptionsEnabled,
text = R.string.attachment_voice_message,
icon = R.drawable.ic_mic_on,
onClick = onRecordAudioMessageClicked,
)
)
}
Expand All @@ -363,6 +372,7 @@

private data class AttachmentOptionItem(
val shouldShow: Boolean = true,
val isEnabled: Boolean = true,

Check warning on line 375 in app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/AttachmentOptions.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/com/wire/android/ui/home/messagecomposer/AttachmentOptions.kt#L375

Added line #L375 was not covered by tests
@StringRes val text: Int,
@DrawableRes val icon: Int,
val onClick: () -> Unit
Expand All @@ -377,6 +387,7 @@
onImagesPicked = {},
onAttachmentPicked = {},
isFileSharingEnabled = true,
areAttachmentOptionsEnabled = true,
tempWritableImageUri = null,
tempWritableVideoUri = null,
onRecordAudioMessageClicked = {},
Expand All @@ -398,6 +409,7 @@
onAttachmentPicked = {},
onImagesPicked = {},
isFileSharingEnabled = true,
areAttachmentOptionsEnabled = true,
tempWritableImageUri = null,
tempWritableVideoUri = null,
onRecordAudioMessageClicked = {},
Expand All @@ -420,6 +432,7 @@
onAttachmentPicked = {},
onImagesPicked = {},
isFileSharingEnabled = true,
areAttachmentOptionsEnabled = true,
tempWritableImageUri = null,
tempWritableVideoUri = null,
onRecordAudioMessageClicked = {},
Expand All @@ -442,6 +455,7 @@
onAttachmentPicked = {},
onImagesPicked = {},
isFileSharingEnabled = true,
areAttachmentOptionsEnabled = true,
tempWritableImageUri = null,
tempWritableVideoUri = null,
onRecordAudioMessageClicked = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,13 @@ fun EnabledMessageComposer(
additionalOptionStateHolder.toRichTextEditing()
},
onCloseRichEditingButtonClicked = additionalOptionStateHolder::toAttachmentAndAdditionalOptionsMenu,
onDrawingModeClicked = openDrawingCanvas,
isFileSharingEnabled = messageComposerViewState.value.isFileSharingEnabled
onDrawingModeClicked = {
if (messageComposerViewState.value.areAttachmentOptionsEnabled) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for an extra condition here since the button will be disabled when areAttachmentOptionsEnabled == false

openDrawingCanvas()
}
},
isFileSharingEnabled = messageComposerViewState.value.isFileSharingEnabled,
areAttachmentOptionsEnabled = messageComposerViewState.value.areAttachmentOptionsEnabled,
)
}
}
Expand Down Expand Up @@ -453,6 +458,7 @@ fun EnabledMessageComposer(
AdditionalOptionSubMenu(
optionsVisible = inputStateHolder.optionsVisible,
isFileSharingEnabled = messageComposerViewState.value.isFileSharingEnabled,
areAttachmentOptionsEnabled = messageComposerViewState.value.areAttachmentOptionsEnabled,
additionalOptionsState = additionalOptionStateHolder.additionalOptionsSubMenuState,
onRecordAudioMessageClicked = {
if (!messageComposerViewState.value.isCallOngoing) {
Expand Down
Loading
Loading