Merge branch 'develop' into feature/bma/removeOldResources
This commit is contained in:
commit
5f16297939
85 changed files with 562 additions and 321 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
<!--- TOC -->
|
<!--- TOC -->
|
||||||
|
|
||||||
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
||||||
|
* [Developer onboarding](#developer-onboarding)
|
||||||
* [Android Studio settings](#android-studio-settings)
|
* [Android Studio settings](#android-studio-settings)
|
||||||
* [Compilation](#compilation)
|
* [Compilation](#compilation)
|
||||||
* [Strings](#strings)
|
* [Strings](#strings)
|
||||||
|
|
@ -32,6 +33,10 @@ Element X Android support can be found in this room: [.
|
||||||
|
|
||||||
## Android Studio settings
|
## Android Studio settings
|
||||||
|
|
||||||
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
|
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import io.element.android.libraries.designsystem.utils.SnackbarMessage
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
|
|
@ -48,13 +48,13 @@ class LoggedInEventProcessor @Inject constructor(
|
||||||
fun observeEvents(coroutineScope: CoroutineScope) {
|
fun observeEvents(coroutineScope: CoroutineScope) {
|
||||||
observingJob = coroutineScope.launch {
|
observingJob = coroutineScope.launch {
|
||||||
displayLeftRoomMessage.onEach {
|
displayLeftRoomMessage.onEach {
|
||||||
displayMessage(R.string.common_current_user_left_room)
|
displayMessage(CommonStrings.common_current_user_left_room)
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
|
|
||||||
displayVerificationSuccessfulMessage
|
displayVerificationSuccessfulMessage
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach {
|
.onEach {
|
||||||
displayMessage(R.string.common_verification_complete)
|
displayMessage(CommonStrings.common_verification_complete)
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnalyticsPreferencesView(
|
fun AnalyticsPreferencesView(
|
||||||
|
|
@ -43,11 +43,11 @@ fun AnalyticsPreferencesView(
|
||||||
state.eventSink(AnalyticsOptInEvents.EnableAnalytics(isEnabled = isEnabled))
|
state.eventSink(AnalyticsOptInEvents.EnableAnalytics(isEnabled = isEnabled))
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferenceCategory(title = stringResource(id = StringR.string.screen_analytics_settings_share_data)) {
|
PreferenceCategory(title = stringResource(id = CommonStrings.screen_analytics_settings_share_data)) {
|
||||||
val firstPart = stringResource(id = StringR.string.screen_analytics_settings_help_us_improve, state.applicationName)
|
val firstPart = stringResource(id = CommonStrings.screen_analytics_settings_help_us_improve, state.applicationName)
|
||||||
val secondPart = buildAnnotatedStringWithColoredPart(
|
val secondPart = buildAnnotatedStringWithColoredPart(
|
||||||
StringR.string.screen_analytics_settings_read_terms,
|
CommonStrings.screen_analytics_settings_read_terms,
|
||||||
StringR.string.screen_analytics_settings_read_terms_content_link
|
CommonStrings.screen_analytics_settings_read_terms_content_link
|
||||||
)
|
)
|
||||||
val title = "$firstPart\n\n$secondPart"
|
val title = "$firstPart\n\n$secondPart"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
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.TextButton
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnalyticsOptInView(
|
fun AnalyticsOptInView(
|
||||||
|
|
@ -199,13 +199,13 @@ private fun AnalyticsOptInFooter(
|
||||||
onClick = { eventSink(AnalyticsOptInEvents.EnableAnalytics(true)) },
|
onClick = { eventSink(AnalyticsOptInEvents.EnableAnalytics(true)) },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(id = StringR.string.action_ok))
|
Text(text = stringResource(id = CommonStrings.action_ok))
|
||||||
}
|
}
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = { eventSink(AnalyticsOptInEvents.EnableAnalytics(false)) },
|
onClick = { eventSink(AnalyticsOptInEvents.EnableAnalytics(false)) },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(id = StringR.string.action_not_now))
|
Text(text = stringResource(id = CommonStrings.action_not_now))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ import io.element.android.libraries.designsystem.theme.components.CenterAlignedT
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
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.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -107,7 +107,7 @@ fun AddPeopleViewTopBar(
|
||||||
modifier = Modifier.padding(horizontal = 8.dp),
|
modifier = Modifier.padding(horizontal = 8.dp),
|
||||||
onClick = onNextPressed,
|
onClick = onNextPressed,
|
||||||
) {
|
) {
|
||||||
val textActionResId = if (hasSelectedUsers) StringR.string.action_next else StringR.string.action_skip
|
val textActionResId = if (hasSelectedUsers) CommonStrings.action_next else CommonStrings.action_skip
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = textActionResId),
|
text = stringResource(id = textActionResId),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import io.element.android.libraries.designsystem.theme.components.SearchBar
|
||||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.components.SelectedUsersList
|
import io.element.android.libraries.matrix.ui.components.SelectedUsersList
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.usersearch.api.UserSearchResult
|
import io.element.android.libraries.usersearch.api.UserSearchResult
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ fun SearchUserBar(
|
||||||
isMultiSelectionEnabled: Boolean,
|
isMultiSelectionEnabled: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
showBackButton: Boolean = true,
|
showBackButton: Boolean = true,
|
||||||
placeHolderTitle: String = stringResource(R.string.common_search_for_someone),
|
placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone),
|
||||||
onActiveChanged: (Boolean) -> Unit = {},
|
onActiveChanged: (Boolean) -> Unit = {},
|
||||||
onTextChanged: (String) -> Unit = {},
|
onTextChanged: (String) -> Unit = {},
|
||||||
onUserSelected: (MatrixUser) -> Unit = {},
|
onUserSelected: (MatrixUser) -> Unit = {},
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||||
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
@ -131,7 +131,7 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||||
dataStore.clearCachedData()
|
dataStore.clearCachedData()
|
||||||
analyticsService.capture(CreatedRoom(isDM = false))
|
analyticsService.capture(CreatedRoom(isDM = false))
|
||||||
}
|
}
|
||||||
}.execute(createRoomAction)
|
}.runCatchingUpdatingState(createRoomAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun uploadAvatar(avatarUri: Uri): String {
|
private suspend fun uploadAvatar(avatarUri: Uri): String {
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,8 @@ 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.AvatarActionBottomSheet
|
||||||
import io.element.android.libraries.matrix.ui.components.SelectedUsersList
|
import io.element.android.libraries.matrix.ui.components.SelectedUsersList
|
||||||
import io.element.android.libraries.matrix.ui.components.UnsavedAvatar
|
import io.element.android.libraries.matrix.ui.components.UnsavedAvatar
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -84,7 +84,7 @@ fun ConfigureRoomView(
|
||||||
|
|
||||||
if (state.createRoomAction is Async.Success) {
|
if (state.createRoomAction is Async.Success) {
|
||||||
LaunchedEffect(state.createRoomAction) {
|
LaunchedEffect(state.createRoomAction) {
|
||||||
onRoomCreated(state.createRoomAction.state)
|
onRoomCreated(state.createRoomAction.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,7 +158,7 @@ fun ConfigureRoomView(
|
||||||
|
|
||||||
when (state.createRoomAction) {
|
when (state.createRoomAction) {
|
||||||
is Async.Loading -> {
|
is Async.Loading -> {
|
||||||
ProgressDialog(text = stringResource(StringR.string.common_creating_room))
|
ProgressDialog(text = stringResource(CommonStrings.common_creating_room))
|
||||||
}
|
}
|
||||||
|
|
||||||
is Async.Failure -> {
|
is Async.Failure -> {
|
||||||
|
|
@ -198,7 +198,7 @@ fun ConfigureRoomToolbar(
|
||||||
onClick = onNextPressed,
|
onClick = onNextPressed,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.action_create),
|
text = stringResource(CommonStrings.action_create),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +227,7 @@ fun RoomNameWithAvatar(
|
||||||
LabelledTextField(
|
LabelledTextField(
|
||||||
label = stringResource(R.string.screen_create_room_room_name_label),
|
label = stringResource(R.string.screen_create_room_room_name_label),
|
||||||
value = roomName,
|
value = roomName,
|
||||||
placeholder = stringResource(StringR.string.common_room_name_placeholder),
|
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
onValueChange = onRoomNameChanged,
|
onValueChange = onRoomNameChanged,
|
||||||
)
|
)
|
||||||
|
|
@ -244,7 +244,7 @@ fun RoomTopic(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
label = stringResource(R.string.screen_create_room_topic_label),
|
label = stringResource(R.string.screen_create_room_topic_label),
|
||||||
value = topic,
|
value = topic,
|
||||||
placeholder = stringResource(StringR.string.common_topic_placeholder),
|
placeholder = stringResource(CommonStrings.common_topic_placeholder),
|
||||||
onValueChange = onTopicChanged,
|
onValueChange = onTopicChanged,
|
||||||
maxLines = 3,
|
maxLines = 3,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
|
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
|
@ -91,9 +91,9 @@ class CreateRoomRootNode @AssistedInject constructor(
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
context = context,
|
context = context,
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = context.getString(R.string.action_invite_friends),
|
chooserTitle = context.getString(CommonStrings.action_invite_friends),
|
||||||
text = context.getString(R.string.invite_friends_text, appName, permalink),
|
text = context.getString(CommonStrings.invite_friends_text, appName, permalink),
|
||||||
extraTitle = context.getString(R.string.invite_friends_rich_title, appName),
|
extraTitle = context.getString(CommonStrings.invite_friends_rich_title, appName),
|
||||||
noActivityFoundMessage = context.getString(io.element.android.libraries.androidutils.R.string.error_no_compatible_app_found)
|
noActivityFoundMessage = context.getString(io.element.android.libraries.androidutils.R.string.error_no_compatible_app_found)
|
||||||
)
|
)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import io.element.android.features.createroom.impl.userlist.UserListPresenter
|
||||||
import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs
|
import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.meta.BuildMeta
|
import io.element.android.libraries.core.meta.BuildMeta
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
@ -95,6 +95,6 @@ class CreateRoomRootPresenter @Inject constructor(
|
||||||
suspend {
|
suspend {
|
||||||
matrixClient.createDM(user.userId).getOrThrow()
|
matrixClient.createDM(user.userId).getOrThrow()
|
||||||
.also { analyticsService.capture(CreatedRoom(isDM = true)) }
|
.also { analyticsService.capture(CreatedRoom(isDM = true)) }
|
||||||
}.execute(startDmAction)
|
}.runCatchingUpdatingState(startDmAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
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.Text
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.designsystem.R as DrawableR
|
import io.element.android.libraries.designsystem.R as DrawableR
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -69,7 +69,7 @@ fun CreateRoomRootView(
|
||||||
) {
|
) {
|
||||||
if (state.startDmAction is Async.Success) {
|
if (state.startDmAction is Async.Success) {
|
||||||
LaunchedEffect(state.startDmAction) {
|
LaunchedEffect(state.startDmAction) {
|
||||||
onOpenDM(state.startDmAction.state)
|
onOpenDM(state.startDmAction.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ fun CreateRoomRootView(
|
||||||
|
|
||||||
when (state.startDmAction) {
|
when (state.startDmAction) {
|
||||||
is Async.Loading -> {
|
is Async.Loading -> {
|
||||||
ProgressDialog(text = stringResource(id = StringR.string.common_starting_chat))
|
ProgressDialog(text = stringResource(id = CommonStrings.common_starting_chat))
|
||||||
}
|
}
|
||||||
|
|
||||||
is Async.Failure -> {
|
is Async.Failure -> {
|
||||||
|
|
@ -137,7 +137,7 @@ fun CreateRoomRootViewTopBar(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = StringR.string.action_start_chat),
|
text = stringResource(id = CommonStrings.action_start_chat),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
)
|
)
|
||||||
|
|
@ -146,7 +146,7 @@ fun CreateRoomRootViewTopBar(
|
||||||
IconButton(onClick = onClosePressed) {
|
IconButton(onClick = onClosePressed) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(id = StringR.string.action_close),
|
contentDescription = stringResource(id = CommonStrings.action_close),
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +169,7 @@ fun CreateRoomActionButtonsList(
|
||||||
)
|
)
|
||||||
CreateRoomActionButton(
|
CreateRoomActionButton(
|
||||||
iconRes = DrawableR.drawable.ic_share,
|
iconRes = DrawableR.drawable.ic_share,
|
||||||
text = stringResource(id = StringR.string.action_invite_friends_to_app, state.applicationName),
|
text = stringResource(id = CommonStrings.action_invite_friends_to_app, state.applicationName),
|
||||||
onClick = onInvitePeopleClicked,
|
onClick = onInvitePeopleClicked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.features.invitelist.impl.model.InviteListInviteSummary
|
||||||
import io.element.android.features.invitelist.impl.model.InviteSender
|
import io.element.android.features.invitelist.impl.model.InviteSender
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
@ -135,7 +135,7 @@ class InviteListPresenter @Inject constructor(
|
||||||
it.acceptInvitation().getOrThrow()
|
it.acceptInvitation().getOrThrow()
|
||||||
}
|
}
|
||||||
roomId
|
roomId
|
||||||
}.execute(acceptedAction)
|
}.runCatchingUpdatingState(acceptedAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<Async<Unit>>) = launch {
|
private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<Async<Unit>>) = launch {
|
||||||
|
|
@ -143,7 +143,7 @@ class InviteListPresenter @Inject constructor(
|
||||||
client.getRoom(roomId)?.use {
|
client.getRoom(roomId)?.use {
|
||||||
it.rejectInvitation().getOrThrow()
|
it.rejectInvitation().getOrThrow()
|
||||||
} ?: Unit
|
} ?: Unit
|
||||||
}.execute(declinedAction)
|
}.runCatchingUpdatingState(declinedAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RoomSummary.Filled.toInviteSummary(seen: Boolean) = details.run {
|
private fun RoomSummary.Filled.toInviteSummary(seen: Boolean) = details.run {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun InviteListView(
|
fun InviteListView(
|
||||||
|
|
@ -58,7 +58,7 @@ fun InviteListView(
|
||||||
) {
|
) {
|
||||||
if (state.acceptedAction is Async.Success) {
|
if (state.acceptedAction is Async.Success) {
|
||||||
LaunchedEffect(state.acceptedAction) {
|
LaunchedEffect(state.acceptedAction) {
|
||||||
onInviteAccepted(state.acceptedAction.state)
|
onInviteAccepted(state.acceptedAction.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,8 +82,8 @@ fun InviteListView(
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
content = stringResource(contentResource, state.declineConfirmationDialog.name),
|
content = stringResource(contentResource, state.declineConfirmationDialog.name),
|
||||||
title = stringResource(titleResource),
|
title = stringResource(titleResource),
|
||||||
submitText = stringResource(StringR.string.action_decline),
|
submitText = stringResource(CommonStrings.action_decline),
|
||||||
cancelText = stringResource(StringR.string.action_cancel),
|
cancelText = stringResource(CommonStrings.action_cancel),
|
||||||
emphasizeSubmitButton = true,
|
emphasizeSubmitButton = true,
|
||||||
onSubmitClicked = { state.eventSink(InviteListEvents.ConfirmDeclineInvite) },
|
onSubmitClicked = { state.eventSink(InviteListEvents.ConfirmDeclineInvite) },
|
||||||
onDismiss = { state.eventSink(InviteListEvents.CancelDeclineInvite) }
|
onDismiss = { state.eventSink(InviteListEvents.CancelDeclineInvite) }
|
||||||
|
|
@ -92,18 +92,18 @@ fun InviteListView(
|
||||||
|
|
||||||
if (state.acceptedAction is Async.Failure) {
|
if (state.acceptedAction is Async.Failure) {
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
content = stringResource(StringR.string.error_unknown),
|
content = stringResource(CommonStrings.error_unknown),
|
||||||
title = stringResource(StringR.string.common_error),
|
title = stringResource(CommonStrings.common_error),
|
||||||
submitText = stringResource(StringR.string.action_ok),
|
submitText = stringResource(CommonStrings.action_ok),
|
||||||
onDismiss = { state.eventSink(InviteListEvents.DismissAcceptError) }
|
onDismiss = { state.eventSink(InviteListEvents.DismissAcceptError) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.declinedAction is Async.Failure) {
|
if (state.declinedAction is Async.Failure) {
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
content = stringResource(StringR.string.error_unknown),
|
content = stringResource(CommonStrings.error_unknown),
|
||||||
title = stringResource(StringR.string.common_error),
|
title = stringResource(CommonStrings.common_error),
|
||||||
submitText = stringResource(StringR.string.action_ok),
|
submitText = stringResource(CommonStrings.action_ok),
|
||||||
onDismiss = { state.eventSink(InviteListEvents.DismissDeclineError) }
|
onDismiss = { state.eventSink(InviteListEvents.DismissDeclineError) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ fun InviteListContent(
|
||||||
BackButton(onClick = onBackClicked)
|
BackButton(onClick = onBackClicked)
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
Text(text = stringResource(StringR.string.action_invites_list))
|
Text(text = stringResource(CommonStrings.action_invites_list))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.noFontPadding
|
import io.element.android.libraries.designsystem.theme.noFontPadding
|
||||||
import io.element.android.libraries.designsystem.theme.roomListUnreadIndicator
|
import io.element.android.libraries.designsystem.theme.roomListUnreadIndicator
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
private val minHeight = 72.dp
|
private val minHeight = 72.dp
|
||||||
|
|
||||||
|
|
@ -143,7 +143,7 @@ internal fun DefaultInviteSummaryRow(
|
||||||
// CTAs
|
// CTAs
|
||||||
Row(Modifier.padding(top = 12.dp)) {
|
Row(Modifier.padding(top = 12.dp)) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
content = { Text(stringResource(StringR.string.action_decline), style = ElementTextStyles.Button) },
|
content = { Text(stringResource(CommonStrings.action_decline), style = ElementTextStyles.Button) },
|
||||||
onClick = onDeclineClicked,
|
onClick = onDeclineClicked,
|
||||||
modifier = Modifier.weight(1f).heightIn(max = 36.dp),
|
modifier = Modifier.weight(1f).heightIn(max = 36.dp),
|
||||||
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 0.dp),
|
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 0.dp),
|
||||||
|
|
@ -152,7 +152,7 @@ internal fun DefaultInviteSummaryRow(
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
content = { Text(stringResource(StringR.string.action_accept), style = ElementTextStyles.Button) },
|
content = { Text(stringResource(CommonStrings.action_accept), style = ElementTextStyles.Button) },
|
||||||
onClick = onAcceptClicked,
|
onClick = onAcceptClicked,
|
||||||
modifier = Modifier.weight(1f).heightIn(max = 36.dp),
|
modifier = Modifier.weight(1f).heightIn(max = 36.dp),
|
||||||
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 0.dp),
|
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 0.dp),
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LeaveRoomView(
|
fun LeaveRoomView(
|
||||||
|
|
@ -50,19 +49,19 @@ private fun LeaveRoomConfirmationDialog(
|
||||||
when (state.confirmation) {
|
when (state.confirmation) {
|
||||||
is LeaveRoomState.Confirmation.Hidden -> {}
|
is LeaveRoomState.Confirmation.Hidden -> {}
|
||||||
is LeaveRoomState.Confirmation.PrivateRoom -> LeaveRoomConfirmationDialog(
|
is LeaveRoomState.Confirmation.PrivateRoom -> LeaveRoomConfirmationDialog(
|
||||||
text = StringR.string.leave_room_alert_private_subtitle,
|
text = CommonStrings.leave_room_alert_private_subtitle,
|
||||||
roomId = state.confirmation.roomId,
|
roomId = state.confirmation.roomId,
|
||||||
eventSink = state.eventSink,
|
eventSink = state.eventSink,
|
||||||
)
|
)
|
||||||
|
|
||||||
is LeaveRoomState.Confirmation.LastUserInRoom -> LeaveRoomConfirmationDialog(
|
is LeaveRoomState.Confirmation.LastUserInRoom -> LeaveRoomConfirmationDialog(
|
||||||
text = StringR.string.leave_room_alert_empty_subtitle,
|
text = CommonStrings.leave_room_alert_empty_subtitle,
|
||||||
roomId = state.confirmation.roomId,
|
roomId = state.confirmation.roomId,
|
||||||
eventSink = state.eventSink,
|
eventSink = state.eventSink,
|
||||||
)
|
)
|
||||||
|
|
||||||
is LeaveRoomState.Confirmation.Generic -> LeaveRoomConfirmationDialog(
|
is LeaveRoomState.Confirmation.Generic -> LeaveRoomConfirmationDialog(
|
||||||
text = StringR.string.leave_room_alert_subtitle,
|
text = CommonStrings.leave_room_alert_subtitle,
|
||||||
roomId = state.confirmation.roomId,
|
roomId = state.confirmation.roomId,
|
||||||
eventSink = state.eventSink,
|
eventSink = state.eventSink,
|
||||||
)
|
)
|
||||||
|
|
@ -77,7 +76,7 @@ private fun LeaveRoomConfirmationDialog(
|
||||||
) {
|
) {
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
content = stringResource(text),
|
content = stringResource(text),
|
||||||
submitText = stringResource(R.string.action_leave),
|
submitText = stringResource(CommonStrings.action_leave),
|
||||||
onSubmitClicked = { eventSink(LeaveRoomEvent.LeaveRoom(roomId)) },
|
onSubmitClicked = { eventSink(LeaveRoomEvent.LeaveRoom(roomId)) },
|
||||||
onDismiss = { eventSink(LeaveRoomEvent.HideConfirmation) },
|
onDismiss = { eventSink(LeaveRoomEvent.HideConfirmation) },
|
||||||
)
|
)
|
||||||
|
|
@ -90,7 +89,7 @@ private fun LeaveRoomProgressDialog(
|
||||||
when (state.progress) {
|
when (state.progress) {
|
||||||
is LeaveRoomState.Progress.Hidden -> {}
|
is LeaveRoomState.Progress.Hidden -> {}
|
||||||
is LeaveRoomState.Progress.Shown -> ProgressDialog(
|
is LeaveRoomState.Progress.Shown -> ProgressDialog(
|
||||||
text = stringResource(StringR.string.common_leaving_room),
|
text = stringResource(CommonStrings.common_leaving_room),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +101,7 @@ private fun LeaveRoomErrorDialog(
|
||||||
when (state.error) {
|
when (state.error) {
|
||||||
is LeaveRoomState.Error.Hidden -> {}
|
is LeaveRoomState.Error.Hidden -> {}
|
||||||
is LeaveRoomState.Error.Shown -> ErrorDialog(
|
is LeaveRoomState.Error.Shown -> ErrorDialog(
|
||||||
content = stringResource(StringR.string.error_unknown),
|
content = stringResource(CommonStrings.error_unknown),
|
||||||
onDismiss = { state.eventSink(LeaveRoomEvent.HideError) }
|
onDismiss = { state.eventSink(LeaveRoomEvent.HideError) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.features.location.api.R
|
import io.element.android.features.location.api.R
|
||||||
import io.element.android.libraries.ui.strings.R as StringsR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun StaticMapPlaceholder(
|
internal fun StaticMapPlaceholder(
|
||||||
|
|
@ -76,7 +76,7 @@ internal fun StaticMapPlaceholder(
|
||||||
imageVector = Icons.Default.Refresh,
|
imageVector = Icons.Default.Refresh,
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
Text(text = stringResource(id = StringsR.string.action_static_map_load))
|
Text(text = stringResource(id = CommonStrings.action_static_map_load))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProviderDat
|
||||||
import io.element.android.features.login.impl.error.ChangeServerError
|
import io.element.android.features.login.impl.error.ChangeServerError
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.data.tryOrNull
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -71,6 +71,6 @@ class ChangeServerPresenter @Inject constructor(
|
||||||
// Valid, remember user choice
|
// Valid, remember user choice
|
||||||
accountProviderDataSource.userSelection(data)
|
accountProviderDataSource.userSelection(data)
|
||||||
}.getOrThrow()
|
}.getOrThrow()
|
||||||
}.execute(changeServerAction, errorMapping = ChangeServerError::from)
|
}.runCatchingUpdatingState(changeServerAction, errorTransform = ChangeServerError::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import io.element.android.features.login.impl.R
|
import io.element.android.features.login.impl.R
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun SlidingSyncNotSupportedDialog(
|
internal fun SlidingSyncNotSupportedDialog(
|
||||||
|
|
@ -32,11 +32,11 @@ internal fun SlidingSyncNotSupportedDialog(
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onDismiss = onDismiss,
|
onDismiss = onDismiss,
|
||||||
submitText = stringResource(StringR.string.action_learn_more),
|
submitText = stringResource(CommonStrings.action_learn_more),
|
||||||
onSubmitClicked = onLearnMoreClicked,
|
onSubmitClicked = onLearnMoreClicked,
|
||||||
onCancelClicked = onDismiss,
|
onCancelClicked = onDismiss,
|
||||||
emphasizeSubmitButton = true,
|
emphasizeSubmitButton = true,
|
||||||
title = stringResource(StringR.string.dialog_title_error),
|
title = stringResource(CommonStrings.dialog_title_error),
|
||||||
content = stringResource(R.string.screen_change_server_error_no_sliding_sync_message),
|
content = stringResource(R.string.screen_change_server_error_no_sliding_sync_message),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,16 +21,16 @@ import io.element.android.features.login.impl.R
|
||||||
import io.element.android.libraries.matrix.api.auth.AuthErrorCode
|
import io.element.android.libraries.matrix.api.auth.AuthErrorCode
|
||||||
import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
||||||
import io.element.android.libraries.matrix.api.auth.errorCode
|
import io.element.android.libraries.matrix.api.auth.errorCode
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
fun loginError(
|
fun loginError(
|
||||||
throwable: Throwable
|
throwable: Throwable
|
||||||
): Int {
|
): Int {
|
||||||
val authException = throwable as? AuthenticationException ?: return StringR.string.error_unknown
|
val authException = throwable as? AuthenticationException ?: return CommonStrings.error_unknown
|
||||||
return when (authException.errorCode) {
|
return when (authException.errorCode) {
|
||||||
AuthErrorCode.FORBIDDEN -> R.string.screen_login_error_invalid_credentials
|
AuthErrorCode.FORBIDDEN -> R.string.screen_login_error_invalid_credentials
|
||||||
AuthErrorCode.USER_DEACTIVATED -> R.string.screen_login_error_deactivated_account
|
AuthErrorCode.USER_DEACTIVATED -> R.string.screen_login_error_deactivated_account
|
||||||
AuthErrorCode.UNKNOWN -> StringR.string.error_unknown
|
AuthErrorCode.UNKNOWN -> CommonStrings.error_unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.features.login.impl.accountprovider.AccountProviderDat
|
||||||
import io.element.android.features.login.impl.error.ChangeServerError
|
import io.element.android.features.login.impl.error.ChangeServerError
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.data.tryOrNull
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -95,6 +95,6 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor(
|
||||||
throw IllegalStateException("Unsupported login flow")
|
throw IllegalStateException("Unsupported login flow")
|
||||||
}
|
}
|
||||||
}.getOrThrow()
|
}.getOrThrow()
|
||||||
}.execute(loginFlowAction, errorMapping = ChangeServerError::from)
|
}.runCatchingUpdatingState(loginFlowAction, errorTransform = ChangeServerError::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ fun ConfirmAccountProviderView(
|
||||||
}
|
}
|
||||||
is Async.Loading -> Unit // The Continue button shows the loading state
|
is Async.Loading -> Unit // The Continue button shows the loading state
|
||||||
is Async.Success -> {
|
is Async.Success -> {
|
||||||
when (val loginFlowState = state.loginFlow.state) {
|
when (val loginFlowState = state.loginFlow.data) {
|
||||||
is LoginFlow.OidcFlow -> onOidcDetails(loginFlowState.oidcDetails)
|
is LoginFlow.OidcFlow -> onOidcDetails(loginFlowState.oidcDetails)
|
||||||
LoginFlow.PasswordLogin -> onLoginPasswordNeeded()
|
LoginFlow.PasswordLogin -> onLoginPasswordNeeded()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ import io.element.android.libraries.designsystem.theme.components.autofill
|
||||||
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
|
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -213,7 +213,7 @@ internal fun LoginForm(
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
loginFieldState = ""
|
loginFieldState = ""
|
||||||
}) {
|
}) {
|
||||||
Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(StringR.string.action_clear))
|
Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(CommonStrings.action_clear))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else null,
|
} else null,
|
||||||
|
|
@ -248,7 +248,7 @@ internal fun LoginForm(
|
||||||
val image =
|
val image =
|
||||||
if (passwordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
|
if (passwordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
|
||||||
val description =
|
val description =
|
||||||
if (passwordVisible) stringResource(StringR.string.a11y_hide_password) else stringResource(StringR.string.a11y_show_password)
|
if (passwordVisible) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password)
|
||||||
|
|
||||||
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
||||||
Icon(imageVector = image, description)
|
Icon(imageVector = image, description)
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
|
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?type=design&node-id=611-61435
|
* https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?type=design&node-id=611-61435
|
||||||
|
|
@ -143,7 +143,7 @@ fun SearchAccountProviderView(
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Close,
|
imageVector = Icons.Filled.Close,
|
||||||
contentDescription = stringResource(StringR.string.action_clear)
|
contentDescription = stringResource(CommonStrings.action_clear)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +171,7 @@ fun SearchAccountProviderView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Async.Success -> {
|
is Async.Success -> {
|
||||||
items(state.userInputResult.state) { homeserverData ->
|
items(state.userInputResult.data) { homeserverData ->
|
||||||
val item = homeserverData.toAccountProvider()
|
val item = homeserverData.toAccountProvider()
|
||||||
AccountProviderView(
|
AccountProviderView(
|
||||||
item = item,
|
item = item,
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ package io.element.android.features.login.impl.error
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.login.impl.R
|
import io.element.android.features.login.impl.R
|
||||||
import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
import io.element.android.libraries.matrix.api.auth.AuthenticationException
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
class ErrorFormatterTests {
|
class ErrorFormatterTests {
|
||||||
|
|
||||||
|
|
@ -28,19 +28,19 @@ class ErrorFormatterTests {
|
||||||
@Test
|
@Test
|
||||||
fun `loginError - invalid unknown error returns unknown error message`() {
|
fun `loginError - invalid unknown error returns unknown error message`() {
|
||||||
val error = Throwable("Some unknown error")
|
val error = Throwable("Some unknown error")
|
||||||
assertThat(loginError(error)).isEqualTo(StringR.string.error_unknown)
|
assertThat(loginError(error)).isEqualTo(CommonStrings.error_unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `loginError - invalid auth error returns unknown error message`() {
|
fun `loginError - invalid auth error returns unknown error message`() {
|
||||||
val error = AuthenticationException.SlidingSyncNotAvailable("Some message. Also contains M_FORBIDDEN, but won't be parsed")
|
val error = AuthenticationException.SlidingSyncNotAvailable("Some message. Also contains M_FORBIDDEN, but won't be parsed")
|
||||||
assertThat(loginError(error)).isEqualTo(StringR.string.error_unknown)
|
assertThat(loginError(error)).isEqualTo(CommonStrings.error_unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `loginError - unknown error returns unknown error message`() {
|
fun `loginError - unknown error returns unknown error message`() {
|
||||||
val error = AuthenticationException.Generic("M_UNKNOWN")
|
val error = AuthenticationException.Generic("M_UNKNOWN")
|
||||||
assertThat(loginError(error)).isEqualTo(StringR.string.error_unknown)
|
assertThat(loginError(error)).isEqualTo(CommonStrings.error_unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LogoutPreferenceView(
|
fun LogoutPreferenceView(
|
||||||
|
|
@ -81,7 +81,7 @@ fun LogoutPreferenceView(
|
||||||
fun LogoutPreferenceContent(
|
fun LogoutPreferenceContent(
|
||||||
onClick: () -> Unit = {},
|
onClick: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
PreferenceCategory(title = stringResource(id = StringR.string.settings_title_general)) {
|
PreferenceCategory(title = stringResource(id = CommonStrings.settings_title_general)) {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(id = R.string.screen_signout_preference_item),
|
title = stringResource(id = R.string.screen_signout_preference_item),
|
||||||
icon = Icons.Default.Logout,
|
icon = Icons.Default.Logout,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.features.logout.api.LogoutPreferenceEvents
|
||||||
import io.element.android.features.logout.api.LogoutPreferencePresenter
|
import io.element.android.features.logout.api.LogoutPreferencePresenter
|
||||||
import io.element.android.features.logout.api.LogoutPreferenceState
|
import io.element.android.features.logout.api.LogoutPreferenceState
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -59,6 +59,6 @@ class DefaultLogoutPreferencePresenter @Inject constructor(private val matrixCli
|
||||||
private fun CoroutineScope.logout(logoutAction: MutableState<Async<Unit>>) = launch {
|
private fun CoroutineScope.logout(logoutAction: MutableState<Async<Unit>>) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
matrixClient.logout()
|
matrixClient.logout()
|
||||||
}.execute(logoutAction)
|
}.runCatchingUpdatingState(logoutAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,9 @@ import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import io.element.android.libraries.ui.strings.R as StringsR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -195,7 +195,7 @@ private fun AttachmentStateView(
|
||||||
is AttachmentsState.Previewing -> LaunchedEffect(state) {
|
is AttachmentsState.Previewing -> LaunchedEffect(state) {
|
||||||
onPreviewAttachments(state.attachments)
|
onPreviewAttachments(state.attachments)
|
||||||
}
|
}
|
||||||
is AttachmentsState.Sending -> ProgressDialog(text = stringResource(id = StringsR.string.common_loading))
|
is AttachmentsState.Sending -> ProgressDialog(text = stringResource(id = CommonStrings.common_loading))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import dagger.assisted.AssistedInject
|
||||||
import io.element.android.features.messages.impl.attachments.Attachment
|
import io.element.android.features.messages.impl.attachments.Attachment
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.executeResult
|
import io.element.android.libraries.architecture.runUpdatingState
|
||||||
import io.element.android.libraries.mediaupload.api.MediaSender
|
import io.element.android.libraries.mediaupload.api.MediaSender
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -83,8 +83,8 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
|
||||||
mediaAttachment: Attachment.Media,
|
mediaAttachment: Attachment.Media,
|
||||||
sendActionState: MutableState<Async<Unit>>,
|
sendActionState: MutableState<Async<Unit>>,
|
||||||
) {
|
) {
|
||||||
suspend {
|
sendActionState.runUpdatingState {
|
||||||
mediaSender.sendMedia(mediaAttachment.localMedia.uri, mediaAttachment.localMedia.info.mimeType, mediaAttachment.compressIfPossible)
|
mediaSender.sendMedia(mediaAttachment.localMedia.uri, mediaAttachment.localMedia.info.mimeType, mediaAttachment.compressIfPossible)
|
||||||
}.executeResult(sendActionState)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
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.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.ui.strings.R as StringsR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AttachmentsPreviewView(
|
fun AttachmentsPreviewView(
|
||||||
|
|
@ -92,7 +91,7 @@ private fun AttachmentSendStateView(
|
||||||
) {
|
) {
|
||||||
when (sendActionState) {
|
when (sendActionState) {
|
||||||
is Async.Loading -> {
|
is Async.Loading -> {
|
||||||
ProgressDialog(text = stringResource(id = R.string.common_loading))
|
ProgressDialog(text = stringResource(id = CommonStrings.common_loading))
|
||||||
}
|
}
|
||||||
|
|
||||||
is Async.Failure -> {
|
is Async.Failure -> {
|
||||||
|
|
@ -151,10 +150,10 @@ private fun AttachmentsPreviewBottomActions(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
TextButton(onClick = onCancelClicked) {
|
TextButton(onClick = onCancelClicked) {
|
||||||
Text(stringResource(id = StringsR.string.action_cancel))
|
Text(stringResource(id = CommonStrings.action_cancel))
|
||||||
}
|
}
|
||||||
TextButton(onClick = onSendClicked) {
|
TextButton(onClick = onSendClicked) {
|
||||||
Text(stringResource(id = StringsR.string.action_send))
|
Text(stringResource(id = CommonStrings.action_send))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,14 @@
|
||||||
package io.element.android.features.messages.impl.attachments.preview.error
|
package io.element.android.features.messages.impl.attachments.preview.error
|
||||||
|
|
||||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
fun sendAttachmentError(
|
fun sendAttachmentError(
|
||||||
throwable: Throwable
|
throwable: Throwable
|
||||||
): Int {
|
): Int {
|
||||||
return if (throwable is MediaPreProcessor.Failure) {
|
return if (throwable is MediaPreProcessor.Failure) {
|
||||||
R.string.screen_media_upload_preview_error_failed_processing
|
CommonStrings.screen_media_upload_preview_error_failed_processing
|
||||||
} else {
|
} else {
|
||||||
R.string.screen_media_upload_preview_error_failed_sending
|
CommonStrings.screen_media_upload_preview_error_failed_sending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,12 @@ import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.isLoading
|
|
||||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ import io.element.android.libraries.designsystem.theme.roomListRoomName
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDetails
|
import io.element.android.libraries.matrix.api.room.RoomSummaryDetails
|
||||||
import io.element.android.libraries.matrix.ui.components.SelectedRoom
|
import io.element.android.libraries.matrix.ui.components.SelectedRoom
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -111,7 +111,7 @@ fun ForwardMessagesView(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = {
|
topBar = {
|
||||||
CenterAlignedTopAppBar(
|
CenterAlignedTopAppBar(
|
||||||
title = { Text(stringResource(StringR.string.common_forward_message), style = ElementTextStyles.Bold.callout) },
|
title = { Text(stringResource(CommonStrings.common_forward_message), style = ElementTextStyles.Bold.callout) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
BackButton(onClick = { onBackButton(state) })
|
BackButton(onClick = { onBackButton(state) })
|
||||||
},
|
},
|
||||||
|
|
@ -120,7 +120,7 @@ fun ForwardMessagesView(
|
||||||
enabled = state.selectedRooms.isNotEmpty(),
|
enabled = state.selectedRooms.isNotEmpty(),
|
||||||
onClick = { state.eventSink(ForwardMessagesEvents.ForwardEvent) }
|
onClick = { state.eventSink(ForwardMessagesEvents.ForwardEvent) }
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(StringR.string.action_send))
|
Text(text = stringResource(CommonStrings.action_send))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -132,7 +132,7 @@ fun ForwardMessagesView(
|
||||||
.consumeWindowInsets(paddingValues)
|
.consumeWindowInsets(paddingValues)
|
||||||
) {
|
) {
|
||||||
SearchBar<ImmutableList<RoomSummaryDetails>>(
|
SearchBar<ImmutableList<RoomSummaryDetails>>(
|
||||||
placeHolderTitle = stringResource(StringR.string.action_search),
|
placeHolderTitle = stringResource(CommonStrings.action_search),
|
||||||
query = state.query,
|
query = state.query,
|
||||||
onQueryChange = { state.eventSink(ForwardMessagesEvents.UpdateQuery(it)) },
|
onQueryChange = { state.eventSink(ForwardMessagesEvents.UpdateQuery(it)) },
|
||||||
active = state.isSearchActive,
|
active = state.isSearchActive,
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@ import io.element.android.libraries.designsystem.utils.SnackbarMessage
|
||||||
import io.element.android.libraries.designsystem.utils.collectSnackbarMessageAsState
|
import io.element.android.libraries.designsystem.utils.collectSnackbarMessageAsState
|
||||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||||
import io.element.android.libraries.matrix.api.media.MediaFile
|
import io.element.android.libraries.matrix.api.media.MediaFile
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import io.element.android.libraries.androidutils.R as UtilsR
|
import io.element.android.libraries.androidutils.R as UtilsR
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
class MediaViewerPresenter @AssistedInject constructor(
|
class MediaViewerPresenter @AssistedInject constructor(
|
||||||
@Assisted private val inputs: MediaViewerNode.Inputs,
|
@Assisted private val inputs: MediaViewerNode.Inputs,
|
||||||
|
|
@ -117,9 +117,9 @@ class MediaViewerPresenter @AssistedInject constructor(
|
||||||
|
|
||||||
private fun CoroutineScope.saveOnDisk(localMedia: Async<LocalMedia>) = launch {
|
private fun CoroutineScope.saveOnDisk(localMedia: Async<LocalMedia>) = launch {
|
||||||
if (localMedia is Async.Success) {
|
if (localMedia is Async.Success) {
|
||||||
localMediaActions.saveOnDisk(localMedia.state)
|
localMediaActions.saveOnDisk(localMedia.data)
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
val snackbarMessage = SnackbarMessage(StringR.string.common_file_saved_on_disk_android)
|
val snackbarMessage = SnackbarMessage(CommonStrings.common_file_saved_on_disk_android)
|
||||||
snackbarDispatcher.post(snackbarMessage)
|
snackbarDispatcher.post(snackbarMessage)
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
|
|
@ -131,7 +131,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
||||||
|
|
||||||
private fun CoroutineScope.share(localMedia: Async<LocalMedia>) = launch {
|
private fun CoroutineScope.share(localMedia: Async<LocalMedia>) = launch {
|
||||||
if (localMedia is Async.Success) {
|
if (localMedia is Async.Success) {
|
||||||
localMediaActions.share(localMedia.state)
|
localMediaActions.share(localMedia.data)
|
||||||
.onFailure {
|
.onFailure {
|
||||||
val snackbarMessage = SnackbarMessage(mediaActionsError(it))
|
val snackbarMessage = SnackbarMessage(mediaActionsError(it))
|
||||||
snackbarDispatcher.post(snackbarMessage)
|
snackbarDispatcher.post(snackbarMessage)
|
||||||
|
|
@ -141,7 +141,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
||||||
|
|
||||||
private fun CoroutineScope.open(localMedia: Async<LocalMedia>) = launch {
|
private fun CoroutineScope.open(localMedia: Async<LocalMedia>) = launch {
|
||||||
if (localMedia is Async.Success) {
|
if (localMedia is Async.Success) {
|
||||||
localMediaActions.open(localMedia.state)
|
localMediaActions.open(localMedia.data)
|
||||||
.onFailure {
|
.onFailure {
|
||||||
val snackbarMessage = SnackbarMessage(mediaActionsError(it))
|
val snackbarMessage = SnackbarMessage(mediaActionsError(it))
|
||||||
snackbarDispatcher.post(snackbarMessage)
|
snackbarDispatcher.post(snackbarMessage)
|
||||||
|
|
@ -153,7 +153,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
||||||
return if (throwable is ActivityNotFoundException) {
|
return if (throwable is ActivityNotFoundException) {
|
||||||
UtilsR.string.error_no_compatible_app_found
|
UtilsR.string.error_no_compatible_app_found
|
||||||
} else {
|
} else {
|
||||||
StringR.string.error_unknown
|
CommonStrings.error_unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ import io.element.android.features.messages.impl.media.local.LocalMediaView
|
||||||
import io.element.android.features.messages.impl.media.local.MediaInfo
|
import io.element.android.features.messages.impl.media.local.MediaInfo
|
||||||
import io.element.android.features.messages.impl.media.local.rememberLocalMediaViewState
|
import io.element.android.features.messages.impl.media.local.rememberLocalMediaViewState
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.isLoading
|
|
||||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
|
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
|
||||||
|
|
@ -69,8 +68,8 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MediaViewerView(
|
fun MediaViewerView(
|
||||||
|
|
@ -131,7 +130,7 @@ fun MediaViewerView(
|
||||||
) {
|
) {
|
||||||
if (state.downloadedMedia is Async.Failure) {
|
if (state.downloadedMedia is Async.Failure) {
|
||||||
ErrorView(
|
ErrorView(
|
||||||
errorMessage = stringResource(id = StringR.string.error_unknown),
|
errorMessage = stringResource(id = CommonStrings.error_unknown),
|
||||||
onRetry = ::onRetry,
|
onRetry = ::onRetry,
|
||||||
onDismiss = ::onDismissError
|
onDismiss = ::onDismissError
|
||||||
)
|
)
|
||||||
|
|
@ -188,7 +187,7 @@ private fun MediaViewerTopBar(
|
||||||
eventSink(MediaViewerEvents.OpenWith)
|
eventSink(MediaViewerEvents.OpenWith)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Icon(imageVector = Icons.Default.OpenInNew, contentDescription = stringResource(id = StringR.string.action_open_with))
|
Icon(imageVector = Icons.Default.OpenInNew, contentDescription = stringResource(id = CommonStrings.action_open_with))
|
||||||
}
|
}
|
||||||
IconButton(
|
IconButton(
|
||||||
enabled = actionsEnabled,
|
enabled = actionsEnabled,
|
||||||
|
|
@ -196,7 +195,7 @@ private fun MediaViewerTopBar(
|
||||||
eventSink(MediaViewerEvents.SaveOnDisk)
|
eventSink(MediaViewerEvents.SaveOnDisk)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Icon(imageVector = Icons.Default.Download, contentDescription = stringResource(id = StringR.string.action_save))
|
Icon(imageVector = Icons.Default.Download, contentDescription = stringResource(id = CommonStrings.action_save))
|
||||||
}
|
}
|
||||||
IconButton(
|
IconButton(
|
||||||
enabled = actionsEnabled,
|
enabled = actionsEnabled,
|
||||||
|
|
@ -204,7 +203,7 @@ private fun MediaViewerTopBar(
|
||||||
eventSink(MediaViewerEvents.Share)
|
eventSink(MediaViewerEvents.Share)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Icon(imageVector = Icons.Default.Share, contentDescription = stringResource(id = StringR.string.action_share))
|
Icon(imageVector = Icons.Default.Share, contentDescription = stringResource(id = CommonStrings.action_share))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,15 @@ import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.executeResult
|
import io.element.android.libraries.architecture.runUpdatingState
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
|
||||||
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
|
||||||
import io.element.android.libraries.designsystem.utils.SnackbarMessage
|
import io.element.android.libraries.designsystem.utils.SnackbarMessage
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
class ReportMessagePresenter @AssistedInject constructor(
|
class ReportMessagePresenter @AssistedInject constructor(
|
||||||
private val room: MatrixRoom,
|
private val room: MatrixRoom,
|
||||||
|
|
@ -87,12 +86,12 @@ class ReportMessagePresenter @AssistedInject constructor(
|
||||||
blockUser: Boolean,
|
blockUser: Boolean,
|
||||||
result: MutableState<Async<Unit>>,
|
result: MutableState<Async<Unit>>,
|
||||||
) = launch {
|
) = launch {
|
||||||
suspend {
|
result.runUpdatingState {
|
||||||
val userIdToBlock = userId.takeIf { blockUser }
|
val userIdToBlock = userId.takeIf { blockUser }
|
||||||
room.reportContent(eventId, reason, userIdToBlock)
|
room.reportContent(eventId, reason, userIdToBlock)
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
snackbarDispatcher.post(SnackbarMessage(StringR.string.common_report_submitted))
|
snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_report_submitted))
|
||||||
}
|
}
|
||||||
}.executeResult(result)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ import io.element.android.libraries.designsystem.theme.components.CenterAlignedT
|
||||||
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
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.Text
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -74,7 +74,7 @@ fun ReportMessageView(
|
||||||
}
|
}
|
||||||
is Async.Failure -> {
|
is Async.Failure -> {
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
content = stringResource(StringR.string.error_unknown),
|
content = stringResource(CommonStrings.error_unknown),
|
||||||
onDismiss = { state.eventSink(ReportMessageEvents.ClearError) }
|
onDismiss = { state.eventSink(ReportMessageEvents.ClearError) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@ fun ReportMessageView(
|
||||||
CenterAlignedTopAppBar(
|
CenterAlignedTopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
stringResource(StringR.string.action_report_content),
|
stringResource(CommonStrings.action_report_content),
|
||||||
style = ElementTextStyles.Regular.callout,
|
style = ElementTextStyles.Regular.callout,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Medium,
|
||||||
)
|
)
|
||||||
|
|
@ -112,14 +112,14 @@ fun ReportMessageView(
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = state.reason,
|
value = state.reason,
|
||||||
onValueChange = { state.eventSink(ReportMessageEvents.UpdateReason(it)) },
|
onValueChange = { state.eventSink(ReportMessageEvents.UpdateReason(it)) },
|
||||||
placeholder = { Text(stringResource(StringR.string.report_content_hint)) },
|
placeholder = { Text(stringResource(CommonStrings.report_content_hint)) },
|
||||||
enabled = !isSending,
|
enabled = !isSending,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.heightIn(min = 90.dp)
|
.heightIn(min = 90.dp)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.report_content_explanation),
|
text = stringResource(CommonStrings.report_content_explanation),
|
||||||
style = ElementTextStyles.Regular.caption1,
|
style = ElementTextStyles.Regular.caption1,
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
textAlign = TextAlign.Start,
|
textAlign = TextAlign.Start,
|
||||||
|
|
@ -133,11 +133,11 @@ fun ReportMessageView(
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.screen_report_content_block_user),
|
text = stringResource(CommonStrings.screen_report_content_block_user),
|
||||||
style = ElementTextStyles.Regular.callout,
|
style = ElementTextStyles.Regular.callout,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.screen_report_content_block_user_hint),
|
text = stringResource(CommonStrings.screen_report_content_block_user_hint),
|
||||||
style = ElementTextStyles.Regular.bodyMD,
|
style = ElementTextStyles.Regular.bodyMD,
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
)
|
)
|
||||||
|
|
@ -152,7 +152,7 @@ fun ReportMessageView(
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
ButtonWithProgress(
|
ButtonWithProgress(
|
||||||
text = stringResource(StringR.string.action_send),
|
text = stringResource(CommonStrings.action_send),
|
||||||
enabled = state.reason.isNotBlank() && !isSending,
|
enabled = state.reason.isNotBlank() && !isSending,
|
||||||
showProgress = isSending,
|
showProgress = isSending,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventSendState
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineEventTimestampView(
|
fun TimelineEventTimestampView(
|
||||||
|
|
@ -70,7 +70,7 @@ fun TimelineEventTimestampView(
|
||||||
) {
|
) {
|
||||||
if (isMessageEdited) {
|
if (isMessageEdited) {
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.common_edited_suffix),
|
stringResource(CommonStrings.common_edited_suffix),
|
||||||
style = ElementTextStyles.Regular.caption2,
|
style = ElementTextStyles.Regular.caption2,
|
||||||
color = tint ?: MaterialTheme.colorScheme.secondary,
|
color = tint ?: MaterialTheme.colorScheme.secondary,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemEncryptedView(
|
fun TimelineItemEncryptedView(
|
||||||
|
|
@ -35,8 +34,8 @@ fun TimelineItemEncryptedView(
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
TimelineItemInformativeView(
|
TimelineItemInformativeView(
|
||||||
text = stringResource(id = StringR.string.common_decryption_error),
|
text = stringResource(id = CommonStrings.common_decryption_error),
|
||||||
iconDescription = stringResource(id = StringR.string.dialog_title_warning),
|
iconDescription = stringResource(id = CommonStrings.dialog_title_warning),
|
||||||
icon = Icons.Default.Warning,
|
icon = Icons.Default.Warning,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemRedactedView(
|
fun TimelineItemRedactedView(
|
||||||
|
|
@ -34,8 +33,8 @@ fun TimelineItemRedactedView(
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
TimelineItemInformativeView(
|
TimelineItemInformativeView(
|
||||||
text = stringResource(id = StringR.string.common_message_removed),
|
text = stringResource(id = CommonStrings.common_message_removed),
|
||||||
iconDescription = stringResource(id = StringR.string.common_message_removed),
|
iconDescription = stringResource(id = CommonStrings.common_message_removed),
|
||||||
icon = Icons.Default.Delete,
|
icon = Icons.Default.Delete,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemUnknownView(
|
fun TimelineItemUnknownView(
|
||||||
|
|
@ -34,8 +33,8 @@ fun TimelineItemUnknownView(
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
TimelineItemInformativeView(
|
TimelineItemInformativeView(
|
||||||
text = stringResource(id = StringR.string.common_unsupported_event),
|
text = stringResource(id = CommonStrings.common_unsupported_event),
|
||||||
iconDescription = stringResource(id = StringR.string.dialog_title_warning),
|
iconDescription = stringResource(id = CommonStrings.dialog_title_warning),
|
||||||
icon = Icons.Default.Info,
|
icon = Icons.Default.Info,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
import io.element.android.libraries.di.ApplicationContext
|
import io.element.android.libraries.di.ApplicationContext
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ContributesBinding(RoomScope::class)
|
@ContributesBinding(RoomScope::class)
|
||||||
|
|
@ -42,12 +42,12 @@ class MessageSummaryFormatterImpl @Inject constructor(
|
||||||
is TimelineItemTextBasedContent -> event.content.body
|
is TimelineItemTextBasedContent -> event.content.body
|
||||||
is TimelineItemStateContent -> event.content.body
|
is TimelineItemStateContent -> event.content.body
|
||||||
is TimelineItemProfileChangeContent -> event.content.body
|
is TimelineItemProfileChangeContent -> event.content.body
|
||||||
is TimelineItemEncryptedContent -> context.getString(R.string.common_unable_to_decrypt)
|
is TimelineItemEncryptedContent -> context.getString(CommonStrings.common_unable_to_decrypt)
|
||||||
is TimelineItemRedactedContent -> context.getString(R.string.common_message_removed)
|
is TimelineItemRedactedContent -> context.getString(CommonStrings.common_message_removed)
|
||||||
is TimelineItemUnknownContent -> context.getString(R.string.common_unsupported_event)
|
is TimelineItemUnknownContent -> context.getString(CommonStrings.common_unsupported_event)
|
||||||
is TimelineItemImageContent -> context.getString(R.string.common_image)
|
is TimelineItemImageContent -> context.getString(CommonStrings.common_image)
|
||||||
is TimelineItemVideoContent -> context.getString(R.string.common_video)
|
is TimelineItemVideoContent -> context.getString(CommonStrings.common_video)
|
||||||
is TimelineItemFileContent -> context.getString(R.string.common_file)
|
is TimelineItemFileContent -> context.getString(CommonStrings.common_file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ import io.element.android.libraries.designsystem.ElementTextStyles
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.theme.LocalColors
|
import io.element.android.libraries.designsystem.theme.LocalColors
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConnectivityIndicatorView(
|
fun ConnectivityIndicatorView(
|
||||||
|
|
@ -98,7 +98,7 @@ private fun Indicator(modifier: Modifier = Modifier) {
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.common_offline),
|
text = stringResource(CommonStrings.common_offline),
|
||||||
style = ElementTextStyles.Regular.bodyMD.copy(fontWeight = FontWeight.Medium),
|
style = ElementTextStyles.Regular.bodyMD.copy(fontWeight = FontWeight.Medium),
|
||||||
color = tint,
|
color = tint,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase
|
||||||
import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase
|
import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.bool.orFalse
|
import io.element.android.libraries.core.bool.orFalse
|
||||||
import io.element.android.libraries.featureflag.api.Feature
|
import io.element.android.libraries.featureflag.api.Feature
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
|
|
@ -128,13 +128,13 @@ class DeveloperSettingsPresenter @Inject constructor(
|
||||||
private fun CoroutineScope.computeCacheSize(cacheSize: MutableState<Async<String>>) = launch {
|
private fun CoroutineScope.computeCacheSize(cacheSize: MutableState<Async<String>>) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
computeCacheSizeUseCase()
|
computeCacheSizeUseCase()
|
||||||
}.execute(cacheSize)
|
}.runCatchingUpdatingState(cacheSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.clearCache(clearCacheAction: MutableState<Async<Unit>>) = launch {
|
private fun CoroutineScope.clearCache(clearCacheAction: MutableState<Async<Unit>>) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
clearCacheUseCase()
|
clearCacheUseCase()
|
||||||
}.execute(clearCacheAction)
|
}.runCatchingUpdatingState(clearCacheAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import io.element.android.libraries.architecture.Async
|
|
||||||
import io.element.android.libraries.architecture.isLoading
|
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceView
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceView
|
||||||
|
|
@ -32,7 +30,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.featureflag.ui.FeatureListView
|
import io.element.android.libraries.featureflag.ui.FeatureListView
|
||||||
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
|
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DeveloperSettingsView(
|
fun DeveloperSettingsView(
|
||||||
|
|
@ -44,7 +42,7 @@ fun DeveloperSettingsView(
|
||||||
PreferenceView(
|
PreferenceView(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackPressed = onBackPressed,
|
onBackPressed = onBackPressed,
|
||||||
title = stringResource(id = R.string.common_developer_options)
|
title = stringResource(id = CommonStrings.common_developer_options)
|
||||||
) {
|
) {
|
||||||
// Note: this is OK to hardcode strings in this debug screen.
|
// Note: this is OK to hardcode strings in this debug screen.
|
||||||
PreferenceCategory(title = "Feature flags") {
|
PreferenceCategory(title = "Feature flags") {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.preview.LargeHeightPreview
|
import io.element.android.libraries.designsystem.preview.LargeHeightPreview
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.components.MatrixUserProvider
|
import io.element.android.libraries.matrix.ui.components.MatrixUserProvider
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PreferencesRootView(
|
fun PreferencesRootView(
|
||||||
|
|
@ -50,7 +50,7 @@ fun PreferencesRootView(
|
||||||
PreferenceView(
|
PreferenceView(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackPressed = onBackPressed,
|
onBackPressed = onBackPressed,
|
||||||
title = stringResource(id = StringR.string.common_settings)
|
title = stringResource(id = CommonStrings.common_settings)
|
||||||
) {
|
) {
|
||||||
UserPreferences(state.myUser)
|
UserPreferences(state.myUser)
|
||||||
AnalyticsPreferencesView(
|
AnalyticsPreferencesView(
|
||||||
|
|
@ -71,9 +71,9 @@ fun PreferencesRootView(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DeveloperPreferencesView(onOpenDeveloperSettings: () -> Unit) {
|
fun DeveloperPreferencesView(onOpenDeveloperSettings: () -> Unit) {
|
||||||
PreferenceCategory(title = stringResource(id = StringR.string.common_developer_options)) {
|
PreferenceCategory(title = stringResource(id = CommonStrings.common_developer_options)) {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(id = StringR.string.common_developer_options),
|
title = stringResource(id = CommonStrings.common_developer_options),
|
||||||
icon = Icons.Default.DeveloperMode,
|
icon = Icons.Default.DeveloperMode,
|
||||||
onClick = onOpenDeveloperSettings
|
onClick = onOpenDeveloperSettings
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import io.element.android.libraries.designsystem.components.dialogs.Confirmation
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CrashDetectionView(
|
fun CrashDetectionView(
|
||||||
|
|
@ -56,10 +56,10 @@ fun CrashDetectionContent(
|
||||||
onDismiss: () -> Unit = { },
|
onDismiss: () -> Unit = { },
|
||||||
) {
|
) {
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
title = stringResource(id = StringR.string.action_report_bug),
|
title = stringResource(id = CommonStrings.action_report_bug),
|
||||||
content = stringResource(id = R.string.crash_detection_dialog_content, /* TODO App name */ "Element"),
|
content = stringResource(id = R.string.crash_detection_dialog_content, /* TODO App name */ "Element"),
|
||||||
submitText = stringResource(id = StringR.string.action_yes),
|
submitText = stringResource(id = CommonStrings.action_yes),
|
||||||
cancelText = stringResource(id = StringR.string.action_no),
|
cancelText = stringResource(id = CommonStrings.action_no),
|
||||||
onCancelClicked = onNoClicked,
|
onCancelClicked = onNoClicked,
|
||||||
onSubmitClicked = onYesClicked,
|
onSubmitClicked = onYesClicked,
|
||||||
onDismiss = onDismiss,
|
onDismiss = onDismiss,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RageshakeDetectionView(
|
fun RageshakeDetectionView(
|
||||||
|
|
@ -88,11 +88,11 @@ fun RageshakeDialogContent(
|
||||||
onYesClicked: () -> Unit = { },
|
onYesClicked: () -> Unit = { },
|
||||||
) {
|
) {
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
title = stringResource(id = StringR.string.action_report_bug),
|
title = stringResource(id = CommonStrings.action_report_bug),
|
||||||
content = stringResource(id = R.string.rageshake_detection_dialog_content),
|
content = stringResource(id = R.string.rageshake_detection_dialog_content),
|
||||||
thirdButtonText = stringResource(id = StringR.string.action_disable),
|
thirdButtonText = stringResource(id = CommonStrings.action_disable),
|
||||||
submitText = stringResource(id = StringR.string.action_yes),
|
submitText = stringResource(id = CommonStrings.action_yes),
|
||||||
cancelText = stringResource(id = StringR.string.action_no),
|
cancelText = stringResource(id = CommonStrings.action_no),
|
||||||
onCancelClicked = onNoClicked,
|
onCancelClicked = onNoClicked,
|
||||||
onThirdButtonClicked = onDisableClicked,
|
onThirdButtonClicked = onDisableClicked,
|
||||||
onSubmitClicked = onYesClicked,
|
onSubmitClicked = onYesClicked,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RageshakePreferencesView(
|
fun RageshakePreferencesView(
|
||||||
|
|
@ -47,23 +47,23 @@ fun RageshakePreferencesView(
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
PreferenceCategory(title = stringResource(id = StringR.string.action_report_bug)) {
|
PreferenceCategory(title = stringResource(id = CommonStrings.action_report_bug)) {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(id = StringR.string.action_report_bug),
|
title = stringResource(id = CommonStrings.action_report_bug),
|
||||||
icon = Icons.Default.BugReport,
|
icon = Icons.Default.BugReport,
|
||||||
onClick = onOpenRageshake
|
onClick = onOpenRageshake
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
PreferenceCategory(title = stringResource(id = StringR.string.settings_rageshake)) {
|
PreferenceCategory(title = stringResource(id = CommonStrings.settings_rageshake)) {
|
||||||
if (state.isSupported) {
|
if (state.isSupported) {
|
||||||
PreferenceSwitch(
|
PreferenceSwitch(
|
||||||
title = stringResource(id = StringR.string.preference_rageshake),
|
title = stringResource(id = CommonStrings.preference_rageshake),
|
||||||
isChecked = state.isEnabled,
|
isChecked = state.isEnabled,
|
||||||
onCheckedChange = ::onEnabledChanged
|
onCheckedChange = ::onEnabledChanged
|
||||||
)
|
)
|
||||||
PreferenceSlide(
|
PreferenceSlide(
|
||||||
title = stringResource(id = StringR.string.settings_rageshake_detection_threshold),
|
title = stringResource(id = CommonStrings.settings_rageshake_detection_threshold),
|
||||||
// summary = stringResource(id = StringR.string.settings_rageshake_detection_threshold_summary),
|
// summary = stringResource(id = CommonStrings.settings_rageshake_detection_threshold_summary),
|
||||||
value = state.sensitivity,
|
value = state.sensitivity,
|
||||||
enabled = state.isEnabled,
|
enabled = state.isEnabled,
|
||||||
steps = 3 /* 5 possible values - steps are in ]0, 1[ */,
|
steps = 3 /* 5 possible values - steps are in ]0, 1[ */,
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre
|
||||||
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BugReportView(
|
fun BugReportView(
|
||||||
|
|
@ -90,7 +90,7 @@ fun BugReportView(
|
||||||
val isFormEnabled = state.sending !is Async.Loading
|
val isFormEnabled = state.sending !is Async.Loading
|
||||||
// Title
|
// Title
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = StringR.string.action_report_bug),
|
text = stringResource(id = CommonStrings.action_report_bug),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp),
|
.padding(horizontal = 16.dp, vertical = 16.dp),
|
||||||
|
|
@ -190,7 +190,7 @@ fun BugReportView(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 32.dp)
|
.padding(vertical = 32.dp)
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(id = StringR.string.action_send))
|
Text(text = stringResource(id = CommonStrings.action_send))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when (state.sending) {
|
when (state.sending) {
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -198,7 +198,7 @@ internal fun RoomDetailsTopBar(
|
||||||
onDismissRequest = { showMenu = false },
|
onDismissRequest = { showMenu = false },
|
||||||
) {
|
) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(id = StringR.string.action_edit)) },
|
text = { Text(stringResource(id = CommonStrings.action_edit)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
// Explicitly close the menu before handling the action, as otherwise it stays open during the
|
// Explicitly close the menu before handling the action, as otherwise it stays open during the
|
||||||
// transition and renders really badly.
|
// transition and renders really badly.
|
||||||
|
|
@ -250,7 +250,7 @@ internal fun TopicSection(
|
||||||
onActionClicked: (RoomDetailsAction) -> Unit,
|
onActionClicked: (RoomDetailsAction) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
PreferenceCategory(title = stringResource(StringR.string.common_topic), modifier = modifier) {
|
PreferenceCategory(title = stringResource(CommonStrings.common_topic), modifier = modifier) {
|
||||||
if (roomTopic is RoomTopicState.CanAddTopic) {
|
if (roomTopic is RoomTopicState.CanAddTopic) {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(R.string.screen_room_details_add_topic_title),
|
title = stringResource(R.string.screen_room_details_add_topic_title),
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||||
|
|
@ -154,7 +154,7 @@ class RoomDetailsEditPresenter @Inject constructor(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (results.all { it.isSuccess }) Unit else results.first { it.isFailure }.getOrThrow()
|
if (results.all { it.isSuccess }) Unit else results.first { it.isFailure }.getOrThrow()
|
||||||
}.execute(action)
|
}.runCatchingUpdatingState(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updateAvatar(avatarUri: Uri?): Result<Unit> {
|
private suspend fun updateAvatar(avatarUri: Uri?): Result<Unit> {
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ 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.TextButton
|
||||||
import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet
|
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.components.UnsavedAvatar
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -121,7 +121,7 @@ fun RoomDetailsEditView(
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.action_save),
|
text = stringResource(CommonStrings.action_save),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +145,7 @@ fun RoomDetailsEditView(
|
||||||
LabelledTextField(
|
LabelledTextField(
|
||||||
label = stringResource(id = R.string.screen_room_details_room_name_label),
|
label = stringResource(id = R.string.screen_room_details_room_name_label),
|
||||||
value = state.roomName,
|
value = state.roomName,
|
||||||
placeholder = stringResource(StringR.string.common_room_name_placeholder),
|
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomName(it)) },
|
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomName(it)) },
|
||||||
)
|
)
|
||||||
|
|
@ -160,9 +160,9 @@ fun RoomDetailsEditView(
|
||||||
|
|
||||||
if (state.canChangeTopic) {
|
if (state.canChangeTopic) {
|
||||||
LabelledTextField(
|
LabelledTextField(
|
||||||
label = stringResource(StringR.string.common_topic),
|
label = stringResource(CommonStrings.common_topic),
|
||||||
value = state.roomTopic,
|
value = state.roomTopic,
|
||||||
placeholder = stringResource(StringR.string.common_topic_placeholder),
|
placeholder = stringResource(CommonStrings.common_topic_placeholder),
|
||||||
maxLines = 10,
|
maxLines = 10,
|
||||||
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(it)) },
|
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(it)) },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,11 @@ import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.apperror.api.AppErrorStateService
|
import io.element.android.services.apperror.api.AppErrorStateService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@ContributesNode(RoomScope::class)
|
@ContributesNode(RoomScope::class)
|
||||||
class RoomInviteMembersNode @AssistedInject constructor(
|
class RoomInviteMembersNode @AssistedInject constructor(
|
||||||
|
|
@ -65,8 +65,8 @@ class RoomInviteMembersNode @AssistedInject constructor(
|
||||||
|
|
||||||
if (anyInviteFailed) {
|
if (anyInviteFailed) {
|
||||||
appErrorStateService.showError(
|
appErrorStateService.showError(
|
||||||
title = context.getString(StringR.string.common_unable_to_invite_title),
|
title = context.getString(CommonStrings.common_unable_to_invite_title),
|
||||||
body = context.getString(StringR.string.common_unable_to_invite_message),
|
body = context.getString(CommonStrings.common_unable_to_invite_message),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import androidx.compose.runtime.setValue
|
||||||
import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource
|
import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.execute
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
|
|
@ -147,7 +147,7 @@ class RoomInviteMembersPresenter @Inject constructor(
|
||||||
withContext(coroutineDispatchers.io) {
|
withContext(coroutineDispatchers.io) {
|
||||||
roomMemberListDataSource.search("").toImmutableList()
|
roomMemberListDataSource.search("").toImmutableList()
|
||||||
}
|
}
|
||||||
}.execute(roomMembers)
|
}.runCatchingUpdatingState(roomMembers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ import io.element.android.libraries.matrix.ui.components.CheckableUserRow
|
||||||
import io.element.android.libraries.matrix.ui.components.SelectedUsersList
|
import io.element.android.libraries.matrix.ui.components.SelectedUsersList
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -131,7 +131,7 @@ fun RoomInviteMembersTopBar(
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = onSendPressed,
|
onClick = onSendPressed,
|
||||||
content = {
|
content = {
|
||||||
Text(stringResource(StringR.string.action_send))
|
Text(stringResource(CommonStrings.action_send))
|
||||||
},
|
},
|
||||||
enabled = canSend,
|
enabled = canSend,
|
||||||
)
|
)
|
||||||
|
|
@ -147,7 +147,7 @@ private fun RoomInviteMembersSearchBar(
|
||||||
selectedUsers: ImmutableList<MatrixUser>,
|
selectedUsers: ImmutableList<MatrixUser>,
|
||||||
active: Boolean,
|
active: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
placeHolderTitle: String = stringResource(StringR.string.common_search_for_someone),
|
placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone),
|
||||||
onActiveChanged: (Boolean) -> Unit = {},
|
onActiveChanged: (Boolean) -> Unit = {},
|
||||||
onTextChanged: (String) -> Unit = {},
|
onTextChanged: (String) -> Unit = {},
|
||||||
onUserToggled: (MatrixUser) -> Unit = {},
|
onUserToggled: (MatrixUser) -> Unit = {},
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.features.roomdetails.impl.R
|
import io.element.android.features.roomdetails.impl.R
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.isLoading
|
|
||||||
import io.element.android.libraries.designsystem.ElementTextStyles
|
import io.element.android.libraries.designsystem.ElementTextStyles
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
|
|
@ -61,8 +60,8 @@ import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.components.MatrixUserRow
|
import io.element.android.libraries.matrix.ui.components.MatrixUserRow
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -100,7 +99,7 @@ fun RoomMemberListView(
|
||||||
query = state.searchQuery,
|
query = state.searchQuery,
|
||||||
state = state.searchResults,
|
state = state.searchResults,
|
||||||
active = state.isSearchActive,
|
active = state.isSearchActive,
|
||||||
placeHolderTitle = stringResource(StringR.string.common_search_for_someone),
|
placeHolderTitle = stringResource(CommonStrings.common_search_for_someone),
|
||||||
onActiveChanged = { state.eventSink(RoomMemberListEvents.OnSearchActiveChanged(it)) },
|
onActiveChanged = { state.eventSink(RoomMemberListEvents.OnSearchActiveChanged(it)) },
|
||||||
onTextChanged = { state.eventSink(RoomMemberListEvents.UpdateSearchQuery(it)) },
|
onTextChanged = { state.eventSink(RoomMemberListEvents.UpdateSearchQuery(it)) },
|
||||||
onUserSelected = ::onUserSelected,
|
onUserSelected = ::onUserSelected,
|
||||||
|
|
@ -110,7 +109,7 @@ fun RoomMemberListView(
|
||||||
if (!state.isSearchActive) {
|
if (!state.isSearchActive) {
|
||||||
if (state.roomMembers is Async.Success) {
|
if (state.roomMembers is Async.Success) {
|
||||||
RoomMemberList(
|
RoomMemberList(
|
||||||
roomMembers = state.roomMembers.state,
|
roomMembers = state.roomMembers.data,
|
||||||
showMembersCount = true,
|
showMembersCount = true,
|
||||||
onUserSelected = ::onUserSelected
|
onUserSelected = ::onUserSelected
|
||||||
)
|
)
|
||||||
|
|
@ -221,7 +220,7 @@ private fun RoomMemberListTopBar(
|
||||||
onClick = onInvitePressed,
|
onClick = onInvitePressed,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.action_invite),
|
text = stringResource(CommonStrings.action_invite),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ import io.element.android.libraries.designsystem.preview.LargeHeightPreview
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
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.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -129,7 +129,7 @@ internal fun RoomMemberHeaderSection(
|
||||||
@Composable
|
@Composable
|
||||||
internal fun RoomMemberMainActionsSection(onShareUser: () -> Unit, modifier: Modifier = Modifier) {
|
internal fun RoomMemberMainActionsSection(onShareUser: () -> Unit, modifier: Modifier = Modifier) {
|
||||||
Row(modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
Row(modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||||
MainActionButton(title = stringResource(StringR.string.action_share), icon = Icons.Outlined.Share, onClick = onShareUser)
|
MainActionButton(title = stringResource(CommonStrings.action_share), icon = Icons.Outlined.Share, onClick = onShareUser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ internal fun RoomMemberMainActionsSection(onShareUser: () -> Unit, modifier: Mod
|
||||||
internal fun SendMessageSection(onSendMessage: () -> Unit, modifier: Modifier = Modifier) {
|
internal fun SendMessageSection(onSendMessage: () -> Unit, modifier: Modifier = Modifier) {
|
||||||
PreferenceCategory(modifier = modifier) {
|
PreferenceCategory(modifier = modifier) {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = stringResource(StringR.string.action_send_message),
|
title = stringResource(CommonStrings.action_send_message),
|
||||||
icon = Icons.Outlined.ChatBubbleOutline,
|
icon = Icons.Outlined.ChatBubbleOutline,
|
||||||
onClick = onSendMessage,
|
onClick = onSendMessage,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ class RoomMemberListPresenterTests {
|
||||||
|
|
||||||
val loadedState = awaitItem()
|
val loadedState = awaitItem()
|
||||||
Truth.assertThat(loadedState.roomMembers).isInstanceOf(Async.Success::class.java)
|
Truth.assertThat(loadedState.roomMembers).isInstanceOf(Async.Success::class.java)
|
||||||
Truth.assertThat((loadedState.roomMembers as Async.Success).state.invited).isEqualTo(listOf(aVictor(), aWalter()))
|
Truth.assertThat((loadedState.roomMembers as Async.Success).data.invited).isEqualTo(listOf(aVictor(), aWalter()))
|
||||||
Truth.assertThat((loadedState.roomMembers as Async.Success).state.joined).isNotEmpty()
|
Truth.assertThat((loadedState.roomMembers as Async.Success).data.joined).isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet
|
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -86,13 +86,13 @@ private fun RoomListModalBottomSheetContent(
|
||||||
)
|
)
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(text = stringResource(id = StringR.string.common_settings))
|
Text(text = stringResource(id = CommonStrings.common_settings))
|
||||||
},
|
},
|
||||||
modifier = Modifier.clickable { onRoomSettingsClicked(contextMenu.roomId) },
|
modifier = Modifier.clickable { onRoomSettingsClicked(contextMenu.roomId) },
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Outlined.Settings,
|
imageVector = Icons.Outlined.Settings,
|
||||||
contentDescription = stringResource(id = StringR.string.common_settings),
|
contentDescription = stringResource(id = CommonStrings.common_settings),
|
||||||
modifier = Modifier.size(20.dp),
|
modifier = Modifier.size(20.dp),
|
||||||
tint = MaterialTheme.colorScheme.onSurface,
|
tint = MaterialTheme.colorScheme.onSurface,
|
||||||
)
|
)
|
||||||
|
|
@ -101,7 +101,7 @@ private fun RoomListModalBottomSheetContent(
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = StringR.string.action_leave_room),
|
text = stringResource(id = CommonStrings.action_leave_room),
|
||||||
color = ElementTheme.colors.textActionCritical,
|
color = ElementTheme.colors.textActionCritical,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -109,7 +109,7 @@ private fun RoomListModalBottomSheetContent(
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(
|
Icon(
|
||||||
resourceId = VectorIcons.DoorOpen,
|
resourceId = VectorIcons.DoorOpen,
|
||||||
contentDescription = stringResource(id = StringR.string.action_leave_room),
|
contentDescription = stringResource(id = CommonStrings.action_leave_room),
|
||||||
modifier = Modifier.size(20.dp),
|
modifier = Modifier.size(20.dp),
|
||||||
tint = ElementTheme.colors.textActionCritical,
|
tint = ElementTheme.colors.textActionCritical,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,16 @@ import io.element.android.libraries.designsystem.utils.SnackbarMessage
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
open class RoomListStateProvider : PreviewParameterProvider<RoomListState> {
|
open class RoomListStateProvider : PreviewParameterProvider<RoomListState> {
|
||||||
override val values: Sequence<RoomListState>
|
override val values: Sequence<RoomListState>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aRoomListState(),
|
aRoomListState(),
|
||||||
aRoomListState().copy(displayVerificationPrompt = true),
|
aRoomListState().copy(displayVerificationPrompt = true),
|
||||||
aRoomListState().copy(snackbarMessage = SnackbarMessage(StringR.string.common_verification_complete)),
|
aRoomListState().copy(snackbarMessage = SnackbarMessage(CommonStrings.common_verification_complete)),
|
||||||
aRoomListState().copy(hasNetworkConnection = false),
|
aRoomListState().copy(hasNetworkConnection = false),
|
||||||
aRoomListState().copy(invitesState = InvitesState.SeenInvites),
|
aRoomListState().copy(invitesState = InvitesState.SeenInvites),
|
||||||
aRoomListState().copy(invitesState = InvitesState.NewInvites),
|
aRoomListState().copy(invitesState = InvitesState.NewInvites),
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,8 @@ import io.element.android.libraries.designsystem.theme.roomListUnreadIndicator
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.libraries.designsystem.R as DrawableR
|
import io.element.android.libraries.designsystem.R as DrawableR
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListView(
|
fun RoomListView(
|
||||||
|
|
@ -229,7 +229,7 @@ fun RoomListContent(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(StringR.string.action_invites_list),
|
text = stringResource(CommonStrings.action_invites_list),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
style = noFontPadding,
|
style = noFontPadding,
|
||||||
)
|
)
|
||||||
|
|
@ -314,7 +314,7 @@ internal fun RequestVerificationHeader(
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.clickable(onClick = onDismissClicked),
|
modifier = Modifier.clickable(onClick = onDismissClicked),
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(StringR.string.action_close)
|
contentDescription = stringResource(CommonStrings.action_close)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
@ -325,7 +325,7 @@ internal fun RequestVerificationHeader(
|
||||||
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 7.dp),
|
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 7.dp),
|
||||||
onClick = onVerifyClicked,
|
onClick = onVerifyClicked,
|
||||||
) {
|
) {
|
||||||
Text(stringResource(StringR.string.action_continue), style = ElementTextStyles.Button)
|
Text(stringResource(CommonStrings.action_continue), style = ElementTextStyles.Button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -109,7 +109,7 @@ private fun DefaultRoomListTopBar(
|
||||||
onClick = onOpenSettings
|
onClick = onOpenSettings
|
||||||
) {
|
) {
|
||||||
val avatarData by remember { derivedStateOf { matrixUser.getAvatarData() } }
|
val avatarData by remember { derivedStateOf { matrixUser.getAvatarData() } }
|
||||||
Avatar(avatarData, contentDescription = stringResource(StringR.string.common_settings))
|
Avatar(avatarData, contentDescription = stringResource(CommonStrings.common_settings))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -117,7 +117,7 @@ private fun DefaultRoomListTopBar(
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onSearchClicked,
|
onClick = onSearchClicked,
|
||||||
) {
|
) {
|
||||||
Icon(Icons.Default.Search, contentDescription = stringResource(StringR.string.action_search))
|
Icon(Icons.Default.Search, contentDescription = stringResource(CommonStrings.action_search))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ import io.element.android.libraries.designsystem.theme.components.TextField
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.copy
|
import io.element.android.libraries.designsystem.utils.copy
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun RoomListSearchResultView(
|
internal fun RoomListSearchResultView(
|
||||||
|
|
@ -150,7 +150,7 @@ internal fun RoomListSearchResultContent(
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(R.string.action_cancel)
|
contentDescription = stringResource(CommonStrings.action_cancel)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as FlowStep
|
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as FlowStep
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VerifySelfSessionView(
|
fun VerifySelfSessionView(
|
||||||
|
|
@ -190,8 +190,8 @@ internal fun BottomMenu(screenState: VerifySelfSessionState, goBack: () -> Unit)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
val negativeButtonTitle = when (verificationViewState) {
|
val negativeButtonTitle = when (verificationViewState) {
|
||||||
FlowStep.Initial -> StringR.string.action_cancel
|
FlowStep.Initial -> CommonStrings.action_cancel
|
||||||
FlowStep.Canceled -> StringR.string.action_cancel
|
FlowStep.Canceled -> CommonStrings.action_cancel
|
||||||
is FlowStep.Verifying -> R.string.screen_session_verification_they_dont_match
|
is FlowStep.Verifying -> R.string.screen_session_verification_they_dont_match
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,8 @@ dependencies {
|
||||||
api(libs.dagger)
|
api(libs.dagger)
|
||||||
api(libs.appyx.core)
|
api(libs.appyx.core)
|
||||||
api(libs.androidx.lifecycle.runtime)
|
api(libs.androidx.lifecycle.runtime)
|
||||||
|
|
||||||
|
testImplementation(libs.test.junit)
|
||||||
|
testImplementation(libs.coroutines.test)
|
||||||
|
testImplementation(libs.test.truth)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,51 +18,152 @@ package io.element.android.libraries.architecture
|
||||||
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sealed type that allows to model an asynchronous operation.
|
||||||
|
*/
|
||||||
@Stable
|
@Stable
|
||||||
sealed interface Async<out T> {
|
sealed interface Async<out T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a failed operation.
|
||||||
|
*
|
||||||
|
* @param T the type of data returned by the operation.
|
||||||
|
* @property error the error that caused the operation to fail.
|
||||||
|
* @property prevData the data returned by a previous successful run of the operation if any.
|
||||||
|
*/
|
||||||
|
data class Failure<out T>(
|
||||||
|
val error: Throwable,
|
||||||
|
val prevData: T? = null,
|
||||||
|
) : Async<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an operation that is currently ongoing.
|
||||||
|
*
|
||||||
|
* @param T the type of data returned by the operation.
|
||||||
|
* @property prevData the data returned by a previous successful run of the operation if any.
|
||||||
|
*/
|
||||||
|
data class Loading<out T>(
|
||||||
|
val prevData: T? = null,
|
||||||
|
) : Async<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a successful operation.
|
||||||
|
*
|
||||||
|
* @param T the type of data returned by the operation.
|
||||||
|
* @property data the data returned by the operation.
|
||||||
|
*/
|
||||||
|
data class Success<out T>(
|
||||||
|
val data: T,
|
||||||
|
) : Async<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an uninitialized operation (i.e. yet to be run).
|
||||||
|
*/
|
||||||
object Uninitialized : Async<Nothing>
|
object Uninitialized : Async<Nothing>
|
||||||
data class Loading<out T>(val prevState: T? = null) : Async<T>
|
|
||||||
data class Failure<out T>(val error: Throwable, val prevState: T? = null) : Async<T>
|
|
||||||
data class Success<out T>(val state: T) : Async<T>
|
|
||||||
|
|
||||||
fun dataOrNull(): T? {
|
/**
|
||||||
return when (this) {
|
* Returns the data returned by the operation, or null otherwise.
|
||||||
is Failure -> prevState
|
*
|
||||||
is Loading -> prevState
|
* Please note this method may return stale data if the operation is not [Success].
|
||||||
is Success -> state
|
*/
|
||||||
Uninitialized -> null
|
fun dataOrNull(): T? = when (this) {
|
||||||
|
is Failure -> prevData
|
||||||
|
is Loading -> prevData
|
||||||
|
is Success -> data
|
||||||
|
Uninitialized -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the error that caused the operation to fail, or null otherwise.
|
||||||
|
*/
|
||||||
|
fun errorOrNull(): Throwable? = when (this) {
|
||||||
|
is Failure -> error
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isFailure(): Boolean = this is Failure<T>
|
||||||
|
|
||||||
|
fun isLoading(): Boolean = this is Loading<T>
|
||||||
|
|
||||||
|
fun isSuccess(): Boolean = this is Success<T>
|
||||||
|
|
||||||
|
fun isUninitialized(): Boolean = this == Uninitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <T> MutableState<Async<T>>.runCatchingUpdatingState(
|
||||||
|
errorTransform: (Throwable) -> Throwable = { it },
|
||||||
|
block: () -> T,
|
||||||
|
): Result<T> = runUpdatingState(
|
||||||
|
state = this,
|
||||||
|
errorTransform = errorTransform,
|
||||||
|
resultBlock = {
|
||||||
|
runCatching {
|
||||||
|
block()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
)
|
||||||
|
|
||||||
suspend inline fun <T> (suspend () -> T).execute(
|
suspend inline fun <T> (suspend () -> T).runCatchingUpdatingState(
|
||||||
state: MutableState<Async<T>>,
|
state: MutableState<Async<T>>,
|
||||||
errorMapping: ((Throwable) -> Throwable) = { it },
|
errorTransform: (Throwable) -> Throwable = { it },
|
||||||
) {
|
): Result<T> = runUpdatingState(
|
||||||
try {
|
state = state,
|
||||||
state.value = Async.Loading()
|
errorTransform = errorTransform,
|
||||||
val result = this()
|
resultBlock = {
|
||||||
state.value = Async.Success(result)
|
runCatching {
|
||||||
} catch (error: Throwable) {
|
this()
|
||||||
state.value = Async.Failure(errorMapping.invoke(error))
|
}
|
||||||
}
|
},
|
||||||
}
|
)
|
||||||
|
|
||||||
suspend inline fun <T> (suspend () -> Result<T>).executeResult(state: MutableState<Async<T>>) {
|
suspend inline fun <T> MutableState<Async<T>>.runUpdatingState(
|
||||||
if (state.value !is Async.Success) {
|
errorTransform: (Throwable) -> Throwable = { it },
|
||||||
state.value = Async.Loading()
|
resultBlock: () -> Result<T>,
|
||||||
|
): Result<T> = runUpdatingState(
|
||||||
|
state = this,
|
||||||
|
errorTransform = errorTransform,
|
||||||
|
resultBlock = resultBlock,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the specified [Result]-returning function [resultBlock]
|
||||||
|
* encapsulating its progress and return value into an [Async] while
|
||||||
|
* posting its updates to the MutableState [state].
|
||||||
|
*
|
||||||
|
* @param T the type of data returned by the operation.
|
||||||
|
* @param state the [MutableState] to post updates to.
|
||||||
|
* @param errorTransform a function to transform the error before posting it.
|
||||||
|
* @param resultBlock a suspending function that returns a [Result].
|
||||||
|
* @return the [Result] returned by [resultBlock].
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||||
|
suspend inline fun <T> runUpdatingState(
|
||||||
|
state: MutableState<Async<T>>,
|
||||||
|
errorTransform: (Throwable) -> Throwable = { it },
|
||||||
|
resultBlock: suspend () -> Result<T>,
|
||||||
|
): Result<T> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(resultBlock, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
this().fold(
|
val prevData = state.value.dataOrNull()
|
||||||
|
state.value = Async.Loading(prevData = prevData)
|
||||||
|
return resultBlock().fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
state.value = Async.Success(it)
|
state.value = Async.Success(it)
|
||||||
|
Result.success(it)
|
||||||
},
|
},
|
||||||
onFailure = {
|
onFailure = {
|
||||||
state.value = Async.Failure(it)
|
val error = errorTransform(it)
|
||||||
|
state.value = Async.Failure(
|
||||||
|
error = error,
|
||||||
|
prevData = prevData,
|
||||||
|
)
|
||||||
|
Result.failure(error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Async<T>.isLoading(): Boolean {
|
|
||||||
return this is Async.Loading<T>
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.architecture
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class AsyncKtTest {
|
||||||
|
@Test
|
||||||
|
fun `updates state when block returns success`() = runTest {
|
||||||
|
val state = TestableMutableState<Async<Int>>(Async.Uninitialized)
|
||||||
|
|
||||||
|
val result = runUpdatingState(state) {
|
||||||
|
delay(1)
|
||||||
|
Result.success(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(result.isSuccess).isTrue()
|
||||||
|
assertThat(result.getOrNull()).isEqualTo(1)
|
||||||
|
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Uninitialized)
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Loading(null))
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Success(1))
|
||||||
|
state.assertNoMoreValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updates state when block returns failure`() = runTest {
|
||||||
|
val state = TestableMutableState<Async<Int>>(Async.Uninitialized)
|
||||||
|
|
||||||
|
val result = runUpdatingState(state) {
|
||||||
|
delay(1)
|
||||||
|
Result.failure(MyThrowable("hello"))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(result.isFailure).isTrue()
|
||||||
|
assertThat(result.exceptionOrNull()).isEqualTo(MyThrowable("hello"))
|
||||||
|
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Uninitialized)
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Loading(null))
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Failure<Int>(MyThrowable("hello")))
|
||||||
|
state.assertNoMoreValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updates state when block returns failure transforming the error`() = runTest {
|
||||||
|
val state = TestableMutableState<Async<Int>>(Async.Uninitialized)
|
||||||
|
|
||||||
|
val result = runUpdatingState(state, { MyThrowable(it.message + " world") }) {
|
||||||
|
delay(1)
|
||||||
|
Result.failure(MyThrowable("hello"))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(result.isFailure).isTrue()
|
||||||
|
assertThat(result.exceptionOrNull()).isEqualTo(MyThrowable("hello world"))
|
||||||
|
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Uninitialized)
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Loading(null))
|
||||||
|
assertThat(state.popFirst()).isEqualTo(Async.Failure<Int>(MyThrowable("hello world")))
|
||||||
|
state.assertNoMoreValues()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fake [MutableState] that allows to record all the states that were set.
|
||||||
|
*/
|
||||||
|
private class TestableMutableState<T>(
|
||||||
|
value: T
|
||||||
|
) : MutableState<T> {
|
||||||
|
|
||||||
|
private val _deque = ArrayDeque<T>(listOf(value))
|
||||||
|
|
||||||
|
override var value: T
|
||||||
|
get() = _deque.last()
|
||||||
|
set(value) {
|
||||||
|
_deque.addLast(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the states that were set in the order they were set.
|
||||||
|
*/
|
||||||
|
fun popFirst(): T = _deque.removeFirst()
|
||||||
|
|
||||||
|
fun assertNoMoreValues() {
|
||||||
|
assertThat(_deque).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun component1(): T = value
|
||||||
|
|
||||||
|
override operator fun component2(): (T) -> Unit = { value = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception that is also a data class so we can compare it using equals.
|
||||||
|
*/
|
||||||
|
private data class MyThrowable(val myMessage: String) : Throwable(myMessage)
|
||||||
|
|
@ -31,7 +31,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Button
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AsyncFailure(
|
fun AsyncFailure(
|
||||||
|
|
@ -45,11 +45,11 @@ fun AsyncFailure(
|
||||||
.padding(vertical = 32.dp),
|
.padding(vertical = 32.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Text(text = throwable.message ?: stringResource(id = StringR.string.error_unknown))
|
Text(text = throwable.message ?: stringResource(id = CommonStrings.error_unknown))
|
||||||
if (onRetry != null) {
|
if (onRetry != null) {
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
Button(onClick = onRetry) {
|
Button(onClick = onRetry) {
|
||||||
Text(text = stringResource(id = StringR.string.action_retry))
|
Text(text = stringResource(id = CommonStrings.action_retry))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,14 @@ import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BackButton(
|
fun BackButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
imageVector: ImageVector = Icons.Default.ArrowBack,
|
imageVector: ImageVector = Icons.Default.ArrowBack,
|
||||||
contentDescription: String = stringResource(StringR.string.action_back),
|
contentDescription: String = stringResource(CommonStrings.action_back),
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import androidx.compose.ui.unit.Dp
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
import io.element.android.libraries.designsystem.utils.BooleanProvider
|
import io.element.android.libraries.designsystem.utils.BooleanProvider
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -41,8 +41,8 @@ fun ConfirmationDialog(
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
submitText: String = stringResource(id = StringR.string.action_ok),
|
submitText: String = stringResource(id = CommonStrings.action_ok),
|
||||||
cancelText: String = stringResource(id = StringR.string.action_cancel),
|
cancelText: String = stringResource(id = CommonStrings.action_cancel),
|
||||||
thirdButtonText: String? = null,
|
thirdButtonText: String? = null,
|
||||||
emphasizeSubmitButton: Boolean = false,
|
emphasizeSubmitButton: Boolean = false,
|
||||||
onCancelClicked: () -> Unit = onDismiss,
|
onCancelClicked: () -> Unit = onDismiss,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -91,8 +91,8 @@ private fun ErrorDialogContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
object ErrorDialogDefaults {
|
object ErrorDialogDefaults {
|
||||||
val title: String @Composable get() = stringResource(id = StringR.string.dialog_title_error)
|
val title: String @Composable get() = stringResource(id = CommonStrings.dialog_title_error)
|
||||||
val submitText: String @Composable get() = stringResource(id = StringR.string.action_ok)
|
val submitText: String @Composable get() = stringResource(id = CommonStrings.action_ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(group = PreviewGroup.Dialogs)
|
@Preview(group = PreviewGroup.Dialogs)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import androidx.compose.ui.unit.Dp
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RetryDialog(
|
fun RetryDialog(
|
||||||
|
|
@ -109,9 +109,9 @@ private fun RetryDialogContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
object RetryDialogDefaults {
|
object RetryDialogDefaults {
|
||||||
val title: String @Composable get() = stringResource(id = StringR.string.dialog_title_error)
|
val title: String @Composable get() = stringResource(id = CommonStrings.dialog_title_error)
|
||||||
val retryText: String @Composable get() = stringResource(id = StringR.string.action_retry)
|
val retryText: String @Composable get() = stringResource(id = CommonStrings.action_retry)
|
||||||
val dismissText: String @Composable get() = stringResource(id = StringR.string.action_cancel)
|
val dismissText: String @Composable get() = stringResource(id = CommonStrings.action_cancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(group = PreviewGroup.Dialogs)
|
@Preview(group = PreviewGroup.Dialogs)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
import io.element.android.libraries.designsystem.theme.LocalColors
|
import io.element.android.libraries.designsystem.theme.LocalColors
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -100,7 +100,7 @@ fun <T> SearchBar(
|
||||||
IconButton(onClick = { onQueryChange("") }) {
|
IconButton(onClick = { onQueryChange("") }) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(R.string.action_clear),
|
contentDescription = stringResource(CommonStrings.action_clear),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +110,7 @@ fun <T> SearchBar(
|
||||||
{
|
{
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Search,
|
imageVector = Icons.Default.Search,
|
||||||
contentDescription = stringResource(R.string.action_search),
|
contentDescription = stringResource(CommonStrings.action_search),
|
||||||
tint = MaterialTheme.colorScheme.tertiary,
|
tint = MaterialTheme.colorScheme.tertiary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +135,7 @@ fun <T> SearchBar(
|
||||||
Spacer(Modifier.size(80.dp))
|
Spacer(Modifier.size(80.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.common_no_results),
|
text = stringResource(CommonStrings.common_no_results),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
color = MaterialTheme.colorScheme.tertiary,
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,9 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
class DefaultRoomLastMessageFormatter @Inject constructor(
|
class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
|
|
@ -66,7 +66,7 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
return when (val content = event.content) {
|
return when (val content = event.content) {
|
||||||
is MessageContent -> processMessageContents(content, senderDisplayName, isDmRoom)
|
is MessageContent -> processMessageContents(content, senderDisplayName, isDmRoom)
|
||||||
RedactedContent -> {
|
RedactedContent -> {
|
||||||
val message = sp.getString(StringR.string.common_message_removed)
|
val message = sp.getString(CommonStrings.common_message_removed)
|
||||||
if (!isDmRoom) {
|
if (!isDmRoom) {
|
||||||
prefix(message, senderDisplayName)
|
prefix(message, senderDisplayName)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -77,7 +77,7 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
content.body
|
content.body
|
||||||
}
|
}
|
||||||
is UnableToDecryptContent -> {
|
is UnableToDecryptContent -> {
|
||||||
val message = sp.getString(StringR.string.common_decryption_error)
|
val message = sp.getString(CommonStrings.common_decryption_error)
|
||||||
if (!isDmRoom) {
|
if (!isDmRoom) {
|
||||||
prefix(message, senderDisplayName)
|
prefix(message, senderDisplayName)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -94,7 +94,7 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
stateContentFormatter.format(content, senderDisplayName, isOutgoing, RenderingMode.RoomList)
|
stateContentFormatter.format(content, senderDisplayName, isOutgoing, RenderingMode.RoomList)
|
||||||
}
|
}
|
||||||
is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> {
|
is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> {
|
||||||
prefixIfNeeded(sp.getString(StringR.string.common_unsupported_event), senderDisplayName, isDmRoom)
|
prefixIfNeeded(sp.getString(CommonStrings.common_unsupported_event), senderDisplayName, isDmRoom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,19 +111,19 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
messageType.body
|
messageType.body
|
||||||
}
|
}
|
||||||
is VideoMessageType -> {
|
is VideoMessageType -> {
|
||||||
sp.getString(StringR.string.common_video)
|
sp.getString(CommonStrings.common_video)
|
||||||
}
|
}
|
||||||
is ImageMessageType -> {
|
is ImageMessageType -> {
|
||||||
sp.getString(StringR.string.common_image)
|
sp.getString(CommonStrings.common_image)
|
||||||
}
|
}
|
||||||
is FileMessageType -> {
|
is FileMessageType -> {
|
||||||
sp.getString(StringR.string.common_file)
|
sp.getString(CommonStrings.common_file)
|
||||||
}
|
}
|
||||||
is AudioMessageType -> {
|
is AudioMessageType -> {
|
||||||
sp.getString(StringR.string.common_audio)
|
sp.getString(CommonStrings.common_audio)
|
||||||
}
|
}
|
||||||
UnknownMessageType -> {
|
UnknownMessageType -> {
|
||||||
sp.getString(StringR.string.common_unsupported_event)
|
sp.getString(CommonStrings.common_unsupported_event)
|
||||||
}
|
}
|
||||||
is NoticeMessageType -> {
|
is NoticeMessageType -> {
|
||||||
messageType.body
|
messageType.body
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ class DefaultTimelineEventFormatter @Inject constructor(
|
||||||
if (buildMeta.isDebuggable) {
|
if (buildMeta.isDebuggable) {
|
||||||
error("You should not use this formatter for this event: $event")
|
error("You should not use this formatter for this event: $event")
|
||||||
}
|
}
|
||||||
sp.getString(R.string.common_unsupported_event)
|
sp.getString(CommonStrings.common_unsupported_event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ package io.element.android.libraries.eventformatter.impl
|
||||||
import io.element.android.libraries.eventformatter.impl.mode.RenderingMode
|
import io.element.android.libraries.eventformatter.impl.mode.RenderingMode
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
|
||||||
|
|
||||||
class StateContentFormatter @Inject constructor(
|
class StateContentFormatter @Inject constructor(
|
||||||
private val sp: StringProvider,
|
private val sp: StringProvider,
|
||||||
|
|
@ -50,7 +50,7 @@ class StateContentFormatter @Inject constructor(
|
||||||
sp.getString(R.string.state_event_room_created, senderDisplayName)
|
sp.getString(R.string.state_event_room_created, senderDisplayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OtherState.RoomEncryption -> sp.getString(StringR.string.common_encryption_enabled)
|
is OtherState.RoomEncryption -> sp.getString(CommonStrings.common_encryption_enabled)
|
||||||
is OtherState.RoomName -> {
|
is OtherState.RoomName -> {
|
||||||
val hasRoomName = content.name != null
|
val hasRoomName = content.name != null
|
||||||
when {
|
when {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDetails
|
import io.element.android.libraries.matrix.api.room.RoomSummaryDetails
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SelectedRoom(
|
fun SelectedRoom(
|
||||||
|
|
@ -84,7 +84,7 @@ fun SelectedRoom(
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(id = StringR.string.action_remove),
|
contentDescription = stringResource(id = CommonStrings.action_remove),
|
||||||
tint = MaterialTheme.colorScheme.onPrimary,
|
tint = MaterialTheme.colorScheme.onPrimary,
|
||||||
modifier = Modifier.padding(2.dp)
|
modifier = Modifier.padding(2.dp)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SelectedUser(
|
fun SelectedUser(
|
||||||
|
|
@ -83,7 +83,7 @@ fun SelectedUser(
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(id = StringR.string.action_remove),
|
contentDescription = stringResource(id = CommonStrings.action_remove),
|
||||||
tint = MaterialTheme.colorScheme.onPrimary,
|
tint = MaterialTheme.colorScheme.onPrimary,
|
||||||
modifier = Modifier.padding(2.dp)
|
modifier = Modifier.padding(2.dp)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.noFontPadding
|
import io.element.android.libraries.designsystem.theme.noFontPadding
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UnresolvedUserRow(
|
fun UnresolvedUserRow(
|
||||||
|
|
@ -94,7 +94,7 @@ fun UnresolvedUserRow(
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.common_invite_unknown_profile),
|
text = stringResource(CommonStrings.common_invite_unknown_profile),
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
lineHeight = 16.sp,
|
lineHeight = 16.sp,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import androidx.compose.material.icons.outlined.PhotoCamera
|
||||||
import androidx.compose.material.icons.outlined.PhotoLibrary
|
import androidx.compose.material.icons.outlined.PhotoLibrary
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import io.element.android.libraries.ui.strings.R
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
sealed class AvatarAction(
|
sealed class AvatarAction(
|
||||||
|
|
@ -31,7 +31,7 @@ sealed class AvatarAction(
|
||||||
val icon: ImageVector,
|
val icon: ImageVector,
|
||||||
val destructive: Boolean = false,
|
val destructive: Boolean = false,
|
||||||
) {
|
) {
|
||||||
object TakePhoto : AvatarAction(titleResId = R.string.action_take_photo, icon = Icons.Outlined.PhotoCamera)
|
object TakePhoto : AvatarAction(titleResId = CommonStrings.action_take_photo, icon = Icons.Outlined.PhotoCamera)
|
||||||
object ChoosePhoto : AvatarAction(titleResId = R.string.action_choose_photo, icon = Icons.Outlined.PhotoLibrary)
|
object ChoosePhoto : AvatarAction(titleResId = CommonStrings.action_choose_photo, icon = Icons.Outlined.PhotoLibrary)
|
||||||
object Remove : AvatarAction(titleResId = R.string.action_remove, icon = Icons.Outlined.Delete, destructive = true)
|
object Remove : AvatarAction(titleResId = CommonStrings.action_remove, icon = Icons.Outlined.Delete, destructive = true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -146,7 +146,7 @@ fun TextComposer(
|
||||||
contentPadding = PaddingValues(top = 10.dp, bottom = 10.dp, start = 12.dp, end = 42.dp),
|
contentPadding = PaddingValues(top = 10.dp, bottom = 10.dp, start = 12.dp, end = 42.dp),
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
placeholder = {
|
placeholder = {
|
||||||
Text(stringResource(StringR.string.common_message), style = defaultTypography)
|
Text(stringResource(CommonStrings.common_message), style = defaultTypography)
|
||||||
},
|
},
|
||||||
colors = TextFieldDefaults.colors(
|
colors = TextFieldDefaults.colors(
|
||||||
unfocusedTextColor = MaterialTheme.colorScheme.secondary,
|
unfocusedTextColor = MaterialTheme.colorScheme.secondary,
|
||||||
|
|
@ -225,7 +225,7 @@ private fun EditingModeView(
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(StringR.string.action_close),
|
contentDescription = stringResource(CommonStrings.action_close),
|
||||||
tint = MaterialTheme.colorScheme.secondary,
|
tint = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(16.dp)
|
.size(16.dp)
|
||||||
|
|
@ -283,7 +283,7 @@ private fun ReplyToModeView(
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = stringResource(StringR.string.action_close),
|
contentDescription = stringResource(CommonStrings.action_close),
|
||||||
tint = MaterialTheme.colorScheme.secondary,
|
tint = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(16.dp)
|
.size(16.dp)
|
||||||
|
|
@ -367,8 +367,8 @@ private fun BoxScope.SendButton(
|
||||||
else -> R.drawable.ic_send
|
else -> R.drawable.ic_send
|
||||||
}
|
}
|
||||||
val contentDescription = when (composerMode) {
|
val contentDescription = when (composerMode) {
|
||||||
is MessageComposerMode.Edit -> stringResource(StringR.string.action_edit)
|
is MessageComposerMode.Edit -> stringResource(CommonStrings.action_edit)
|
||||||
else -> stringResource(StringR.string.action_send)
|
else -> stringResource(CommonStrings.action_send)
|
||||||
}
|
}
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(16.dp),
|
modifier = Modifier.size(16.dp),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.ui.strings
|
||||||
|
|
||||||
|
typealias CommonPlurals = R.plurals
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.ui.strings
|
||||||
|
|
||||||
|
typealias CommonStrings = R.string
|
||||||
|
|
@ -130,5 +130,5 @@ System\.currentTimeMillis\(\)===1
|
||||||
### Suspicious String template. Please check that the string template will behave as expected, i.e. the class field and not the whole object will be used. For instance `Timber.d("$event.type")` is not correct, you should write `Timber.d("${event.type}")`. In the former the whole event content will be logged, since it's a data class. If this is expected (i.e. to fix false positive), please add explicit curly braces (`{` and `}`) around the variable, for instance `"elementLogs.${i}.txt"`
|
### Suspicious String template. Please check that the string template will behave as expected, i.e. the class field and not the whole object will be used. For instance `Timber.d("$event.type")` is not correct, you should write `Timber.d("${event.type}")`. In the former the whole event content will be logged, since it's a data class. If this is expected (i.e. to fix false positive), please add explicit curly braces (`{` and `}`) around the variable, for instance `"elementLogs.${i}.txt"`
|
||||||
\$[a-zA-Z_]\w*\??\.[a-zA-Z_]
|
\$[a-zA-Z_]\w*\??\.[a-zA-Z_]
|
||||||
|
|
||||||
### Use `import io.element.android.libraries.ui.strings.R as StringsR` then `StringR.string.<stringKey>` instead
|
### Use `import io.element.android.libraries.ui.strings.CommonStrings` then `CommonStrings.<stringKey>` instead
|
||||||
io\.element\.android\.libraries\.ui\.strings\.R\.
|
import io\.element\.android\.libraries\.ui\.strings\.R
|
||||||
|
|
|
||||||
|
|
@ -155,14 +155,6 @@ if (buildFilesWithMissingProcessor.length > 0) {
|
||||||
warn("You have made changes to a file containing a `@Preview` annotated function but its module doesn't include the showkase processor. Missing processor in: " + buildFilesWithMissingProcessor.join(", "))
|
warn("You have made changes to a file containing a `@Preview` annotated function but its module doesn't include the showkase processor. Missing processor in: " + buildFilesWithMissingProcessor.join(", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for screenshots on view changes
|
|
||||||
const hasChangedViews = filesWithPreviews.length > 0
|
|
||||||
if (hasChangedViews) {
|
|
||||||
if (!pr.body.includes("user-images")) {
|
|
||||||
warn("You seem to have made changes to views. Please consider adding screenshots.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for pngs on resources
|
// Check for pngs on resources
|
||||||
const hasPngs = editedFiles.filter(file => {
|
const hasPngs = editedFiles.filter(file => {
|
||||||
file.toLowerCase().endsWith(".png") && !file.includes("snapshots/images/") // Exclude screenshots
|
file.toLowerCase().endsWith(".png") && !file.includes("snapshots/images/") // Exclude screenshots
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue