diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/crash/CrashReportSubmit.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/crash/CrashReportSubmit.kt
index 1477beb..80b7259 100644
--- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/crash/CrashReportSubmit.kt
+++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/crash/CrashReportSubmit.kt
@@ -9,25 +9,44 @@ import androidx.core.net.toUri
import de.jeanlucmakiola.calendula.R
/**
- * Hand the captured crash report off to the user's chosen channel: the report
- * is copied to the clipboard (the reliable path for a full stack trace) and the
- * project's Gitea "new issue" page is opened with the body prefilled. Nothing is
- * sent automatically — the app has no network access; the user reviews and
- * submits the issue themselves.
+ * Hand the captured crash report off to the user's email app: the report is
+ * copied to the clipboard (a safety net) and a pre-addressed email is composed
+ * with the report as the body. Nothing is sent automatically — the app has no
+ * network access; the user reviews and sends the mail themselves.
+ *
+ * Email is used rather than the web issue tracker because filing a Gitea issue
+ * requires an account on the instance, which anonymous reporters don't have —
+ * whereas anyone can send an email from the app they already use.
*/
fun submitCrashReport(context: Context, report: String) {
copyReportToClipboard(context, report)
- val opened = runCatching {
- context.startActivity(Intent(Intent.ACTION_VIEW, buildIssueUri(context, report)))
- }.isSuccess
+ val subject = context.getString(R.string.crash_report_issue_title)
+ val body = context.getString(R.string.crash_report_body_template, "```\n$report\n```")
+ val opened = sendReportEmail(context, subject, body)
val message = if (opened) R.string.crash_report_copied else R.string.crash_report_open_failed
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}
-/** Open the issue tracker's template chooser for a manual (non-crash) report. */
-fun openIssueTracker(context: Context) {
- val uri = context.getString(R.string.report_issue_choose_url).toUri()
- runCatching { context.startActivity(Intent(Intent.ACTION_VIEW, uri)) }
+/** Compose a fresh problem-report email for a manual (non-crash) report. */
+fun reportIssueByEmail(context: Context) {
+ val subject = context.getString(R.string.report_issue_subject)
+ val body = context.getString(R.string.report_issue_body_template)
+ sendReportEmail(context, subject, body)
+}
+
+/**
+ * Open the user's email app with a pre-addressed, prefilled message. The
+ * `mailto:` data URI guarantees only email apps resolve the intent (a plain
+ * ACTION_SEND would also offer messengers). The body rides in an extra rather
+ * than the URI, so there is no URL-length ceiling on the report.
+ */
+private fun sendReportEmail(context: Context, subject: String, body: String): Boolean {
+ val email = context.getString(R.string.report_issue_email)
+ val intent = Intent(Intent.ACTION_SENDTO, "mailto:$email".toUri()).apply {
+ putExtra(Intent.EXTRA_SUBJECT, subject)
+ putExtra(Intent.EXTRA_TEXT, body)
+ }
+ return runCatching { context.startActivity(intent) }.isSuccess
}
private fun copyReportToClipboard(context: Context, report: String) {
@@ -35,27 +54,3 @@ private fun copyReportToClipboard(context: Context, report: String) {
val label = context.getString(R.string.crash_report_clip_label)
clipboard.setPrimaryClip(ClipData.newPlainText(label, report))
}
-
-/**
- * The Gitea `issues/new` URL with `title` and `body` prefilled. A full report
- * can blow past URL-length limits, so an over-long one is left out of the link
- * (with a "paste from clipboard" placeholder) — the clipboard copy is the
- * source of truth in that case.
- */
-private fun buildIssueUri(context: Context, report: String) =
- context.getString(R.string.report_issue_url).toUri().buildUpon()
- .appendQueryParameter("title", context.getString(R.string.crash_report_issue_title))
- .appendQueryParameter("body", buildIssueBody(context, report))
- .build()
-
-private fun buildIssueBody(context: Context, report: String): String {
- val block = if (report.length > MAX_URL_REPORT_CHARS) {
- context.getString(R.string.crash_report_body_paste)
- } else {
- "```\n$report\n```"
- }
- return context.getString(R.string.crash_report_body_template, block)
-}
-
-/** Keep the prefilled body comfortably under common URL-length ceilings. */
-private const val MAX_URL_REPORT_CHARS = 6_000
diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt
index 4d1a06f..f7c6cc6 100644
--- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt
+++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt
@@ -80,7 +80,7 @@ import de.jeanlucmakiola.calendula.data.prefs.ThemeMode
import de.jeanlucmakiola.calendula.data.prefs.WeekStartPref
import de.jeanlucmakiola.calendula.domain.EventFormField
import de.jeanlucmakiola.calendula.ui.crash.CrashReportDialog
-import de.jeanlucmakiola.calendula.ui.crash.openIssueTracker
+import de.jeanlucmakiola.calendula.ui.crash.reportIssueByEmail
import de.jeanlucmakiola.calendula.ui.crash.submitCrashReport
import de.jeanlucmakiola.calendula.ui.common.CollapsingScaffold
import de.jeanlucmakiola.calendula.ui.common.GroupedRow
@@ -209,10 +209,10 @@ private fun SettingsHub(
}
/**
- * Opens the project's issue tracker to report a problem. If a crash report was
- * captured (and not yet sent), it surfaces that report first via the same
- * dialog the next-launch prompt uses; otherwise it opens the issue template
- * chooser. No data leaves the device until the user submits the issue.
+ * Composes a problem-report email. If a crash report was captured (and not yet
+ * sent), it surfaces that report first via the same dialog the next-launch
+ * prompt uses; otherwise it opens a blank report email. No data leaves the
+ * device until the user sends the mail themselves.
*/
@Composable
private fun ReportProblemRow(position: Position) {
@@ -226,7 +226,7 @@ private fun ReportProblemRow(position: Position) {
leading = { CategoryIcon(Icons.Default.BugReport, ChipAccent.Neutral) },
onClick = {
val pending = CrashReporter.pendingReport(context)
- if (pending != null) report = pending else openIssueTracker(context)
+ if (pending != null) report = pending else reportIssueByEmail(context)
},
)
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 4ec4c11..3fdeba9 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -283,7 +283,7 @@
Version %1$s
Calendula-App-Symbol
Problem melden
- Absturzbericht senden oder Issue-Tracker öffnen
+ Absturzbericht oder Feedback per E-Mail senden
Kalender
@@ -347,8 +347,9 @@
Nicht jetzt
Absturzbericht
Calendula-Absturzbericht
- Bericht in die Zwischenablage kopiert
- Der Issue-Tracker konnte nicht geöffnet werden. Der Bericht ist in deiner Zwischenablage.
+ Bericht kopiert — E-Mail-App wird geöffnet
+ Keine E-Mail-App gefunden. Der Bericht ist in deiner Zwischenablage.
Danke, dass du einen Absturz in Calendula meldest. Bitte ergänze, was du gerade getan hast, und sende dann ab.\n\n### Was ist passiert\n\n\n### Absturzbericht\n%1$s\n
- _(Der Bericht war zu lang für diesen Link — füge ihn aus deiner Zwischenablage hier ein.)_
+ Calendula — Problemmeldung
+ Bitte beschreibe das aufgetretene Problem und was du gerade getan hast.\n\n
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7801091..0be0675 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -280,7 +280,7 @@
Version %1$s
Calendula app icon
Report a problem
- Send a crash report or open the issue tracker
+ Send a crash report or feedback by email
Calendars
@@ -351,10 +351,10 @@
Not now
Crash report
Calendula crash report
- Report copied to your clipboard
- Couldn\'t open the issue tracker. The report is on your clipboard.
- Thanks for reporting a crash in Calendula. Please add anything you remember about what you were doing, then submit.\n\n### What happened\n\n\n### Crash report\n%1$s\n
- _(The report was too long for this link — paste it from your clipboard here.)_
- https://gitea.jeanlucmakiola.de/makiolaj/calendula/issues/new
- https://gitea.jeanlucmakiola.de/makiolaj/calendula/issues/new/choose
+ Report copied — opening your email app
+ No email app found. The report is on your clipboard.
+ Thanks for reporting a crash in Calendula. Please add anything you remember about what you were doing, then send.\n\n### What happened\n\n\n### Crash report\n%1$s\n
+ mail@jeanlucmakiola.de
+ Calendula — problem report
+ Please describe the problem you ran into, and what you were doing when it happened.\n\n