Skip to content

Commit b79d17c

Browse files
authored
Merge 1a758a2 into 93c1e3f
2 parents 93c1e3f + 1a758a2 commit b79d17c

File tree

11 files changed

+953
-8
lines changed

11 files changed

+953
-8
lines changed

CHANGELOG.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Add New User Feedback form ([#4384](https://github.com/getsentry/sentry-java/pull/4384))
8+
- We now introduce SentryUserFeedbackDialog, which extends AlertDialog, inheriting the show() and cancel() methods, among others.
9+
- The dialog integrates with the current dialog theme, so it's compatible with dark mode, and can be customized with a custom xml style.
10+
- ```styles.xml or themes.xml
11+
<!-- Application theme. -->
12+
<style name="MyAppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
13+
...
14+
current theme customizations
15+
...
16+
<!-- Set a dialog theme if not already done. -->
17+
<item name="android:dialogTheme">@style/MyAppDialogTheme</item>
18+
</style>
19+
20+
<!-- Edit application dialog theme. -->
21+
<style name="MyAppDialogTheme" parent="Theme.AppCompat.DayNight.Dialog">
22+
<!-- Set the style of the feedback dialog title. -->
23+
<item name="android:windowTitleStyle">@style/FeedbackFormTitleStyle</item>
24+
25+
<!-- Set the color of title, cancel button text, and non editable texts. -->
26+
<item name="android:textColor">@color/colorPrimary</item>
27+
<!-- Set the color of editable texts. -->
28+
<item name="android:editTextColor">@color/colorPrimaryDark</item>
29+
<!-- Set the color of the hint of editable texts. -->
30+
<item name="android:textColorHint">@color/colorPrimaryDark</item>
31+
<!-- Set the color of the send button text. -->
32+
<item name="android:textColorPrimaryInverse">@android:color/white</item>
33+
34+
<!-- Set the background color of the send button. -->
35+
<item name="android:colorPrimary">@color/colorPrimary</item>
36+
<!-- Set the background color of the cancel button. -->
37+
<item name="android:colorBackground">@android:color/black</item>
38+
<!-- Set the color tint of the image logo. -->
39+
<item name="android:colorForeground">@color/colorPrimary</item>
40+
</style>
41+
42+
<style name="FeedbackFormTitleStyle">
43+
<!-- Customize your theme here. -->
44+
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Title</item>
45+
</style>
46+
```
47+
348
## 8.12.0
449

550
### Features

sentry-android-core/api/sentry-android-core.api

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,13 @@ public final class io/sentry/android/core/SentryPerformanceProvider {
385385
public fun shutdown ()V
386386
}
387387

388+
public final class io/sentry/android/core/SentryUserFeedbackDialog : android/app/AlertDialog {
389+
public fun <init> (Landroid/content/Context;)V
390+
public fun <init> (Landroid/content/Context;I)V
391+
public fun <init> (Landroid/content/Context;ZLandroid/content/DialogInterface$OnCancelListener;)V
392+
public fun setCancelable (Z)V
393+
}
394+
388395
public class io/sentry/android/core/SpanFrameMetricsCollector : io/sentry/IPerformanceContinuousCollector, io/sentry/android/core/internal/util/SentryFrameMetricsCollector$FrameMetricsCollectorListener {
389396
protected final field lock Lio/sentry/util/AutoClosableReentrantLock;
390397
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/internal/util/SentryFrameMetricsCollector;)V
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package io.sentry.android.core;
2+
3+
import android.app.AlertDialog;
4+
import android.content.Context;
5+
import android.os.Bundle;
6+
import android.view.View;
7+
import android.widget.Button;
8+
import android.widget.EditText;
9+
import android.widget.ImageView;
10+
import android.widget.TextView;
11+
import android.widget.Toast;
12+
import io.sentry.Sentry;
13+
import io.sentry.SentryFeedbackOptions;
14+
import io.sentry.protocol.Feedback;
15+
import io.sentry.protocol.SentryId;
16+
import io.sentry.protocol.User;
17+
import org.jetbrains.annotations.NotNull;
18+
import org.jetbrains.annotations.Nullable;
19+
20+
public final class SentryUserFeedbackDialog extends AlertDialog {
21+
22+
private boolean isCancelable = false;
23+
24+
public SentryUserFeedbackDialog(final @NotNull Context context) {
25+
super(context);
26+
isCancelable = false;
27+
}
28+
29+
public SentryUserFeedbackDialog(
30+
final @NotNull Context context,
31+
final boolean cancelable,
32+
@Nullable final OnCancelListener cancelListener) {
33+
super(context, cancelable, cancelListener);
34+
isCancelable = cancelable;
35+
}
36+
37+
public SentryUserFeedbackDialog(final @NotNull Context context, final int themeResId) {
38+
super(context, themeResId);
39+
isCancelable = false;
40+
}
41+
42+
@Override
43+
public void setCancelable(boolean cancelable) {
44+
super.setCancelable(cancelable);
45+
isCancelable = cancelable;
46+
}
47+
48+
@Override
49+
protected void onCreate(Bundle savedInstanceState) {
50+
super.onCreate(savedInstanceState);
51+
setContentView(R.layout.sentry_dialog_user_feedback);
52+
setCancelable(isCancelable);
53+
54+
final @NotNull SentryFeedbackOptions feedbackOptions =
55+
Sentry.getCurrentScopes().getOptions().getFeedbackOptions();
56+
final @NotNull TextView lblTitle = findViewById(R.id.sentry_dialog_user_feedback_title);
57+
final @NotNull ImageView imgLogo = findViewById(R.id.sentry_dialog_user_feedback_logo);
58+
final @NotNull TextView lblName = findViewById(R.id.sentry_dialog_user_feedback_txt_name);
59+
final @NotNull EditText edtName = findViewById(R.id.sentry_dialog_user_feedback_edt_name);
60+
final @NotNull TextView lblEmail = findViewById(R.id.sentry_dialog_user_feedback_txt_email);
61+
final @NotNull EditText edtEmail = findViewById(R.id.sentry_dialog_user_feedback_edt_email);
62+
final @NotNull TextView lblMessage =
63+
findViewById(R.id.sentry_dialog_user_feedback_txt_description);
64+
final @NotNull EditText edtMessage =
65+
findViewById(R.id.sentry_dialog_user_feedback_edt_description);
66+
final @NotNull Button btnSend = findViewById(R.id.sentry_dialog_user_feedback_btn_send);
67+
final @NotNull Button btnCancel = findViewById(R.id.sentry_dialog_user_feedback_btn_cancel);
68+
69+
if (feedbackOptions.isShowBranding()) {
70+
imgLogo.setVisibility(View.VISIBLE);
71+
} else {
72+
imgLogo.setVisibility(View.GONE);
73+
}
74+
75+
if (!feedbackOptions.isShowName() && !feedbackOptions.isNameRequired()) {
76+
lblName.setVisibility(View.GONE);
77+
edtName.setVisibility(View.GONE);
78+
} else {
79+
lblName.setVisibility(View.VISIBLE);
80+
edtName.setVisibility(View.VISIBLE);
81+
lblName.setText(feedbackOptions.getNameLabel());
82+
edtName.setHint(feedbackOptions.getNamePlaceholder());
83+
if (feedbackOptions.isNameRequired()) {
84+
lblName.append(feedbackOptions.getIsRequiredLabel());
85+
}
86+
}
87+
88+
if (!feedbackOptions.isShowEmail() && !feedbackOptions.isEmailRequired()) {
89+
lblEmail.setVisibility(View.GONE);
90+
edtEmail.setVisibility(View.GONE);
91+
} else {
92+
lblEmail.setVisibility(View.VISIBLE);
93+
edtEmail.setVisibility(View.VISIBLE);
94+
lblEmail.setText(feedbackOptions.getEmailLabel());
95+
edtEmail.setHint(feedbackOptions.getEmailPlaceholder());
96+
if (feedbackOptions.isEmailRequired()) {
97+
lblEmail.append(feedbackOptions.getIsRequiredLabel());
98+
}
99+
}
100+
101+
if (feedbackOptions.isUseSentryUser()) {
102+
final @Nullable User user = Sentry.getCurrentScopes().getScope().getUser();
103+
if (user != null) {
104+
edtName.setText(user.getName());
105+
edtEmail.setText(user.getEmail());
106+
}
107+
}
108+
109+
lblMessage.setText(feedbackOptions.getMessageLabel());
110+
edtMessage.setHint(feedbackOptions.getMessagePlaceholder());
111+
lblTitle.setText(feedbackOptions.getFormTitle());
112+
113+
btnSend.setText(feedbackOptions.getSubmitButtonLabel());
114+
btnSend.setOnClickListener(
115+
v -> {
116+
final @NotNull Feedback feedback = new Feedback(edtMessage.getText().toString());
117+
feedback.setName(edtName.getText().toString());
118+
feedback.setContactEmail(edtEmail.getText().toString());
119+
120+
SentryId id = Sentry.captureFeedback(feedback);
121+
if (!id.equals(SentryId.EMPTY_ID)) {
122+
Toast.makeText(
123+
getContext(), feedbackOptions.getSuccessMessageText(), Toast.LENGTH_SHORT)
124+
.show();
125+
final @Nullable SentryFeedbackOptions.SentryFeedbackCallback onSubmitSuccess =
126+
feedbackOptions.getOnSubmitSuccess();
127+
if (onSubmitSuccess != null) {
128+
onSubmitSuccess.call(feedback);
129+
}
130+
} else {
131+
final @Nullable SentryFeedbackOptions.SentryFeedbackCallback onSubmitError =
132+
feedbackOptions.getOnSubmitError();
133+
if (onSubmitError != null) {
134+
onSubmitError.call(feedback);
135+
}
136+
}
137+
cancel();
138+
});
139+
140+
btnCancel.setText(feedbackOptions.getCancelButtonLabel());
141+
btnCancel.setOnClickListener(v -> cancel());
142+
143+
final @Nullable Runnable onFormClose = feedbackOptions.getOnFormClose();
144+
if (onFormClose != null) {
145+
setOnDismissListener(dialog -> onFormClose.run());
146+
}
147+
}
148+
149+
@Override
150+
protected void onStart() {
151+
super.onStart();
152+
final @NotNull SentryFeedbackOptions feedbackOptions =
153+
Sentry.getCurrentScopes().getOptions().getFeedbackOptions();
154+
final @Nullable Runnable onFormOpen = feedbackOptions.getOnFormOpen();
155+
if (onFormOpen != null) {
156+
onFormOpen.run();
157+
}
158+
}
159+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<shape xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:shape="rectangle">
4+
5+
<solid android:color="@android:color/transparent" />
6+
<stroke
7+
android:width="1dp"
8+
android:color="#FFAAAAAA" /> <!-- border color -->
9+
<corners android:radius="4dp" />
10+
<padding
11+
android:left="8dp"
12+
android:top="8dp"
13+
android:right="8dp"
14+
android:bottom="8dp" />
15+
</shape>
Binary file not shown.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
tools:ignore="HardcodedText"
7+
android:theme="?android:attr/dialogTheme"
8+
android:padding="24dp">
9+
10+
11+
<TextView
12+
android:id="@+id/sentry_dialog_user_feedback_title"
13+
android:layout_width="match_parent"
14+
android:layout_height="wrap_content"
15+
android:text="Report a Bug"
16+
style="?android:attr/windowTitleStyle"
17+
android:textStyle="bold"
18+
android:layout_marginBottom="16dp"
19+
android:layout_alignParentTop="true"
20+
android:layout_alignEnd="@+id/sentry_dialog_user_feedback_logo" />
21+
22+
<ImageView
23+
android:id="@+id/sentry_dialog_user_feedback_logo"
24+
android:layout_width="32dp"
25+
android:layout_height="32dp"
26+
android:layout_alignTop="@+id/sentry_dialog_user_feedback_title"
27+
android:layout_alignBottom="@+id/sentry_dialog_user_feedback_title"
28+
android:layout_alignParentEnd="true"
29+
android:tint="?android:attr/colorForeground"
30+
android:src="@drawable/sentry_logo_dark_400x352"/>
31+
32+
<TextView
33+
android:id="@+id/sentry_dialog_user_feedback_txt_name"
34+
android:layout_width="match_parent"
35+
android:layout_height="wrap_content"
36+
android:text="Name"
37+
android:layout_marginTop="4dp"
38+
android:textStyle="bold"
39+
android:layout_below="@id/sentry_dialog_user_feedback_title" />
40+
41+
<EditText
42+
android:id="@+id/sentry_dialog_user_feedback_edt_name"
43+
android:layout_width="match_parent"
44+
android:layout_height="wrap_content"
45+
android:hint="Your Name"
46+
android:inputType="textPersonName"
47+
android:background="@drawable/edit_text_border"
48+
android:paddingHorizontal="8dp"
49+
android:layout_below="@id/sentry_dialog_user_feedback_txt_name" />
50+
51+
<TextView
52+
android:id="@+id/sentry_dialog_user_feedback_txt_email"
53+
android:layout_width="match_parent"
54+
android:layout_height="wrap_content"
55+
android:text="Email"
56+
android:layout_marginTop="8dp"
57+
android:textStyle="bold"
58+
android:layout_below="@id/sentry_dialog_user_feedback_edt_name" />
59+
60+
<EditText
61+
android:id="@+id/sentry_dialog_user_feedback_edt_email"
62+
android:layout_width="match_parent"
63+
android:layout_height="wrap_content"
64+
android:hint="your.email@example.org"
65+
android:inputType="textEmailAddress"
66+
android:background="@drawable/edit_text_border"
67+
android:paddingHorizontal="8dp"
68+
android:layout_below="@id/sentry_dialog_user_feedback_txt_email" />
69+
70+
<TextView
71+
android:id="@+id/sentry_dialog_user_feedback_txt_description"
72+
android:layout_width="match_parent"
73+
android:layout_height="wrap_content"
74+
android:text="Description (Required)"
75+
android:layout_marginTop="8dp"
76+
android:textStyle="bold"
77+
android:layout_below="@id/sentry_dialog_user_feedback_edt_email" />
78+
79+
<EditText
80+
android:id="@+id/sentry_dialog_user_feedback_edt_description"
81+
android:layout_width="match_parent"
82+
android:layout_height="wrap_content"
83+
android:lines="6"
84+
android:inputType="textMultiLine"
85+
android:gravity="top|start"
86+
android:hint="What's the bug? What did you expect?"
87+
android:background="@drawable/edit_text_border"
88+
android:paddingHorizontal="8dp"
89+
android:layout_below="@id/sentry_dialog_user_feedback_txt_description" />
90+
91+
<Button
92+
android:id="@+id/sentry_dialog_user_feedback_btn_send"
93+
android:layout_width="match_parent"
94+
android:layout_height="wrap_content"
95+
android:backgroundTint="?android:attr/colorPrimary"
96+
android:textColor="?android:attr/textColorPrimaryInverse"
97+
android:layout_marginTop="32dp"
98+
android:text="Send Bug Report"
99+
android:layout_below="@id/sentry_dialog_user_feedback_edt_description" />
100+
101+
<Button
102+
android:id="@+id/sentry_dialog_user_feedback_btn_cancel"
103+
android:layout_width="match_parent"
104+
android:layout_height="wrap_content"
105+
android:layout_marginTop="8dp"
106+
android:backgroundTint="?android:attr/colorBackground"
107+
android:text="Cancel"
108+
android:layout_below="@id/sentry_dialog_user_feedback_btn_send" />
109+
110+
</RelativeLayout>

sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import io.sentry.ISpan;
99
import io.sentry.MeasurementUnit;
1010
import io.sentry.Sentry;
11+
import io.sentry.android.core.SentryUserFeedbackDialog;
1112
import io.sentry.instrumentation.file.SentryFileOutputStream;
12-
import io.sentry.protocol.Feedback;
1313
import io.sentry.protocol.User;
1414
import io.sentry.samples.android.compose.ComposeActivity;
1515
import io.sentry.samples.android.databinding.ActivityMainBinding;
@@ -69,12 +69,7 @@ protected void onCreate(Bundle savedInstanceState) {
6969

7070
binding.sendUserFeedback.setOnClickListener(
7171
view -> {
72-
Feedback feedback =
73-
new Feedback("It broke on Android. I don't know why, but this happens.");
74-
feedback.setContactEmail("john@me.com");
75-
feedback.setName("John Me");
76-
77-
Sentry.captureFeedback(feedback);
72+
new SentryUserFeedbackDialog(this).show();
7873
});
7974

8075
binding.addAttachment.setOnClickListener(

0 commit comments

Comments
 (0)