Skip to content

Commit 9f19891

Browse files
authored
Merge 2bf99b5 into 212ffbf
2 parents 212ffbf + 2bf99b5 commit 9f19891

File tree

8 files changed

+929
-0
lines changed

8 files changed

+929
-0
lines changed

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

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

400+
public final class io/sentry/android/core/SentryUserFeedbackDialog : android/app/AlertDialog {
401+
public fun <init> (Landroid/content/Context;)V
402+
public fun <init> (Landroid/content/Context;I)V
403+
public fun <init> (Landroid/content/Context;ZLandroid/content/DialogInterface$OnCancelListener;)V
404+
public fun setCancelable (Z)V
405+
}
406+
400407
public class io/sentry/android/core/SpanFrameMetricsCollector : io/sentry/IPerformanceContinuousCollector, io/sentry/android/core/internal/util/SentryFrameMetricsCollector$FrameMetricsCollectorListener {
401408
protected final field lock Lio/sentry/util/AutoClosableReentrantLock;
402409
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/internal/util/SentryFrameMetricsCollector;)V
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package io.sentry.android.core;
2+
3+
import android.app.AlertDialog;
4+
import android.content.Context;
5+
import android.content.res.ColorStateList;
6+
import android.graphics.Color;
7+
import android.os.Bundle;
8+
import android.view.View;
9+
import android.widget.Button;
10+
import android.widget.EditText;
11+
import android.widget.ImageView;
12+
import android.widget.TextView;
13+
import android.widget.Toast;
14+
import io.sentry.Sentry;
15+
import io.sentry.SentryFeedbackOptions;
16+
import io.sentry.protocol.Feedback;
17+
import io.sentry.protocol.SentryId;
18+
import io.sentry.protocol.User;
19+
import org.jetbrains.annotations.NotNull;
20+
import org.jetbrains.annotations.Nullable;
21+
22+
public final class SentryUserFeedbackDialog extends AlertDialog {
23+
24+
private boolean isCancelable = false;
25+
26+
public SentryUserFeedbackDialog(final @NotNull Context context) {
27+
super(context);
28+
isCancelable = false;
29+
}
30+
31+
public SentryUserFeedbackDialog(
32+
final @NotNull Context context,
33+
final boolean cancelable,
34+
@Nullable final OnCancelListener cancelListener) {
35+
super(context, cancelable, cancelListener);
36+
isCancelable = cancelable;
37+
}
38+
39+
public SentryUserFeedbackDialog(final @NotNull Context context, final int themeResId) {
40+
super(context, themeResId);
41+
isCancelable = false;
42+
}
43+
44+
@Override
45+
public void setCancelable(boolean cancelable) {
46+
super.setCancelable(cancelable);
47+
isCancelable = cancelable;
48+
}
49+
50+
@Override
51+
protected void onCreate(Bundle savedInstanceState) {
52+
super.onCreate(savedInstanceState);
53+
setContentView(R.layout.sentry_dialog_user_feedback);
54+
setCancelable(isCancelable);
55+
56+
final @NotNull SentryFeedbackOptions feedbackOptions =
57+
Sentry.getCurrentScopes().getOptions().getFeedbackOptions();
58+
final @NotNull TextView lblTitle = findViewById(R.id.sentry_dialog_user_feedback_title);
59+
final @NotNull ImageView imgLogo = findViewById(R.id.sentry_dialog_user_feedback_logo);
60+
final @NotNull TextView lblName = findViewById(R.id.sentry_dialog_user_feedback_txt_name);
61+
final @NotNull EditText edtName = findViewById(R.id.sentry_dialog_user_feedback_edt_name);
62+
final @NotNull TextView lblEmail = findViewById(R.id.sentry_dialog_user_feedback_txt_email);
63+
final @NotNull EditText edtEmail = findViewById(R.id.sentry_dialog_user_feedback_edt_email);
64+
final @NotNull TextView lblMessage =
65+
findViewById(R.id.sentry_dialog_user_feedback_txt_description);
66+
final @NotNull EditText edtMessage =
67+
findViewById(R.id.sentry_dialog_user_feedback_edt_description);
68+
final @NotNull Button btnSend = findViewById(R.id.sentry_dialog_user_feedback_btn_send);
69+
final @NotNull Button btnCancel = findViewById(R.id.sentry_dialog_user_feedback_btn_cancel);
70+
71+
if (feedbackOptions.isShowBranding()) {
72+
imgLogo.setVisibility(View.VISIBLE);
73+
} else {
74+
imgLogo.setVisibility(View.GONE);
75+
}
76+
imgLogo.setImageTintList(ColorStateList.valueOf(lblTitle.getTextColors().getDefaultColor()));
77+
78+
if (!feedbackOptions.isShowName() && !feedbackOptions.isNameRequired()) {
79+
lblName.setVisibility(View.GONE);
80+
edtName.setVisibility(View.GONE);
81+
} else {
82+
lblName.setVisibility(View.VISIBLE);
83+
edtName.setVisibility(View.VISIBLE);
84+
lblName.setText(feedbackOptions.getNameLabel());
85+
edtName.setHint(feedbackOptions.getNamePlaceholder());
86+
if (feedbackOptions.isNameRequired()) {
87+
lblName.append(feedbackOptions.getIsRequiredLabel());
88+
}
89+
}
90+
91+
if (!feedbackOptions.isShowEmail() && !feedbackOptions.isEmailRequired()) {
92+
lblEmail.setVisibility(View.GONE);
93+
edtEmail.setVisibility(View.GONE);
94+
} else {
95+
lblEmail.setVisibility(View.VISIBLE);
96+
edtEmail.setVisibility(View.VISIBLE);
97+
lblEmail.setText(feedbackOptions.getEmailLabel());
98+
edtEmail.setHint(feedbackOptions.getEmailPlaceholder());
99+
if (feedbackOptions.isEmailRequired()) {
100+
lblEmail.append(feedbackOptions.getIsRequiredLabel());
101+
}
102+
}
103+
104+
if (feedbackOptions.isUseSentryUser()) {
105+
final @Nullable User user = Sentry.getCurrentScopes().getScope().getUser();
106+
if (user != null) {
107+
edtName.setText(user.getName());
108+
edtEmail.setText(user.getEmail());
109+
}
110+
}
111+
112+
lblMessage.setText(feedbackOptions.getMessageLabel());
113+
edtMessage.setHint(feedbackOptions.getMessagePlaceholder());
114+
lblTitle.setText(feedbackOptions.getFormTitle());
115+
116+
btnSend.setBackgroundColor(Color.parseColor(feedbackOptions.getSubmitBackgroundHex()));
117+
btnSend.setTextColor(Color.parseColor(feedbackOptions.getSubmitForegroundHex()));
118+
btnSend.setText(feedbackOptions.getSubmitButtonLabel());
119+
btnSend.setOnClickListener(
120+
v -> {
121+
final @NotNull Feedback feedback = new Feedback(edtMessage.getText().toString());
122+
feedback.setName(edtName.getText().toString());
123+
feedback.setContactEmail(edtEmail.getText().toString());
124+
125+
SentryId id = Sentry.captureFeedback(feedback);
126+
if (!id.equals(SentryId.EMPTY_ID)) {
127+
Toast.makeText(
128+
getContext(), feedbackOptions.getSuccessMessageText(), Toast.LENGTH_SHORT)
129+
.show();
130+
final @Nullable SentryFeedbackOptions.SentryFeedbackCallback onSubmitSuccess =
131+
feedbackOptions.getOnSubmitSuccess();
132+
if (onSubmitSuccess != null) {
133+
onSubmitSuccess.call(feedback);
134+
}
135+
} else {
136+
final @Nullable SentryFeedbackOptions.SentryFeedbackCallback onSubmitError =
137+
feedbackOptions.getOnSubmitError();
138+
if (onSubmitError != null) {
139+
onSubmitError.call(feedback);
140+
}
141+
}
142+
cancel();
143+
});
144+
145+
btnCancel.setText(feedbackOptions.getCancelButtonLabel());
146+
btnCancel.setOnClickListener(v -> cancel());
147+
148+
final @Nullable Runnable onFormClose = feedbackOptions.getOnFormClose();
149+
if (onFormClose != null) {
150+
setOnDismissListener(dialog -> onFormClose.run());
151+
}
152+
}
153+
154+
@Override
155+
protected void onStart() {
156+
super.onStart();
157+
final @NotNull SentryFeedbackOptions feedbackOptions =
158+
Sentry.getCurrentScopes().getOptions().getFeedbackOptions();
159+
final @Nullable Runnable onFormOpen = feedbackOptions.getOnFormOpen();
160+
if (onFormOpen != null) {
161+
onFormOpen.run();
162+
}
163+
}
164+
}
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>
2.79 KB
Loading
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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:padding="24dp">
8+
9+
10+
<TextView
11+
android:id="@+id/sentry_dialog_user_feedback_title"
12+
android:layout_width="match_parent"
13+
android:layout_height="wrap_content"
14+
android:text="Report a Bug"
15+
style="@android:style/TextAppearance.DialogWindowTitle"
16+
android:textStyle="bold"
17+
android:layout_marginBottom="16dp"
18+
android:layout_alignParentTop="true"
19+
android:layout_alignEnd="@+id/sentry_dialog_user_feedback_logo" />
20+
21+
<ImageView
22+
android:id="@+id/sentry_dialog_user_feedback_logo"
23+
android:layout_width="32dp"
24+
android:layout_height="32dp"
25+
android:layout_alignTop="@+id/sentry_dialog_user_feedback_title"
26+
android:layout_alignBottom="@+id/sentry_dialog_user_feedback_title"
27+
android:layout_alignParentEnd="true"
28+
android:src="@drawable/sentry_logo_dark_400x352"/>
29+
30+
<TextView
31+
android:id="@+id/sentry_dialog_user_feedback_txt_name"
32+
android:layout_width="match_parent"
33+
android:layout_height="wrap_content"
34+
android:text="Name"
35+
android:layout_marginTop="4dp"
36+
style="@android:style/TextAppearance.Widget.TextView"
37+
android:layout_below="@id/sentry_dialog_user_feedback_title" />
38+
39+
<EditText
40+
android:id="@+id/sentry_dialog_user_feedback_edt_name"
41+
android:layout_width="match_parent"
42+
android:layout_height="wrap_content"
43+
android:hint="Your Name"
44+
android:inputType="textPersonName"
45+
style="@android:style/TextAppearance.Widget.EditText"
46+
android:background="@drawable/edit_text_border"
47+
android:paddingHorizontal="8dp"
48+
android:layout_below="@id/sentry_dialog_user_feedback_txt_name" />
49+
50+
<TextView
51+
android:id="@+id/sentry_dialog_user_feedback_txt_email"
52+
android:layout_width="match_parent"
53+
android:layout_height="wrap_content"
54+
android:text="Email"
55+
android:layout_marginTop="8dp"
56+
style="@android:style/TextAppearance.Widget.TextView"
57+
android:layout_below="@id/sentry_dialog_user_feedback_edt_name" />
58+
59+
<EditText
60+
android:id="@+id/sentry_dialog_user_feedback_edt_email"
61+
android:layout_width="match_parent"
62+
android:layout_height="wrap_content"
63+
android:hint="your.email@example.org"
64+
android:inputType="textEmailAddress"
65+
style="@android:style/TextAppearance.Widget.EditText"
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+
style="@android:style/TextAppearance.Widget.TextView"
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+
style="@android:style/TextAppearance.Widget.EditText"
88+
android:background="@drawable/edit_text_border"
89+
android:paddingHorizontal="8dp"
90+
android:layout_below="@id/sentry_dialog_user_feedback_txt_description" />
91+
92+
<Button
93+
android:id="@+id/sentry_dialog_user_feedback_btn_send"
94+
android:layout_width="match_parent"
95+
android:layout_height="wrap_content"
96+
android:backgroundTint="#584AC0"
97+
android:textColor="@android:color/white"
98+
android:layout_marginTop="32dp"
99+
android:text="Send Bug Report"
100+
android:layout_below="@id/sentry_dialog_user_feedback_edt_description" />
101+
102+
<Button
103+
android:id="@+id/sentry_dialog_user_feedback_btn_cancel"
104+
android:layout_width="match_parent"
105+
android:layout_height="wrap_content"
106+
android:backgroundTint="#FAF9FD"
107+
android:layout_marginTop="8dp"
108+
android:text="Cancel"
109+
android:layout_below="@id/sentry_dialog_user_feedback_btn_send" />
110+
111+
</RelativeLayout>

sentry/api/sentry.api

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2908,6 +2908,63 @@ public final class io/sentry/SentryExecutorService : io/sentry/ISentryExecutorSe
29082908
public fun submit (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
29092909
}
29102910

2911+
public final class io/sentry/SentryFeedbackOptions {
2912+
public fun <init> ()V
2913+
public fun getCancelButtonLabel ()Ljava/lang/String;
2914+
public fun getConfirmButtonLabel ()Ljava/lang/String;
2915+
public fun getEmailLabel ()Ljava/lang/String;
2916+
public fun getEmailPlaceholder ()Ljava/lang/String;
2917+
public fun getFormTitle ()Ljava/lang/String;
2918+
public fun getIsRequiredLabel ()Ljava/lang/String;
2919+
public fun getMessageLabel ()Ljava/lang/String;
2920+
public fun getMessagePlaceholder ()Ljava/lang/String;
2921+
public fun getNameLabel ()Ljava/lang/String;
2922+
public fun getNamePlaceholder ()Ljava/lang/String;
2923+
public fun getOnFormClose ()Ljava/lang/Runnable;
2924+
public fun getOnFormOpen ()Ljava/lang/Runnable;
2925+
public fun getOnSubmitError ()Lio/sentry/SentryFeedbackOptions$SentryFeedbackCallback;
2926+
public fun getOnSubmitSuccess ()Lio/sentry/SentryFeedbackOptions$SentryFeedbackCallback;
2927+
public fun getSubmitBackgroundHex ()Ljava/lang/String;
2928+
public fun getSubmitButtonLabel ()Ljava/lang/String;
2929+
public fun getSubmitForegroundHex ()Ljava/lang/String;
2930+
public fun getSuccessMessageText ()Ljava/lang/String;
2931+
public fun isEmailRequired ()Z
2932+
public fun isNameRequired ()Z
2933+
public fun isShowBranding ()Z
2934+
public fun isShowEmail ()Z
2935+
public fun isShowName ()Z
2936+
public fun isUseSentryUser ()Z
2937+
public fun setCancelButtonLabel (Ljava/lang/String;)V
2938+
public fun setConfirmButtonLabel (Ljava/lang/String;)V
2939+
public fun setEmailLabel (Ljava/lang/String;)V
2940+
public fun setEmailPlaceholder (Ljava/lang/String;)V
2941+
public fun setEmailRequired (Z)V
2942+
public fun setFormTitle (Ljava/lang/String;)V
2943+
public fun setIsRequiredLabel (Ljava/lang/String;)V
2944+
public fun setMessageLabel (Ljava/lang/String;)V
2945+
public fun setMessagePlaceholder (Ljava/lang/String;)V
2946+
public fun setNameLabel (Ljava/lang/String;)V
2947+
public fun setNamePlaceholder (Ljava/lang/String;)V
2948+
public fun setNameRequired (Z)V
2949+
public fun setOnFormClose (Ljava/lang/Runnable;)V
2950+
public fun setOnFormOpen (Ljava/lang/Runnable;)V
2951+
public fun setOnSubmitError (Lio/sentry/SentryFeedbackOptions$SentryFeedbackCallback;)V
2952+
public fun setOnSubmitSuccess (Lio/sentry/SentryFeedbackOptions$SentryFeedbackCallback;)V
2953+
public fun setShowBranding (Z)V
2954+
public fun setShowEmail (Z)V
2955+
public fun setShowName (Z)V
2956+
public fun setSubmitBackgroundHex (Ljava/lang/String;)V
2957+
public fun setSubmitButtonLabel (Ljava/lang/String;)V
2958+
public fun setSubmitForegroundHex (Ljava/lang/String;)V
2959+
public fun setSuccessMessageText (Ljava/lang/String;)V
2960+
public fun setUseSentryUser (Z)V
2961+
public fun toString ()Ljava/lang/String;
2962+
}
2963+
2964+
public abstract interface class io/sentry/SentryFeedbackOptions$SentryFeedbackCallback {
2965+
public abstract fun call (Lio/sentry/protocol/Feedback;)V
2966+
}
2967+
29112968
public final class io/sentry/SentryInstantDate : io/sentry/SentryDate {
29122969
public fun <init> ()V
29132970
public fun <init> (Ljava/time/Instant;)V
@@ -3095,6 +3152,7 @@ public class io/sentry/SentryOptions {
30953152
public fun getExecutorService ()Lio/sentry/ISentryExecutorService;
30963153
public fun getExperimental ()Lio/sentry/ExperimentalOptions;
30973154
public fun getFatalLogger ()Lio/sentry/ILogger;
3155+
public fun getFeedbackOptions ()Lio/sentry/SentryFeedbackOptions;
30983156
public fun getFlushTimeoutMillis ()J
30993157
public fun getFullyDisplayedReporter ()Lio/sentry/FullyDisplayedReporter;
31003158
public fun getGestureTargetLocators ()Ljava/util/List;
@@ -3237,6 +3295,7 @@ public class io/sentry/SentryOptions {
32373295
public fun setEnvironment (Ljava/lang/String;)V
32383296
public fun setExecutorService (Lio/sentry/ISentryExecutorService;)V
32393297
public fun setFatalLogger (Lio/sentry/ILogger;)V
3298+
public fun setFeedbackOptions (Lio/sentry/SentryFeedbackOptions;)V
32403299
public fun setFlushTimeoutMillis (J)V
32413300
public fun setForceInit (Z)V
32423301
public fun setFullyDisplayedReporter (Lio/sentry/FullyDisplayedReporter;)V

0 commit comments

Comments
 (0)