diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 03cd10c6d9..f2ee6a904d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -46,6 +46,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManager.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManager.kt
index a5c70c6a7a..88d0d3adce 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManager.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManager.kt
@@ -2,6 +2,9 @@ package com.x8bit.bitwarden.ui.platform.manager.intent
import android.content.Intent
import android.net.Uri
+import androidx.activity.compose.ManagedActivityResultLauncher
+import androidx.activity.result.ActivityResult
+import androidx.compose.runtime.Composable
/**
* A manager class for simplifying the handling of Android Intents within a given context.
@@ -28,8 +31,36 @@ interface IntentManager {
*/
fun launchUri(uri: Uri)
+ /**
+ * Start an activity using the provided [Intent] and provides a callback, via [onResult], for
+ * retrieving the [ActivityResult].
+ */
+ @Composable
+ fun launchActivityForResult(
+ onResult: (ActivityResult) -> Unit,
+ ): ManagedActivityResultLauncher
+
/**
* Launches the share sheet with the given [text].
*/
fun shareText(text: String)
+
+ /**
+ * Processes the [activityResult] and attempts to get the relevant file data from it.
+ */
+ fun getFileDataFromIntent(activityResult: ActivityResult): FileData?
+
+ /**
+ * Creates an intent for choosing a file saved to disk.
+ */
+ fun createFileChooserIntent(withCameraIntents: Boolean): Intent
+
+ /**
+ * Represents file information.
+ */
+ data class FileData(
+ val fileName: String,
+ val uri: Uri,
+ val sizeBytes: Long,
+ )
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManagerImpl.kt
index cc29907615..f5a8a93487 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManagerImpl.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/manager/intent/IntentManagerImpl.kt
@@ -1,18 +1,53 @@
package com.x8bit.bitwarden.ui.platform.manager.intent
+import android.app.Activity
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.net.Uri
+import android.provider.MediaStore
+import androidx.activity.compose.ManagedActivityResultLauncher
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.browser.customtabs.CustomTabsIntent
+import androidx.compose.runtime.Composable
+import androidx.core.content.ContextCompat
+import androidx.core.content.FileProvider
+import com.x8bit.bitwarden.BuildConfig
+import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
+import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
+import java.io.File
+import java.time.Clock
+
+/**
+ * The authority used for pulling in photos from the camera.
+ *
+ * Note: This must match the file provider authority in the manifest.
+ */
+private const val FILE_PROVIDER_AUTHORITY: String = "${BuildConfig.APPLICATION_ID}.fileprovider"
+
+/**
+ * Temporary file name for a camera image.
+ */
+private const val TEMP_CAMERA_IMAGE_NAME: String = "temp_camera_image.jpg"
+
+/**
+ * This directory must also be declared in file_paths.xml
+ */
+private const val TEMP_CAMERA_IMAGE_DIR: String = "camera_temp"
/**
* The default implementation of the [IntentManager] for simplifying the handling of Android
* Intents within a given context.
*/
+@Suppress("TooManyFunctions")
@OmitFromCoverage
class IntentManagerImpl(
private val context: Context,
+ private val clock: Clock = Clock.systemDefaultZone(),
) : IntentManager {
override fun exitApplication() {
@@ -28,6 +63,15 @@ class IntentManagerImpl(
context.startActivity(intent)
}
+ @Composable
+ override fun launchActivityForResult(
+ onResult: (ActivityResult) -> Unit,
+ ): ManagedActivityResultLauncher =
+ rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.StartActivityForResult(),
+ onResult = onResult,
+ )
+
override fun startCustomTabsActivity(uri: Uri) {
CustomTabsIntent
.Builder()
@@ -51,4 +95,98 @@ class IntentManagerImpl(
}
startActivity(Intent.createChooser(sendIntent, null))
}
+
+ override fun getFileDataFromIntent(activityResult: ActivityResult): IntentManager.FileData? {
+ if (activityResult.resultCode != Activity.RESULT_OK) return null
+ val uri = activityResult.data?.data
+ return if (uri != null) getLocalFileData(uri) else getCameraFileData()
+ }
+
+ override fun createFileChooserIntent(withCameraIntents: Boolean): Intent {
+ val chooserIntent = Intent.createChooser(
+ Intent(Intent.ACTION_OPEN_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType("*/*"),
+ ContextCompat.getString(context, R.string.file_source),
+ )
+
+ if (withCameraIntents) {
+ val tmpDir = File(context.filesDir, TEMP_CAMERA_IMAGE_DIR)
+ val file = File(tmpDir, TEMP_CAMERA_IMAGE_NAME)
+ if (!file.exists()) {
+ file.parentFile?.mkdirs()
+ file.createNewFile()
+ }
+ val outputFileUri = FileProvider.getUriForFile(
+ context,
+ FILE_PROVIDER_AUTHORITY,
+ file,
+ )
+
+ chooserIntent.putExtra(
+ Intent.EXTRA_INITIAL_INTENTS,
+ getCameraIntents(outputFileUri).toTypedArray(),
+ )
+ }
+
+ return chooserIntent
+ }
+
+ private fun getCameraFileData(): IntentManager.FileData {
+ val tmpDir = File(context.filesDir, TEMP_CAMERA_IMAGE_DIR)
+ val file = File(tmpDir, TEMP_CAMERA_IMAGE_NAME)
+ val uri = FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, file)
+ val fileName = "photo_${clock.instant().toFormattedPattern(pattern = "yyyyMMddHHmmss")}.jpg"
+ return IntentManager.FileData(
+ fileName = fileName,
+ uri = uri,
+ sizeBytes = file.length(),
+ )
+ }
+
+ private fun getLocalFileData(uri: Uri): IntentManager.FileData? =
+ context
+ .contentResolver
+ .query(
+ uri,
+ arrayOf(
+ MediaStore.MediaColumns.DISPLAY_NAME,
+ MediaStore.MediaColumns.SIZE,
+ ),
+ null,
+ null,
+ null,
+ )
+ ?.use { cursor ->
+ if (!cursor.moveToFirst()) return@use null
+ val fileName = cursor
+ .getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)
+ .takeIf { it >= 0 }
+ ?.let { cursor.getString(it) }
+ val fileSize = cursor
+ .getColumnIndex(MediaStore.MediaColumns.SIZE)
+ .takeIf { it >= 0 }
+ ?.let { cursor.getLong(it) }
+ if (fileName == null || fileSize == null) return@use null
+ IntentManager.FileData(
+ fileName = fileName,
+ uri = uri,
+ sizeBytes = fileSize,
+ )
+ }
+
+ private fun getCameraIntents(outputUri: Uri): List {
+ val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+ return context
+ .packageManager
+ .queryIntentActivities(captureIntent, PackageManager.MATCH_ALL)
+ .map {
+ val packageName = it.activityInfo.packageName
+ Intent(captureIntent).apply {
+ component = ComponentName(packageName, it.activityInfo.name)
+ setPackage(packageName)
+ putExtra(MediaStore.EXTRA_OUTPUT, outputUri)
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt
index 71f963800b..7efa7f26de 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt
@@ -1,5 +1,6 @@
package com.x8bit.bitwarden.ui.tools.feature.send.addsend
+import android.Manifest
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -42,6 +43,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButton
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.BitwardenWideSwitch
import com.x8bit.bitwarden.ui.platform.components.SegmentedButtonState
+import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandlers
@@ -54,8 +56,13 @@ fun AddSendContent(
state: AddSendState.ViewState.Content,
isAddMode: Boolean,
addSendHandlers: AddSendHandlers,
+ permissionsManager: PermissionsManager,
modifier: Modifier = Modifier,
) {
+ val chooseFileCameraPermissionLauncher = permissionsManager.getLauncher { isGranted ->
+ addSendHandlers.onChooseFileClick(isGranted)
+ }
+
Column(
modifier = modifier
.verticalScroll(rememberScrollState()),
@@ -118,7 +125,13 @@ fun AddSendContent(
Spacer(modifier = Modifier.height(8.dp))
BitwardenFilledTonalButton(
label = stringResource(id = R.string.choose_file),
- onClick = addSendHandlers.onChooseFileCLick,
+ onClick = {
+ if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) {
+ addSendHandlers.onChooseFileClick(true)
+ } else {
+ chooseFileCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
+ }
+ },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt
index 63204a1bd2..945b9b70c8 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt
@@ -35,7 +35,9 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
+import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
+import com.x8bit.bitwarden.ui.platform.theme.LocalPermissionsManager
import com.x8bit.bitwarden.ui.platform.util.persistentListOfNotNull
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandlers
@@ -48,6 +50,7 @@ import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandler
fun AddSendScreen(
viewModel: AddSendViewModel = hiltViewModel(),
intentManager: IntentManager = LocalIntentManager.current,
+ permissionsManager: PermissionsManager = LocalPermissionsManager.current,
onNavigateBack: () -> Unit,
) {
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
@@ -55,9 +58,22 @@ fun AddSendScreen(
val context = LocalContext.current
val resources = context.resources
+ val fileChooserLauncher = intentManager.launchActivityForResult { activityResult ->
+ intentManager.getFileDataFromIntent(activityResult)?.let {
+ viewModel.trySendAction(AddSendAction.FileChoose(it))
+ }
+ }
+
EventsEffect(viewModel = viewModel) { event ->
when (event) {
is AddSendEvent.NavigateBack -> onNavigateBack()
+
+ is AddSendEvent.ShowChooserSheet -> {
+ fileChooserLauncher.launch(
+ intentManager.createFileChooserIntent(event.withCameraOption),
+ )
+ }
+
is AddSendEvent.ShowShareSheet -> {
intentManager.shareText(event.message)
}
@@ -159,6 +175,7 @@ fun AddSendScreen(
state = viewState,
isAddMode = state.isAddMode,
addSendHandlers = remember(viewModel) { AddSendHandlers.create(viewModel) },
+ permissionsManager = permissionsManager,
modifier = modifier,
)
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt
index f214e10afb..3b31129383 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt
@@ -21,6 +21,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.base.util.concat
+import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.model.AddSendType
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.util.toSendView
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.util.toViewState
@@ -119,6 +120,7 @@ class AddSendViewModel @Inject constructor(
override fun handleAction(action: AddSendAction): Unit = when (action) {
AddSendAction.CopyLinkClick -> handleCopyLinkClick()
AddSendAction.DeleteClick -> handleDeleteClick()
+ is AddSendAction.FileChoose -> handeFileChose(action)
AddSendAction.RemovePasswordClick -> handleRemovePasswordClick()
AddSendAction.ShareLinkClick -> handleShareLinkClick()
is AddSendAction.CloseClick -> handleCloseClick()
@@ -129,7 +131,7 @@ class AddSendViewModel @Inject constructor(
is AddSendAction.SaveClick -> handleSaveClick()
is AddSendAction.FileTypeClick -> handleFileTypeClick()
is AddSendAction.TextTypeClick -> handleTextTypeClick()
- is AddSendAction.ChooseFileClick -> handleChooseFileClick()
+ is AddSendAction.ChooseFileClick -> handleChooseFileClick(action)
is AddSendAction.NameChange -> handleNameChange(action)
is AddSendAction.MaxAccessCountChange -> handleMaxAccessCountChange(action)
is AddSendAction.TextChange -> handleTextChange(action)
@@ -354,6 +356,11 @@ class AddSendViewModel @Inject constructor(
}
}
+ private fun handeFileChose(action: AddSendAction.FileChoose) {
+ // TODO: Process the chosen file (BIT-493)
+ sendEvent(AddSendEvent.ShowToast("Not Yet Implemented".asText()))
+ }
+
private fun handleRemovePasswordClick() {
onEdit {
mutableStateFlow.update {
@@ -511,9 +518,8 @@ class AddSendViewModel @Inject constructor(
}
}
- private fun handleChooseFileClick() {
- // TODO: allow for file upload: BIT-1085
- sendEvent(AddSendEvent.ShowToast("Not Implemented: File Upload".asText()))
+ private fun handleChooseFileClick(action: AddSendAction.ChooseFileClick) {
+ sendEvent(AddSendEvent.ShowChooserSheet(action.isCameraPermissionGranted))
}
private fun handleMaxAccessCountChange(action: AddSendAction.MaxAccessCountChange) {
@@ -721,6 +727,11 @@ sealed class AddSendEvent {
*/
data object NavigateBack : AddSendEvent()
+ /**
+ * Show file chooser sheet.
+ */
+ data class ShowChooserSheet(val withCameraOption: Boolean) : AddSendEvent()
+
/**
* Show share sheet.
*/
@@ -737,6 +748,11 @@ sealed class AddSendEvent {
*/
sealed class AddSendAction {
+ /**
+ * User has chosen a file to be part of the send.
+ */
+ data class FileChoose(val fileData: IntentManager.FileData) : AddSendAction()
+
/**
* User clicked the remove password button.
*/
@@ -805,7 +821,9 @@ sealed class AddSendAction {
/**
* User clicked the choose file button.
*/
- data object ChooseFileClick : AddSendAction()
+ data class ChooseFileClick(
+ val isCameraPermissionGranted: Boolean,
+ ) : AddSendAction()
/**
* User toggled the "hide text by default" toggle.
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/handlers/AddSendHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/handlers/AddSendHandlers.kt
index dac92be9f4..5a66d11521 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/handlers/AddSendHandlers.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/handlers/AddSendHandlers.kt
@@ -12,7 +12,7 @@ data class AddSendHandlers(
val onNamChange: (String) -> Unit,
val onFileTypeSelect: () -> Unit,
val onTextTypeSelect: () -> Unit,
- val onChooseFileCLick: () -> Unit,
+ val onChooseFileClick: (hasPermission: Boolean) -> Unit,
val onTextChange: (String) -> Unit,
val onIsHideByDefaultToggle: (Boolean) -> Unit,
val onMaxAccessCountChange: (Int) -> Unit,
@@ -36,7 +36,7 @@ data class AddSendHandlers(
onNamChange = { viewModel.trySendAction(AddSendAction.NameChange(it)) },
onFileTypeSelect = { viewModel.trySendAction(AddSendAction.FileTypeClick) },
onTextTypeSelect = { viewModel.trySendAction(AddSendAction.TextTypeClick) },
- onChooseFileCLick = { viewModel.trySendAction(AddSendAction.ChooseFileClick) },
+ onChooseFileClick = { viewModel.trySendAction(AddSendAction.ChooseFileClick(it)) },
onTextChange = { viewModel.trySendAction(AddSendAction.TextChange(it)) },
onIsHideByDefaultToggle = {
viewModel.trySendAction(AddSendAction.HideByDefaultToggle(it))
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 0000000000..21f70570f3
--- /dev/null
+++ b/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt
index ab93e8cd65..fbe7a71ba6 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt
@@ -24,6 +24,7 @@ import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFl
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
+import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.model.AddSendType
import com.x8bit.bitwarden.ui.util.isEditableText
import com.x8bit.bitwarden.ui.util.isProgressBar
@@ -44,7 +45,8 @@ class AddSendScreenTest : BaseComposeTest() {
private var onNavigateBackCalled = false
- private val intentManager: IntentManager = mockk {
+ private val permissionsManager = FakePermissionManager()
+ private val intentManager: IntentManager = mockk(relaxed = true) {
every { shareText(any()) } just runs
}
private val mutableEventFlow = bufferedMutableSharedFlow()
@@ -60,6 +62,7 @@ class AddSendScreenTest : BaseComposeTest() {
AddSendScreen(
viewModel = viewModel,
intentManager = intentManager,
+ permissionsManager = permissionsManager,
onNavigateBack = { onNavigateBackCalled = true },
)
}
@@ -329,7 +332,8 @@ class AddSendScreenTest : BaseComposeTest() {
}
@Test
- fun `Choose file button click should send ChooseFileClick`() {
+ fun `Choose file button click with permission should send ChooseFileClick`() {
+ permissionsManager.checkPermissionResult = true
mutableStateFlow.value = DEFAULT_STATE.copy(
viewState = DEFAULT_VIEW_STATE.copy(
selectedType = AddSendState.ViewState.Content.SendType.File,
@@ -339,7 +343,32 @@ class AddSendScreenTest : BaseComposeTest() {
.onNodeWithText("Choose file")
.performScrollTo()
.performClick()
- verify { viewModel.trySendAction(AddSendAction.ChooseFileClick) }
+ verify {
+ viewModel.trySendAction(
+ AddSendAction.ChooseFileClick(isCameraPermissionGranted = true),
+ )
+ }
+ }
+
+ @Suppress("MaxLineLength")
+ @Test
+ fun `Choose file button click without permission should request permission and send ChooseFileClick`() {
+ permissionsManager.checkPermissionResult = false
+ permissionsManager.getPermissionsResult = false
+ mutableStateFlow.value = DEFAULT_STATE.copy(
+ viewState = DEFAULT_VIEW_STATE.copy(
+ selectedType = AddSendState.ViewState.Content.SendType.File,
+ ),
+ )
+ composeTestRule
+ .onNodeWithText("Choose file")
+ .performScrollTo()
+ .performClick()
+ verify {
+ viewModel.trySendAction(
+ AddSendAction.ChooseFileClick(isCameraPermissionGranted = false),
+ )
+ }
}
@Test
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt
index 8ca20747d6..ebd656b34d 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt
@@ -581,14 +581,21 @@ class AddSendViewModelTest : BaseViewModelTest() {
}
@Test
- fun `ChooseFileClick should emit ShowToast`() = runTest {
+ fun `FileChose should emit ShowToast`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
- viewModel.trySendAction(AddSendAction.ChooseFileClick)
- assertEquals(
- AddSendEvent.ShowToast("Not Implemented: File Upload".asText()),
- awaitItem(),
- )
+ viewModel.trySendAction(AddSendAction.FileChoose(fileData = mockk()))
+ assertEquals(AddSendEvent.ShowToast("Not Yet Implemented".asText()), awaitItem())
+ }
+ }
+
+ @Test
+ fun `ChooseFileClick should emit ShowToast`() = runTest {
+ val arePermissionsGranted = true
+ val viewModel = createViewModel()
+ viewModel.eventFlow.test {
+ viewModel.trySendAction(AddSendAction.ChooseFileClick(arePermissionsGranted))
+ assertEquals(AddSendEvent.ShowChooserSheet(arePermissionsGranted), awaitItem())
}
}