diff --git a/app/build.gradle b/app/build.gradle
index c3051a005..1758e3e60 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -187,7 +187,7 @@ dependencies {
// https://developer.android.com/jetpack/androidx/releases/compose-material
implementation "androidx.compose.material:material"
implementation "androidx.compose.material:material-icons-extended"
- debugImplementation "androidx.compose.ui:ui-tooling"
+ implementation "androidx.compose.ui:ui-tooling"
implementation "androidx.compose.ui:ui-tooling-preview"
androidTestImplementation "androidx.compose.ui:ui-test-junit4"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d5ddc99ab..5d6ebf6d1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
-
+
@@ -34,6 +34,11 @@
+
+
+ v.setPadding(0, 0, 0, 0)
+ insets
+ }
+ val errorMessage: String = intent.getStringExtra(ERROR_REPORT_KEY).toString()
+
+ setContent {
+ SettingsProvider {
+ AppTheme(useDarkTheme = LocalDarkTheme.current.isDarkTheme()) {
+ val clipboardManager = LocalClipboardManager.current
+ val appVersion = getCurrentVersion().toString()
+ val deviceModel = "${Build.MANUFACTURER} ${Build.MODEL}"
+ val androidVersion =
+ "Android ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})"
+
+ val errorReport =
+ "Version: $appVersion\nDevice: $deviceModel\nSystem: $androidVersion\n\nStack trace: \n\n$errorMessage"
+
+ CrashReportPage(text = errorReport) {
+ clipboardManager.setText(AnnotatedString(errorReport))
+ }
+ }
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (isFinishing) finishAffinity()
+ }
+
+ companion object {
+ const val ERROR_REPORT_KEY = "error_stack_trace"
+ }
+
+}
+
+
+@OptIn(ExperimentalTextApi::class)
+@Composable
+@Preview(apiLevel = 33)
+fun CrashReportPage(
+ text: String = "Version: 0.9.11\n" +
+ "Model: Google Pixel 6 Pro\n" + "System: Android 13 (API 33)\n\n" +
+ "Stack trace: \n" +
+ "\nFATAL EXCEPTION: main\n" +
+ "Process: me.ash.reader, PID: 29184\n" +
+ "java.lang.IllegalArgumentException: performMeasureAndLayout called during measure layout\n" +
+ "\tat androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:133)\n" +
+ "\tat androidx.compose.ui.platform.AndroidComposeView.measureAndLayout(AndroidComposeView.android.kt:34)\n" +
+ "\tat androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:15)\n" +
+ "\tat android.view.View.draw(View.java:24193)\n" +
+ "\tat android.view.View.updateDisplayListIfDirty(View.java:23056)\n" +
+ "\tat android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4550)\n",
+ onClick: () -> Unit = {}
+) {
+ val context = LocalContext.current
+ val openLinkPreference = LocalOpenLink.current
+ val openLinkSpecificBrowserPreference = LocalOpenLinkSpecificBrowser.current
+
+ Scaffold(
+ modifier = Modifier.fillMaxSize(),
+ containerColor = MaterialTheme.colorScheme.surfaceContainer,
+ bottomBar = {}) {
+ Column(
+ modifier = Modifier
+ .padding(it)
+ .verticalScroll(rememberScrollState())
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.BugReport,
+ contentDescription = null,
+ modifier = Modifier
+ .padding(top = 24.dp)
+ .padding(horizontal = 16.dp)
+ .size(64.dp),
+ tint = MaterialTheme.colorScheme.surfaceTint
+ )
+
+ Text(
+ text = stringResource(R.string.unexpected_error_title),
+ style = MaterialTheme.typography.headlineLarge,
+ modifier = Modifier
+ .padding(start = 16.dp, end = 16.dp, top = 12.dp)
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+
+
+ val hyperLinkText = stringResource(R.string.submit_bug_report)
+ val msg = stringResource(R.string.unexpected_error_msg).format(hyperLinkText)
+
+ val annotatedString = buildAnnotatedString {
+ append(msg.format(hyperLinkText))
+ val startIndex = msg.indexOf(hyperLinkText)
+ val endIndex = startIndex + hyperLinkText.length
+ addUrlAnnotation(
+ UrlAnnotation("https://github.com/Ashinch/ReadYou/issues/new?assignees=&labels=bug&projects=&template=bug_report.md&title="),
+ start = startIndex,
+ end = endIndex
+ )
+ addStyle(
+ SpanStyle(
+ color = MaterialTheme.colorScheme.primary,
+ textDecoration = TextDecoration.Underline,
+ ), start = startIndex,
+ end = endIndex
+ )
+ }
+
+ ClickableText(
+ text = annotatedString,
+ style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onSurface),
+ modifier = Modifier.padding(horizontal = 16.dp),
+ onClick = { index ->
+ annotatedString.getUrlAnnotations(index, index).firstOrNull()?.let { range ->
+ context.openURL(
+ url = range.item.url,
+ openLink = openLinkPreference,
+ specificBrowser = openLinkSpecificBrowserPreference
+ )
+ }
+ }
+ )
+
+ Row(
+ modifier = Modifier
+ .padding(vertical = 16.dp, horizontal = 16.dp)
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.End
+ ) {
+ Spacer(modifier = Modifier.width(12.dp))
+ Button(
+ onClick = onClick,
+ modifier = Modifier
+ .padding(),
+ contentPadding = ButtonDefaults.ButtonWithIconContentPadding
+ ) {
+ Icon(
+ imageVector = Icons.Rounded.ContentCopy,
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(text = stringResource(R.string.copy_error_report))
+ }
+ }
+
+
+ Surface(
+ shape = MaterialTheme.shapes.large,
+ color = MaterialTheme.colorScheme.surface,
+ modifier = Modifier.padding(12.dp)
+ ) {
+ Column {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.bodyMedium.copy(
+ fontFamily = FontFamily.Monospace
+ ),
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier
+ .padding(16.dp)
+ .fillMaxWidth()
+ )
+ }
+
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 472c9b750..84a71d19c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -408,4 +408,8 @@
Grey out articles
All read
Read, excluding starred
+ Oops! Something went wrong…
+ Copy error report
+ submit a bug report on GitHub
+ The app encountered an unexpected error and had to close.\n\nTo help us identify and fix this issue quickly, you can %1$s with the error stack trace below.