mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-05 12:54:35 +00:00
Report problem: add an optional TextField to provide a GitHub issue number. (#6911)
* Report problem: add an optional TextField to provide a GitHub issue number. * Add leading icon `#`. * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
+2
@@ -20,6 +20,7 @@ interface BugReporter {
|
|||||||
* @param problemDescription the bug description
|
* @param problemDescription the bug description
|
||||||
* @param canContact true if the user opt in to be contacted directly
|
* @param canContact true if the user opt in to be contacted directly
|
||||||
* @param sendPushRules true to include the push rules
|
* @param sendPushRules true to include the push rules
|
||||||
|
* @param ghIssueNumber it not null, the GitHub issue number to link the bug report to.
|
||||||
* @param listener the listener
|
* @param listener the listener
|
||||||
*/
|
*/
|
||||||
suspend fun sendBugReport(
|
suspend fun sendBugReport(
|
||||||
@@ -29,6 +30,7 @@ interface BugReporter {
|
|||||||
problemDescription: String,
|
problemDescription: String,
|
||||||
canContact: Boolean = false,
|
canContact: Boolean = false,
|
||||||
sendPushRules: Boolean = false,
|
sendPushRules: Boolean = false,
|
||||||
|
ghIssueNumber: Int? = null,
|
||||||
listener: BugReporterListener
|
listener: BugReporterListener
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+1
@@ -18,4 +18,5 @@ sealed interface BugReportEvents {
|
|||||||
data class SetCanContact(val canContact: Boolean) : BugReportEvents
|
data class SetCanContact(val canContact: Boolean) : BugReportEvents
|
||||||
data class SetSendScreenshot(val sendScreenshot: Boolean) : BugReportEvents
|
data class SetSendScreenshot(val sendScreenshot: Boolean) : BugReportEvents
|
||||||
data class SetSendPushRules(val sendPushRules: Boolean) : BugReportEvents
|
data class SetSendPushRules(val sendPushRules: Boolean) : BugReportEvents
|
||||||
|
data class SetGhIssueNumber(val ghIssueNumber: Int?) : BugReportEvents
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -113,6 +113,9 @@ class BugReportPresenter(
|
|||||||
sendingProgress.floatValue = 0f
|
sendingProgress.floatValue = 0f
|
||||||
sendingAction.value = AsyncAction.Uninitialized
|
sendingAction.value = AsyncAction.Uninitialized
|
||||||
}
|
}
|
||||||
|
is BugReportEvents.SetGhIssueNumber -> updateFormState(formState) {
|
||||||
|
copy(ghIssueNumber = event.ghIssueNumber)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +145,8 @@ class BugReportPresenter(
|
|||||||
problemDescription = formState.description,
|
problemDescription = formState.description,
|
||||||
canContact = formState.canContact,
|
canContact = formState.canContact,
|
||||||
sendPushRules = formState.sendPushRules,
|
sendPushRules = formState.sendPushRules,
|
||||||
listener = listener
|
ghIssueNumber = formState.ghIssueNumber,
|
||||||
|
listener = listener,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -32,6 +32,7 @@ data class BugReportFormState(
|
|||||||
val canContact: Boolean,
|
val canContact: Boolean,
|
||||||
val sendScreenshot: Boolean,
|
val sendScreenshot: Boolean,
|
||||||
val sendPushRules: Boolean,
|
val sendPushRules: Boolean,
|
||||||
|
val ghIssueNumber: Int?,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
companion object {
|
companion object {
|
||||||
val Default = BugReportFormState(
|
val Default = BugReportFormState(
|
||||||
@@ -40,6 +41,7 @@ data class BugReportFormState(
|
|||||||
canContact = false,
|
canContact = false,
|
||||||
sendScreenshot = false,
|
sendScreenshot = false,
|
||||||
sendPushRules = false,
|
sendPushRules = false,
|
||||||
|
ghIssueNumber = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+43
@@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import coil3.request.CachePolicy
|
import coil3.request.CachePolicy
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.rageshake.impl.R
|
import io.element.android.features.rageshake.impl.R
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||||
@@ -155,6 +156,48 @@ fun BugReportView(
|
|||||||
title = stringResource(R.string.screen_bug_report_send_notification_settings_title),
|
title = stringResource(R.string.screen_bug_report_send_notification_settings_title),
|
||||||
subtitle = stringResource(R.string.screen_bug_report_send_notification_settings_description),
|
subtitle = stringResource(R.string.screen_bug_report_send_notification_settings_description),
|
||||||
)
|
)
|
||||||
|
PreferenceRow {
|
||||||
|
var ghIssueNumberState by textFieldState(
|
||||||
|
stateValue = state.formState.ghIssueNumber?.toString() ?: ""
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
value = ghIssueNumberState,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.onTabOrEnterKeyFocusNext(LocalFocusManager.current),
|
||||||
|
enabled = isFormEnabled,
|
||||||
|
label = stringResource(id = R.string.screen_bug_report_github_issue_label),
|
||||||
|
placeholder = "1234",
|
||||||
|
supportingText = stringResource(id = R.string.screen_bug_report_github_issue_description),
|
||||||
|
leadingIcon = {
|
||||||
|
Text(
|
||||||
|
text = "#",
|
||||||
|
style = ElementTheme.typography.fontBodyLgMedium,
|
||||||
|
color = ElementTheme.colors.textSecondary,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onValueChange = {
|
||||||
|
if (it.isEmpty()) {
|
||||||
|
ghIssueNumberState = ""
|
||||||
|
eventSink(BugReportEvents.SetGhIssueNumber(null))
|
||||||
|
} else {
|
||||||
|
val number = it.toIntOrNull()?.takeIf { ghInt -> ghInt in 1..99_999 }
|
||||||
|
number?.let { ghIssueNumber ->
|
||||||
|
ghIssueNumberState = ghIssueNumber.toString()
|
||||||
|
eventSink(BugReportEvents.SetGhIssueNumber(ghIssueNumber))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Number,
|
||||||
|
imeAction = ImeAction.Next,
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(onNext = {
|
||||||
|
keyboardController?.hide()
|
||||||
|
}),
|
||||||
|
singleLine = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
// Submit
|
// Submit
|
||||||
PreferenceRow {
|
PreferenceRow {
|
||||||
Button(
|
Button(
|
||||||
|
|||||||
+4
@@ -123,6 +123,7 @@ class DefaultBugReporter(
|
|||||||
problemDescription: String,
|
problemDescription: String,
|
||||||
canContact: Boolean,
|
canContact: Boolean,
|
||||||
sendPushRules: Boolean,
|
sendPushRules: Boolean,
|
||||||
|
ghIssueNumber: Int?,
|
||||||
listener: BugReporterListener,
|
listener: BugReporterListener,
|
||||||
) {
|
) {
|
||||||
val url = bugReporterUrlProvider.provide().first()
|
val url = bugReporterUrlProvider.provide().first()
|
||||||
@@ -144,6 +145,9 @@ class DefaultBugReporter(
|
|||||||
val crashCallStack = crashDataStore.crashInfo().first()
|
val crashCallStack = crashDataStore.crashInfo().first()
|
||||||
val bugDescription = buildString {
|
val bugDescription = buildString {
|
||||||
append(problemDescription)
|
append(problemDescription)
|
||||||
|
ghIssueNumber?.let {
|
||||||
|
append("\n\nhttps://github.com/element-hq/element-x-android/issues/$it")
|
||||||
|
}
|
||||||
if (crashCallStack.isNotEmpty() && withCrashLogs) {
|
if (crashCallStack.isNotEmpty() && withCrashLogs) {
|
||||||
append("\n\n\n\n--------------------------------- crash call stack ---------------------------------\n")
|
append("\n\n\n\n--------------------------------- crash call stack ---------------------------------\n")
|
||||||
append(crashCallStack)
|
append(crashCallStack)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
<string name="screen_bug_report_editor_placeholder">"Describe the problem…"</string>
|
<string name="screen_bug_report_editor_placeholder">"Describe the problem…"</string>
|
||||||
<string name="screen_bug_report_editor_supporting">"If possible, please write the description in English."</string>
|
<string name="screen_bug_report_editor_supporting">"If possible, please write the description in English."</string>
|
||||||
<string name="screen_bug_report_error_description_too_short">"The description is too short, please provide more details about what happened. Thanks!"</string>
|
<string name="screen_bug_report_error_description_too_short">"The description is too short, please provide more details about what happened. Thanks!"</string>
|
||||||
|
<string name="screen_bug_report_github_issue_description">"You can enter the number of an associated GitHub issue, if any."</string>
|
||||||
|
<string name="screen_bug_report_github_issue_label">"GitHub issue"</string>
|
||||||
<string name="screen_bug_report_include_crash_logs">"Send crash logs"</string>
|
<string name="screen_bug_report_include_crash_logs">"Send crash logs"</string>
|
||||||
<string name="screen_bug_report_include_logs">"Allow logs"</string>
|
<string name="screen_bug_report_include_logs">"Allow logs"</string>
|
||||||
<string name="screen_bug_report_include_logs_error">"Your logs are excessively large so cannot be included in this report, please send them to us another way."</string>
|
<string name="screen_bug_report_include_logs_error">"Your logs are excessively large so cannot be included in this report, please send them to us another way."</string>
|
||||||
|
|||||||
+12
@@ -107,6 +107,18 @@ class BugReportPresenterTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - set GitHub issue number`() = runTest {
|
||||||
|
val presenter = createPresenter()
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetGhIssueNumber(1))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(ghIssueNumber = 1))
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetGhIssueNumber(null))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(ghIssueNumber = null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - reset all`() = runTest {
|
fun `present - reset all`() = runTest {
|
||||||
val presenter = createPresenter(
|
val presenter = createPresenter(
|
||||||
|
|||||||
+1
@@ -28,6 +28,7 @@ class FakeBugReporter(val mode: Mode = Mode.Success) : BugReporter {
|
|||||||
problemDescription: String,
|
problemDescription: String,
|
||||||
canContact: Boolean,
|
canContact: Boolean,
|
||||||
sendPushRules: Boolean,
|
sendPushRules: Boolean,
|
||||||
|
ghIssueNumber: Int?,
|
||||||
listener: BugReporterListener,
|
listener: BugReporterListener,
|
||||||
) {
|
) {
|
||||||
delay(100)
|
delay(100)
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4a10513e98757e17cc3ffb8302807896839a78d036331e79bb207686f3f9db86
|
oid sha256:a4b243025f40d5d4a91e32d59a6cac9ec21a273aaddbfac020cb26b3dc86c906
|
||||||
size 47842
|
size 53339
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:05efb0fa45bb6440e75e9280b219cfdac83c372efe9e6d6254b4bbe516f8b998
|
oid sha256:e98722e0c21fe6b509b2bdf4a9ce7f78a1c83b606411329d2fd97a676fc4bed3
|
||||||
size 112842
|
size 113728
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:833d21633cb0f153b660112fcfd0923c588cd26b64005403a007d7782ecfe5d5
|
oid sha256:44eed3e8a093977f51d706acbec65cf29d592dcf0af3cdc9fce85d2b8e570eb9
|
||||||
size 45138
|
size 51038
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4a10513e98757e17cc3ffb8302807896839a78d036331e79bb207686f3f9db86
|
oid sha256:a4b243025f40d5d4a91e32d59a6cac9ec21a273aaddbfac020cb26b3dc86c906
|
||||||
size 47842
|
size 53339
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ebe22ec065cc6dff2133dcc573a82e003d9061ae0446c2d8c13f4e1fba1f3c19
|
oid sha256:781287977ff2637fe6479c3653270783c4374bc10fffb91da8b45d4e4f588a98
|
||||||
size 37056
|
size 41744
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f647e92bf813ead7affcdb6ad07076fe9d739f6a4c0016b9787912f032e27476
|
oid sha256:f690c34f97eec23f01bfdc3c2606a229bb12abb91fe86fb79c89da79b08480a0
|
||||||
size 46567
|
size 52049
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:cdfbb9f70a97724a1b6687ad4f199efc2c9bcc5f29fe9475a17ee6e52e5ecf8e
|
oid sha256:751b442e5aecd9d3938817f8a1af11b7cc1d250c1166c9e8bd3154a85268471d
|
||||||
size 110829
|
size 111765
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1cfab4886243e6c914f466f5f127ec0347b0ab30ee43fb95c7bc82d2b16325d5
|
oid sha256:0719e803112640729fe2b59c40373343db3e9f2e8dded9258d4b6c44547f8fd1
|
||||||
size 43727
|
size 49420
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f647e92bf813ead7affcdb6ad07076fe9d739f6a4c0016b9787912f032e27476
|
oid sha256:f690c34f97eec23f01bfdc3c2606a229bb12abb91fe86fb79c89da79b08480a0
|
||||||
size 46567
|
size 52049
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8c24515cc18b3c5cc52f2acfcee4faa65c02d8d5c8be847d4b1ec5671a858210
|
oid sha256:1cb10ddf4a9dee4a001276554cf32cf874062e1e5d7d0ebb673f6417641530bf
|
||||||
size 35201
|
size 39730
|
||||||
|
|||||||
Reference in New Issue
Block a user