Error dialog refinements
This commit is contained in:
parent
bdcecee3e9
commit
feb2907cd4
7 changed files with 272 additions and 106 deletions
|
|
@ -1,30 +1,37 @@
|
|||
package io.heckel.ntfy.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.ScrollView
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.ConnectionError
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.util.copyToClipboard
|
||||
|
||||
class ConnectionErrorFragment : DialogFragment() {
|
||||
private lateinit var repository: Repository
|
||||
private var connectionErrors: Map<String, ConnectionError> = emptyMap()
|
||||
private var selectedBaseUrl: String? = null
|
||||
private var detailsVisible = false
|
||||
private var filterBaseUrl: String? = null
|
||||
|
||||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var serverLabel: TextView
|
||||
private lateinit var serverSpinner: Spinner
|
||||
private lateinit var errorTextView: TextView
|
||||
private lateinit var showDetailsTextView: TextView
|
||||
private lateinit var detailsScrollView: ScrollView
|
||||
private lateinit var detailsScrollView: HorizontalScrollView
|
||||
private lateinit var stackTraceTextView: TextView
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
|
@ -32,14 +39,43 @@ class ConnectionErrorFragment : DialogFragment() {
|
|||
throw IllegalStateException("Activity cannot be null")
|
||||
}
|
||||
|
||||
// Get optional baseUrl filter from arguments
|
||||
filterBaseUrl = arguments?.getString(ARG_BASE_URL)
|
||||
|
||||
// Dependencies
|
||||
repository = Repository.getInstance(requireContext())
|
||||
connectionErrors = repository.getConnectionErrors()
|
||||
|
||||
// Get connection errors, optionally filtered by baseUrl
|
||||
val allErrors = repository.getConnectionErrors()
|
||||
connectionErrors = if (filterBaseUrl != null) {
|
||||
allErrors.filterKeys { it == filterBaseUrl }
|
||||
} else {
|
||||
allErrors
|
||||
}
|
||||
|
||||
// Build root view
|
||||
val view = requireActivity().layoutInflater.inflate(R.layout.fragment_connection_error_dialog, null)
|
||||
|
||||
// Setup toolbar
|
||||
toolbar = view.findViewById(R.id.connection_error_dialog_toolbar)
|
||||
toolbar.setNavigationOnClickListener { dismiss() }
|
||||
toolbar.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.connection_error_dialog_action_copy -> {
|
||||
copyErrorToClipboard()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// Tint menu icons to match toolbar text color
|
||||
val iconColor = MaterialColors.getColor(requireContext(), R.attr.colorOnSurface, Color.BLACK)
|
||||
val copyMenuItem = toolbar.menu.findItem(R.id.connection_error_dialog_action_copy)
|
||||
copyMenuItem?.icon?.setTint(iconColor)
|
||||
|
||||
// Get view references
|
||||
serverLabel = view.findViewById(R.id.connection_error_dialog_server_label)
|
||||
serverSpinner = view.findViewById(R.id.connection_error_dialog_server_spinner)
|
||||
errorTextView = view.findViewById(R.id.connection_error_dialog_error_text)
|
||||
showDetailsTextView = view.findViewById(R.id.connection_error_dialog_show_details)
|
||||
|
|
@ -49,6 +85,7 @@ class ConnectionErrorFragment : DialogFragment() {
|
|||
// Setup server spinner if multiple errors
|
||||
val baseUrls = connectionErrors.keys.toList()
|
||||
if (baseUrls.size > 1) {
|
||||
serverLabel.visibility = View.VISIBLE
|
||||
serverSpinner.visibility = View.VISIBLE
|
||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, baseUrls)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
|
|
@ -61,6 +98,7 @@ class ConnectionErrorFragment : DialogFragment() {
|
|||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||
}
|
||||
} else {
|
||||
serverLabel.visibility = View.GONE
|
||||
serverSpinner.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
|
@ -74,12 +112,21 @@ class ConnectionErrorFragment : DialogFragment() {
|
|||
updateDetailsVisibility()
|
||||
}
|
||||
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.connection_error_dialog_dismiss) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.create()
|
||||
// Build dialog
|
||||
val dialog = Dialog(requireContext(), R.style.Theme_App_FullScreenDialog)
|
||||
dialog.setContentView(view)
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog?.window?.apply {
|
||||
setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateErrorDisplay() {
|
||||
|
|
@ -106,7 +153,31 @@ class ConnectionErrorFragment : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun copyErrorToClipboard() {
|
||||
val error = selectedBaseUrl?.let { connectionErrors[it] } ?: return
|
||||
val text = buildString {
|
||||
appendLine("Server: ${error.baseUrl}")
|
||||
appendLine("Error: ${error.message}")
|
||||
appendLine()
|
||||
appendLine("Stack trace:")
|
||||
append(error.getStackTraceString().ifEmpty { "No stack trace available" })
|
||||
}
|
||||
copyToClipboard(requireContext(), "connection error", text)
|
||||
Toast.makeText(context, R.string.connection_error_dialog_copied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "NtfyConnectionErrorFragment"
|
||||
private const val ARG_BASE_URL = "base_url"
|
||||
|
||||
fun newInstance(baseUrl: String? = null): ConnectionErrorFragment {
|
||||
val fragment = ConnectionErrorFragment()
|
||||
if (baseUrl != null) {
|
||||
val args = Bundle()
|
||||
args.putString(ARG_BASE_URL, baseUrl)
|
||||
fragment.arguments = args
|
||||
}
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -361,6 +361,11 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
|
|||
SubscriberServiceManager.refresh(this)
|
||||
}
|
||||
|
||||
// Observe connection errors and update menu item visibility
|
||||
repository.getConnectionErrorsLiveData().observe(this) { errors ->
|
||||
showHideConnectionErrorMenuItem(errors)
|
||||
}
|
||||
|
||||
// Mark this subscription as "open" so we don't receive notifications for it
|
||||
repository.detailViewSubscriptionId.set(subscriptionId)
|
||||
|
||||
|
|
@ -508,6 +513,7 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
|
|||
showHideInstantMenuItems(subscriptionInstant)
|
||||
showHideMutedUntilMenuItems(subscriptionMutedUntil)
|
||||
showHideCopyMenuItems(subscription.baseUrl)
|
||||
showHideConnectionErrorMenuItem(repository.getConnectionErrors())
|
||||
updateTitle(subscriptionDisplayName)
|
||||
}
|
||||
}
|
||||
|
|
@ -550,6 +556,7 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
|
|||
showHideInstantMenuItems(subscriptionInstant)
|
||||
showHideMutedUntilMenuItems(subscriptionMutedUntil)
|
||||
showHideCopyMenuItems(subscriptionBaseUrl)
|
||||
showHideConnectionErrorMenuItem(repository.getConnectionErrors())
|
||||
|
||||
// Regularly check if "notification muted" time has passed
|
||||
// NOTE: This is done here, because then we know that we've initialized the menu items.
|
||||
|
|
@ -603,6 +610,10 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
|
|||
onInstantEnableClick(enable = false)
|
||||
true
|
||||
}
|
||||
R.id.detail_menu_connection_error -> {
|
||||
onConnectionErrorClick()
|
||||
true
|
||||
}
|
||||
R.id.detail_menu_copy_url -> {
|
||||
onCopyUrlClick()
|
||||
true
|
||||
|
|
@ -668,6 +679,12 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
|
|||
}
|
||||
}
|
||||
|
||||
private fun onConnectionErrorClick() {
|
||||
Log.d(TAG, "Showing connection error dialog for ${subscriptionBaseUrl}")
|
||||
val connectionErrorFragment = ConnectionErrorFragment.newInstance(subscriptionBaseUrl)
|
||||
connectionErrorFragment.show(supportFragmentManager, ConnectionErrorFragment.TAG)
|
||||
}
|
||||
|
||||
override fun onNotificationMutedUntilChanged(mutedUntilTimestamp: Long) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
Log.d(TAG, "Setting subscription 'muted until' to $mutedUntilTimestamp")
|
||||
|
|
@ -800,6 +817,17 @@ class DetailActivity : AppCompatActivity(), NotificationFragment.NotificationSet
|
|||
}
|
||||
}
|
||||
|
||||
private fun showHideConnectionErrorMenuItem(errors: Map<String, io.heckel.ntfy.db.ConnectionError>) {
|
||||
if (!this::menu.isInitialized) {
|
||||
return
|
||||
}
|
||||
runOnUiThread {
|
||||
val connectionErrorItem = menu.findItem(R.id.detail_menu_connection_error)
|
||||
// Only show if there's an error for this subscription's base URL
|
||||
connectionErrorItem?.isVisible = errors.containsKey(subscriptionBaseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTitle(subscriptionDisplayName: String) {
|
||||
runOnUiThread {
|
||||
title = subscriptionDisplayName
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
showHideNotificationMenuItems()
|
||||
showHideConnectionErrorMenuItem(repository.getConnectionErrors())
|
||||
redrawList()
|
||||
}
|
||||
|
||||
|
|
@ -492,6 +493,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific
|
|||
}
|
||||
|
||||
showHideNotificationMenuItems()
|
||||
showHideConnectionErrorMenuItem(repository.getConnectionErrors())
|
||||
checkSubscriptionsMuted() // This is done here, because then we know that we've initialized the menu
|
||||
return true
|
||||
}
|
||||
|
|
@ -628,7 +630,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific
|
|||
|
||||
private fun onConnectionErrorClick() {
|
||||
Log.d(TAG, "Showing connection error dialog")
|
||||
val connectionErrorFragment = ConnectionErrorFragment()
|
||||
val connectionErrorFragment = ConnectionErrorFragment.newInstance()
|
||||
connectionErrorFragment.show(supportFragmentManager, ConnectionErrorFragment.TAG)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,111 +1,158 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_title"
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/connection_error_dialog_app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:text="@string/connection_error_dialog_title"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
android:background="?attr/colorSurface"
|
||||
app:elevation="0dp"
|
||||
app:liftOnScroll="false">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/connection_error_dialog_server_spinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/connection_error_dialog_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/connection_error_dialog_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorSurface"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="12dp"
|
||||
app:navigationIcon="@drawable/ic_close_white_24dp"
|
||||
app:navigationIconTint="?attr/colorOnSurface"
|
||||
app:title="@string/connection_error_dialog_title"
|
||||
app:titleTextColor="?attr/colorOnSurface"
|
||||
app:menu="@menu/menu_connection_error_dialog" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/connection_error_dialog_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@drawable/ic_warning_amber_24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/connection_error_dialog_server_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/connection_error_dialog_message"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintTop_toBottomOf="@id/connection_error_dialog_icon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_error_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintTop_toBottomOf="@id/connection_error_dialog_message"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_show_details"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/connection_error_dialog_show_details"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?android:attr/colorAccent"
|
||||
android:textStyle="bold"
|
||||
android:padding="8dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:layout_constraintTop_toBottomOf="@id/connection_error_dialog_error_text"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/connection_error_dialog_details_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:maxHeight="200dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/connection_error_dialog_show_details"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="?dialogPreferredPadding"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_stack_trace"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:fontFamily="monospace"
|
||||
android:textSize="10sp" />
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<!-- Server selector (only visible when multiple servers have errors) -->
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_server_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/connection_error_dialog_server_label"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/connection_error_dialog_server_spinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Warning icon and message -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/connection_error_dialog_icon"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/ic_warning_amber_24dp"
|
||||
android:contentDescription="@string/connection_error_dialog_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/connection_error_dialog_message"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Error message -->
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_error_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/connection_error_dialog_error_label"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textStyle="bold"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_error_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:padding="8dp" />
|
||||
|
||||
<!-- Show/Hide details toggle -->
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_show_details"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/connection_error_dialog_show_details"
|
||||
android:textColor="?android:attr/colorAccent"
|
||||
android:textStyle="bold"
|
||||
android:padding="8dp"
|
||||
android:background="?android:attr/selectableItemBackground" />
|
||||
|
||||
<!-- Stack trace (scrollable horizontally, no word wrap) -->
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/connection_error_dialog_details_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone"
|
||||
android:fillViewport="true">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxHeight="300dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection_error_dialog_stack_trace"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:background="?attr/colorSurfaceVariant"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:fontFamily="monospace"
|
||||
android:textSize="10sp"
|
||||
android:scrollHorizontally="true"
|
||||
android:singleLine="false" />
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
9
app/src/main/res/menu/menu_connection_error_dialog.xml
Normal file
9
app/src/main/res/menu/menu_connection_error_dialog.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/connection_error_dialog_action_copy"
|
||||
android:icon="@drawable/ic_content_copy_white_24dp"
|
||||
android:title="@string/connection_error_dialog_copy"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
|
|
@ -26,6 +26,12 @@
|
|||
android:icon="@drawable/ic_bolt_white_24dp"
|
||||
android:title="@string/detail_menu_disable_instant"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_connection_error"
|
||||
android:icon="@drawable/ic_warning_white_24dp"
|
||||
android:title="@string/main_menu_connection_error"
|
||||
android:visible="false"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/detail_menu_settings"
|
||||
android:title="@string/detail_menu_settings" />
|
||||
|
|
|
|||
|
|
@ -292,11 +292,14 @@
|
|||
<!-- Connection error dialog -->
|
||||
<string name="connection_error_dialog_title">Connection Error</string>
|
||||
<string name="connection_error_dialog_message">There was a problem connecting to the server. The app will keep trying to reconnect.</string>
|
||||
<string name="connection_error_dialog_server_label">Server</string>
|
||||
<string name="connection_error_dialog_error_label">Error message</string>
|
||||
<string name="connection_error_dialog_show_details">Show details</string>
|
||||
<string name="connection_error_dialog_hide_details">Hide details</string>
|
||||
<string name="connection_error_dialog_no_stack_trace">No additional details available</string>
|
||||
<string name="connection_error_dialog_no_error">No error</string>
|
||||
<string name="connection_error_dialog_dismiss">Dismiss</string>
|
||||
<string name="connection_error_dialog_copy">Copy</string>
|
||||
<string name="connection_error_dialog_copied">Error details copied to clipboard</string>
|
||||
|
||||
<!-- Notification popup -->
|
||||
<string name="notification_popup_action_open">Open</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue