Skip to content

Commit e45f4d7

Browse files
committed
add error activity
1 parent 445128d commit e45f4d7

3 files changed

Lines changed: 110 additions & 97 deletions

File tree

app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt

Lines changed: 52 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,29 @@ import android.content.Intent
1010
import android.os.Build
1111
import android.os.Bundle
1212
import android.util.Log
13-
import android.view.Menu
14-
import android.view.MenuItem
1513
import androidx.appcompat.app.AlertDialog
16-
import androidx.appcompat.app.AppCompatActivity
1714
import androidx.core.content.IntentCompat
1815
import androidx.core.net.toUri
1916
import com.grack.nanojson.JsonWriter
17+
import dagger.hilt.android.AndroidEntryPoint
2018
import java.time.ZonedDateTime
2119
import java.time.format.DateTimeFormatter
2220
import org.schabi.newpipe.BuildConfig
2321
import org.schabi.newpipe.R
24-
import org.schabi.newpipe.databinding.ActivityErrorBinding
22+
import org.schabi.newpipe.ui.BaseActivity
23+
import org.schabi.newpipe.ui.screens.ErrorReportScreen
2524
import org.schabi.newpipe.util.Localization
26-
import org.schabi.newpipe.util.ThemeHelper
2725
import org.schabi.newpipe.util.external_communication.ShareUtils
28-
import org.schabi.newpipe.util.text.setTextWithLinks
2926

3027
/**
3128
* This activity is used to show error details and allow reporting them in various ways.
3229
* Use [ErrorUtil.openActivity] to correctly open this activity.
3330
*/
34-
class ErrorActivity : AppCompatActivity() {
31+
@AndroidEntryPoint
32+
class ErrorActivity : BaseActivity() {
3533
private lateinit var errorInfo: ErrorInfo
3634
private lateinit var currentTimeStamp: String
3735

38-
private lateinit var binding: ActivityErrorBinding
39-
4036
private val contentCountryString: String
4137
get() = Localization.getPreferredContentCountry(this).countryCode
4238

@@ -49,11 +45,7 @@ class ErrorActivity : AppCompatActivity() {
4945
private val osString: String
5046
get() {
5147
val name = System.getProperty("os.name")!!
52-
val osBase = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
53-
Build.VERSION.BASE_OS.ifEmpty { "Android" }
54-
} else {
55-
"Android"
56-
}
48+
val osBase = Build.VERSION.BASE_OS.ifEmpty { "Android" }
5749
return "$name $osBase ${Build.VERSION.RELEASE} - ${Build.VERSION.SDK_INT}"
5850
}
5951

@@ -67,73 +59,53 @@ class ErrorActivity : AppCompatActivity() {
6759
override fun onCreate(savedInstanceState: Bundle?) {
6860
super.onCreate(savedInstanceState)
6961

70-
ThemeHelper.setDayNightMode(this)
71-
ThemeHelper.setTheme(this)
72-
73-
binding = ActivityErrorBinding.inflate(layoutInflater)
74-
setContentView(binding.getRoot())
75-
76-
setSupportActionBar(binding.toolbarLayout.toolbar)
77-
supportActionBar?.apply {
78-
setDisplayHomeAsUpEnabled(true)
79-
setTitle(R.string.error_report_title)
80-
setDisplayShowTitleEnabled(true)
81-
}
82-
8362
errorInfo = IntentCompat.getParcelableExtra(intent, ERROR_INFO, ErrorInfo::class.java)!!
8463

85-
// important add guru meditation
86-
addGuruMeditation()
8764
// print current time, as zoned ISO8601 timestamp
8865
currentTimeStamp = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
8966

90-
binding.errorReportEmailButton.setOnClickListener { _ ->
91-
openPrivacyPolicyDialog(this, "EMAIL")
92-
}
93-
94-
binding.errorReportCopyButton.setOnClickListener { _ ->
95-
ShareUtils.copyToClipboard(this, buildMarkdown())
96-
}
97-
98-
binding.errorReportGitHubButton.setOnClickListener { _ ->
99-
openPrivacyPolicyDialog(this, "GITHUB")
100-
}
101-
102-
// normal bugreport
103-
buildInfo(errorInfo)
104-
binding.errorMessageView.setTextWithLinks(errorInfo.getMessage(this))
105-
binding.errorView.text = formErrorText(errorInfo.stackTraces)
106-
10767
// print stack trace once again for debugging:
10868
errorInfo.stackTraces.forEach { Log.e(TAG, it) }
109-
}
110-
111-
override fun onCreateOptionsMenu(menu: Menu): Boolean {
112-
menuInflater.inflate(R.menu.error_menu, menu)
113-
return true
114-
}
115-
116-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
117-
return when (item.itemId) {
118-
android.R.id.home -> {
119-
onBackPressed()
120-
true
121-
}
122-
123-
R.id.menu_item_share_error -> {
124-
ShareUtils.shareText(
125-
applicationContext,
126-
getString(R.string.error_report_title),
127-
buildJson()
128-
)
129-
true
130-
}
13169

132-
else -> false
70+
val sorryMessage = getString(R.string.sorry_string) + "\n" + getString(R.string.guru_meditation)
71+
val errorMessage = errorInfo.getMessage(this).toString()
72+
val infoLabels = getString(R.string.info_labels)
73+
val infoValues = buildInfoString()
74+
val errorDetails = formErrorText(errorInfo.stackTraces)
75+
76+
composeSetContent {
77+
ErrorReportScreen(
78+
sorryMessage = sorryMessage,
79+
errorMessage = errorMessage,
80+
infoLabels = infoLabels,
81+
infoValues = infoValues,
82+
errorDetails = errorDetails,
83+
onBackClick = { finish() },
84+
onReportViaEmail = { comment ->
85+
openPrivacyPolicyDialog(this, "EMAIL", comment)
86+
},
87+
onCopyForGitHub = { comment ->
88+
ShareUtils.copyToClipboard(this, buildMarkdown(comment))
89+
},
90+
onReportOnGitHub = {
91+
openPrivacyPolicyDialog(this, "GITHUB")
92+
},
93+
onShareError = { comment ->
94+
ShareUtils.shareText(
95+
applicationContext,
96+
getString(R.string.error_report_title),
97+
buildJson(comment)
98+
)
99+
}
100+
)
133101
}
134102
}
135103

136-
private fun openPrivacyPolicyDialog(context: Context, action: String) {
104+
private fun openPrivacyPolicyDialog(
105+
context: Context,
106+
action: String,
107+
comment: String = ""
108+
) {
137109
AlertDialog.Builder(context)
138110
.setIcon(android.R.drawable.ic_dialog_alert)
139111
.setTitle(R.string.privacy_policy_title)
@@ -148,7 +120,7 @@ class ErrorActivity : AppCompatActivity() {
148120
.setData("mailto:".toUri()) // only email apps should handle this
149121
.putExtra(Intent.EXTRA_EMAIL, arrayOf(ERROR_EMAIL_ADDRESS))
150122
.putExtra(Intent.EXTRA_SUBJECT, errorEmailSubject)
151-
.putExtra(Intent.EXTRA_TEXT, buildJson())
123+
.putExtra(Intent.EXTRA_TEXT, buildJson(comment))
152124
ShareUtils.openIntentInApp(context, intent)
153125
} else if (action == "GITHUB") { // open the NewPipe issue page on GitHub
154126
ShareUtils.openUrlInApp(this, ERROR_GITHUB_ISSUE_URL)
@@ -163,24 +135,20 @@ class ErrorActivity : AppCompatActivity() {
163135
return stacktrace.joinToString(separator + "\n", separator + "\n", separator)
164136
}
165137

166-
private fun buildInfo(info: ErrorInfo) {
167-
binding.errorInfoLabelsView.text = getString(R.string.info_labels)
168-
169-
val text = info.userAction.message + "\n" +
170-
info.request + "\n" +
138+
private fun buildInfoString(): String {
139+
return errorInfo.userAction.message + "\n" +
140+
errorInfo.request + "\n" +
171141
contentLanguageString + "\n" +
172142
contentCountryString + "\n" +
173143
appLanguage + "\n" +
174-
info.getServiceName() + "\n" +
144+
errorInfo.getServiceName() + "\n" +
175145
currentTimeStamp + "\n" +
176146
packageName + "\n" +
177147
BuildConfig.VERSION_NAME + "\n" +
178148
osString
179-
180-
binding.errorInfosView.text = text
181149
}
182150

183-
private fun buildJson(): String {
151+
private fun buildJson(comment: String): String {
184152
try {
185153
return JsonWriter.string()
186154
.`object`()
@@ -195,7 +163,7 @@ class ErrorActivity : AppCompatActivity() {
195163
.value("os", osString)
196164
.value("time", currentTimeStamp)
197165
.array("exceptions", errorInfo.stackTraces.toList())
198-
.value("user_comment", binding.errorCommentBox.getText().toString())
166+
.value("user_comment", comment)
199167
.end()
200168
.done()
201169
} catch (exception: Exception) {
@@ -205,12 +173,11 @@ class ErrorActivity : AppCompatActivity() {
205173
return ""
206174
}
207175

208-
private fun buildMarkdown(): String {
176+
private fun buildMarkdown(comment: String): String {
209177
try {
210178
return buildString(1024) {
211-
val userComment = binding.errorCommentBox.text.toString()
212-
if (userComment.isNotEmpty()) {
213-
appendLine(userComment)
179+
if (comment.isNotEmpty()) {
180+
appendLine(comment)
214181
}
215182

216183
// basic error info
@@ -223,7 +190,6 @@ class ErrorActivity : AppCompatActivity() {
223190
appendLine("* __Service:__ ${errorInfo.getServiceName()}")
224191
appendLine("* __Timestamp:__ $currentTimeStamp")
225192
appendLine("* __Package:__ $packageName")
226-
appendLine("* __Service:__ ${errorInfo.getServiceName()}")
227193
appendLine("* __Version:__ ${BuildConfig.VERSION_NAME}")
228194
appendLine("* __OS:__ $osString")
229195

@@ -260,18 +226,9 @@ class ErrorActivity : AppCompatActivity() {
260226
}
261227
}
262228

263-
private fun addGuruMeditation() {
264-
// just an easter egg
265-
var text = binding.errorSorryView.text.toString()
266-
text += "\n" + getString(R.string.guru_meditation)
267-
binding.errorSorryView.text = text
268-
}
269-
270229
companion object {
271-
// LOG TAGS
272230
private val TAG = ErrorActivity::class.java.toString()
273231

274-
// BUNDLE TAGS
275232
const val ERROR_INFO = "error_info"
276233

277234
private const val ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025-2026 NewPipe e.V. <https://newpipe-ev.de>
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
6+
package org.schabi.newpipe.ui
7+
8+
import android.graphics.Color
9+
import android.os.Build
10+
import android.os.Bundle
11+
import androidx.activity.ComponentActivity
12+
import androidx.activity.SystemBarStyle
13+
import androidx.activity.compose.setContent
14+
import androidx.activity.enableEdgeToEdge
15+
import androidx.compose.runtime.Composable
16+
import org.schabi.newpipe.ui.theme.AppTheme
17+
18+
/**
19+
* Base activity for Compose-based screens. Provides edge-to-edge display and
20+
* wraps Compose content in [AppTheme].
21+
*
22+
* Subclasses should be annotated with `@AndroidEntryPoint` if they need Hilt injection.
23+
*/
24+
open class BaseActivity : ComponentActivity() {
25+
26+
override fun onCreate(savedInstanceState: Bundle?) {
27+
enableEdgeToEdge(
28+
navigationBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT)
29+
)
30+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
31+
window.isNavigationBarContrastEnforced = false
32+
}
33+
super.onCreate(savedInstanceState)
34+
}
35+
36+
/**
37+
* Sets the Compose content wrapped in [AppTheme]. Call this instead of [setContent] directly.
38+
*/
39+
fun composeSetContent(content: @Composable () -> Unit) {
40+
setContent {
41+
AppTheme(content = content)
42+
}
43+
}
44+
}

app/src/main/java/org/schabi/newpipe/ui/screens/ErrorReportScreen.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import androidx.compose.foundation.rememberScrollState
1717
import androidx.compose.foundation.text.selection.SelectionContainer
1818
import androidx.compose.foundation.verticalScroll
1919
import androidx.compose.material3.Button
20+
import androidx.compose.material3.Icon
21+
import androidx.compose.material3.IconButton
2022
import androidx.compose.material3.MaterialTheme
2123
import androidx.compose.material3.OutlinedTextField
2224
import androidx.compose.material3.Surface
@@ -27,6 +29,7 @@ import androidx.compose.runtime.mutableStateOf
2729
import androidx.compose.runtime.saveable.rememberSaveable
2830
import androidx.compose.runtime.setValue
2931
import androidx.compose.ui.Modifier
32+
import androidx.compose.ui.res.painterResource
3033
import androidx.compose.ui.res.stringResource
3134
import androidx.compose.ui.text.font.FontFamily
3235
import androidx.compose.ui.text.font.FontWeight
@@ -47,13 +50,22 @@ fun ErrorReportScreen(
4750
onBackClick: () -> Unit,
4851
onReportViaEmail: (comment: String) -> Unit,
4952
onCopyForGitHub: (comment: String) -> Unit,
50-
onReportOnGitHub: () -> Unit
53+
onReportOnGitHub: () -> Unit,
54+
onShareError: (comment: String) -> Unit = {}
5155
) {
5256
var comment by rememberSaveable { mutableStateOf("") }
5357

5458
ScaffoldWithToolbar(
5559
title = stringResource(R.string.error_report_title),
56-
onBackClick = onBackClick
60+
onBackClick = onBackClick,
61+
actions = {
62+
IconButton(onClick = { onShareError(comment) }) {
63+
Icon(
64+
painter = painterResource(R.drawable.ic_share),
65+
contentDescription = stringResource(R.string.share)
66+
)
67+
}
68+
}
5769
) { paddingValues ->
5870
Column(
5971
modifier = Modifier

0 commit comments

Comments
 (0)