From 869a3cea9b54f6af798873f7fab841fa3f16370a Mon Sep 17 00:00:00 2001 From: "Yevhen Babiichuk (DustDFG)" Date: Tue, 10 Feb 2026 01:32:18 +0200 Subject: [PATCH 1/5] ErrorActivity small refactor --- .../schabi/newpipe/error/ErrorActivity.java | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index 160dcca4d..e183ebd71 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -85,8 +85,6 @@ public class ErrorActivity extends AppCompatActivity { activityErrorBinding = ActivityErrorBinding.inflate(getLayoutInflater()); setContentView(activityErrorBinding.getRoot()); - final Intent intent = getIntent(); - setSupportActionBar(activityErrorBinding.toolbarLayout.toolbar); final ActionBar actionBar = getSupportActionBar(); @@ -96,13 +94,12 @@ public class ErrorActivity extends AppCompatActivity { actionBar.setDisplayShowTitleEnabled(true); } - errorInfo = IntentCompat.getParcelableExtra(intent, ERROR_INFO, ErrorInfo.class); + errorInfo = IntentCompat.getParcelableExtra(getIntent(), ERROR_INFO, ErrorInfo.class); // important add guru meditation addGuruMeditation(); // print current time, as zoned ISO8601 timestamp - final ZonedDateTime now = ZonedDateTime.now(); - currentTimeStamp = now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + currentTimeStamp = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); activityErrorBinding.errorReportEmailButton.setOnClickListener(v -> openPrivacyPolicyDialog(this, "EMAIL")); @@ -160,9 +157,7 @@ public class ErrorActivity extends AppCompatActivity { final Intent i = new Intent(Intent.ACTION_SENDTO) .setData(Uri.parse("mailto:")) // only email apps should handle this .putExtra(Intent.EXTRA_EMAIL, new String[]{ERROR_EMAIL_ADDRESS}) - .putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT - + getString(R.string.app_name) + " " - + BuildConfig.VERSION_NAME) + .putExtra(Intent.EXTRA_SUBJECT, getErrorEmailSubject()) .putExtra(Intent.EXTRA_TEXT, buildJson()); ShareUtils.openIntentInApp(context, i); } else if (action.equals("GITHUB")) { // open the NewPipe issue page on GitHub @@ -180,12 +175,10 @@ public class ErrorActivity extends AppCompatActivity { } private void buildInfo(final ErrorInfo info) { - String text = ""; - activityErrorBinding.errorInfoLabelsView.setText(getString(R.string.info_labels) .replace("\\n", "\n")); - text += getUserActionString(info.getUserAction()) + "\n" + final String text = info.getUserAction().getMessage() + "\n" + info.getRequest() + "\n" + getContentLanguageString() + "\n" + getContentCountryString() + "\n" @@ -203,7 +196,7 @@ public class ErrorActivity extends AppCompatActivity { try { return JsonWriter.string() .object() - .value("user_action", getUserActionString(errorInfo.getUserAction())) + .value("user_action", errorInfo.getUserAction().getMessage()) .value("request", errorInfo.getRequest()) .value("content_language", getContentLanguageString()) .value("content_country", getContentCountryString()) @@ -239,7 +232,7 @@ public class ErrorActivity extends AppCompatActivity { htmlErrorReport .append("## Exception") .append("\n* __User Action:__ ") - .append(getUserActionString(errorInfo.getUserAction())) + .append(errorInfo.getUserAction().getMessage()) .append("\n* __Request:__ ").append(errorInfo.getRequest()) .append("\n* __Content Country:__ ").append(getContentCountryString()) .append("\n* __Content Language:__ ").append(getContentLanguageString()) @@ -286,14 +279,6 @@ public class ErrorActivity extends AppCompatActivity { } } - private String getUserActionString(final UserAction userAction) { - if (userAction == null) { - return "Your description is in another castle."; - } else { - return userAction.getMessage(); - } - } - private String getContentCountryString() { return Localization.getPreferredContentCountry(this).getCountryCode(); } @@ -306,6 +291,10 @@ public class ErrorActivity extends AppCompatActivity { return Localization.getAppLocale().toString(); } + private String getErrorEmailSubject() { + return ERROR_EMAIL_SUBJECT + getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME; + } + private String getOsString() { final String osBase = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? Build.VERSION.BASE_OS : "Android"; From 4a7eaed3a70f0a5ec599253c59b39bde173ca404 Mon Sep 17 00:00:00 2001 From: "Yevhen Babiichuk (DustDFG)" Date: Tue, 10 Feb 2026 09:32:43 +0200 Subject: [PATCH 2/5] ErrorActivity convert to kotlin Co-authored-by: Aayush Gupta --- .../schabi/newpipe/error/ErrorActivity.java | 313 ------------------ .../org/schabi/newpipe/error/ErrorActivity.kt | 281 ++++++++++++++++ 2 files changed, 281 insertions(+), 313 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java create mode 100644 app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java deleted file mode 100644 index e183ebd71..000000000 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ /dev/null @@ -1,313 +0,0 @@ -package org.schabi.newpipe.error; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.IntentCompat; - -import com.grack.nanojson.JsonWriter; - -import org.schabi.newpipe.BuildConfig; -import org.schabi.newpipe.R; -import org.schabi.newpipe.databinding.ActivityErrorBinding; -import org.schabi.newpipe.util.Localization; -import org.schabi.newpipe.util.ThemeHelper; -import org.schabi.newpipe.util.external_communication.ShareUtils; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.stream.Collectors; - -/* - * Created by Christian Schabesberger on 24.10.15. - * - * Copyright (C) Christian Schabesberger 2016 - * ErrorActivity.java is part of NewPipe. - * - * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * < - * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * < - * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - */ - -/** - * This activity is used to show error details and allow reporting them in various ways. Use {@link - * ErrorUtil#openActivity(Context, ErrorInfo)} to correctly open this activity. - */ -public class ErrorActivity extends AppCompatActivity { - // LOG TAGS - public static final String TAG = ErrorActivity.class.toString(); - // BUNDLE TAGS - public static final String ERROR_INFO = "error_info"; - - public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org"; - public static final String ERROR_EMAIL_SUBJECT = "Exception in "; - - public static final String ERROR_GITHUB_ISSUE_URL = - "https://github.com/TeamNewPipe/NewPipe/issues"; - - private ErrorInfo errorInfo; - private String currentTimeStamp; - - private ActivityErrorBinding activityErrorBinding; - - - //////////////////////////////////////////////////////////////////////// - // Activity lifecycle - //////////////////////////////////////////////////////////////////////// - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ThemeHelper.setDayNightMode(this); - ThemeHelper.setTheme(this); - - activityErrorBinding = ActivityErrorBinding.inflate(getLayoutInflater()); - setContentView(activityErrorBinding.getRoot()); - - setSupportActionBar(activityErrorBinding.toolbarLayout.toolbar); - - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setTitle(R.string.error_report_title); - actionBar.setDisplayShowTitleEnabled(true); - } - - errorInfo = IntentCompat.getParcelableExtra(getIntent(), ERROR_INFO, ErrorInfo.class); - - // important add guru meditation - addGuruMeditation(); - // print current time, as zoned ISO8601 timestamp - currentTimeStamp = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); - - activityErrorBinding.errorReportEmailButton.setOnClickListener(v -> - openPrivacyPolicyDialog(this, "EMAIL")); - - activityErrorBinding.errorReportCopyButton.setOnClickListener(v -> - ShareUtils.copyToClipboard(this, buildMarkdown())); - - activityErrorBinding.errorReportGitHubButton.setOnClickListener(v -> - openPrivacyPolicyDialog(this, "GITHUB")); - - // normal bugreport - buildInfo(errorInfo); - activityErrorBinding.errorMessageView.setText(errorInfo.getMessage(this)); - activityErrorBinding.errorView.setText(formErrorText(errorInfo.getStackTraces())); - - // print stack trace once again for debugging: - for (final String e : errorInfo.getStackTraces()) { - Log.e(TAG, e); - } - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - final MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.error_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - case R.id.menu_item_share_error: - ShareUtils.shareText(getApplicationContext(), - getString(R.string.error_report_title), buildJson()); - return true; - default: - return false; - } - } - - private void openPrivacyPolicyDialog(final Context context, final String action) { - new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.privacy_policy_title) - .setMessage(R.string.start_accept_privacy_policy) - .setCancelable(false) - .setNeutralButton(R.string.read_privacy_policy, (dialog, which) -> - ShareUtils.openUrlInApp(context, - context.getString(R.string.privacy_policy_url))) - .setPositiveButton(R.string.accept, (dialog, which) -> { - if (action.equals("EMAIL")) { // send on email - final Intent i = new Intent(Intent.ACTION_SENDTO) - .setData(Uri.parse("mailto:")) // only email apps should handle this - .putExtra(Intent.EXTRA_EMAIL, new String[]{ERROR_EMAIL_ADDRESS}) - .putExtra(Intent.EXTRA_SUBJECT, getErrorEmailSubject()) - .putExtra(Intent.EXTRA_TEXT, buildJson()); - ShareUtils.openIntentInApp(context, i); - } else if (action.equals("GITHUB")) { // open the NewPipe issue page on GitHub - ShareUtils.openUrlInApp(this, ERROR_GITHUB_ISSUE_URL); - } - }) - .setNegativeButton(R.string.decline, null) - .show(); - } - - private String formErrorText(final String[] el) { - final String separator = "-------------------------------------"; - return Arrays.stream(el) - .collect(Collectors.joining(separator + "\n", separator + "\n", separator)); - } - - private void buildInfo(final ErrorInfo info) { - activityErrorBinding.errorInfoLabelsView.setText(getString(R.string.info_labels) - .replace("\\n", "\n")); - - final String text = info.getUserAction().getMessage() + "\n" - + info.getRequest() + "\n" - + getContentLanguageString() + "\n" - + getContentCountryString() + "\n" - + getAppLanguage() + "\n" - + info.getServiceName() + "\n" - + currentTimeStamp + "\n" - + getPackageName() + "\n" - + BuildConfig.VERSION_NAME + "\n" - + getOsString(); - - activityErrorBinding.errorInfosView.setText(text); - } - - private String buildJson() { - try { - return JsonWriter.string() - .object() - .value("user_action", errorInfo.getUserAction().getMessage()) - .value("request", errorInfo.getRequest()) - .value("content_language", getContentLanguageString()) - .value("content_country", getContentCountryString()) - .value("app_language", getAppLanguage()) - .value("service", errorInfo.getServiceName()) - .value("package", getPackageName()) - .value("version", BuildConfig.VERSION_NAME) - .value("os", getOsString()) - .value("time", currentTimeStamp) - .array("exceptions", Arrays.asList(errorInfo.getStackTraces())) - .value("user_comment", activityErrorBinding.errorCommentBox.getText() - .toString()) - .end() - .done(); - } catch (final Throwable e) { - Log.e(TAG, "Error while erroring: Could not build json"); - e.printStackTrace(); - } - - return ""; - } - - private String buildMarkdown() { - try { - final StringBuilder htmlErrorReport = new StringBuilder(); - - final String userComment = activityErrorBinding.errorCommentBox.getText().toString(); - if (!userComment.isEmpty()) { - htmlErrorReport.append(userComment).append("\n"); - } - - // basic error info - htmlErrorReport - .append("## Exception") - .append("\n* __User Action:__ ") - .append(errorInfo.getUserAction().getMessage()) - .append("\n* __Request:__ ").append(errorInfo.getRequest()) - .append("\n* __Content Country:__ ").append(getContentCountryString()) - .append("\n* __Content Language:__ ").append(getContentLanguageString()) - .append("\n* __App Language:__ ").append(getAppLanguage()) - .append("\n* __Service:__ ").append(errorInfo.getServiceName()) - .append("\n* __Timestamp:__ ").append(currentTimeStamp) - .append("\n* __Package:__ ").append(getPackageName()) - .append("\n* __Service:__ ").append(errorInfo.getServiceName()) - .append("\n* __Version:__ ").append(BuildConfig.VERSION_NAME) - .append("\n* __OS:__ ").append(getOsString()).append("\n"); - - - // Collapse all logs to a single paragraph when there are more than one - // to keep the GitHub issue clean. - if (errorInfo.getStackTraces().length > 1) { - htmlErrorReport - .append("
Exceptions (") - .append(errorInfo.getStackTraces().length) - .append(")

\n"); - } - - // add the logs - for (int i = 0; i < errorInfo.getStackTraces().length; i++) { - htmlErrorReport.append("

Crash log "); - if (errorInfo.getStackTraces().length > 1) { - htmlErrorReport.append(i + 1); - } - htmlErrorReport.append("") - .append("

\n") - .append("\n```\n").append(errorInfo.getStackTraces()[i]).append("\n```\n") - .append("

\n"); - } - - // make sure to close everything - if (errorInfo.getStackTraces().length > 1) { - htmlErrorReport.append("

\n"); - } - htmlErrorReport.append("
\n"); - return htmlErrorReport.toString(); - } catch (final Throwable e) { - Log.e(TAG, "Error while erroring: Could not build markdown"); - e.printStackTrace(); - return ""; - } - } - - private String getContentCountryString() { - return Localization.getPreferredContentCountry(this).getCountryCode(); - } - - private String getContentLanguageString() { - return Localization.getPreferredLocalization(this).getLocalizationCode(); - } - - private String getAppLanguage() { - return Localization.getAppLocale().toString(); - } - - private String getErrorEmailSubject() { - return ERROR_EMAIL_SUBJECT + getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME; - } - - private String getOsString() { - final String osBase = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - ? Build.VERSION.BASE_OS : "Android"; - return System.getProperty("os.name") - + " " + (osBase.isEmpty() ? "Android" : osBase) - + " " + Build.VERSION.RELEASE - + " - " + Build.VERSION.SDK_INT; - } - - private void addGuruMeditation() { - //just an easter egg - String text = activityErrorBinding.errorSorryView.getText().toString(); - text += "\n" + getString(R.string.guru_meditation); - activityErrorBinding.errorSorryView.setText(text); - } -} diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt new file mode 100644 index 000000000..b48dd29be --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt @@ -0,0 +1,281 @@ +/* + * SPDX-FileCopyrightText: 2015-2026 NewPipe contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package org.schabi.newpipe.error + +import android.content.Context +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.IntentCompat +import androidx.core.net.toUri +import com.grack.nanojson.JsonWriter +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import org.schabi.newpipe.BuildConfig +import org.schabi.newpipe.R +import org.schabi.newpipe.databinding.ActivityErrorBinding +import org.schabi.newpipe.util.Localization +import org.schabi.newpipe.util.ThemeHelper +import org.schabi.newpipe.util.external_communication.ShareUtils + +/** + * This activity is used to show error details and allow reporting them in various ways. + * Use [ErrorUtil.openActivity] to correctly open this activity. + */ +class ErrorActivity : AppCompatActivity() { + private lateinit var errorInfo: ErrorInfo + private lateinit var currentTimeStamp: String + + private lateinit var activityErrorBinding: ActivityErrorBinding + + private val contentCountryString: String + get() = Localization.getPreferredContentCountry(this).countryCode + + private val contentLanguageString: String + get() = Localization.getPreferredLocalization(this).localizationCode + + private val appLanguage: String + get() = Localization.getAppLocale().toString() + + private val osString: String + get() { + val name = System.getProperty("os.name")!! + val osBase = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Build.VERSION.BASE_OS.ifEmpty { "Android" } + } else { + "Android" + } + return "$name $osBase ${Build.VERSION.RELEASE} - ${Build.VERSION.SDK_INT}" + } + + private val errorEmailSubject: String + get() = "$ERROR_EMAIL_SUBJECT ${getString(R.string.app_name)} ${BuildConfig.VERSION_NAME}" + + // ///////////////////////////////////////////////////////////////////// + // Activity lifecycle + // ///////////////////////////////////////////////////////////////////// + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + ThemeHelper.setDayNightMode(this) + ThemeHelper.setTheme(this) + + activityErrorBinding = ActivityErrorBinding.inflate(layoutInflater) + setContentView(activityErrorBinding.getRoot()) + + setSupportActionBar(activityErrorBinding.toolbarLayout.toolbar) + supportActionBar?.apply { + setDisplayHomeAsUpEnabled(true) + setTitle(R.string.error_report_title) + setDisplayShowTitleEnabled(true) + } + + errorInfo = IntentCompat.getParcelableExtra(intent, ERROR_INFO, ErrorInfo::class.java)!! + + // important add guru meditation + addGuruMeditation() + // print current time, as zoned ISO8601 timestamp + currentTimeStamp = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + + activityErrorBinding.errorReportEmailButton.setOnClickListener { _ -> + openPrivacyPolicyDialog(this, "EMAIL") + } + + activityErrorBinding.errorReportCopyButton.setOnClickListener { _ -> + ShareUtils.copyToClipboard(this, buildMarkdown()) + } + + activityErrorBinding.errorReportGitHubButton.setOnClickListener { _ -> + openPrivacyPolicyDialog(this, "GITHUB") + } + + // normal bugreport + buildInfo(errorInfo) + activityErrorBinding.errorMessageView.text = errorInfo.getMessage(this) + activityErrorBinding.errorView.text = formErrorText(errorInfo.stackTraces) + + // print stack trace once again for debugging: + errorInfo.stackTraces.forEach { Log.e(TAG, it) } + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.error_menu, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + android.R.id.home -> { + onBackPressed() + true + } + + R.id.menu_item_share_error -> { + ShareUtils.shareText( + applicationContext, + getString(R.string.error_report_title), + buildJson() + ) + true + } + + else -> false + } + } + + private fun openPrivacyPolicyDialog(context: Context, action: String) { + AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.privacy_policy_title) + .setMessage(R.string.start_accept_privacy_policy) + .setCancelable(false) + .setNeutralButton(R.string.read_privacy_policy) { _, _ -> + ShareUtils.openUrlInApp(context, context.getString(R.string.privacy_policy_url)) + } + .setPositiveButton(R.string.accept) { _, _ -> + if (action == "EMAIL") { // send on email + val i = Intent(Intent.ACTION_SENDTO) + .setData("mailto:".toUri()) // only email apps should handle this + .putExtra(Intent.EXTRA_EMAIL, arrayOf(ERROR_EMAIL_ADDRESS)) + .putExtra(Intent.EXTRA_SUBJECT, errorEmailSubject) + .putExtra(Intent.EXTRA_TEXT, buildJson()) + ShareUtils.openIntentInApp(context, i) + } else if (action == "GITHUB") { // open the NewPipe issue page on GitHub + ShareUtils.openUrlInApp(this, ERROR_GITHUB_ISSUE_URL) + } + } + .setNegativeButton(R.string.decline, null) + .show() + } + + private fun formErrorText(el: Array): String { + val separator = "-------------------------------------" + return el.joinToString(separator + "\n", separator + "\n", separator) + } + + private fun buildInfo(info: ErrorInfo) { + activityErrorBinding.errorInfoLabelsView.text = getString(R.string.info_labels) + .replace("\\n", "\n") + + val text = info.userAction.message + "\n" + + info.request + "\n" + + contentLanguageString + "\n" + + contentCountryString + "\n" + + appLanguage + "\n" + + info.getServiceName() + "\n" + + currentTimeStamp + "\n" + + packageName + "\n" + + BuildConfig.VERSION_NAME + "\n" + + osString + + activityErrorBinding.errorInfosView.text = text + } + + private fun buildJson(): String { + try { + return JsonWriter.string() + .`object`() + .value("user_action", errorInfo.userAction.message) + .value("request", errorInfo.request) + .value("content_language", contentLanguageString) + .value("content_country", contentCountryString) + .value("app_language", appLanguage) + .value("service", errorInfo.getServiceName()) + .value("package", packageName) + .value("version", BuildConfig.VERSION_NAME) + .value("os", osString) + .value("time", currentTimeStamp) + .array("exceptions", errorInfo.stackTraces.toList()) + .value("user_comment", activityErrorBinding.errorCommentBox.getText().toString()) + .end() + .done() + } catch (error: Throwable) { + Log.e(TAG, "Error while erroring: Could not build json", error) + } + + return "" + } + + private fun buildMarkdown(): String { + try { + return buildString(1024) { + val userComment = activityErrorBinding.errorCommentBox.getText().toString() + if (!userComment.isEmpty()) { + appendLine(userComment) + } + + // basic error info + appendLine("## Exception") + appendLine("* __User Action:__ ${errorInfo.userAction.message}") + appendLine("* __Request:__ ${errorInfo.request}") + appendLine("* __Content Country:__ $contentCountryString") + appendLine("* __Content Language:__ $contentLanguageString") + appendLine("* __App Language:__ $appLanguage") + appendLine("* __Service:__ ${errorInfo.getServiceName()}") + appendLine("* __Timestamp:__ $currentTimeStamp") + appendLine("* __Package:__ $packageName") + appendLine("* __Service:__ ${errorInfo.getServiceName()}") + appendLine("* __Version:__ ${BuildConfig.VERSION_NAME}") + appendLine("* __OS:__ $osString") + + // Collapse all logs to a single paragraph when there are more than one + // to keep the GitHub issue clean. + if (errorInfo.stackTraces.size > 1) { + append("
Exceptions (") + append(errorInfo.stackTraces.size) + append(")

\n") + } + + // add the logs + for (i in errorInfo.stackTraces.indices) { + append("

Crash log ") + if (errorInfo.stackTraces.size > 1) { + append(i + 1) + } + append("") + append("

\n") + append("\n```\n${errorInfo.stackTraces[i]}\n```\n") + append("

\n") + } + + // make sure to close everything + if (errorInfo.stackTraces.size > 1) { + append("

\n") + } + append("
\n") + } + } catch (error: Throwable) { + Log.e(TAG, "Error while erroring: Could not build markdown", error) + return "" + } + } + + private fun addGuruMeditation() { + // just an easter egg + var text = activityErrorBinding.errorSorryView.getText().toString() + text += "\n" + getString(R.string.guru_meditation) + activityErrorBinding.errorSorryView.text = text + } + + companion object { + // LOG TAGS + val TAG: String = ErrorActivity::class.java.toString() + + // BUNDLE TAGS + const val ERROR_INFO: String = "error_info" + + const val ERROR_EMAIL_ADDRESS: String = "crashreport@newpipe.schabi.org" + const val ERROR_EMAIL_SUBJECT: String = "Exception in " + + const val ERROR_GITHUB_ISSUE_URL: String = "https://github.com/TeamNewPipe/NewPipe/issues" + } +} From d7a4435e943fc59687cfb161c087c1492d0e09ed Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Wed, 11 Feb 2026 18:39:34 +0800 Subject: [PATCH 3/5] ErrorActivity: Use better variable names and encapsulation Signed-off-by: Aayush Gupta --- .../org/schabi/newpipe/error/ErrorActivity.kt | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt index b48dd29be..32f9769a1 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt @@ -34,7 +34,7 @@ class ErrorActivity : AppCompatActivity() { private lateinit var errorInfo: ErrorInfo private lateinit var currentTimeStamp: String - private lateinit var activityErrorBinding: ActivityErrorBinding + private lateinit var binding: ActivityErrorBinding private val contentCountryString: String get() = Localization.getPreferredContentCountry(this).countryCode @@ -69,10 +69,10 @@ class ErrorActivity : AppCompatActivity() { ThemeHelper.setDayNightMode(this) ThemeHelper.setTheme(this) - activityErrorBinding = ActivityErrorBinding.inflate(layoutInflater) - setContentView(activityErrorBinding.getRoot()) + binding = ActivityErrorBinding.inflate(layoutInflater) + setContentView(binding.getRoot()) - setSupportActionBar(activityErrorBinding.toolbarLayout.toolbar) + setSupportActionBar(binding.toolbarLayout.toolbar) supportActionBar?.apply { setDisplayHomeAsUpEnabled(true) setTitle(R.string.error_report_title) @@ -86,22 +86,22 @@ class ErrorActivity : AppCompatActivity() { // print current time, as zoned ISO8601 timestamp currentTimeStamp = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) - activityErrorBinding.errorReportEmailButton.setOnClickListener { _ -> + binding.errorReportEmailButton.setOnClickListener { _ -> openPrivacyPolicyDialog(this, "EMAIL") } - activityErrorBinding.errorReportCopyButton.setOnClickListener { _ -> + binding.errorReportCopyButton.setOnClickListener { _ -> ShareUtils.copyToClipboard(this, buildMarkdown()) } - activityErrorBinding.errorReportGitHubButton.setOnClickListener { _ -> + binding.errorReportGitHubButton.setOnClickListener { _ -> openPrivacyPolicyDialog(this, "GITHUB") } // normal bugreport buildInfo(errorInfo) - activityErrorBinding.errorMessageView.text = errorInfo.getMessage(this) - activityErrorBinding.errorView.text = formErrorText(errorInfo.stackTraces) + binding.errorMessageView.text = errorInfo.getMessage(this) + binding.errorView.text = formErrorText(errorInfo.stackTraces) // print stack trace once again for debugging: errorInfo.stackTraces.forEach { Log.e(TAG, it) } @@ -143,12 +143,12 @@ class ErrorActivity : AppCompatActivity() { } .setPositiveButton(R.string.accept) { _, _ -> if (action == "EMAIL") { // send on email - val i = Intent(Intent.ACTION_SENDTO) + val intent = Intent(Intent.ACTION_SENDTO) .setData("mailto:".toUri()) // only email apps should handle this .putExtra(Intent.EXTRA_EMAIL, arrayOf(ERROR_EMAIL_ADDRESS)) .putExtra(Intent.EXTRA_SUBJECT, errorEmailSubject) .putExtra(Intent.EXTRA_TEXT, buildJson()) - ShareUtils.openIntentInApp(context, i) + ShareUtils.openIntentInApp(context, intent) } else if (action == "GITHUB") { // open the NewPipe issue page on GitHub ShareUtils.openUrlInApp(this, ERROR_GITHUB_ISSUE_URL) } @@ -157,13 +157,13 @@ class ErrorActivity : AppCompatActivity() { .show() } - private fun formErrorText(el: Array): String { + private fun formErrorText(stacktrace: Array): String { val separator = "-------------------------------------" - return el.joinToString(separator + "\n", separator + "\n", separator) + return stacktrace.joinToString(separator + "\n", separator + "\n", separator) } private fun buildInfo(info: ErrorInfo) { - activityErrorBinding.errorInfoLabelsView.text = getString(R.string.info_labels) + binding.errorInfoLabelsView.text = getString(R.string.info_labels) .replace("\\n", "\n") val text = info.userAction.message + "\n" + @@ -177,7 +177,7 @@ class ErrorActivity : AppCompatActivity() { BuildConfig.VERSION_NAME + "\n" + osString - activityErrorBinding.errorInfosView.text = text + binding.errorInfosView.text = text } private fun buildJson(): String { @@ -195,7 +195,7 @@ class ErrorActivity : AppCompatActivity() { .value("os", osString) .value("time", currentTimeStamp) .array("exceptions", errorInfo.stackTraces.toList()) - .value("user_comment", activityErrorBinding.errorCommentBox.getText().toString()) + .value("user_comment", binding.errorCommentBox.getText().toString()) .end() .done() } catch (error: Throwable) { @@ -208,7 +208,7 @@ class ErrorActivity : AppCompatActivity() { private fun buildMarkdown(): String { try { return buildString(1024) { - val userComment = activityErrorBinding.errorCommentBox.getText().toString() + val userComment = binding.errorCommentBox.getText().toString() if (!userComment.isEmpty()) { appendLine(userComment) } @@ -261,21 +261,21 @@ class ErrorActivity : AppCompatActivity() { private fun addGuruMeditation() { // just an easter egg - var text = activityErrorBinding.errorSorryView.getText().toString() + var text = binding.errorSorryView.text.toString() text += "\n" + getString(R.string.guru_meditation) - activityErrorBinding.errorSorryView.text = text + binding.errorSorryView.text = text } companion object { // LOG TAGS - val TAG: String = ErrorActivity::class.java.toString() + private val TAG = ErrorActivity::class.java.toString() // BUNDLE TAGS - const val ERROR_INFO: String = "error_info" + const val ERROR_INFO = "error_info" - const val ERROR_EMAIL_ADDRESS: String = "crashreport@newpipe.schabi.org" - const val ERROR_EMAIL_SUBJECT: String = "Exception in " + private const val ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org" + private const val ERROR_EMAIL_SUBJECT = "Exception in " - const val ERROR_GITHUB_ISSUE_URL: String = "https://github.com/TeamNewPipe/NewPipe/issues" + private const val ERROR_GITHUB_ISSUE_URL = "https://github.com/TeamNewPipe/NewPipe/issues" } } From 8968aab5785b326b4aebcb5f7ea91c4f54629e1f Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Wed, 11 Feb 2026 18:41:10 +0800 Subject: [PATCH 4/5] ErrorActivity: Catch exceptions not throwables Signed-off-by: Aayush Gupta --- .../main/java/org/schabi/newpipe/error/ErrorActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt index 32f9769a1..7fbeb1716 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt @@ -198,8 +198,8 @@ class ErrorActivity : AppCompatActivity() { .value("user_comment", binding.errorCommentBox.getText().toString()) .end() .done() - } catch (error: Throwable) { - Log.e(TAG, "Error while erroring: Could not build json", error) + } catch (exception: Exception) { + Log.e(TAG, "Error while erroring: Could not build json", exception) } return "" @@ -253,8 +253,8 @@ class ErrorActivity : AppCompatActivity() { } append("
\n") } - } catch (error: Throwable) { - Log.e(TAG, "Error while erroring: Could not build markdown", error) + } catch (exception: Exception) { + Log.e(TAG, "Error while erroring: Could not build markdown", exception) return "" } } From c3dbed54e50430b585e9d7b88cf22c9f3a6cc54c Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Wed, 11 Feb 2026 21:39:01 +0800 Subject: [PATCH 5/5] ErrorActivity: Kotlin-fy buildMarkdown method Signed-off-by: Aayush Gupta --- .../org/schabi/newpipe/error/ErrorActivity.kt | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt index 7fbeb1716..b29190a55 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.kt @@ -208,8 +208,8 @@ class ErrorActivity : AppCompatActivity() { private fun buildMarkdown(): String { try { return buildString(1024) { - val userComment = binding.errorCommentBox.getText().toString() - if (!userComment.isEmpty()) { + val userComment = binding.errorCommentBox.text.toString() + if (userComment.isNotEmpty()) { appendLine(userComment) } @@ -229,28 +229,27 @@ class ErrorActivity : AppCompatActivity() { // Collapse all logs to a single paragraph when there are more than one // to keep the GitHub issue clean. - if (errorInfo.stackTraces.size > 1) { + if (errorInfo.stackTraces.isNotEmpty()) { append("
Exceptions (") append(errorInfo.stackTraces.size) append(")

\n") - } - // add the logs - for (i in errorInfo.stackTraces.indices) { - append("

Crash log ") - if (errorInfo.stackTraces.size > 1) { - append(i + 1) + // add the logs + errorInfo.stackTraces.forEachIndexed { index, stacktrace -> + append("
Crash log ") + if (errorInfo.stackTraces.isNotEmpty()) { + append(index + 1) + } + append("") + append("

\n") + append("\n```\n${stacktrace}\n```\n") + append("

\n") } - append("
") - append("

\n") - append("\n```\n${errorInfo.stackTraces[i]}\n```\n") - append("

\n") - } - // make sure to close everything - if (errorInfo.stackTraces.size > 1) { + // make sure to close everything append("

\n") } + append("
\n") } } catch (exception: Exception) {