WIP pick avatar image
This commit is contained in:
@@ -48,6 +48,7 @@ dependencies {
|
||||
implementation(projects.features.userlist.api)
|
||||
api(projects.features.createroom.api)
|
||||
implementation(libs.coil.compose) // FIXME temp
|
||||
implementation(projects.libraries.mediapickers)
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.coroutines.test)
|
||||
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
sealed interface ConfigureRoomEvents {
|
||||
data class RoomNameChanged(val name: String) : ConfigureRoomEvents
|
||||
data class TopicChanged(val topic: String) : ConfigureRoomEvents
|
||||
data class AvatarUriChanged(val uri: Uri?) : ConfigureRoomEvents
|
||||
data class RoomPrivacyChanged(val privacy: RoomPrivacy?) : ConfigureRoomEvents
|
||||
data class RemoveFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents
|
||||
data class CreateRoom(val config: CreateRoomConfig) : ConfigureRoomEvents
|
||||
|
||||
@@ -26,6 +26,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListEvents
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.execute
|
||||
@@ -34,6 +37,8 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
import io.element.android.libraries.mediapickers.PickerProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
@@ -41,6 +46,7 @@ import javax.inject.Inject
|
||||
class ConfigureRoomPresenter @Inject constructor(
|
||||
private val dataStore: CreateRoomDataStore,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val mediaPickerProvider: PickerProvider,
|
||||
) : Presenter<ConfigureRoomState> {
|
||||
|
||||
@Composable
|
||||
@@ -52,6 +58,13 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(onResult = { uri ->
|
||||
if (uri != null) dataStore.setAvatarUrl(uri.toString())
|
||||
})
|
||||
val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker(onResult = { uri ->
|
||||
if (uri != null) dataStore.setAvatarUrl(uri.toString())
|
||||
})
|
||||
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
val createRoomAction: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
|
||||
|
||||
@@ -62,7 +75,6 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
|
||||
fun handleEvents(event: ConfigureRoomEvents) {
|
||||
when (event) {
|
||||
is ConfigureRoomEvents.AvatarUriChanged -> dataStore.setAvatarUrl(event.uri?.toString())
|
||||
is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name)
|
||||
is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic)
|
||||
is ConfigureRoomEvents.RoomPrivacyChanged -> dataStore.setPrivacy(event.privacy)
|
||||
@@ -72,9 +84,27 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun handleAvatarEvents(event: AvatarActionListEvents) {
|
||||
when (event) {
|
||||
is AvatarActionListEvents.HandleAction -> when (event.action) {
|
||||
AvatarAction.ChoosePhoto -> galleryImagePicker.launch()
|
||||
AvatarAction.TakePhoto -> cameraPhotoPicker.launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val avatarActionListState = AvatarActionListState(
|
||||
actions = persistentListOf(
|
||||
AvatarAction.ChoosePhoto,
|
||||
AvatarAction.TakePhoto,
|
||||
),
|
||||
eventSink = ::handleAvatarEvents,
|
||||
)
|
||||
|
||||
return ConfigureRoomState(
|
||||
config = createRoomConfig.value,
|
||||
isCreateButtonEnabled = isCreateButtonEnabled,
|
||||
avatarActionListState = avatarActionListState,
|
||||
createRoomAction = createRoomAction.value,
|
||||
eventSink = ::handleEvents,
|
||||
)
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
data class ConfigureRoomState(
|
||||
val config: CreateRoomConfig,
|
||||
val isCreateButtonEnabled: Boolean,
|
||||
val avatarActionListState: AvatarActionListState,
|
||||
val createRoomAction: Async<RoomId>,
|
||||
val eventSink: (ConfigureRoomEvents) -> Unit
|
||||
)
|
||||
|
||||
@@ -18,8 +18,11 @@ package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListState
|
||||
import io.element.android.features.userlist.api.aListOfSelectedUsers
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomState> {
|
||||
override val values: Sequence<ConfigureRoomState>
|
||||
@@ -40,6 +43,10 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomSt
|
||||
fun aConfigureRoomState() = ConfigureRoomState(
|
||||
config = CreateRoomConfig(),
|
||||
isCreateButtonEnabled = false,
|
||||
avatarActionListState = AvatarActionListState(
|
||||
actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto),
|
||||
eventSink = {},
|
||||
),
|
||||
createRoomAction = Async.Uninitialized,
|
||||
eventSink = {}
|
||||
eventSink = { },
|
||||
)
|
||||
|
||||
@@ -14,12 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
@@ -27,12 +26,15 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.selection.selectableGroup
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.ModalBottomSheetValue
|
||||
import androidx.compose.material.rememberModalBottomSheetState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -44,6 +46,8 @@ import io.element.android.features.createroom.impl.R
|
||||
import io.element.android.features.createroom.impl.components.Avatar
|
||||
import io.element.android.features.createroom.impl.components.LabelledTextField
|
||||
import io.element.android.features.createroom.impl.components.RoomPrivacyOption
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListEvents
|
||||
import io.element.android.features.createroom.impl.configureroom.avatar.AvatarActionListView
|
||||
import io.element.android.features.userlist.api.components.SelectedUsersList
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||
@@ -56,6 +60,7 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.coroutines.launch
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
@@ -65,13 +70,23 @@ fun ConfigureRoomView(
|
||||
onBackPressed: () -> Unit = {},
|
||||
onRoomCreated: (RoomId) -> Unit = {},
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val itemActionsBottomSheetState = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Hidden,
|
||||
)
|
||||
|
||||
if (state.createRoomAction is Async.Success) {
|
||||
LaunchedEffect(state.createRoomAction) {
|
||||
onRoomCreated(state.createRoomAction.state)
|
||||
}
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
fun onAvatarClicked() {
|
||||
coroutineScope.launch {
|
||||
itemActionsBottomSheetState.show()
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
@@ -92,7 +107,7 @@ fun ConfigureRoomView(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
avatarUri = state.config.avatarUrl?.toUri(),
|
||||
roomName = state.config.roomName.orEmpty(),
|
||||
onAvatarClick = { Toast.makeText(context, "not implemented yet", Toast.LENGTH_SHORT).show() },
|
||||
onAvatarClick = ::onAvatarClicked,
|
||||
onRoomNameChanged = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) },
|
||||
)
|
||||
RoomTopic(
|
||||
@@ -114,10 +129,17 @@ fun ConfigureRoomView(
|
||||
}
|
||||
}
|
||||
|
||||
AvatarActionListView(
|
||||
state = state.avatarActionListState,
|
||||
modalBottomSheetState = itemActionsBottomSheetState,
|
||||
onActionSelected = { state.avatarActionListState.eventSink(AvatarActionListEvents.HandleAction(it)) }
|
||||
)
|
||||
|
||||
when (state.createRoomAction) {
|
||||
is Async.Loading -> {
|
||||
ProgressDialog(text = stringResource(StringR.string.common_creating_room))
|
||||
}
|
||||
|
||||
is Async.Failure -> {
|
||||
RetryDialog(
|
||||
content = stringResource(R.string.screen_create_room_error_creating_room),
|
||||
@@ -125,6 +147,7 @@ fun ConfigureRoomView(
|
||||
onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom(state.config)) },
|
||||
)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom.avatar
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.PhotoCamera
|
||||
import androidx.compose.material.icons.filled.PhotoLibrary
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import io.element.android.libraries.ui.strings.R
|
||||
|
||||
@Immutable
|
||||
sealed class AvatarAction(
|
||||
@StringRes val titleResId: Int,
|
||||
val icon: ImageVector,
|
||||
) {
|
||||
object TakePhoto : AvatarAction(titleResId = R.string.action_take_photo, icon = Icons.Default.PhotoCamera)
|
||||
object ChoosePhoto : AvatarAction(titleResId = R.string.action_choose_photo, icon = Icons.Default.PhotoLibrary)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom.avatar
|
||||
|
||||
sealed interface AvatarActionListEvents {
|
||||
data class HandleAction(val action: AvatarAction) : AvatarActionListEvents
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom.avatar
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
data class AvatarActionListState(
|
||||
val actions: ImmutableList<AvatarAction>,
|
||||
val eventSink: (AvatarActionListEvents) -> Unit,
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom.avatar
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
open class ActionListStateProvider : PreviewParameterProvider<AvatarActionListState> {
|
||||
override val values: Sequence<AvatarActionListState>
|
||||
get() = sequenceOf(anActionListState())
|
||||
}
|
||||
|
||||
fun anActionListState() = AvatarActionListState(
|
||||
actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto),
|
||||
eventSink = {}
|
||||
)
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalMaterialApi::class, ExperimentalMaterialApi::class)
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom.avatar
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.ListItem
|
||||
import androidx.compose.material.ModalBottomSheetState
|
||||
import androidx.compose.material.ModalBottomSheetValue
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheetLayout
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun AvatarActionListView(
|
||||
state: AvatarActionListState,
|
||||
modalBottomSheetState: ModalBottomSheetState,
|
||||
modifier: Modifier = Modifier,
|
||||
onActionSelected: (action: AvatarAction) -> Unit = {},
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
fun onItemActionClicked(itemAction: AvatarAction) {
|
||||
onActionSelected(itemAction)
|
||||
coroutineScope.launch {
|
||||
modalBottomSheetState.hide()
|
||||
}
|
||||
}
|
||||
|
||||
ModalBottomSheetLayout(
|
||||
modifier = modifier,
|
||||
sheetState = modalBottomSheetState,
|
||||
sheetContent = {
|
||||
SheetContent(
|
||||
state = state,
|
||||
onActionClicked = ::onItemActionClicked,
|
||||
modifier = Modifier
|
||||
.navigationBarsPadding()
|
||||
.imePadding()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SheetContent(
|
||||
state: AvatarActionListState,
|
||||
modifier: Modifier = Modifier,
|
||||
onActionClicked: (AvatarAction) -> Unit = { },
|
||||
) {
|
||||
val actions = state.actions
|
||||
LazyColumn(
|
||||
modifier = modifier.fillMaxWidth()
|
||||
) {
|
||||
items(
|
||||
items = actions,
|
||||
) { action ->
|
||||
ListItem(
|
||||
modifier = Modifier.clickable { onActionClicked(action) },
|
||||
text = {
|
||||
Text(text = stringResource(action.titleResId))
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = action.icon,
|
||||
contentDescription = stringResource(action.titleResId),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SheetContentLightPreview(@PreviewParameter(ActionListStateProvider::class) state: AvatarActionListState) =
|
||||
ElementPreviewLight { ContentToPreview(state) }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SheetContentDarkPreview(@PreviewParameter(ActionListStateProvider::class) state: AvatarActionListState) =
|
||||
ElementPreviewDark { ContentToPreview(state) }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(state: AvatarActionListState) {
|
||||
AvatarActionListView(
|
||||
state = state,
|
||||
modalBottomSheetState = ModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -26,6 +26,13 @@ sealed interface PickerType<Input, Output> {
|
||||
fun getContract(): ActivityResultContract<Input, Output>
|
||||
fun getDefaultRequest(): Input
|
||||
|
||||
object Image : PickerType<PickVisualMediaRequest, Uri?> {
|
||||
override fun getContract() = ActivityResultContracts.PickVisualMedia()
|
||||
override fun getDefaultRequest(): PickVisualMediaRequest {
|
||||
return PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
|
||||
}
|
||||
}
|
||||
|
||||
object ImageAndVideo : PickerType<PickVisualMediaRequest, Uri?> {
|
||||
override fun getContract() = ActivityResultContracts.PickVisualMedia()
|
||||
override fun getDefaultRequest(): PickVisualMediaRequest {
|
||||
|
||||
@@ -59,6 +59,20 @@ class PickerProviderImpl constructor(private val isInTest: Boolean) : PickerProv
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers and returns a [PickerLauncher] for a gallery picture.
|
||||
* [onResult] will be called with either the selected file's [Uri] or `null` if nothing was selected.
|
||||
*/
|
||||
@Composable
|
||||
fun registerGalleryImagePicker(onResult: (Uri?) -> Unit): PickerLauncher<PickVisualMediaRequest, Uri?> {
|
||||
// Tests and UI preview can't handle Contexts, so we might as well disable the whole picker
|
||||
return if (LocalInspectionMode.current || isInTest) {
|
||||
NoOpPickerLauncher { onResult(null) }
|
||||
} else {
|
||||
rememberPickerLauncher(type = PickerType.Image) { uri -> onResult(uri) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers and returns a [PickerLauncher] for a gallery item, either a picture or a video.
|
||||
* [onResult] will be called with either the selected file's [Uri] or `null` if nothing was selected.
|
||||
|
||||
Reference in New Issue
Block a user