Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enter to sent message UI part-2 [WPB-15369] #3845

Merged
merged 15 commits into from
Feb 5, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ fun WireLabelledCheckbox(
fun WireCheckbox(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)?,
enabled: Boolean = true,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
Checkbox(
checked = checked,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class MessageComposerViewModel @Inject constructor(
}

private fun getEnterToSendState() {
viewModelScope.launch(dispatchers.io()) {
viewModelScope.launch {
globalDataStore.enterToSendFlow().first().also {
messageComposerViewState.value = messageComposerViewState.value.copy(enterToSend = it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,14 @@ fun EnabledMessageComposer(
}
val keyboardOptions by remember {
derivedStateOf {
if (messageComposerStateHolder.messageComposerViewState.value.enterToSend) {
if (messageComposerViewState.value.enterToSend) {
KeyboardOptions.Companion.MessageComposerEnterToSend
} else {
KeyboardOptions.Companion.MessageComposerDefault
}
}
}

val keyboardActionHandler by remember {
derivedStateOf {
KeyboardActionHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import com.wire.android.ui.common.clickable
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.destinations.AboutThisAppScreenDestination
import com.wire.android.ui.destinations.AppSettingsScreenDestination
import com.wire.android.ui.destinations.AppearanceScreenDestination
import com.wire.android.ui.destinations.CustomizationScreenDestination
import com.wire.android.ui.destinations.BackupAndRestoreScreenDestination
import com.wire.android.ui.destinations.DebugScreenDestination
import com.wire.android.ui.destinations.DependenciesScreenDestination
Expand Down Expand Up @@ -157,10 +157,10 @@ sealed class SettingsItem(open val id: String, open val title: UIText) {
direction = MyAccountScreenDestination
)

data object Appearance : DirectionItem(
id = "appearance_settings",
title = UIText.StringResource(R.string.settings_appearance_label),
direction = AppearanceScreenDestination
data object Customization : DirectionItem(
id = "customization_settings",
title = UIText.StringResource(R.string.settings_customization_label),
direction = CustomizationScreenDestination
)

data object NetworkSettings : DirectionItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ fun SettingsScreenContent(
header = context.getString(R.string.settings_account_settings_label),
items = buildList {
add(SettingsItem.YourAccount)
add(SettingsItem.Appearance)
add(SettingsItem.PrivacySettings)
add(SettingsItem.ManageDevices)
if (BackUpSettings) {
Expand All @@ -117,6 +116,7 @@ fun SettingsScreenContent(
folderWithElements(
header = context.getString(R.string.app_settings_screen_title),
items = buildList {
add(SettingsItem.Customization)
if (AppSettings) {
add(SettingsItem.AppSettings)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.wire.android.ui.home.settings.appearance

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
Expand Down Expand Up @@ -48,6 +49,10 @@ import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.scaffold.WireScaffold
import com.wire.android.ui.common.selectableBackground
import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar
import com.wire.android.ui.home.conversations.details.options.ArrowType
import com.wire.android.ui.home.conversations.details.options.GroupConversationOptionsItem
import com.wire.android.ui.home.conversationslist.common.FolderHeader
import com.wire.android.ui.home.settings.SwitchState
import com.wire.android.ui.theme.ThemeData
import com.wire.android.ui.theme.ThemeOption
import com.wire.android.ui.theme.wireColorScheme
Expand All @@ -58,24 +63,26 @@ import com.wire.android.util.ui.PreviewMultipleThemes
@RootNavGraph
@WireDestination
@Composable
fun AppearanceScreen(
fun CustomizationScreen(
navigator: Navigator,
viewModel: AppearanceViewModel = hiltViewModel()
viewModel: CustomizationViewModel = hiltViewModel()
) {
val lazyListState: LazyListState = rememberLazyListState()
AppearanceScreenContent(
CustomizationScreenContent(
lazyListState = lazyListState,
state = viewModel.state,
onThemeOptionChanged = viewModel::selectThemeOption,
onBackPressed = navigator::navigateBack
onBackPressed = navigator::navigateBack,
onEnterToSendClicked = viewModel::selectPressEnterToSendOption,
)
}

@Composable
fun AppearanceScreenContent(
state: AppearanceState,
fun CustomizationScreenContent(
state: CustomizationState,
onThemeOptionChanged: (ThemeOption) -> Unit,
onBackPressed: () -> Unit,
onEnterToSendClicked: (Boolean) -> Unit,
modifier: Modifier = Modifier,
lazyListState: LazyListState = rememberLazyListState()
) {
Expand All @@ -86,7 +93,7 @@ fun AppearanceScreenContent(
WireCenterAlignedTopAppBar(
onNavigationPressed = onBackPressed,
elevation = 0.dp,
title = stringResource(id = R.string.settings_appearance_label)
title = stringResource(id = R.string.settings_customization_label)
)
}
) { internalPadding ->
Expand All @@ -105,10 +112,36 @@ fun AppearanceScreenContent(
},
onItemClicked = onThemeOptionChanged
)
item {
CustomizationOptionsContent(
enterToSendState = state.pressEnterToSentState,
enterToSendClicked = onEnterToSendClicked
)
}
}
}
}

@Composable
fun CustomizationOptionsContent(
enterToSendState: Boolean,
enterToSendClicked: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth()
) {
FolderHeader(stringResource(R.string.custimization_options_header_title))
GroupConversationOptionsItem(
title = stringResource(R.string.press_enter_to_send_title),
switchState = SwitchState.Enabled(value = enterToSendState, onCheckedChange = enterToSendClicked),
arrowType = ArrowType.NONE,
subtitle = stringResource(id = R.string.press_enter_to_send_text)
)
}
}

private fun LazyListScope.folderWithElements(
header: String,
items: List<ThemeData>,
Expand Down Expand Up @@ -167,8 +200,9 @@ fun ThemeOptionItem(
@PreviewMultipleThemes
@Composable
fun PreviewSettingsScreen() {
AppearanceScreenContent(
AppearanceState(),
CustomizationScreenContent(
CustomizationState(),
{},
{},
{},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.wire.android.ui.home.settings.appearance

import com.wire.android.ui.theme.ThemeOption

data class AppearanceState(
data class CustomizationState(
val selectedThemeOption: ThemeOption = ThemeOption.SYSTEM,
val pressEnterToSentState: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,35 @@ import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class AppearanceViewModel @Inject constructor(
class CustomizationViewModel @Inject constructor(
private val globalDataStore: GlobalDataStore,
) : ViewModel() {
var state by mutableStateOf(AppearanceState())
var state by mutableStateOf(CustomizationState())
private set

init {
observeThemeState()
observePressEnterToSendState()
}

private fun observePressEnterToSendState() {
viewModelScope.launch {
globalDataStore.enterToSendFlow().collect { state = state.copy(pressEnterToSentState = it) }
}
}

private fun observeThemeState() {
viewModelScope.launch {
globalDataStore.selectedThemeOptionFlow().collect { option -> state = state.copy(selectedThemeOption = option) }
}
}

fun selectPressEnterToSendOption(option: Boolean) {
viewModelScope.launch {
globalDataStore.setEnterToSend(option)
}
}

fun selectThemeOption(option: ThemeOption) {
viewModelScope.launch {
globalDataStore.setThemeOption(option)
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,6 @@
<string name="settings_keep_connection_to_websocket_description">Verbessern Sie den Empfang von Benachrichtigungen, indem Sie eine ständige Verbindung zu %1$s aufrechterhalten. Es ersetzt die Benachrichtigungsdienste, wenn die Google-Dienste auf Ihrem Gerät nicht verfügbar sind.</string>
<string name="settings_service_is_running">Dienst wird ausgeführt</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">Erscheinungsbild</string>
<string name="settings_appearance_theme_label">Hintergrund</string>
<string name="settings_appearance_theme_option_system">Mit Systemeinstellungen synchronisieren</string>
<string name="settings_appearance_theme_option_default_hint">(Standard)</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-hu/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,6 @@
<string name="settings_keep_connection_to_websocket_description">Javítson az értesítések fogadásán a(z) %1$s szolgáltatáshoz való állandó kapcsolattal. Ez helyettesíti az értesítési szolgáltatásokat, ha a Google-szolgáltatások nem elérhetők az eszközén.</string>
<string name="settings_service_is_running">szolgáltatás fut</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">Megjelenés</string>
<string name="settings_appearance_theme_label">Téma</string>
<string name="settings_appearance_theme_option_system">Rendszerbeállítások használata</string>
<string name="settings_appearance_theme_option_default_hint">(Alapértelmezett)</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,6 @@ Rispondendo qui, verr&#224; riagganciata l\'altra chiamata.</string>
<string name="settings_keep_connection_to_websocket_description">Migliora la ricezione di notifiche mantenendo una costante connessione a %1$s. Questo servizio sostituir&#224; i servizi di notifica se Google Services non sono disponibili sul tuo dispositivo.</string>
<string name="settings_service_is_running">il servizio &#232; in esecuzione</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">Aspetto</string>
<string name="settings_appearance_theme_label">Tema</string>
<string name="settings_appearance_theme_option_system">Sincronizza con le impostazioni di sistema</string>
<string name="settings_appearance_theme_option_default_hint">(Predefinito)</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,6 @@
<string name="settings_keep_connection_to_websocket_description">Позволяет оптимизировать получение уведомлений, поддерживая постоянное соединение с %1$s. Эта опция заменит службу уведомлений, если Google Services недоступны на устройстве.</string>
<string name="settings_service_is_running">активен</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">Внешний вид</string>
<string name="settings_appearance_theme_label">Тема</string>
<string name="settings_appearance_theme_option_system">Как в системе</string>
<string name="settings_appearance_theme_option_default_hint">(По умолчанию)</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-si/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,6 @@
<string name="settings_keep_connection_to_websocket_description">%1$s වෙත ස්ථායී සම්බන්ධතාවයක් පවත්වා ගැනීමෙන් දැනුම්දීම් ලැබීම වැඩි දියුණු කරගන්න. ඔබගේ උපාංගයේ ගූගල් සේවා නැති නම් දැනුම්දීමේ සේවා සඳහා විසඳුමක් වේ.</string>
<string name="settings_service_is_running">සේවාව ධාවනය වෙමින්</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">පෙනුම</string>
<string name="settings_appearance_theme_label">තේමාව</string>
<string name="settings_appearance_theme_option_system">පද්ධතියේ සැකසුම් සමඟ සමමුහූර්තය</string>
<string name="settings_appearance_theme_option_default_hint">(පෙරනිමි)</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-sv/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,6 @@
<string name="settings_network_settings_label">Nätverksinställningar</string>
<string name="settings_manage_devices_label">Hantera dina enheter</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">Utseende</string>
<string name="settings_appearance_theme_label">Tema</string>
<string name="settings_appearance_theme_option_default_hint">(Standard)</string>
<string name="settings_appearance_theme_option_light">Ljust läge</string>
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@
<string name="settings_keep_connection_to_websocket_description">Improve receiving notifications by keeping a constant connection to %1$s. It will replace notification services if Google Services are not available on your device.</string>
<string name="settings_service_is_running">service is running</string>
<!--Settings, Appearance -->
<string name="settings_appearance_label">Appearance</string>
<string name="settings_customization_label">Customization</string>
<string name="settings_appearance_theme_label">Theme</string>
<string name="settings_appearance_theme_option_system">Sync with system settings</string>
<string name="settings_appearance_theme_option_default_hint">(Default)</string>
Expand Down Expand Up @@ -1696,5 +1696,8 @@ In group conversations, the group admin can overwrite this setting.</string>
<string name="new_folder_error_name_empty">Please enter folder name.</string>
<string name="new_folder_error_name_exceeded_limit_error">Minimum of 1 and maximum of 64 characters</string>
<string name="new_folder_failure">“%1$s” folder could not be added</string>
<string name="press_enter_to_send_title">Press Enter to send</string>
<string name="press_enter_to_send_text">If this is on, messages can be sent with the Enter key on the Keyboard</string>
<string name="custimization_options_header_title">Options</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ internal class MessageComposerViewModelArrangement {
)
}

fun withSuccessfulViewModelInit() = apply {
fun withSuccessfulViewModelInit(
enterToSend: Boolean = false,
) = apply {
coEvery { isFileSharingEnabledUseCase() } returns FileSharingStatus(FileSharingStatus.Value.EnabledAll, null)
coEvery { observeOngoingCallsUseCase() } returns emptyFlow()
coEvery { observeEstablishedCallsUseCase() } returns emptyFlow()
Expand All @@ -180,6 +182,7 @@ internal class MessageComposerViewModelArrangement {
InteractionAvailability.ENABLED
)
)
coEvery { globalDataStore.enterToSendFlow() } returns flowOf(enterToSend)
}

fun withSaveDraftMessage() = apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.internal.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

Expand Down Expand Up @@ -94,4 +95,28 @@ class MessageComposerViewModelTest {
// then
assertEquals(InteractionAvailability.DISABLED, viewModel.messageComposerViewState.value.interactionAvailability)
}

@Test
fun `given enter to send is enabled, when init, then update state`() = runTest {
// given
val (_, viewModel) = MessageComposerViewModelArrangement()
.withSuccessfulViewModelInit(enterToSend = true)
.arrange()
// when

// then
assertTrue(viewModel.messageComposerViewState.value.enterToSend)
}

@Test
fun `given enter to send is disabled, when init, then update state`() = runTest {
// given
val (_, viewModel) = MessageComposerViewModelArrangement()
.withSuccessfulViewModelInit(enterToSend = false)
.arrange()
// when

// then
assertTrue(!viewModel.messageComposerViewState.value.enterToSend)
}
}
Loading
Loading