BIT-2114 & BIT-2137: Add Give Feedback link to Other screen (#1166)

This commit is contained in:
Caleb Derosier 2024-03-21 15:46:04 -06:00 committed by Álison Fernandes
parent dc4b61c503
commit 45b1e332b4
5 changed files with 67 additions and 0 deletions

View file

@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.hilt.navigation.compose.hiltViewModel
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequency
@ -41,9 +42,12 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenSelectionDialo
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
import com.x8bit.bitwarden.ui.platform.components.dialog.row.BitwardenSelectionRow
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenExternalLinkRow
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenTextRow
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
/**
* Displays the other screen.
@ -54,11 +58,15 @@ import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
fun OtherScreen(
onNavigateBack: () -> Unit,
viewModel: OtherViewModel = hiltViewModel(),
intentManager: IntentManager = LocalIntentManager.current,
) {
val state by viewModel.stateFlow.collectAsState()
EventsEffect(viewModel = viewModel) { event ->
when (event) {
OtherEvent.NavigateBack -> onNavigateBack.invoke()
OtherEvent.NavigateToFeedbackForm -> {
intentManager.launchUri("https://livefrontinc.typeform.com/to/irgrRu4a".toUri())
}
}
}
@ -158,6 +166,16 @@ fun OtherScreen(
.semantics { testTag = "AllowScreenCaptureSwitch" }
.padding(horizontal = 16.dp),
)
BitwardenExternalLinkRow(
text = stringResource(R.string.give_feedback),
onConfirmClick = remember(viewModel) {
{ viewModel.trySendAction(OtherAction.GiveFeedbackClick) }
},
dialogTitle = stringResource(R.string.continue_to_give_feedback),
dialogMessage = stringResource(R.string.continue_to_provide_feedback),
withDivider = false,
)
}
}
}

View file

@ -60,6 +60,7 @@ class OtherViewModel @Inject constructor(
is OtherAction.AllowSyncToggle -> handleAllowSyncToggled(action)
OtherAction.BackClick -> handleBackClicked()
is OtherAction.ClearClipboardFrequencyChange -> handleClearClipboardFrequencyChanged(action)
OtherAction.GiveFeedbackClick -> handleGiveFeedbackClicked()
OtherAction.SyncNowButtonClick -> handleSyncNowButtonClicked()
is OtherAction.Internal -> handleInternalAction(action)
}
@ -87,6 +88,10 @@ class OtherViewModel @Inject constructor(
settingsRepo.clearClipboardFrequency = action.clearClipboardFrequency
}
private fun handleGiveFeedbackClicked() {
sendEvent(OtherEvent.NavigateToFeedbackForm)
}
private fun handleSyncNowButtonClicked() {
mutableStateFlow.update {
it.copy(dialogState = OtherState.DialogState.Loading(R.string.syncing.asText()))
@ -146,6 +151,11 @@ sealed class OtherEvent {
* Navigate back.
*/
data object NavigateBack : OtherEvent()
/**
* Navigate to the feedback form.
*/
data object NavigateToFeedbackForm : OtherEvent()
}
/**
@ -178,6 +188,11 @@ sealed class OtherAction {
val clearClipboardFrequency: ClearClipboardFrequency,
) : OtherAction()
/**
* Indicates that the user clicked the Give feedback button.
*/
data object GiveFeedbackClick : OtherAction()
/**
* Indicates that the user clicked the Sync Now button.
*/

View file

@ -3,4 +3,8 @@
<string name="app_name" translatable="false">Bitwarden Dev</string>
<string name="duo_title" translatable="false">Duo</string>
<string name="duo_org_title" translatable="false">Duo (%1$s)</string>
<!-- TODO BIT-2140: Update typeform strings -->
<string name="give_feedback" translatable="false">Give feedback</string>
<string name="continue_to_give_feedback" translatable="false">Continue to Give feedback?</string>
<string name="continue_to_provide_feedback" translatable="false">Select continue to provide feedback on your experience in a web form.</string>
</resources>

View file

@ -13,6 +13,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.ClearClipboardFrequenc
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import io.mockk.every
import io.mockk.mockk
@ -32,6 +33,9 @@ class OtherScreenTest : BaseComposeTest() {
every { eventFlow } returns mutableEventFlow
every { stateFlow } returns mutableStateFlow
}
private val intentManager: IntentManager = mockk {
every { getShareDataFromIntent(any()) } returns null
}
@Before
fun setup() {
@ -39,6 +43,7 @@ class OtherScreenTest : BaseComposeTest() {
OtherScreen(
viewModel = viewModel,
onNavigateBack = { haveCalledNavigateBack = true },
intentManager = intentManager,
)
}
}
@ -144,6 +149,22 @@ class OtherScreenTest : BaseComposeTest() {
.assertIsDisplayed()
.assert(hasAnyAncestor(isDialog()))
}
@Suppress("MaxLineLength")
@Test
fun `on give feedback click should display confirmation dialog and confirm click should emit GiveFeedbackClick`() {
composeTestRule.onNode(isDialog()).assertDoesNotExist()
composeTestRule.onNodeWithText("Give feedback").performClick()
composeTestRule.onNode(isDialog()).assertExists()
composeTestRule
.onAllNodesWithText("Continue")
.filterToOne(hasAnyAncestor(isDialog()))
.performClick()
composeTestRule.onNode(isDialog()).assertDoesNotExist()
verify {
viewModel.trySendAction(OtherAction.GiveFeedbackClick)
}
}
}
private val DEFAULT_STATE = OtherState(

View file

@ -108,6 +108,15 @@ class OtherViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `on GiveFeedbackClick should emit NavigateToFeedbackForm`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(OtherAction.GiveFeedbackClick)
assertEquals(OtherEvent.NavigateToFeedbackForm, awaitItem())
}
}
@Test
fun `on ClearClipboardFrequencyChange should update state`() = runTest {
val viewModel = createViewModel()