diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d998e886f0e..897d7058766 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -141,6 +141,12 @@
+
+
+
+
+
+
@@ -165,6 +171,12 @@
+
+
+
+
+
+
diff --git a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt
index bbe021f761a..f56d19c5dd1 100644
--- a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt
@@ -45,6 +45,7 @@ import com.wire.kalium.logic.feature.asset.GetAssetSizeLimitUseCase
import com.wire.kalium.logic.feature.asset.ScheduleNewAssetMessageResult
import com.wire.kalium.logic.feature.asset.ScheduleNewAssetMessageUseCase
import com.wire.kalium.logic.feature.conversation.ObserveConversationListDetailsUseCase
+import com.wire.kalium.logic.feature.message.SendTextMessageUseCase
import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveSelfDeletionTimerSettingsForConversationUseCase
import com.wire.kalium.logic.feature.selfDeletingMessages.PersistNewSelfDeletionTimerUseCase
import com.wire.kalium.logic.feature.selfDeletingMessages.SelfDeletionTimer
@@ -78,6 +79,7 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
private val observeConversationListDetails: ObserveConversationListDetailsUseCase,
private val fileManager: FileManager,
private val sendAssetMessage: ScheduleNewAssetMessageUseCase,
+ private val sendTextMessage: SendTextMessageUseCase,
private val kaliumFileSystem: KaliumFileSystem,
private val getAssetSizeLimit: GetAssetSizeLimitUseCase,
private val persistNewSelfDeletionTimerUseCase: PersistNewSelfDeletionTimerUseCase,
@@ -260,8 +262,7 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
appLogger.e("Received data from sharing intent ${incomingIntent.streamCount}")
importMediaState = importMediaState.copy(isImporting = true)
if (incomingIntent.streamCount == 0) {
- // if stream count is 0 the type will be text, we check the type to double check if it is text
- // todo : handle the text , we can get the text from incomingIntent.text
+ handleSharedText(incomingIntent.text.toString())
} else {
if (incomingIntent.isSingleShare) {
// ACTION_SEND
@@ -274,6 +275,10 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
importMediaState = importMediaState.copy(isImporting = false)
}
+ private fun handleSharedText(text: String) {
+ importMediaState = importMediaState.copy(importedText = text)
+ }
+
private suspend fun handleSingleIntent(
incomingIntent: ShareCompat.IntentReader,
activity: AppCompatActivity
@@ -303,45 +308,58 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
importMediaState = importMediaState.copy(importedAssets = importedMediaAssets)
}
- fun checkRestrictionsAndSendImportedMedia(onSent: (ConversationId) -> Unit) = viewModelScope.launch(dispatchers.default()) {
- val conversation = importMediaState.selectedConversationItem.firstOrNull() ?: return@launch
- val assetsToSend = importMediaState.importedAssets
+ fun checkRestrictionsAndSendImportedMedia(onSent: (ConversationId) -> Unit) =
+ viewModelScope.launch(dispatchers.default()) {
+ val conversation =
+ importMediaState.selectedConversationItem.firstOrNull() ?: return@launch
+ val assetsToSend = importMediaState.importedAssets
+ val textToSend = importMediaState.importedText
- if (assetsToSend.size > MAX_LIMIT_MEDIA_IMPORT) {
- onSnackbarMessage(ImportMediaSnackbarMessages.MaxAmountOfAssetsReached)
- } else {
- val jobs: MutableCollection = mutableListOf()
- assetsToSend.forEach { importedAsset ->
- val isImage = importedAsset is ImportedMediaAsset.Image
- val job = viewModelScope.launch {
- sendAssetMessage(
+ if (assetsToSend.size > MAX_LIMIT_MEDIA_IMPORT) {
+ onSnackbarMessage(ImportMediaSnackbarMessages.MaxAmountOfAssetsReached)
+ } else {
+ val jobs: MutableCollection = mutableListOf()
+
+ textToSend?.let {
+ sendTextMessage(
conversationId = conversation.conversationId,
- assetDataPath = importedAsset.dataPath,
- assetName = importedAsset.name,
- assetDataSize = importedAsset.size,
- assetMimeType = importedAsset.mimeType,
- assetWidth = if (isImage) (importedAsset as ImportedMediaAsset.Image).width else 0,
- assetHeight = if (isImage) (importedAsset as ImportedMediaAsset.Image).height else 0,
- audioLengthInMs = getAudioLengthInMs(
- dataPath = importedAsset.dataPath,
- mimeType = importedAsset.mimeType
- )
- ).also {
- if (it is ScheduleNewAssetMessageResult.Failure) {
- appLogger.e("Failed to import asset message to conversationId=${conversation.conversationId.toLogString()} ")
- } else {
- appLogger.d("Success importing asset message to conversationId=${conversation.conversationId.toLogString()}")
+ text = it
+ )
+ } ?: assetsToSend.forEach { importedAsset ->
+ val isImage = importedAsset is ImportedMediaAsset.Image
+ val job = viewModelScope.launch {
+ sendAssetMessage(
+ conversationId = conversation.conversationId,
+ assetDataPath = importedAsset.dataPath,
+ assetName = importedAsset.name,
+ assetDataSize = importedAsset.size,
+ assetMimeType = importedAsset.mimeType,
+ assetWidth = if (isImage) (importedAsset as ImportedMediaAsset.Image).width else 0,
+ assetHeight = if (isImage) (importedAsset as ImportedMediaAsset.Image).height else 0,
+ audioLengthInMs = getAudioLengthInMs(
+ dataPath = importedAsset.dataPath,
+ mimeType = importedAsset.mimeType
+ )
+ ).also {
+ val logConversationId = conversation.conversationId.toLogString()
+ if (it is ScheduleNewAssetMessageResult.Failure) {
+ appLogger.e("Failed to import asset message to " +
+ "conversationId=$logConversationId")
+ } else {
+ appLogger.d("Success importing asset message to " +
+ "conversationId=$logConversationId")
+ }
}
}
+ jobs.add(job)
+ }
+
+ jobs.joinAll()
+ withContext(dispatchers.main()) {
+ onSent(conversation.conversationId)
}
- jobs.add(job)
- }
- jobs.joinAll()
- withContext(dispatchers.main()) {
- onSent(conversation.conversationId)
}
}
- }
fun onNewConversationPicked(conversationId: ConversationId) = viewModelScope.launch {
importMediaState = importMediaState.copy(
@@ -455,6 +473,7 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
data class ImportMediaAuthenticatedState(
val avatarAsset: ImageAsset.UserAvatarAsset? = null,
val importedAssets: List = emptyList(),
+ val importedText: String? = null,
val isImporting: Boolean = false,
val shareableConversationListState: ShareableConversationListState = ShareableConversationListState(),
val selectedConversationItem: List = emptyList(),
diff --git a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt
index 07dd39d782b..43dcbe81036 100644
--- a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt
@@ -14,6 +14,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
@@ -34,8 +36,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
-import androidx.compose.foundation.pager.HorizontalPager
-import androidx.compose.foundation.pager.rememberPagerState
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph
import com.wire.android.R
@@ -69,8 +69,8 @@ import com.wire.android.util.CustomTabsHelper
import com.wire.android.util.extension.getActivity
import com.wire.android.util.ui.LinkText
import com.wire.android.util.ui.LinkTextData
-import com.wire.kalium.logic.util.isPositiveNotNull
import com.wire.kalium.logic.data.id.ConversationId
+import com.wire.kalium.logic.util.isPositiveNotNull
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
@@ -84,7 +84,8 @@ fun ImportMediaScreen(
) {
featureFlagNotificationViewModel.loadInitialSync()
- when (val fileSharingRestrictedState = featureFlagNotificationViewModel.featureFlagState.fileSharingRestrictedState) {
+ when (val fileSharingRestrictedState =
+ featureFlagNotificationViewModel.featureFlagState.fileSharingRestrictedState) {
FeatureFlagState.SharingRestrictedState.NO_USER -> {
ImportMediaLoggedOutContent(
fileSharingRestrictedState = fileSharingRestrictedState,
@@ -109,7 +110,12 @@ fun ImportMediaScreen(
onConversationClicked = importMediaViewModel::onConversationClicked,
checkRestrictionsAndSendImportedMedia = {
importMediaViewModel.checkRestrictionsAndSendImportedMedia {
- navigator.navigate(NavigationCommand(ConversationScreenDestination(it), BackStackMode.CLEAR_TILL_START))
+ navigator.navigate(
+ NavigationCommand(
+ ConversationScreenDestination(it),
+ BackStackMode.CLEAR_TILL_START
+ )
+ )
}
},
onNewSelfDeletionTimerPicked = importMediaViewModel::onNewSelfDeletionTimerPicked,
@@ -119,7 +125,8 @@ fun ImportMediaScreen(
val context = LocalContext.current
LaunchedEffect(importMediaViewModel.importMediaState.importedAssets) {
if (importMediaViewModel.importMediaState.importedAssets.isEmpty()) {
- context.getActivity()?.let { importMediaViewModel.handleReceivedDataFromSharingIntent(it) }
+ context.getActivity()
+ ?.let { importMediaViewModel.handleReceivedDataFromSharingIntent(it) }
}
}
}
@@ -271,11 +278,12 @@ fun FileSharingRestrictedContent(
.padding(internalPadding)
.padding(horizontal = dimensions().spacing48x)
) {
- val textRes = if (sharingRestrictedState == FeatureFlagState.SharingRestrictedState.NO_USER) {
- R.string.file_sharing_restricted_description_no_users
- } else {
- R.string.file_sharing_restricted_description_by_team
- }
+ val textRes =
+ if (sharingRestrictedState == FeatureFlagState.SharingRestrictedState.NO_USER) {
+ R.string.file_sharing_restricted_description_no_users
+ } else {
+ R.string.file_sharing_restricted_description_by_team
+ }
Text(
text = stringResource(textRes),
textAlign = TextAlign.Center,
@@ -318,9 +326,11 @@ private fun ImportMediaBottomBar(
} else {
stringResource(id = R.string.import_media_send_button_title)
}
+ val buttonCount =
+ if (state.importedAssets.isNotEmpty() || state.importedText != null) state.selectedConversationItem.size else 0
SendContentButton(
mainButtonText = mainButtonText,
- count = if (state.importedAssets.isNotEmpty()) state.selectedConversationItem.size else 0,
+ count = buttonCount,
onMainButtonClick = checkRestrictionsAndSendImportedMedia,
selfDeletionTimer = selfDeletionTimer,
onSelfDeletionTimerClicked = importMediaScreenState::showBottomSheetMenu,
@@ -348,9 +358,13 @@ private fun ImportMediaContent(
) {
val horizontalPadding = dimensions().spacing8x
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
- val itemWidth = if (isMultipleImport) dimensions().importedMediaAssetSize + horizontalPadding.times(2)
- else screenWidth - (horizontalPadding * 2)
- val contentPadding = PaddingValues(start = horizontalPadding, end = (screenWidth - itemWidth + horizontalPadding))
+ val itemWidth =
+ if (isMultipleImport) dimensions().importedMediaAssetSize + horizontalPadding.times(2)
+ else screenWidth - (horizontalPadding * 2)
+ val contentPadding = PaddingValues(
+ start = horizontalPadding,
+ end = (screenWidth - itemWidth + horizontalPadding)
+ )
val lazyListState = rememberLazyListState()
if (state.isImporting) {
Box(
@@ -379,7 +393,11 @@ private fun ImportMediaContent(
}
}
}
- Divider(color = colorsScheme().outline, thickness = 1.dp, modifier = Modifier.padding(top = dimensions().spacing12x))
+ Divider(
+ color = colorsScheme().outline,
+ thickness = 1.dp,
+ modifier = Modifier.padding(top = dimensions().spacing12x)
+ )
Box(Modifier.padding(dimensions().spacing6x)) {
SearchTopBar(
isSearchActive = searchBarState.isSearchActive,
@@ -420,7 +438,10 @@ private fun ImportMediaContent(
}
@Composable
-private fun SnackBarMessage(infoMessages: SharedFlow, snackbarHostState: SnackbarHostState) {
+private fun SnackBarMessage(
+ infoMessages: SharedFlow,
+ snackbarHostState: SnackbarHostState
+) {
val context = LocalContext.current
LaunchedEffect(Unit) {
infoMessages.collect { message ->
@@ -438,13 +459,23 @@ fun PreviewImportMediaScreenLoggedOut() {
@Preview(showBackground = true)
@Composable
fun PreviewImportMediaScreenRestricted() {
- ImportMediaRestrictedContent(FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM, ImportMediaAuthenticatedState()) {}
+ ImportMediaRestrictedContent(
+ FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM,
+ ImportMediaAuthenticatedState()
+ ) {}
}
@Preview(showBackground = true)
@Composable
fun PreviewImportMediaScreenRegular() {
- ImportMediaRegularContent(ImportMediaAuthenticatedState(), {}, {}, {}, {}, MutableSharedFlow()) {}
+ ImportMediaRegularContent(
+ ImportMediaAuthenticatedState(),
+ {},
+ {},
+ {},
+ {},
+ MutableSharedFlow()
+ ) {}
}
@Preview(showBackground = true)