forked from dsutanto/bChot-android
First Commit
This commit is contained in:
57
features/createroom/impl/build.gradle.kts
Normal file
57
features/createroom/impl/build.gradle.kts
Normal file
@@ -0,0 +1,57 @@
|
||||
import extension.setupDependencyInjection
|
||||
import extension.testCommonDependencies
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.features.createroom.impl"
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
isIncludeAndroidResources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.matrixui)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.deeplink.api)
|
||||
implementation(projects.libraries.mediapickers.api)
|
||||
implementation(projects.libraries.mediaupload.api)
|
||||
implementation(projects.libraries.permissions.api)
|
||||
implementation(projects.libraries.usersearch.impl)
|
||||
implementation(projects.services.analytics.api)
|
||||
implementation(libs.coil.compose)
|
||||
implementation(projects.libraries.featureflag.api)
|
||||
implementation(projects.features.invitepeople.api)
|
||||
api(projects.features.createroom.api)
|
||||
|
||||
testCommonDependencies(libs, true)
|
||||
testImplementation(projects.services.analytics.test)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
testImplementation(projects.libraries.mediapickers.test)
|
||||
testImplementation(projects.libraries.mediaupload.test)
|
||||
testImplementation(projects.libraries.permissions.test)
|
||||
testImplementation(projects.libraries.usersearch.test)
|
||||
testImplementation(projects.features.startchat.test)
|
||||
testImplementation(projects.libraries.featureflag.test)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.replace
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.features.createroom.impl.addpeople.AddPeopleNode
|
||||
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode
|
||||
import io.element.android.libraries.architecture.BackstackView
|
||||
import io.element.android.libraries.architecture.BaseFlowNode
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
@AssistedInject
|
||||
class CreateRoomFlowNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
) : BaseFlowNode<CreateRoomFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.ConfigureRoom,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
buildContext = buildContext,
|
||||
plugins = plugins
|
||||
) {
|
||||
private val callback: CreateRoomEntryPoint.Callback = callback()
|
||||
|
||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.ConfigureRoom -> {
|
||||
val callback = object : ConfigureRoomNode.Callback {
|
||||
override fun onCreateRoomSuccess(roomId: RoomId) {
|
||||
backstack.replace(NavTarget.AddPeople(roomId))
|
||||
}
|
||||
}
|
||||
createNode<ConfigureRoomNode>(buildContext, plugins = listOf(callback))
|
||||
}
|
||||
is NavTarget.AddPeople -> {
|
||||
val inputs = AddPeopleNode.Inputs(navTarget.roomId)
|
||||
val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback {
|
||||
override fun onFinish() {
|
||||
callback.onRoomCreated(navTarget.roomId)
|
||||
}
|
||||
}
|
||||
createNode<AddPeopleNode>(buildContext, plugins = listOf(inputs, callback))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
BackstackView()
|
||||
}
|
||||
|
||||
sealed interface NavTarget : Parcelable {
|
||||
@Parcelize
|
||||
data object ConfigureRoom : NavTarget
|
||||
|
||||
@Parcelize
|
||||
data class AddPeople(val roomId: RoomId) : NavTarget
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl
|
||||
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultCreateRoomEntryPoint : CreateRoomEntryPoint {
|
||||
override fun createNode(
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext,
|
||||
callback: CreateRoomEntryPoint.Callback,
|
||||
): Node {
|
||||
return parentNode.createNode<CreateRoomFlowNode>(buildContext, listOf(callback))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.addpeople
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.invitepeople.api.InvitePeoplePresenter
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleRenderer
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
@AssistedInject
|
||||
class AddPeopleNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
invitePeoplePresenterFactory: InvitePeoplePresenter.Factory,
|
||||
private val invitePeopleRenderer: InvitePeopleRenderer,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
data class Inputs(
|
||||
val roomId: RoomId,
|
||||
) : NodeInputs
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onFinish()
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
private val roomId = inputs<Inputs>().roomId
|
||||
private val invitePeoplePresenter = invitePeoplePresenterFactory.create(
|
||||
joinedRoom = null,
|
||||
roomId = roomId,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = invitePeoplePresenter.present()
|
||||
AddPeopleView(
|
||||
state = state,
|
||||
onFinish = callback::onFinish,
|
||||
) {
|
||||
invitePeopleRenderer.Render(state, Modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.addpeople
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.features.createroom.impl.R
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleState
|
||||
import io.element.android.features.invitepeople.api.InvitePeopleStateProvider
|
||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun AddPeopleView(
|
||||
state: InvitePeopleState,
|
||||
onFinish: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
invitePeopleView: @Composable () -> Unit,
|
||||
) {
|
||||
HeaderFooterPage(
|
||||
modifier = modifier,
|
||||
contentPadding = PaddingValues(0.dp),
|
||||
topBar = {
|
||||
AddPeopleTopBar(onSkipClick = onFinish)
|
||||
},
|
||||
footer = {
|
||||
Button(
|
||||
text = stringResource(CommonStrings.action_finish),
|
||||
onClick = {
|
||||
state.eventSink(InvitePeopleEvents.SendInvites)
|
||||
onFinish()
|
||||
},
|
||||
enabled = state.canInvite,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp)
|
||||
)
|
||||
},
|
||||
content = invitePeopleView
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AddPeopleTopBar(
|
||||
onSkipClick: () -> Unit,
|
||||
) {
|
||||
TopAppBar(
|
||||
titleStr = stringResource(R.string.screen_create_room_add_people_title),
|
||||
actions = {
|
||||
TextButton(
|
||||
text = stringResource(CommonStrings.action_skip),
|
||||
onClick = onSkipClick,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun AddPeopleViewPreview(@PreviewParameter(InvitePeopleStateProvider::class) state: InvitePeopleState) = ElementPreview {
|
||||
AddPeopleView(
|
||||
state = state,
|
||||
invitePeopleView = {},
|
||||
onFinish = {},
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
|
||||
sealed interface ConfigureRoomEvents {
|
||||
data class RoomNameChanged(val name: String) : ConfigureRoomEvents
|
||||
data class TopicChanged(val topic: String) : ConfigureRoomEvents
|
||||
data class RoomVisibilityChanged(val visibilityItem: RoomVisibilityItem) : ConfigureRoomEvents
|
||||
data class RoomAccessChanged(val roomAccess: RoomAccessItem) : ConfigureRoomEvents
|
||||
data class RoomAddressChanged(val roomAddress: String) : ConfigureRoomEvents
|
||||
data object CreateRoom : ConfigureRoomEvents
|
||||
data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents
|
||||
data object CancelCreateRoom : ConfigureRoomEvents
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.lifecycle.subscribe
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import im.vector.app.features.analytics.plan.MobileScreen
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
@AssistedInject
|
||||
class ConfigureRoomNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: ConfigureRoomPresenter,
|
||||
private val analyticsService: AnalyticsService,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
interface Callback : Plugin {
|
||||
fun onCreateRoomSuccess(roomId: RoomId)
|
||||
}
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onResume = {
|
||||
analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreateRoom))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
ConfigureRoomView(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
onBackClick = this::navigateUp,
|
||||
onCreateRoomSuccess = callback::onCreateRoomSuccess,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.core.net.toUri
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
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.room.alias.RoomAliasHelper
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
|
||||
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidityEffect
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import kotlin.jvm.optionals.getOrDefault
|
||||
|
||||
@Inject
|
||||
class ConfigureRoomPresenter(
|
||||
private val dataStore: CreateRoomConfigStore,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val mediaPickerProvider: PickerProvider,
|
||||
private val mediaPreProcessor: MediaPreProcessor,
|
||||
private val analyticsService: AnalyticsService,
|
||||
permissionsPresenterFactory: PermissionsPresenter.Factory,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val roomAliasHelper: RoomAliasHelper,
|
||||
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
|
||||
) : Presenter<ConfigureRoomState> {
|
||||
private val cameraPermissionPresenter: PermissionsPresenter = permissionsPresenterFactory.create(android.Manifest.permission.CAMERA)
|
||||
private var pendingPermissionRequest = false
|
||||
|
||||
@Composable
|
||||
override fun present(): ConfigureRoomState {
|
||||
val cameraPermissionState = cameraPermissionPresenter.present()
|
||||
val createRoomConfig by dataStore.getCreateRoomConfigFlow().collectAsState(CreateRoomConfig())
|
||||
val homeserverName = remember { matrixClient.userIdServerName() }
|
||||
val isKnockFeatureEnabled by remember {
|
||||
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock)
|
||||
}.collectAsState(initial = false)
|
||||
val roomAddressValidity = remember {
|
||||
mutableStateOf<RoomAddressValidity>(RoomAddressValidity.Unknown)
|
||||
}
|
||||
|
||||
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(
|
||||
onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) },
|
||||
)
|
||||
val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker(
|
||||
onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri) }
|
||||
)
|
||||
|
||||
val avatarActions by remember(createRoomConfig.avatarUri) {
|
||||
derivedStateOf {
|
||||
listOfNotNull(
|
||||
AvatarAction.TakePhoto,
|
||||
AvatarAction.ChoosePhoto,
|
||||
AvatarAction.Remove.takeIf { createRoomConfig.avatarUri != null },
|
||||
).toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(cameraPermissionState.permissionGranted) {
|
||||
if (cameraPermissionState.permissionGranted && pendingPermissionRequest) {
|
||||
pendingPermissionRequest = false
|
||||
cameraPhotoPicker.launch()
|
||||
}
|
||||
}
|
||||
|
||||
RoomAddressValidityEffect(
|
||||
client = matrixClient,
|
||||
roomAliasHelper = roomAliasHelper,
|
||||
newRoomAddress = createRoomConfig.roomVisibility.roomAddress().getOrDefault(""),
|
||||
knownRoomAddress = null,
|
||||
) { newRoomAddressValidity ->
|
||||
roomAddressValidity.value = newRoomAddressValidity
|
||||
}
|
||||
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
val createRoomAction: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
|
||||
fun createRoom(config: CreateRoomConfig) {
|
||||
createRoomAction.value = AsyncAction.Uninitialized
|
||||
localCoroutineScope.createRoom(config, createRoomAction)
|
||||
}
|
||||
|
||||
fun handleEvent(event: ConfigureRoomEvents) {
|
||||
when (event) {
|
||||
is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name)
|
||||
is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic)
|
||||
is ConfigureRoomEvents.RoomVisibilityChanged -> dataStore.setRoomVisibility(event.visibilityItem)
|
||||
is ConfigureRoomEvents.RoomAccessChanged -> dataStore.setRoomAccess(event.roomAccess)
|
||||
is ConfigureRoomEvents.RoomAddressChanged -> dataStore.setRoomAddress(event.roomAddress)
|
||||
is ConfigureRoomEvents.CreateRoom -> createRoom(createRoomConfig)
|
||||
is ConfigureRoomEvents.HandleAvatarAction -> {
|
||||
when (event.action) {
|
||||
AvatarAction.ChoosePhoto -> galleryImagePicker.launch()
|
||||
AvatarAction.TakePhoto -> if (cameraPermissionState.permissionGranted) {
|
||||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> dataStore.setAvatarUri(uri = null)
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = AsyncAction.Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
return ConfigureRoomState(
|
||||
isKnockFeatureEnabled = isKnockFeatureEnabled,
|
||||
config = createRoomConfig,
|
||||
avatarActions = avatarActions,
|
||||
createRoomAction = createRoomAction.value,
|
||||
cameraPermissionState = cameraPermissionState,
|
||||
homeserverName = homeserverName,
|
||||
roomAddressValidity = roomAddressValidity.value,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.createRoom(
|
||||
config: CreateRoomConfig,
|
||||
createRoomAction: MutableState<AsyncAction<RoomId>>
|
||||
) = launch {
|
||||
suspend {
|
||||
val avatarUrl = config.avatarUri?.let { uploadAvatar(it.toUri()) }
|
||||
val params = if (config.roomVisibility is RoomVisibilityState.Public) {
|
||||
CreateRoomParameters(
|
||||
name = config.roomName,
|
||||
topic = config.topic,
|
||||
isEncrypted = false,
|
||||
isDirect = false,
|
||||
visibility = RoomVisibility.Public,
|
||||
joinRuleOverride = config.roomVisibility.roomAccess.toJoinRule(),
|
||||
preset = RoomPreset.PUBLIC_CHAT,
|
||||
invite = config.invites.map { it.userId },
|
||||
avatar = avatarUrl,
|
||||
roomAliasName = config.roomVisibility.roomAddress()
|
||||
)
|
||||
} else {
|
||||
CreateRoomParameters(
|
||||
name = config.roomName,
|
||||
topic = config.topic,
|
||||
isEncrypted = config.roomVisibility is RoomVisibilityState.Private,
|
||||
isDirect = false,
|
||||
visibility = RoomVisibility.Private,
|
||||
historyVisibilityOverride = RoomHistoryVisibility.Invited,
|
||||
preset = RoomPreset.PRIVATE_CHAT,
|
||||
invite = config.invites.map { it.userId },
|
||||
avatar = avatarUrl,
|
||||
)
|
||||
}
|
||||
matrixClient.createRoom(params)
|
||||
.onFailure { failure ->
|
||||
Timber.e(failure, "Failed to create room")
|
||||
}
|
||||
.onSuccess {
|
||||
dataStore.clearCachedData()
|
||||
analyticsService.capture(CreatedRoom(isDM = false))
|
||||
}
|
||||
.getOrThrow()
|
||||
}.runCatchingUpdatingState(createRoomAction)
|
||||
}
|
||||
|
||||
private suspend fun uploadAvatar(avatarUri: Uri): String {
|
||||
val preprocessed = mediaPreProcessor.process(
|
||||
uri = avatarUri,
|
||||
mimeType = MimeTypes.Jpeg,
|
||||
deleteOriginal = false,
|
||||
mediaOptimizationConfig = mediaOptimizationConfigProvider.get(),
|
||||
).getOrThrow()
|
||||
val byteArray = preprocessed.file.readBytes()
|
||||
return matrixClient.uploadMedia(MimeTypes.Jpeg, byteArray).getOrThrow()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class ConfigureRoomState(
|
||||
val isKnockFeatureEnabled: Boolean,
|
||||
val config: CreateRoomConfig,
|
||||
val avatarActions: ImmutableList<AvatarAction>,
|
||||
val createRoomAction: AsyncAction<RoomId>,
|
||||
val cameraPermissionState: PermissionsState,
|
||||
val roomAddressValidity: RoomAddressValidity,
|
||||
val homeserverName: String,
|
||||
val eventSink: (ConfigureRoomEvents) -> Unit
|
||||
) {
|
||||
val isValid: Boolean = config.roomName?.isNotEmpty() == true &&
|
||||
(config.roomVisibility is RoomVisibilityState.Private || roomAddressValidity == RoomAddressValidity.Valid)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import io.element.android.libraries.permissions.api.aPermissionsState
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomState> {
|
||||
override val values: Sequence<ConfigureRoomState>
|
||||
get() = sequenceOf(
|
||||
aConfigureRoomState(),
|
||||
aConfigureRoomState(
|
||||
isKnockFeatureEnabled = false,
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
invites = aMatrixUserList().toImmutableList(),
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled("Room-101"),
|
||||
roomAccess = RoomAccess.Knocking,
|
||||
),
|
||||
),
|
||||
),
|
||||
aConfigureRoomState(
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
invites = aMatrixUserList().toImmutableList(),
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled("Room-101"),
|
||||
roomAccess = RoomAccess.Knocking,
|
||||
),
|
||||
),
|
||||
),
|
||||
aConfigureRoomState(
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled("Room-101"),
|
||||
roomAccess = RoomAccess.Knocking,
|
||||
),
|
||||
),
|
||||
roomAddressValidity = RoomAddressValidity.NotAvailable,
|
||||
),
|
||||
aConfigureRoomState(
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled("Room-101"),
|
||||
roomAccess = RoomAccess.Knocking,
|
||||
),
|
||||
),
|
||||
roomAddressValidity = RoomAddressValidity.InvalidSymbols,
|
||||
),
|
||||
aConfigureRoomState(
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled("Room-101"),
|
||||
roomAccess = RoomAccess.Knocking,
|
||||
),
|
||||
),
|
||||
roomAddressValidity = RoomAddressValidity.Valid,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun aConfigureRoomState(
|
||||
config: CreateRoomConfig = CreateRoomConfig(),
|
||||
isKnockFeatureEnabled: Boolean = true,
|
||||
avatarActions: List<AvatarAction> = emptyList(),
|
||||
createRoomAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
|
||||
cameraPermissionState: PermissionsState = aPermissionsState(showDialog = false),
|
||||
homeserverName: String = "matrix.org",
|
||||
roomAddressValidity: RoomAddressValidity = RoomAddressValidity.Valid,
|
||||
eventSink: (ConfigureRoomEvents) -> Unit = { },
|
||||
) = ConfigureRoomState(
|
||||
config = config,
|
||||
isKnockFeatureEnabled = isKnockFeatureEnabled,
|
||||
avatarActions = avatarActions.toImmutableList(),
|
||||
createRoomAction = createRoomAction,
|
||||
cameraPermissionState = cameraPermissionState,
|
||||
homeserverName = homeserverName,
|
||||
roomAddressValidity = roomAddressValidity,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.selection.selectableGroup
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.createroom.impl.R
|
||||
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarType
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
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.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet
|
||||
import io.element.android.libraries.matrix.ui.components.UnsavedAvatar
|
||||
import io.element.android.libraries.matrix.ui.room.address.RoomAddressField
|
||||
import io.element.android.libraries.permissions.api.PermissionsView
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun ConfigureRoomView(
|
||||
state: ConfigureRoomState,
|
||||
onBackClick: () -> Unit,
|
||||
onCreateRoomSuccess: (RoomId) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
val isAvatarActionsSheetVisible = remember { mutableStateOf(false) }
|
||||
|
||||
fun onAvatarClick() {
|
||||
focusManager.clearFocus()
|
||||
isAvatarActionsSheetVisible.value = true
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier.clearFocusOnTap(focusManager),
|
||||
topBar = {
|
||||
ConfigureRoomToolbar(
|
||||
isNextActionEnabled = state.isValid,
|
||||
onBackClick = onBackClick,
|
||||
onNextClick = {
|
||||
focusManager.clearFocus()
|
||||
state.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
},
|
||||
)
|
||||
}
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.imePadding()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.consumeWindowInsets(padding),
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||
) {
|
||||
RoomNameWithAvatar(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
avatarUri = state.config.avatarUri,
|
||||
roomName = state.config.roomName.orEmpty(),
|
||||
onAvatarClick = ::onAvatarClick,
|
||||
onChangeRoomName = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) },
|
||||
)
|
||||
RoomTopic(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
topic = state.config.topic.orEmpty(),
|
||||
onTopicChange = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) },
|
||||
)
|
||||
RoomVisibilityOptions(
|
||||
selected = when (state.config.roomVisibility) {
|
||||
is RoomVisibilityState.Private -> RoomVisibilityItem.Private
|
||||
is RoomVisibilityState.Public -> RoomVisibilityItem.Public
|
||||
},
|
||||
onOptionClick = {
|
||||
focusManager.clearFocus()
|
||||
state.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(it))
|
||||
},
|
||||
)
|
||||
if (state.config.roomVisibility is RoomVisibilityState.Public && state.isKnockFeatureEnabled) {
|
||||
RoomAccessOptions(
|
||||
selected = when (state.config.roomVisibility.roomAccess) {
|
||||
RoomAccess.Anyone -> RoomAccessItem.Anyone
|
||||
RoomAccess.Knocking -> RoomAccessItem.AskToJoin
|
||||
},
|
||||
onOptionClick = {
|
||||
focusManager.clearFocus()
|
||||
state.eventSink(ConfigureRoomEvents.RoomAccessChanged(it))
|
||||
},
|
||||
)
|
||||
RoomAddressField(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
address = state.config.roomVisibility.roomAddress.value,
|
||||
homeserverName = state.homeserverName,
|
||||
addressValidity = state.roomAddressValidity,
|
||||
onAddressChange = { state.eventSink(ConfigureRoomEvents.RoomAddressChanged(it)) },
|
||||
label = stringResource(R.string.screen_create_room_room_address_section_title),
|
||||
supportingText = stringResource(R.string.screen_create_room_room_address_section_footer),
|
||||
)
|
||||
Spacer(Modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AvatarActionBottomSheet(
|
||||
actions = state.avatarActions,
|
||||
isVisible = isAvatarActionsSheetVisible.value,
|
||||
onDismiss = { isAvatarActionsSheetVisible.value = false },
|
||||
onSelectAction = { state.eventSink(ConfigureRoomEvents.HandleAvatarAction(it)) }
|
||||
)
|
||||
|
||||
AsyncActionView(
|
||||
async = state.createRoomAction,
|
||||
progressDialog = {
|
||||
AsyncActionViewDefaults.ProgressDialog(
|
||||
progressText = stringResource(CommonStrings.common_creating_room),
|
||||
)
|
||||
},
|
||||
onSuccess = { onCreateRoomSuccess(it) },
|
||||
errorMessage = { stringResource(R.string.screen_create_room_error_creating_room) },
|
||||
onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom) },
|
||||
onErrorDismiss = { state.eventSink(ConfigureRoomEvents.CancelCreateRoom) },
|
||||
)
|
||||
|
||||
PermissionsView(
|
||||
state = state.cameraPermissionState,
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ConfigureRoomToolbar(
|
||||
isNextActionEnabled: Boolean,
|
||||
onBackClick: () -> Unit,
|
||||
onNextClick: () -> Unit,
|
||||
) {
|
||||
TopAppBar(
|
||||
titleStr = stringResource(R.string.screen_create_room_title),
|
||||
navigationIcon = { BackButton(onClick = onBackClick) },
|
||||
actions = {
|
||||
TextButton(
|
||||
text = stringResource(CommonStrings.action_create),
|
||||
enabled = isNextActionEnabled,
|
||||
onClick = onNextClick,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoomNameWithAvatar(
|
||||
avatarUri: String?,
|
||||
roomName: String,
|
||||
onAvatarClick: () -> Unit,
|
||||
onChangeRoomName: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val a11yAvatar = stringResource(CommonStrings.a11y_room_avatar)
|
||||
UnsavedAvatar(
|
||||
avatarUri = avatarUri,
|
||||
avatarSize = AvatarSize.EditRoomDetails,
|
||||
avatarType = AvatarType.Room(),
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
onClick = onAvatarClick,
|
||||
onClickLabel = stringResource(CommonStrings.action_open_context_menu),
|
||||
)
|
||||
.clearAndSetSemantics {
|
||||
contentDescription = a11yAvatar
|
||||
},
|
||||
)
|
||||
|
||||
TextField(
|
||||
label = stringResource(R.string.screen_create_room_room_name_label),
|
||||
value = roomName,
|
||||
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
|
||||
singleLine = true,
|
||||
onValueChange = onChangeRoomName,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoomTopic(
|
||||
topic: String,
|
||||
onTopicChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TextField(
|
||||
modifier = modifier,
|
||||
label = stringResource(R.string.screen_create_room_topic_label),
|
||||
value = topic,
|
||||
onValueChange = onTopicChange,
|
||||
maxLines = 3,
|
||||
supportingText = stringResource(CommonStrings.common_topic_placeholder),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.Sentences,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConfigureRoomOptions(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.selectableGroup()
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoomVisibilityOptions(
|
||||
selected: RoomVisibilityItem,
|
||||
onOptionClick: (RoomVisibilityItem) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ConfigureRoomOptions(
|
||||
title = stringResource(R.string.screen_create_room_room_visibility_section_title),
|
||||
modifier = modifier,
|
||||
) {
|
||||
RoomVisibilityItem.entries.forEach { item ->
|
||||
val isSelected = item == selected
|
||||
ListItem(
|
||||
leadingContent = ListItemContent.Custom {
|
||||
RoundedIconAtom(
|
||||
size = RoundedIconAtomSize.Big,
|
||||
resourceId = item.icon,
|
||||
tint = if (isSelected) ElementTheme.colors.iconPrimary else ElementTheme.colors.iconSecondary,
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(text = stringResource(item.title)) },
|
||||
supportingContent = { Text(text = stringResource(item.description)) },
|
||||
trailingContent = ListItemContent.RadioButton(selected = isSelected),
|
||||
onClick = { onOptionClick(item) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoomAccessOptions(
|
||||
selected: RoomAccessItem,
|
||||
onOptionClick: (RoomAccessItem) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ConfigureRoomOptions(
|
||||
title = stringResource(R.string.screen_create_room_room_access_section_header),
|
||||
modifier = modifier,
|
||||
) {
|
||||
RoomAccessItem.entries.forEach { item ->
|
||||
ListItem(
|
||||
headlineContent = { Text(text = stringResource(item.title)) },
|
||||
supportingContent = { Text(text = stringResource(item.description)) },
|
||||
trailingContent = ListItemContent.RadioButton(selected = item == selected),
|
||||
onClick = { onOptionClick(item) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewWithLargeHeight
|
||||
@Composable
|
||||
internal fun ConfigureRoomViewLightPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) =
|
||||
ElementPreviewLight { ContentToPreview(state) }
|
||||
|
||||
@PreviewWithLargeHeight
|
||||
@Composable
|
||||
internal fun ConfigureRoomViewDarkPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) =
|
||||
ElementPreviewDark { ContentToPreview(state) }
|
||||
|
||||
@ExcludeFromCoverage
|
||||
@Composable
|
||||
private fun ContentToPreview(state: ConfigureRoomState) {
|
||||
ConfigureRoomView(
|
||||
state = state,
|
||||
onBackClick = {},
|
||||
onCreateRoomSuccess = {},
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
data class CreateRoomConfig(
|
||||
val roomName: String? = null,
|
||||
val topic: String? = null,
|
||||
val avatarUri: String? = null,
|
||||
val invites: ImmutableList<MatrixUser> = persistentListOf(),
|
||||
val roomVisibility: RoomVisibilityState = RoomVisibilityState.Private,
|
||||
)
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.androidutils.file.safeDelete
|
||||
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.getAndUpdate
|
||||
import java.io.File
|
||||
|
||||
@Inject
|
||||
class CreateRoomConfigStore(
|
||||
private val roomAliasHelper: RoomAliasHelper,
|
||||
) {
|
||||
private val createRoomConfigFlow: MutableStateFlow<CreateRoomConfig> = MutableStateFlow(CreateRoomConfig())
|
||||
|
||||
private var cachedAvatarUri: Uri? = null
|
||||
set(value) {
|
||||
field?.path?.let { File(it) }?.safeDelete()
|
||||
field = value
|
||||
}
|
||||
|
||||
fun getCreateRoomConfigFlow(): StateFlow<CreateRoomConfig> = createRoomConfigFlow
|
||||
|
||||
fun setRoomName(roomName: String) {
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
val newVisibility = when (config.roomVisibility) {
|
||||
is RoomVisibilityState.Public -> {
|
||||
val roomAddress = config.roomVisibility.roomAddress
|
||||
if (roomAddress is RoomAddress.AutoFilled || roomName.isEmpty()) {
|
||||
val roomAliasName = roomAliasHelper.roomAliasNameFromRoomDisplayName(roomName)
|
||||
config.roomVisibility.copy(
|
||||
roomAddress = RoomAddress.AutoFilled(roomAliasName),
|
||||
)
|
||||
} else {
|
||||
config.roomVisibility
|
||||
}
|
||||
}
|
||||
else -> config.roomVisibility
|
||||
}
|
||||
config.copy(
|
||||
roomName = roomName.takeIf { it.isNotEmpty() },
|
||||
roomVisibility = newVisibility,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setTopic(topic: String) {
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
config.copy(topic = topic.takeIf { it.isNotEmpty() })
|
||||
}
|
||||
}
|
||||
|
||||
fun setAvatarUri(uri: Uri?, cached: Boolean = false) {
|
||||
cachedAvatarUri = uri.takeIf { cached }
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
config.copy(avatarUri = uri?.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun setRoomVisibility(visibility: RoomVisibilityItem) {
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
config.copy(
|
||||
roomVisibility = when (visibility) {
|
||||
RoomVisibilityItem.Private -> RoomVisibilityState.Private
|
||||
RoomVisibilityItem.Public -> {
|
||||
val roomAliasName = roomAliasHelper.roomAliasNameFromRoomDisplayName(config.roomName.orEmpty())
|
||||
RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled(roomAliasName),
|
||||
roomAccess = RoomAccess.Anyone,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setRoomAddress(address: String) {
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
config.copy(
|
||||
roomVisibility = when (config.roomVisibility) {
|
||||
is RoomVisibilityState.Public -> {
|
||||
val sanitizedAddress = address.lowercase()
|
||||
config.roomVisibility.copy(roomAddress = RoomAddress.Edited(sanitizedAddress))
|
||||
}
|
||||
else -> config.roomVisibility
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setRoomAccess(access: RoomAccessItem) {
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
config.copy(
|
||||
roomVisibility = when (config.roomVisibility) {
|
||||
is RoomVisibilityState.Public -> {
|
||||
when (access) {
|
||||
RoomAccessItem.Anyone -> config.roomVisibility.copy(roomAccess = RoomAccess.Anyone)
|
||||
RoomAccessItem.AskToJoin -> config.roomVisibility.copy(roomAccess = RoomAccess.Knocking)
|
||||
}
|
||||
}
|
||||
else -> config.roomVisibility
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun clearCachedData() {
|
||||
cachedAvatarUri = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
|
||||
enum class RoomAccess {
|
||||
Anyone,
|
||||
Knocking
|
||||
}
|
||||
|
||||
fun RoomAccess.toJoinRule(): JoinRule? {
|
||||
return when (this) {
|
||||
RoomAccess.Anyone -> null
|
||||
RoomAccess.Knocking -> JoinRule.Knock
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import io.element.android.features.createroom.impl.R
|
||||
|
||||
enum class RoomAccessItem(
|
||||
@StringRes val title: Int,
|
||||
@StringRes val description: Int
|
||||
) {
|
||||
Anyone(
|
||||
title = R.string.screen_create_room_room_access_section_anyone_option_title,
|
||||
description = R.string.screen_create_room_room_access_section_anyone_option_description,
|
||||
),
|
||||
AskToJoin(
|
||||
title = R.string.screen_create_room_room_access_section_knocking_option_title,
|
||||
description = R.string.screen_create_room_room_access_section_knocking_option_description,
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
sealed class RoomAddress(open val value: String) {
|
||||
data class AutoFilled(override val value: String) : RoomAddress(value)
|
||||
data class Edited(override val value: String) : RoomAddress(value)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import io.element.android.features.createroom.impl.R
|
||||
import io.element.android.libraries.designsystem.icons.CompoundDrawables
|
||||
|
||||
enum class RoomVisibilityItem(
|
||||
@DrawableRes val icon: Int,
|
||||
@StringRes val title: Int,
|
||||
@StringRes val description: Int
|
||||
) {
|
||||
Private(
|
||||
icon = CompoundDrawables.ic_compound_lock,
|
||||
title = R.string.screen_create_room_private_option_title,
|
||||
description = R.string.screen_create_room_private_option_description,
|
||||
),
|
||||
Public(
|
||||
icon = CompoundDrawables.ic_compound_public,
|
||||
title = R.string.screen_create_room_public_option_title,
|
||||
description = R.string.screen_create_room_public_option_description,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import java.util.Optional
|
||||
|
||||
sealed interface RoomVisibilityState {
|
||||
data object Private : RoomVisibilityState
|
||||
|
||||
data class Public(
|
||||
val roomAddress: RoomAddress,
|
||||
val roomAccess: RoomAccess,
|
||||
) : RoomVisibilityState
|
||||
|
||||
fun roomAddress(): Optional<String> {
|
||||
return when (this) {
|
||||
is Private -> Optional.empty()
|
||||
is Public -> Optional.of(roomAddress.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Новы пакой"</string>
|
||||
<string name="screen_create_room_add_people_title">"Запрасіць карыстальнікаў"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Пры стварэнні пакоя адбылася памылка"</string>
|
||||
<string name="screen_create_room_private_option_description">"Толькі запрошаныя людзі могуць атрымаць доступ да гэтага пакоя. Усе паведамленні абаронены end-to-end шыфраваннем."</string>
|
||||
<string name="screen_create_room_private_option_title">"Прыватны пакой"</string>
|
||||
<string name="screen_create_room_public_option_description">"Любы можа знайсці гэты пакой.
|
||||
Вы можаце змяніць гэта ў любы час у наладах пакоя."</string>
|
||||
<string name="screen_create_room_public_option_title">"Публічны пакой"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Хто заўгодна"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Доступ у пакой"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Папрасіце далучыцца"</string>
|
||||
<string name="screen_create_room_room_name_label">"Назва пакоя"</string>
|
||||
<string name="screen_create_room_title">"Стварыце пакой"</string>
|
||||
<string name="screen_create_room_topic_label">"Тэма (неабавязкова)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Нова стая"</string>
|
||||
<string name="screen_create_room_add_people_title">"Поканване на хора"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Възникна грешка при създаването на стаята"</string>
|
||||
<string name="screen_create_room_private_option_description">"Само поканени хора имат достъп до тази стая. Всички съобщения са шифровани от край до край."</string>
|
||||
<string name="screen_create_room_private_option_title">"Частна стая"</string>
|
||||
<string name="screen_create_room_public_option_description">"Всеки може да намери тази стая.
|
||||
Можете да промените това по всяко време в настройките на стаята."</string>
|
||||
<string name="screen_create_room_public_option_title">"Общодостъпна стая"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Всеки може да се присъедини към тази стая"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Всеки"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"За да бъде тази стая видима в директорията на общодостъпните стаи, ще ви е необходим адрес на стаята."</string>
|
||||
<string name="screen_create_room_room_name_label">"Име на стаята"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Видимост на стаята"</string>
|
||||
<string name="screen_create_room_title">"Създаване на стая"</string>
|
||||
<string name="screen_create_room_topic_label">"Тема за разговор (незадължително)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nová místnost"</string>
|
||||
<string name="screen_create_room_add_people_title">"Pozvat přátele"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Při vytváření místnosti došlo k chybě"</string>
|
||||
<string name="screen_create_room_private_option_description">"Do této místnosti mají přístup pouze pozvaní lidé. Všechny zprávy jsou koncově šifrovány."</string>
|
||||
<string name="screen_create_room_private_option_title">"Soukromá místnost"</string>
|
||||
<string name="screen_create_room_public_option_description">"Tuto místnost může najít kdokoli.
|
||||
To můžete kdykoli změnit v nastavení místnosti."</string>
|
||||
<string name="screen_create_room_public_option_title">"Veřejná místnost"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Do této místnosti může vstoupit kdokoli"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Kdokoliv"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Přístup do místnosti"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Kdokoli může požádat o vstup do místnosti, ale správce nebo moderátor bude muset žádost přijmout"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Požádat o připojení"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Aby byla tato místnost viditelná v adresáři veřejných místností, budete potřebovat adresu místnosti."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Adresa místnosti"</string>
|
||||
<string name="screen_create_room_room_name_label">"Název místnosti"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Viditelnost místnosti"</string>
|
||||
<string name="screen_create_room_title">"Vytvořit místnost"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (nepovinné)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Ystafell newydd"</string>
|
||||
<string name="screen_create_room_add_people_title">"Gwahodd pobl"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Bu gwall wrth greu\'r ystafell"</string>
|
||||
<string name="screen_create_room_private_option_description">"Dim ond pobl wahoddwyd all gael mynediad i\'r ystafell hon. Mae pob neges wedi\'i hamgryptio o\'r dechrau i\'r diwedd."</string>
|
||||
<string name="screen_create_room_private_option_title">"Ystafell breifat"</string>
|
||||
<string name="screen_create_room_public_option_description">"Gall unrhyw un ddod o hyd i\'r ystafell hon.
|
||||
Gallwch newid hyn unrhyw bryd yng ngosodiadau ystafell."</string>
|
||||
<string name="screen_create_room_public_option_title">"Ystafell gyhoeddus"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Gall unrhyw un ymuno â\'r ystafell hon"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Unrhyw un"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Mynediad i\'r Ystafell"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Gall unrhyw un ofyn am gael ymuno â\'r ystafell ond bydd rhaid i weinyddwr neu gymedrolwr dderbyn y cais"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Gofyn i gael ymuno"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Er mwyn i\'r ystafell hon fod yn weladwy yn y cyfeiriadur ystafelloedd cyhoeddus, bydd angen cyfeiriad ystafell arnoch."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Cyfeiriad yr ystafell"</string>
|
||||
<string name="screen_create_room_room_name_label">"Enw\'r ystafell"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Gwelededd yr ystafell"</string>
|
||||
<string name="screen_create_room_title">"Creu ystafell"</string>
|
||||
<string name="screen_create_room_topic_label">"Pwnc (dewisol)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nyt rum"</string>
|
||||
<string name="screen_create_room_add_people_title">"Invitér andre"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Der opstod en fejl ved oprettelsen af rummet"</string>
|
||||
<string name="screen_create_room_private_option_description">"Kun inviterede personer kan få adgang til dette rum. Alle meddelelser er ende-til-ende krypteret."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privat rum"</string>
|
||||
<string name="screen_create_room_public_option_description">"Alle kan finde dette rum.
|
||||
Du kan ændre dette når som helst i rummets indstillinger."</string>
|
||||
<string name="screen_create_room_public_option_title">"Offentligt rum"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Alle kan deltage i dette rum"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Enhver"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Adgang til rummet"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Alle kan bede om at deltage i rummet, men en administrator eller en moderator skal acceptere anmodningen"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Spørg om at deltage"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Hvis dette rum skal være synligt i det offentlige register, skal du bruge en rum-adresse."</string>
|
||||
<string name="screen_create_room_room_name_label">"Navn på rum"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Rummets synlighed"</string>
|
||||
<string name="screen_create_room_title">"Opret et rum"</string>
|
||||
<string name="screen_create_room_topic_label">"Emne (valgfrit)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Neuer Chat"</string>
|
||||
<string name="screen_create_room_add_people_title">"Nutzer einladen"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Beim Erstellen des Chats ist ein Fehler aufgetreten"</string>
|
||||
<string name="screen_create_room_private_option_description">"Nur eingeladene Personen haben Zutritt zu diesem Chat. Alle Nachrichten sind Ende-zu-Ende verschlüsselt."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privater Chat"</string>
|
||||
<string name="screen_create_room_public_option_description">"Jeder kann diesen Chat finden.
|
||||
Du kannst dies jederzeit in den Einstellungen des Chats ändern."</string>
|
||||
<string name="screen_create_room_public_option_title">"Öffentlicher Chat"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Jeder darf diesem Chat beitreten"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Jeder"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Chat Zugang"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Jeder kann den Beitritt zum Chat erbitten, aber ein Admin oder Moderator muss die Anfrage akzeptieren."</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Beitritt beantragen"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Du benötigst eine Chat-Adresse, damit dieser Chat im öffentlichen Verzeichnis sichtbar ist."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Chatroom Adresse"</string>
|
||||
<string name="screen_create_room_room_name_label">"Chat-Name"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">" Sichtbarkeit des Chats"</string>
|
||||
<string name="screen_create_room_title">"Chat erstellen"</string>
|
||||
<string name="screen_create_room_topic_label">"Thema (optional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Νέα αίθουσα"</string>
|
||||
<string name="screen_create_room_add_people_title">"Πρόσκληση ατόμων"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Προέκυψε σφάλμα κατά τη δημιουργία της αίθουσας"</string>
|
||||
<string name="screen_create_room_private_option_description">"Μόνο τα άτομα που έχουν προσκληθεί μπορούν να έχουν πρόσβαση σε αυτή την αίθουσα. Όλα τα μηνύματα είναι κρυπτογραφημένα από άκρο σε άκρο."</string>
|
||||
<string name="screen_create_room_private_option_title">"Ιδιωτική αίθουσα"</string>
|
||||
<string name="screen_create_room_public_option_description">"Ο καθένας μπορεί να βρει αυτή την αίθουσα.
|
||||
Αυτό μπορείτε να το αλλάξετε ανά πάσα στιγμή στις ρυθμίσεις της αίθουσας."</string>
|
||||
<string name="screen_create_room_public_option_title">"Δημόσια αίθουσα"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Οποιοσδήποτε μπορεί να συμμετάσχει σε αυτή την αίθουσα"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Οποιοσδήποτε"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Πρόσβαση στην Αίθουσα"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή ένας συντονιστής θα πρέπει να αποδεχτεί το αίτημα"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Αίτημα συμμετοχής"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Για να είναι ορατή αυτή η αίθουσα στον δημόσιο κατάλογο αιθουσών, θα χρειαστείτε μια διεύθυνση αίθουσας."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Διεύθυνση δωματίου"</string>
|
||||
<string name="screen_create_room_room_name_label">"Όνομα αίθουσας"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Ορατότητα αίθουσας"</string>
|
||||
<string name="screen_create_room_title">"Δημιουργία αίθουσας"</string>
|
||||
<string name="screen_create_room_topic_label">"Θέμα (προαιρετικό)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nueva sala"</string>
|
||||
<string name="screen_create_room_add_people_title">"Invitar personas"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Se ha producido un error al crear la sala"</string>
|
||||
<string name="screen_create_room_private_option_description">"Solo las personas invitadas pueden acceder a esta sala. Todos los mensajes están cifrados de extremo a extremo."</string>
|
||||
<string name="screen_create_room_private_option_title">"Sala privada"</string>
|
||||
<string name="screen_create_room_public_option_description">"Cualquiera puede encontrar esta sala.
|
||||
Puedes cambiar esto en cualquier momento en los ajustes de la sala."</string>
|
||||
<string name="screen_create_room_public_option_title">"Sala pública"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Cualquiera puede unirse a esta sala"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Cualquiera"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Acceso a la sala"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Cualquiera puede solicitar unirse a la sala, pero un administrador o un moderador tendrá que aceptar la solicitud"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Solicitud para unirse"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Para que esta sala sea visible en el directorio de salas públicas, necesitarás una dirección de sala."</string>
|
||||
<string name="screen_create_room_room_name_label">"Nombre de la sala"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Visibilidad de la sala"</string>
|
||||
<string name="screen_create_room_title">"Crear una sala"</string>
|
||||
<string name="screen_create_room_topic_label">"Tema (opcional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Uus jututuba"</string>
|
||||
<string name="screen_create_room_add_people_title">"Kutsu osalejaid"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Jututoa loomisel tekkis viga"</string>
|
||||
<string name="screen_create_room_private_option_description">"Ligipääs siia jututuppa on vaid kutse alusel. Kõik sõnumid siin jututoas on läbivalt krüptitud."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privaatne jututuba"</string>
|
||||
<string name="screen_create_room_public_option_description">"Kõik saavad seda jututuba leida.
|
||||
Sa võid seda jututoa seadistustest alati muuta."</string>
|
||||
<string name="screen_create_room_public_option_title">"Avalik jututuba"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Kõik võivad selle jututoaga liituda"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Kõik"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Ligipääs jututoale"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Kõik võivad paluda selle jututoaga liitumist, kuid peakasutaja või moderaator peavad selle kinnitama"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Küsi võimalust liitumiseks"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Selleks, et see jututuba oleks nähtav jututubade avalikus kataloogis, sa vajad jututoa aadressi."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Jututoa aadress"</string>
|
||||
<string name="screen_create_room_room_name_label">"Jututoa nimi"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Jututoa nähtavus"</string>
|
||||
<string name="screen_create_room_title">"Loo jututuba"</string>
|
||||
<string name="screen_create_room_topic_label">"Teema (kui soovid lisada)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Gela berria"</string>
|
||||
<string name="screen_create_room_add_people_title">"Gonbidatu jendea"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Errorea gertatu da gela sortzean"</string>
|
||||
<string name="screen_create_room_private_option_description">"Gonbidatutako jendea soilik sar daiteke gelara. Mezu guztiak daude ertzetik ertzera zifratuta."</string>
|
||||
<string name="screen_create_room_private_option_title">"Gela pribatua"</string>
|
||||
<string name="screen_create_room_public_option_description">"Edonork aurki dezake gela hau.
|
||||
Gelaren ezarpenetan aldatu dezakezu hobespena."</string>
|
||||
<string name="screen_create_room_public_option_title">"Gela publikoa"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Edonor sar daiteke gela honetara"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Edonork"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Gelarako sarbidea"</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Gelaren helbidea"</string>
|
||||
<string name="screen_create_room_room_name_label">"Gelaren izena"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Gelaren ikusgarritasuna"</string>
|
||||
<string name="screen_create_room_title">"Sortu gela"</string>
|
||||
<string name="screen_create_room_topic_label">"Mintzagaia (aukerakoa)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"اتاق جدید"</string>
|
||||
<string name="screen_create_room_add_people_title">"دعوت افراد"</string>
|
||||
<string name="screen_create_room_error_creating_room">"هنگام ایجاد اتاق خطایی رخ داد"</string>
|
||||
<string name="screen_create_room_private_option_description">"تنها افراد دعوت شده میتوانند به این اتاق دسترسی داشته باشند. همهٔ پیامها رمزنگاری سرتاسری شدهاند."</string>
|
||||
<string name="screen_create_room_private_option_title">"اتاق خصوصی"</string>
|
||||
<string name="screen_create_room_public_option_description">"هرکسی میتواند اتاق را بیابد.
|
||||
میتوانید بعداً در تظیمات اتاق عوضش کنید."</string>
|
||||
<string name="screen_create_room_public_option_title">"اتاق عمومی"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"هرکسی میتواند به این اتاق بپیوندد"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"هرکسی"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"دسترسی اتاق"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"درخواست دعوت"</string>
|
||||
<string name="screen_create_room_room_address_section_title">"نشانی اتاق"</string>
|
||||
<string name="screen_create_room_room_name_label">"نام اتاق"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"نمایانی اتاق"</string>
|
||||
<string name="screen_create_room_title">"ایجاد اتاق"</string>
|
||||
<string name="screen_create_room_topic_label">"موضوع (اختیاری)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Uusi huone"</string>
|
||||
<string name="screen_create_room_add_people_title">"Kutsu henkilöitä"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Huoneen luomisessa tapahtui virhe"</string>
|
||||
<string name="screen_create_room_private_option_description">"Vain kutsutut henkilöt pääsevät tähän huoneeseen. Kaikki viestit ovat päästä päähän salattuja."</string>
|
||||
<string name="screen_create_room_private_option_title">"Yksityinen huone"</string>
|
||||
<string name="screen_create_room_public_option_description">"Kuka tahansa voi löytää tämän huoneen.
|
||||
Voit muuttaa tämän milloin tahansa huoneen asetuksista."</string>
|
||||
<string name="screen_create_room_public_option_title">"Julkinen huone"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Kuka tahansa voi liittyä tähän huoneeseen"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Kuka tahansa"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Huoneeseen Pääsy"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Kuka tahansa voi pyytää saada liittyä huoneeseen, mutta ylläpitäjän tai valvojan on hyväksyttävä pyyntö"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Pyydä liittymistä"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Jotta tämä huone näkyisi julkisessa huonehakemistossa, tarvitset huoneen osoitteen."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Huoneen osoite"</string>
|
||||
<string name="screen_create_room_room_name_label">"Huoneen nimi"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Huoneen näkyvyys"</string>
|
||||
<string name="screen_create_room_title">"Luo huone"</string>
|
||||
<string name="screen_create_room_topic_label">"Aihe (valinnainen)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nouveau salon"</string>
|
||||
<string name="screen_create_room_add_people_title">"Inviter des amis"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Une erreur s’est produite lors de la création du salon"</string>
|
||||
<string name="screen_create_room_private_option_description">"Seules les personnes invitées peuvent accéder à ce salon. Tous les messages sont chiffrés de bout en bout."</string>
|
||||
<string name="screen_create_room_private_option_title">"Salon privé"</string>
|
||||
<string name="screen_create_room_public_option_description">"N’importe qui peut trouver ce salon.
|
||||
Vous pouvez modifier cela à tout moment dans les paramètres du salon."</string>
|
||||
<string name="screen_create_room_public_option_title">"Salon public"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Tout le monde peut rejoindre ce salon"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Tout le monde"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Accès au salon"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Tout le monde peut demander à rejoindre le salon, mais un administrateur ou un modérateur devra accepter la demande"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Demander à rejoindre"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Pour que ce salon soit visible dans le répertoire des salons publics, vous aurez besoin d’une adresse de salon."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Adresse du salon"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nom du salon"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Visibilité du salon"</string>
|
||||
<string name="screen_create_room_title">"Créer un salon"</string>
|
||||
<string name="screen_create_room_topic_label">"Sujet (facultatif)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Új szoba"</string>
|
||||
<string name="screen_create_room_add_people_title">"Ismerősök meghívása"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Hiba történt a szoba létrehozásakor"</string>
|
||||
<string name="screen_create_room_private_option_description">"Csak a meghívottak léphetnek be ebbe a szobába. Az összes üzenet végpontok közti titkosítással van védve."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privát szoba"</string>
|
||||
<string name="screen_create_room_public_option_description">"Bárki megtalálhatja ezt a szobát.
|
||||
Ezt bármikor módosíthatja a szobabeállításokban."</string>
|
||||
<string name="screen_create_room_public_option_title">"Nyilvános szoba"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Bárki csatlakozhat ehhez a szobához"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Bárki"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Szobahozzáférés"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Bárki kérheti, hogy csatlakozzon a szobához, de egy adminisztrátornak vagy moderátornak el kell fogadnia a kérést"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Csatlakozás kérése"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Ahhoz, hogy ez a szoba látható legyen a nyilvános szobák címtárában, meg kell adnia a szoba címét."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Szoba címe"</string>
|
||||
<string name="screen_create_room_room_name_label">"Szoba neve"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Szoba láthatósága"</string>
|
||||
<string name="screen_create_room_title">"Szoba létrehozása"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (nem kötelező)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Ruangan baru"</string>
|
||||
<string name="screen_create_room_add_people_title">"Undang orang-orang"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Terjadi kesalahan saat membuat ruangan"</string>
|
||||
<string name="screen_create_room_private_option_description">"Hanya orang-orang yang diundang dapat mengakses ruangan ini. Semua pesan terenkripsi secara ujung ke ujung."</string>
|
||||
<string name="screen_create_room_private_option_title">"Ruangan pribadi"</string>
|
||||
<string name="screen_create_room_public_option_description">"Siapa pun dapat mencari ruangan ini.
|
||||
Anda dapat mengubah ini kapan pun dalam pengaturan ruangan."</string>
|
||||
<string name="screen_create_room_public_option_title">"Ruangan publik"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Siapa pun dapat bergabung dengan ruangan ini"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Siapa pun"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Akses Ruangan"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Siapa pun dapat meminta untuk bergabung dengan ruangan tetapi administrator atau moderator harus menerima permintaan tersebut"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Minta untuk bergabung"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Alamat ruangan"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nama ruangan"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Keterlihatan ruangan"</string>
|
||||
<string name="screen_create_room_title">"Buat ruangan"</string>
|
||||
<string name="screen_create_room_topic_label">"Topik (opsional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nuova stanza"</string>
|
||||
<string name="screen_create_room_add_people_title">"Invita persone"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Si è verificato un errore durante la creazione della stanza"</string>
|
||||
<string name="screen_create_room_private_option_description">"Solo le persone invitate possono accedere a questa stanza. Tutti i messaggi sono cifrati end-to-end."</string>
|
||||
<string name="screen_create_room_private_option_title">"Stanza privata"</string>
|
||||
<string name="screen_create_room_public_option_description">"Chiunque può trovare questa stanza.
|
||||
Puoi modificarlo in qualsiasi momento nelle impostazioni della stanza."</string>
|
||||
<string name="screen_create_room_public_option_title">"Stanza pubblica"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Chiunque può entrare in questa stanza"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Chiunque"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Accesso alla stanza"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Chiunque può chiedere di entrare nella stanza, ma un amministratore o un moderatore dovrà accettare la richiesta"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Chiedi di entrare"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Affinché questa stanza sia visibile nell\'elenco delle stanze pubbliche, è necessario un indirizzo della stanza."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Indirizzo della stanza"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nome stanza"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Visibilità della stanza"</string>
|
||||
<string name="screen_create_room_title">"Crea una stanza"</string>
|
||||
<string name="screen_create_room_topic_label">"Argomento (facoltativo)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"ახალი ოთახი"</string>
|
||||
<string name="screen_create_room_add_people_title">"ხალხის მოწვევა"</string>
|
||||
<string name="screen_create_room_error_creating_room">"ოთახის შექმნისას შეცდომა მოხდა"</string>
|
||||
<string name="screen_create_room_private_option_description">"ამ ოთახში შეტყობინებები დაშიფრულია. შემდგომ დაშიფვრის გამორთვა შეუძლებელია."</string>
|
||||
<string name="screen_create_room_private_option_title">"კერძო ოთახი"</string>
|
||||
<string name="screen_create_room_public_option_description">"ყველას ამ ოთახის მოძებნა შეუძლია.
|
||||
თქვენ ნებისმიერ დროს შეგიძლიათ ამის შეცვლა ოთახის პარამეტრებში."</string>
|
||||
<string name="screen_create_room_room_name_label">"ოთახის სახელი"</string>
|
||||
<string name="screen_create_room_title">"ოთახის შექმნა"</string>
|
||||
<string name="screen_create_room_topic_label">"თემა (სურვილისამებრ)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"새 방"</string>
|
||||
<string name="screen_create_room_add_people_title">"사람 초대하기"</string>
|
||||
<string name="screen_create_room_error_creating_room">"방을 생성하던 중 오류가 발생했어요"</string>
|
||||
<string name="screen_create_room_private_option_description">"초대받은 사람만 이 방에 액세스할 수 있습니다. 모든 메시지는 종단 간 암호화됩니다."</string>
|
||||
<string name="screen_create_room_private_option_title">"비공개 방"</string>
|
||||
<string name="screen_create_room_public_option_description">"누구나 이 방을 찾을 수 있습니다.
|
||||
방 설정에서 언제든지 변경할 수 있습니다."</string>
|
||||
<string name="screen_create_room_public_option_title">"공개 방"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"누구나 이 방에 참여할 수 있습니다."</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"누구나"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"방 액세스"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"누구나 방에 참여 요청을 할 수 있지만, 관리자나 운영자가 요청을 수락해야 합니다."</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"참가 요청"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"이 방이 공개 방 디렉토리에 표시되려면 방 주소가 필요합니다."</string>
|
||||
<string name="screen_create_room_room_name_label">"방 이름"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"방 표시 여부"</string>
|
||||
<string name="screen_create_room_title">"방 만들기"</string>
|
||||
<string name="screen_create_room_topic_label">"주제 (선택)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Naujas kambarys"</string>
|
||||
<string name="screen_create_room_add_people_title">"Pakviesti žmonių"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Kuriant kambarį įvyko klaida"</string>
|
||||
<string name="screen_create_room_private_option_description">"Į šį kambarį gali patekti tik pakviesti žmonės. Visi pranešimai yra užšifruoti nuo pradžios iki galo."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privatus kambarys"</string>
|
||||
<string name="screen_create_room_public_option_description">"Bet kas gali rasti šį kambarį.
|
||||
Tai galite bet kada pakeisti kambario nustatymuose."</string>
|
||||
<string name="screen_create_room_room_name_label">"Kambario pavadinimas"</string>
|
||||
<string name="screen_create_room_title">"Kurti kambarį"</string>
|
||||
<string name="screen_create_room_topic_label">"Tema (nebūtina)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nytt rom"</string>
|
||||
<string name="screen_create_room_add_people_title">"Inviter folk"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Det oppsto en feil under opprettelsen av rommet"</string>
|
||||
<string name="screen_create_room_private_option_description">"Bare inviterte personer har tilgang til dette rommet. Alle meldinger er ende-til-ende-kryptert."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privat rom"</string>
|
||||
<string name="screen_create_room_public_option_description">"Alle kan finne dette rommet.
|
||||
Du kan endre dette når som helst i rominnstillingene."</string>
|
||||
<string name="screen_create_room_public_option_title">"Offentlig rom"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Alle kan bli med i dette rommet"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Alle"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Tilgang til rom"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Alle kan be om å få bli med i rommet, men en administrator eller moderator må godta forespørselen"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Be om å bli med"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"For at dette rommet skal være synlig i den offentlige romkatalogen, trenger du en romadresse."</string>
|
||||
<string name="screen_create_room_room_name_label">"Romnavn"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Romsynlighet"</string>
|
||||
<string name="screen_create_room_title">"Opprett et rom"</string>
|
||||
<string name="screen_create_room_topic_label">"Emne (valgfritt)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nieuwe kamer"</string>
|
||||
<string name="screen_create_room_add_people_title">"Mensen uitnodigen"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Er is een fout opgetreden bij het aanmaken van de kamer"</string>
|
||||
<string name="screen_create_room_private_option_description">"Alleen uitgenodigde personen hebben toegang tot deze kamer. Alle berichten zijn end-to-end versleuteld."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privé kamer"</string>
|
||||
<string name="screen_create_room_public_option_description">"Iedereen kan deze kamer vinden.
|
||||
Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen."</string>
|
||||
<string name="screen_create_room_public_option_title">"Openbare kamer"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Iedereen kan toetreden tot deze kamer"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Iedereen"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Toegang tot de kamer"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Iedereen kan vragen om toe te treden tot de kamer, maar een beheerder of moderator moet het verzoek accepteren"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Vraag om toe te treden"</string>
|
||||
<string name="screen_create_room_room_name_label">"Naam van de kamer"</string>
|
||||
<string name="screen_create_room_title">"Creëer een kamer"</string>
|
||||
<string name="screen_create_room_topic_label">"Onderwerp (optioneel)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nowy pokój"</string>
|
||||
<string name="screen_create_room_add_people_title">"Zaproś znajomych"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Wystąpił błąd w trakcie tworzenia pokoju"</string>
|
||||
<string name="screen_create_room_private_option_description">"Tylko zaproszone osoby mogą dołączyć do tego pokoju. Wszystkie wiadomości są szyfrowane end-to-end."</string>
|
||||
<string name="screen_create_room_private_option_title">"Pokój prywatny"</string>
|
||||
<string name="screen_create_room_public_option_description">"Każdy może znaleźć ten pokój.
|
||||
Możesz to zmienić w ustawieniach pokoju."</string>
|
||||
<string name="screen_create_room_public_option_title">"Pokój publiczny"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Każdy może dołączyć do tego pokoju"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Wszyscy"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Dostęp do pokoju"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Każdy może poprosić o dołączenie do pokoju, ale administrator lub moderator będzie musiał zatwierdzić prośbę"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Poproś o dołączenie"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Aby ten pokój był widoczny w katalogu pomieszczeń publicznych, będziesz potrzebował adres pokoju."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Adres pokoju"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nazwa pokoju"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Widoczność pomieszczenia"</string>
|
||||
<string name="screen_create_room_title">"Utwórz pokój"</string>
|
||||
<string name="screen_create_room_topic_label">"Temat (opcjonalnie)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nova sala"</string>
|
||||
<string name="screen_create_room_add_people_title">"Convidar pessoas"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Ocorreu um erro ao criar a sala"</string>
|
||||
<string name="screen_create_room_private_option_description">"Apenas as pessoas convidadas podem entrar nesta sala. Todas as mensagens são criptografadas de ponta a ponta."</string>
|
||||
<string name="screen_create_room_private_option_title">"Sala privada"</string>
|
||||
<string name="screen_create_room_public_option_description">"Qualquer um pode encontrar esta sala.
|
||||
Você pode mudar isso a qualquer momento nas configurações da sala."</string>
|
||||
<string name="screen_create_room_public_option_title">"Sala pública"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Qualquer pessoa pode entrar nesta sala"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Qualquer pessoa"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Acesso à sala"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Qualquer pessoa pode pedir para entrar na sala, mas um administrador ou moderador terá de aceitar a solicitação"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Pedir para entrar"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Para que esta sala fique visível no diretório público de salas, você precisará de um endereço de sala."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Endereço da sala"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nome da sala"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Visibilidade da sala"</string>
|
||||
<string name="screen_create_room_title">"Criar uma sala"</string>
|
||||
<string name="screen_create_room_topic_label">"Tópico (opcional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nova sala"</string>
|
||||
<string name="screen_create_room_add_people_title">"Convidar pessoas"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Ocorreu um erro ao criar a sala"</string>
|
||||
<string name="screen_create_room_private_option_description">"Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são cifradas ponta-a-ponta."</string>
|
||||
<string name="screen_create_room_private_option_title">"Sala privada"</string>
|
||||
<string name="screen_create_room_public_option_description">"Qualquer um pode encontrar esta sala.
|
||||
Pode alterar esta opção nas definições da sala."</string>
|
||||
<string name="screen_create_room_public_option_title">"Sala pública"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Qualquer pessoa pode entrar nesta sala"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Qualquer pessoa"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Acesso à sala"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Qualquer pessoa pode pedir para entrar na sala, mas um administrador ou um moderador terá de aceitar o pedido"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Pedir para participar"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Para que esta sala seja visível no diretório público de salas, precisas de um endereço de sala."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Endereço da sala"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nome da sala"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Visibilidade da sala"</string>
|
||||
<string name="screen_create_room_title">"Criar uma sala"</string>
|
||||
<string name="screen_create_room_topic_label">"Descrição (opcional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Cameră nouă"</string>
|
||||
<string name="screen_create_room_add_people_title">"Invitați prieteni"</string>
|
||||
<string name="screen_create_room_error_creating_room">"A apărut o eroare la crearea camerei"</string>
|
||||
<string name="screen_create_room_private_option_description">"Doar persoanele invitate pot accesa această cameră. Toate mesajele sunt criptate end-to-end."</string>
|
||||
<string name="screen_create_room_private_option_title">"Cameră privată"</string>
|
||||
<string name="screen_create_room_public_option_description">"Oricine poate găsi această cameră.
|
||||
Puteți modifica acest lucru oricând în setări."</string>
|
||||
<string name="screen_create_room_public_option_title">"Cameră publică"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Oricine se poate alătura acestei camere"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Oricine"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Acces la cameră"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Oricine poate cere să se alăture camerei, dar un administrator sau un moderator va trebui să accepte cererea"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Cereți să vă alăturați"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Pentru ca această cameră să fie vizibilă în directorul de camere publice, veți avea nevoie de o adresă de cameră."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Adresa camerei"</string>
|
||||
<string name="screen_create_room_room_name_label">"Numele camerei"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Vizibilitatea camerei"</string>
|
||||
<string name="screen_create_room_title">"Creați o cameră"</string>
|
||||
<string name="screen_create_room_topic_label">"Subiect (opțional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Создать новую комнату"</string>
|
||||
<string name="screen_create_room_add_people_title">"Пригласить в комнату"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Произошла ошибка при создании комнаты"</string>
|
||||
<string name="screen_create_room_private_option_description">"Доступ в эту комнату имеют только приглашенные пользователи. Все сообщения защищены сквозным шифрованием."</string>
|
||||
<string name="screen_create_room_private_option_title">"Частная комната"</string>
|
||||
<string name="screen_create_room_public_option_description">"Любой желающий может найти эту комнату.
|
||||
Вы можете изменить это в любое время в настройках комнаты."</string>
|
||||
<string name="screen_create_room_public_option_title">"Общедоступная комната"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Любой желающий может присоединиться к этой комнате"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Любой"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Доступ в комнату"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Любой желающий может подать заявку на присоединение к комнате, но администратор или модератор должен будет принять запрос."</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Попросить присоединиться"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Чтобы эта комната была видна в каталоге общедоступных, вам необходим ее адрес"</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Адрес комнаты"</string>
|
||||
<string name="screen_create_room_room_name_label">"Название комнаты"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Видимость комнаты"</string>
|
||||
<string name="screen_create_room_title">"Создать комнату"</string>
|
||||
<string name="screen_create_room_topic_label">"Тема (необязательно)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nová miestnosť"</string>
|
||||
<string name="screen_create_room_add_people_title">"Pozvať ľudí"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Pri vytváraní miestnosti došlo k chybe"</string>
|
||||
<string name="screen_create_room_private_option_description">"Do tejto miestnosti majú prístup iba pozvaní ľudia. Všetky správy sú end-to-end šifrované."</string>
|
||||
<string name="screen_create_room_private_option_title">"Súkromná miestnosť"</string>
|
||||
<string name="screen_create_room_public_option_description">"Túto miestnosť môže nájsť ktokoľvek.
|
||||
Môžete to kedykoľvek zmeniť v nastaveniach miestnosti."</string>
|
||||
<string name="screen_create_room_public_option_title">"Verejná miestnosť"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Do tejto miestnosti sa môže pripojiť ktokoľvek"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Ktokoľvek"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Prístup do miestnosti"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Ktokoľvek môže požiadať o pripojenie sa k miestnosti, ale administrátor alebo moderátor bude musieť žiadosť schváliť"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Požiadať o pripojenie"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Aby bola táto miestnosť viditeľná v adresári verejných miestností, budete potrebovať adresu miestnosti."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Adresa miestnosti"</string>
|
||||
<string name="screen_create_room_room_name_label">"Názov miestnosti"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Viditeľnosť miestnosti"</string>
|
||||
<string name="screen_create_room_title">"Vytvoriť miestnosť"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (voliteľné)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Nytt rum"</string>
|
||||
<string name="screen_create_room_add_people_title">"Bjud in personer"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Ett fel uppstod när rummet skapades"</string>
|
||||
<string name="screen_create_room_private_option_description">"Endast inbjudna personer har tillgång till detta rum. Alla meddelanden är totalsträckskrypterade."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privat rum"</string>
|
||||
<string name="screen_create_room_public_option_description">"Vem som helst kan hitta det här rummet.
|
||||
Du kan ändra detta när som helst i rumsinställningarna."</string>
|
||||
<string name="screen_create_room_public_option_title">"Offentligt rum"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Vem som helst kan gå med i det här rummet"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Vem som helst"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Rumsåtkomst"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Vem som helst kan be om att gå med i rummet men en administratör eller en moderator måste acceptera begäran"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Be om att gå med"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"För att detta rum ska vara synligt i den allmänna rumskatalogen behöver du en rumsadress."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Rumsadress"</string>
|
||||
<string name="screen_create_room_room_name_label">"Rumsnamn"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Rumssynlighet"</string>
|
||||
<string name="screen_create_room_title">"Skapa ett rum"</string>
|
||||
<string name="screen_create_room_topic_label">"Ämne (valfritt)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Yeni oda"</string>
|
||||
<string name="screen_create_room_add_people_title">"İnsanları davet et"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Oda oluşturulurken bir hata oluştu"</string>
|
||||
<string name="screen_create_room_private_option_description">"Bu odaya yalnızca davet edilen kişiler erişebilir. Tüm mesajlar uçtan uca şifrelenir."</string>
|
||||
<string name="screen_create_room_private_option_title">"Özel oda"</string>
|
||||
<string name="screen_create_room_public_option_description">"Bu odayı herkes bulabilir.
|
||||
Bunu istediğiniz zaman oda ayarlarından değiştirebilirsiniz."</string>
|
||||
<string name="screen_create_room_public_option_title">"Herkese açık oda"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Bu odaya herkes katılabilir"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Herkes"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Oda Erişimi"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Herkes odaya katılmayı isteyebilir ancak bir yönetici veya moderatörün isteği kabul etmesi gerekecektir"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Katılmak için sor"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Bu odanın genel oda dizininde görünür olması için bir oda adresine ihtiyacınız olacaktır."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Oda adresi"</string>
|
||||
<string name="screen_create_room_room_name_label">"Oda adı"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Oda görünürlüğü"</string>
|
||||
<string name="screen_create_room_title">"Bir oda oluştur"</string>
|
||||
<string name="screen_create_room_topic_label">"Konu (isteğe bağlı)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Нова кімната"</string>
|
||||
<string name="screen_create_room_add_people_title">"Запросити людей"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Під час створення кімнати сталася помилка"</string>
|
||||
<string name="screen_create_room_private_option_description">"Лише запрошені люди мають доступ до цієї кімнати. Усі повідомлення захищені наскрізним шифруванням."</string>
|
||||
<string name="screen_create_room_private_option_title">"Приватна кімната (тільки за запрошенням)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Будь-хто може знайти цю кімнату.
|
||||
Ви можете змінити це в будь-який час у налаштуваннях кімнати."</string>
|
||||
<string name="screen_create_room_public_option_title">"Загальнодоступна кімната"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Будь-хто може приєднатися до цієї кімнати"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Кожний"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Доступ до кімнати"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Будь-хто може попросити приєднатися до кімнати, але адміністратор або модератор повинен буде прийняти запит"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Запросити приєднатися"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Щоб цю кімнату було видно в каталозі загальнодоступних кімнат, вам знадобиться її адреса."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Адреса кімнати"</string>
|
||||
<string name="screen_create_room_room_name_label">"Назва кімнати"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Видимість кімнати"</string>
|
||||
<string name="screen_create_room_title">"Створити кімнату"</string>
|
||||
<string name="screen_create_room_topic_label">"Тема (необов\'язково)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"نیا کمرہ"</string>
|
||||
<string name="screen_create_room_add_people_title">"لوگوں کو مدعو کریں"</string>
|
||||
<string name="screen_create_room_error_creating_room">"کمرہ تخلیق کرتے ہوئے ایک نقص واقع ہوا"</string>
|
||||
<string name="screen_create_room_private_option_description">"صرف مدعو لوگ ہی اس کمرے تک رسائی حاصل کر سکتے ہیں۔ تمام پیغامات آخر تا آخر مرموز کردہ ہیں۔"</string>
|
||||
<string name="screen_create_room_private_option_title">"نجی کمرہ"</string>
|
||||
<string name="screen_create_room_public_option_description">"کوئی بھی یہ کمرہ ڈھونڈ سکتا ہے۔
|
||||
آپ اسے کمرے کی ترتیبات میں کسی بھی وقت تبدیل کرسکتے ہیں۔"</string>
|
||||
<string name="screen_create_room_public_option_title">"عوامی کمرہ"</string>
|
||||
<string name="screen_create_room_room_name_label">"کمرے کا نام"</string>
|
||||
<string name="screen_create_room_title">"ایک کمرہ بنائیں"</string>
|
||||
<string name="screen_create_room_topic_label">"موضوع (اختیاری)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Yangi xona"</string>
|
||||
<string name="screen_create_room_add_people_title">"Odamlarni taklif qiling"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Xonani yaratishda xatolik yuz berdi"</string>
|
||||
<string name="screen_create_room_private_option_description">"Faqat taklif etilgan shaxslargina bu xonaga kira oladi. Barcha xabarlar boshdan-oxirigacha shifrlanadi."</string>
|
||||
<string name="screen_create_room_private_option_title">"Shaxsiy xona"</string>
|
||||
<string name="screen_create_room_public_option_description">"Bu xonani har kim topishi mumkin.
|
||||
Buni xona sozlamalaridan istalgan vaqtda oʻzgartirishingiz mumkin."</string>
|
||||
<string name="screen_create_room_public_option_title">"Jamoat xonasi"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Bu xonaga istalgan kishi qo‘shilishi mumkin"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Har kim"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Xonaga kirish"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Xonaga qo‘shilishni istalgan kishi so‘rashi mumkin, lekin administrator yoki moderator so‘rovni qabul qilishi kerak"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Qo‘shilishni so‘rang"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Ushbu xona ommaviy xonalar ro‘yxatida ko‘rinishi uchun sizga xona manzili kerak bo‘ladi."</string>
|
||||
<string name="screen_create_room_room_name_label">"Xona nomi"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Xonaning ko‘rinishi"</string>
|
||||
<string name="screen_create_room_title">"Xonani yaratish"</string>
|
||||
<string name="screen_create_room_topic_label">"Mavzu (ixtiyoriy)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"建立聊天室"</string>
|
||||
<string name="screen_create_room_add_people_title">"邀請夥伴"</string>
|
||||
<string name="screen_create_room_error_creating_room">"建立聊天室時發生錯誤"</string>
|
||||
<string name="screen_create_room_private_option_description">"僅被邀請的人才能存取此聊天室。所有訊息均會端到端加密。"</string>
|
||||
<string name="screen_create_room_private_option_title">"私密聊天室"</string>
|
||||
<string name="screen_create_room_public_option_description">"任何人都可以找到此聊天室。
|
||||
您隨時都可以在聊天室設定中變更此設定。"</string>
|
||||
<string name="screen_create_room_public_option_title">"公開的聊天室"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"任何人都可以加入此聊天室"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"任何人"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"聊天室存取權"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"任何人都可以要求加入聊天室,但管理員或版主必須接受該請求"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"要求加入"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"為了讓此聊天室在公開聊天室目錄中可見,您需要聊天室地址。"</string>
|
||||
<string name="screen_create_room_room_address_section_title">"聊天室地址"</string>
|
||||
<string name="screen_create_room_room_name_label">"聊天室名稱"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"聊天室能見度"</string>
|
||||
<string name="screen_create_room_title">"建立聊天室"</string>
|
||||
<string name="screen_create_room_topic_label">"主題(非必填)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"新聊天室"</string>
|
||||
<string name="screen_create_room_add_people_title">"邀请朋友"</string>
|
||||
<string name="screen_create_room_error_creating_room">"创建聊天室时出错"</string>
|
||||
<string name="screen_create_room_private_option_description">"只有受邀用户才能访问此聊天室。所有消息均经过端到端加密。"</string>
|
||||
<string name="screen_create_room_private_option_title">"私有聊天室"</string>
|
||||
<string name="screen_create_room_public_option_description">"任何人都能找到此聊天室。
|
||||
你可以随时在聊天室设置中更改。"</string>
|
||||
<string name="screen_create_room_public_option_title">"公共聊天室"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"任何人都可以加入此房间"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"任何人"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"房间访问权限"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"任何人都可以请求加入房间,但必须由管理员或审核人接受"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"请求加入"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"要使该房间在公开房间目录中可见,您需要一个房间地址。"</string>
|
||||
<string name="screen_create_room_room_address_section_title">"房间地址"</string>
|
||||
<string name="screen_create_room_room_name_label">"聊天室名称"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"房间可见性"</string>
|
||||
<string name="screen_create_room_title">"创建聊天室"</string>
|
||||
<string name="screen_create_room_topic_label">"主题(可选)"</string>
|
||||
</resources>
|
||||
22
features/createroom/impl/src/main/res/values/localazy.xml
Normal file
22
features/createroom/impl/src/main/res/values/localazy.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"New room"</string>
|
||||
<string name="screen_create_room_add_people_title">"Invite people"</string>
|
||||
<string name="screen_create_room_error_creating_room">"An error occurred when creating the room"</string>
|
||||
<string name="screen_create_room_private_option_description">"Only people invited can access this room. All messages are end-to-end encrypted."</string>
|
||||
<string name="screen_create_room_private_option_title">"Private room"</string>
|
||||
<string name="screen_create_room_public_option_description">"Anyone can find this room.
|
||||
You can change this anytime in room settings."</string>
|
||||
<string name="screen_create_room_public_option_title">"Public room"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Anyone can join this room"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Anyone"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Room Access"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Anyone can ask to join the room but an administrator or a moderator will have to accept the request"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Ask to join"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"In order for this room to be visible in the public room directory, you will need a room address."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Room address"</string>
|
||||
<string name="screen_create_room_room_name_label">"Room name"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Room visibility"</string>
|
||||
<string name="screen_create_room_title">"Create a room"</string>
|
||||
<string name="screen_create_room_topic_label">"Topic (optional)"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.createroom.api.CreateRoomEntryPoint
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.node.TestParentNode
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultCreateRoomEntryPointTest {
|
||||
@get:Rule
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@get:Rule
|
||||
val mainDispatcherRule = MainDispatcherRule()
|
||||
|
||||
@Test
|
||||
fun `test node builder`() {
|
||||
val entryPoint = DefaultCreateRoomEntryPoint()
|
||||
|
||||
val parentNode = TestParentNode.create { buildContext, plugins ->
|
||||
CreateRoomFlowNode(
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
)
|
||||
}
|
||||
val callback = object : CreateRoomEntryPoint.Callback {
|
||||
override fun onRoomCreated(roomId: RoomId) = lambdaError()
|
||||
}
|
||||
val result = entryPoint.createNode(
|
||||
parentNode = parentNode,
|
||||
buildContext = BuildContext.root(null),
|
||||
callback = callback,
|
||||
)
|
||||
assertThat(result.plugins).contains(callback)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.startchat.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import app.cash.turbine.TurbineTestContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomEvents
|
||||
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomPresenter
|
||||
import io.element.android.features.createroom.impl.configureroom.ConfigureRoomState
|
||||
import io.element.android.features.createroom.impl.configureroom.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.configureroom.CreateRoomConfigStore
|
||||
import io.element.android.features.createroom.impl.configureroom.RoomAccess
|
||||
import io.element.android.features.createroom.impl.configureroom.RoomAddress
|
||||
import io.element.android.features.createroom.impl.configureroom.RoomVisibilityItem
|
||||
import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_MESSAGE
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediapickers.test.FakePickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
|
||||
import io.element.android.libraries.mediaupload.test.FakeMediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenter
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.test
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkAll
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import java.io.File
|
||||
import java.util.Optional
|
||||
|
||||
private const val AN_URI_FROM_CAMERA = "content://uri_from_camera"
|
||||
private const val AN_URI_FROM_CAMERA_2 = "content://uri_from_camera_2"
|
||||
private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery"
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class ConfigureRoomPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockkStatic(File::readBytes)
|
||||
every { any<File>().readBytes() } returns byteArrayOf()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
unmockkAll()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val presenter = createConfigureRoomPresenter()
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
assertThat(initialState.config).isEqualTo(CreateRoomConfig())
|
||||
assertThat(initialState.config.roomName).isNull()
|
||||
assertThat(initialState.config.topic).isNull()
|
||||
assertThat(initialState.config.invites).isEmpty()
|
||||
assertThat(initialState.config.avatarUri).isNull()
|
||||
assertThat(initialState.config.roomVisibility).isEqualTo(RoomVisibilityState.Private)
|
||||
assertThat(initialState.createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
assertThat(initialState.homeserverName).isEqualTo("matrix.org")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - create room button is enabled only if the required fields are completed`() = runTest {
|
||||
val presenter = createConfigureRoomPresenter()
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
var config = initialState.config
|
||||
assertThat(initialState.isValid).isFalse()
|
||||
|
||||
// Room name not empty
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomNameChanged(A_ROOM_NAME))
|
||||
var newState: ConfigureRoomState = awaitItem()
|
||||
config = config.copy(roomName = A_ROOM_NAME)
|
||||
assertThat(newState.config).isEqualTo(config)
|
||||
assertThat(newState.isValid).isTrue()
|
||||
|
||||
// Clear room name
|
||||
newState.eventSink(ConfigureRoomEvents.RoomNameChanged(""))
|
||||
newState = awaitItem()
|
||||
config = config.copy(roomName = null)
|
||||
assertThat(newState.config).isEqualTo(config)
|
||||
assertThat(newState.isValid).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - state is updated when fields are changed`() = runTest {
|
||||
val pickerProvider = FakePickerProvider()
|
||||
val permissionsPresenter = FakePermissionsPresenter()
|
||||
val roomAliasHelper = FakeRoomAliasHelper()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
dataStore = CreateRoomConfigStore(roomAliasHelper),
|
||||
pickerProvider = pickerProvider,
|
||||
permissionsPresenter = permissionsPresenter,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
var expectedConfig = CreateRoomConfig()
|
||||
assertThat(initialState.config).isEqualTo(expectedConfig)
|
||||
// Room name
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomNameChanged(A_ROOM_NAME))
|
||||
var newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(roomName = A_ROOM_NAME)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
|
||||
// Room topic
|
||||
newState.eventSink(ConfigureRoomEvents.TopicChanged(A_MESSAGE))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(topic = A_MESSAGE)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
|
||||
// Room avatar
|
||||
// Pick avatar
|
||||
pickerProvider.givenResult(null)
|
||||
// From gallery
|
||||
val uriFromGallery = AN_URI_FROM_GALLERY
|
||||
pickerProvider.givenResult(uriFromGallery.toUri())
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(avatarUri = uriFromGallery)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
// From camera
|
||||
val uriFromCamera = AN_URI_FROM_CAMERA
|
||||
pickerProvider.givenResult(uriFromCamera.toUri())
|
||||
assertThat(newState.cameraPermissionState.permissionGranted).isFalse()
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.TakePhoto))
|
||||
newState = awaitItem()
|
||||
assertThat(newState.cameraPermissionState.showDialog).isTrue()
|
||||
permissionsPresenter.setPermissionGranted()
|
||||
newState = awaitItem()
|
||||
assertThat(newState.cameraPermissionState.permissionGranted).isTrue()
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(avatarUri = uriFromCamera)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
// Do it again, no permission is requested
|
||||
val uriFromCamera2 = AN_URI_FROM_CAMERA_2
|
||||
pickerProvider.givenResult(uriFromCamera2.toUri())
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.TakePhoto))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(avatarUri = uriFromCamera2)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
// Remove
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.Remove))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(avatarUri = null)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
|
||||
// Room privacy
|
||||
newState.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(RoomVisibilityItem.Public))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled(roomAliasHelper.roomAliasNameFromRoomDisplayName(expectedConfig.roomName ?: "")),
|
||||
roomAccess = RoomAccess.Anyone,
|
||||
)
|
||||
)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger create room action`() = runTest {
|
||||
val matrixClient = createMatrixClient()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = matrixClient
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
val createRoomResult = Result.success(RoomId("!createRoomResult:domain"))
|
||||
|
||||
matrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Success::class.java)
|
||||
assertThat(stateAfterCreateRoom.createRoomAction.dataOrNull()).isEqualTo(createRoomResult.getOrNull())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - record analytics when creating room`() = runTest {
|
||||
val matrixClient = createMatrixClient()
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = matrixClient,
|
||||
analyticsService = analyticsService
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
val createRoomResult = Result.success(RoomId("!createRoomResult:domain"))
|
||||
|
||||
matrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
skipItems(2)
|
||||
|
||||
val analyticsEvent = analyticsService.capturedEvents.filterIsInstance<CreatedRoom>().firstOrNull()
|
||||
assertThat(analyticsEvent).isNotNull()
|
||||
assertThat(analyticsEvent?.isDM).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger create room with upload error and retry`() = runTest {
|
||||
val matrixClient = createMatrixClient()
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val mediaPreProcessor = FakeMediaPreProcessor()
|
||||
val dataStore = CreateRoomConfigStore(FakeRoomAliasHelper())
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
dataStore = dataStore,
|
||||
mediaPreProcessor = mediaPreProcessor,
|
||||
matrixClient = matrixClient,
|
||||
analyticsService = analyticsService
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
dataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY))
|
||||
skipItems(1)
|
||||
mediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk())))
|
||||
matrixClient.givenUploadMediaResult(Result.failure(AN_EXCEPTION))
|
||||
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
assertThat(analyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
|
||||
|
||||
matrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL))
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Success::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger retry and cancel actions`() = runTest {
|
||||
val fakeMatrixClient = createMatrixClient()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = fakeMatrixClient
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
val createRoomResult = Result.failure<RoomId>(AN_EXCEPTION)
|
||||
|
||||
fakeMatrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
// Create
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
assertThat((stateAfterCreateRoom.createRoomAction as? AsyncAction.Failure)?.error).isEqualTo(createRoomResult.exceptionOrNull())
|
||||
|
||||
// Retry
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterRetry = awaitItem()
|
||||
assertThat(stateAfterRetry.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
assertThat((stateAfterRetry.createRoomAction as? AsyncAction.Failure)?.error).isEqualTo(createRoomResult.exceptionOrNull())
|
||||
|
||||
// Cancel
|
||||
stateAfterRetry.eventSink(ConfigureRoomEvents.CancelCreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `present - address is invalid when format is invalid`() = runTest {
|
||||
val aliasHelper = FakeRoomAliasHelper(
|
||||
isRoomAliasValidLambda = { false }
|
||||
)
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
roomAliasHelper = aliasHelper
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(RoomVisibilityItem.Public))
|
||||
skipItems(1)
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomAddressChanged("invalid address"))
|
||||
skipItems(1)
|
||||
advanceUntilIdle()
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.roomAddressValidity).isEqualTo(RoomAddressValidity.InvalidSymbols)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `present - address is not available when alias is not available`() = runTest {
|
||||
val fakeMatrixClient = createMatrixClient(isAliasAvailable = false)
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = fakeMatrixClient,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(RoomVisibilityItem.Public))
|
||||
skipItems(1)
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomAddressChanged("address"))
|
||||
skipItems(1)
|
||||
advanceUntilIdle()
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.roomAddressValidity).isEqualTo(RoomAddressValidity.NotAvailable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `present - address is valid when alias is available and format is valid`() = runTest {
|
||||
val fakeMatrixClient = createMatrixClient(isAliasAvailable = true)
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = fakeMatrixClient,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(RoomVisibilityItem.Public))
|
||||
skipItems(1)
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomAddressChanged("address"))
|
||||
skipItems(1)
|
||||
advanceUntilIdle()
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.roomAddressValidity).isEqualTo(RoomAddressValidity.Valid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun TurbineTestContext<ConfigureRoomState>.initialState(): ConfigureRoomState {
|
||||
skipItems(1)
|
||||
return awaitItem()
|
||||
}
|
||||
|
||||
private fun createMatrixClient(isAliasAvailable: Boolean = true) = FakeMatrixClient(
|
||||
userIdServerNameLambda = { "matrix.org" },
|
||||
resolveRoomAliasResult = {
|
||||
val resolvedRoomAlias = if (isAliasAvailable) {
|
||||
Optional.empty()
|
||||
} else {
|
||||
Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
|
||||
}
|
||||
Result.success(resolvedRoomAlias)
|
||||
}
|
||||
)
|
||||
|
||||
private fun createConfigureRoomPresenter(
|
||||
roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper(),
|
||||
dataStore: CreateRoomConfigStore = CreateRoomConfigStore(roomAliasHelper),
|
||||
matrixClient: MatrixClient = createMatrixClient(),
|
||||
pickerProvider: PickerProvider = FakePickerProvider(),
|
||||
mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(),
|
||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||
permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(),
|
||||
isKnockFeatureEnabled: Boolean = true,
|
||||
mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
|
||||
) = ConfigureRoomPresenter(
|
||||
dataStore = dataStore,
|
||||
matrixClient = matrixClient,
|
||||
mediaPickerProvider = pickerProvider,
|
||||
mediaPreProcessor = mediaPreProcessor,
|
||||
analyticsService = analyticsService,
|
||||
permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter),
|
||||
roomAliasHelper = roomAliasHelper,
|
||||
featureFlagService = FakeFeatureFlagService(
|
||||
mapOf(FeatureFlags.Knock.key to isKnockFeatureEnabled)
|
||||
),
|
||||
mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user