forked from github/wulkanowy-mirror
Add error message and bug report button to error dialog (#778)
This commit is contained in:
parent
4bd0459155
commit
366ebc781d
@ -6,19 +6,32 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.HorizontalScrollView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_LONG
|
import android.widget.Toast.LENGTH_LONG
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
||||||
|
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||||
|
import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import io.github.wulkanowy.utils.getString
|
||||||
|
import io.github.wulkanowy.utils.openEmailClient
|
||||||
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
import kotlinx.android.synthetic.main.dialog_error.*
|
import kotlinx.android.synthetic.main.dialog_error.*
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
import java.net.SocketTimeoutException
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ErrorDialog : DialogFragment() {
|
class ErrorDialog : BaseDialogFragment() {
|
||||||
|
|
||||||
private lateinit var error: Throwable
|
private lateinit var error: Throwable
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ARGUMENT_KEY = "Data"
|
private const val ARGUMENT_KEY = "Data"
|
||||||
|
|
||||||
@ -49,6 +62,9 @@ class ErrorDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorDialogContent.text = stringWriter.toString()
|
errorDialogContent.text = stringWriter.toString()
|
||||||
|
with(errorDialogHorizontalScroll) {
|
||||||
|
post { fullScroll(HorizontalScrollView.FOCUS_LEFT) }
|
||||||
|
}
|
||||||
errorDialogCopy.setOnClickListener {
|
errorDialogCopy.setOnClickListener {
|
||||||
val clip = ClipData.newPlainText("wulkanowy", stringWriter.toString())
|
val clip = ClipData.newPlainText("wulkanowy", stringWriter.toString())
|
||||||
activity?.getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
|
activity?.getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
|
||||||
@ -56,6 +72,29 @@ class ErrorDialog : DialogFragment() {
|
|||||||
Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show()
|
Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
errorDialogCancel.setOnClickListener { dismiss() }
|
errorDialogCancel.setOnClickListener { dismiss() }
|
||||||
|
errorDialogReport.setOnClickListener { openEmailClient(stringWriter.toString()) }
|
||||||
|
errorDialogMessage.text = resources.getString(error)
|
||||||
|
errorDialogReport.isEnabled = when (error) {
|
||||||
|
is UnknownHostException,
|
||||||
|
is SocketTimeoutException,
|
||||||
|
is ServiceUnavailableException,
|
||||||
|
is FeatureDisabledException,
|
||||||
|
is FeatureNotAvailableException -> false
|
||||||
|
else -> true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openEmailClient(content: String) {
|
||||||
|
requireContext().openEmailClient(
|
||||||
|
chooserTitle = getString(R.string.about_feedback),
|
||||||
|
email = "wulkanowyinc@gmail.com",
|
||||||
|
subject = "Zgłoszenie błędu",
|
||||||
|
body = requireContext().getString(R.string.about_feedback_template,
|
||||||
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName
|
||||||
|
) + "\n" + content,
|
||||||
|
onActivityNotFound = {
|
||||||
|
requireContext().openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,17 +2,11 @@ package io.github.wulkanowy.ui.base
|
|||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import io.github.wulkanowy.R
|
|
||||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
import io.github.wulkanowy.sdk.exception.BadCredentialsException
|
import io.github.wulkanowy.sdk.exception.BadCredentialsException
|
||||||
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
import io.github.wulkanowy.utils.getString
|
||||||
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
|
||||||
import io.github.wulkanowy.sdk.exception.NotLoggedInException
|
|
||||||
import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
|
|
||||||
import io.github.wulkanowy.utils.security.ScramblerException
|
import io.github.wulkanowy.utils.security.ScramblerException
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.net.SocketTimeoutException
|
|
||||||
import java.net.UnknownHostException
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckerCollector: ChuckerCollector) {
|
open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckerCollector: ChuckerCollector) {
|
||||||
@ -30,18 +24,10 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources,
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open fun proceed(error: Throwable) {
|
protected open fun proceed(error: Throwable) {
|
||||||
resources.run {
|
|
||||||
when (error) {
|
when (error) {
|
||||||
is UnknownHostException -> showErrorMessage(getString(R.string.error_no_internet), error)
|
|
||||||
is SocketTimeoutException -> showErrorMessage(getString(R.string.error_timeout), error)
|
|
||||||
is NotLoggedInException -> showErrorMessage(getString(R.string.error_login_failed), error)
|
|
||||||
is ServiceUnavailableException -> showErrorMessage(getString(R.string.error_service_unavailable), error)
|
|
||||||
is FeatureDisabledException -> showErrorMessage(getString(R.string.error_feature_disabled), error)
|
|
||||||
is ScramblerException, is BadCredentialsException -> onSessionExpired()
|
is ScramblerException, is BadCredentialsException -> onSessionExpired()
|
||||||
is NoCurrentStudentException -> onNoCurrentStudent()
|
is NoCurrentStudentException -> onNoCurrentStudent()
|
||||||
is FeatureNotAvailableException -> showErrorMessage(getString(R.string.error_feature_not_available), error)
|
else -> showErrorMessage(resources.getString(error), error)
|
||||||
else -> showErrorMessage(getString(R.string.error_unknown), error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import dagger.Provides
|
|||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.di.scopes.PerFragment
|
import io.github.wulkanowy.di.scopes.PerFragment
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||||
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
||||||
import io.github.wulkanowy.ui.modules.about.contributor.ContributorFragment
|
import io.github.wulkanowy.ui.modules.about.contributor.ContributorFragment
|
||||||
import io.github.wulkanowy.ui.modules.about.license.LicenseFragment
|
import io.github.wulkanowy.ui.modules.about.license.LicenseFragment
|
||||||
@ -115,6 +116,10 @@ abstract class MainModule {
|
|||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindAccountDialog(): AccountDialog
|
abstract fun bindAccountDialog(): AccountDialog
|
||||||
|
|
||||||
|
@PerFragment
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindErrorDialog(): ErrorDialog
|
||||||
|
|
||||||
@PerFragment
|
@PerFragment
|
||||||
@ContributesAndroidInjector(modules = [MobileDeviceModule::class])
|
@ContributesAndroidInjector(modules = [MobileDeviceModule::class])
|
||||||
abstract fun bindMobileDevices(): MobileDeviceFragment
|
abstract fun bindMobileDevices(): MobileDeviceFragment
|
||||||
@ -132,7 +137,7 @@ abstract class MainModule {
|
|||||||
abstract fun bindLogViewerFragment(): LogViewerFragment
|
abstract fun bindLogViewerFragment(): LogViewerFragment
|
||||||
|
|
||||||
@PerFragment
|
@PerFragment
|
||||||
@ContributesAndroidInjector()
|
@ContributesAndroidInjector
|
||||||
abstract fun bindContributorFragment(): ContributorFragment
|
abstract fun bindContributorFragment(): ContributorFragment
|
||||||
|
|
||||||
@PerFragment
|
@PerFragment
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
||||||
|
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||||
|
import io.github.wulkanowy.sdk.exception.NotLoggedInException
|
||||||
|
import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
|
||||||
|
import java.net.SocketTimeoutException
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
|
||||||
|
fun Resources.getString(error: Throwable) = when (error) {
|
||||||
|
is UnknownHostException -> getString(R.string.error_no_internet)
|
||||||
|
is SocketTimeoutException -> getString(R.string.error_timeout)
|
||||||
|
is NotLoggedInException -> getString(R.string.error_login_failed)
|
||||||
|
is ServiceUnavailableException -> getString(R.string.error_service_unavailable)
|
||||||
|
is FeatureDisabledException -> getString(R.string.error_feature_disabled)
|
||||||
|
is FeatureNotAvailableException -> getString(R.string.error_feature_not_available)
|
||||||
|
else -> getString(R.string.error_unknown)
|
||||||
|
}
|
@ -1,26 +1,49 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minWidth="300dp"
|
android:minWidth="300dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:paddingTop="20dp"
|
||||||
|
android:text="@string/all_details"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/errorDialogMessage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:textSize="21sp"
|
||||||
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/errorDialogNestedScroll"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:overScrollMode="ifContentScrolls">
|
android:overScrollMode="ifContentScrolls"
|
||||||
|
app:layout_constrainedHeight="true"
|
||||||
|
app:layout_constraintHeight_max="300dp"
|
||||||
|
app:layout_constraintHeight_min="200dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/errorDialogHorizontalScroll"
|
||||||
android:layout_width="350dp"
|
android:layout_width="350dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="24dp"
|
android:paddingLeft="24dp"
|
||||||
android:paddingTop="24dp"
|
|
||||||
android:paddingRight="24dp">
|
android:paddingRight="24dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -33,16 +56,31 @@
|
|||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:background="@drawable/ic_all_divider"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:minHeight="52dp"
|
android:minHeight="52dp"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/errorDialogReport"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/about_feedback" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/errorDialogCancel"
|
android:id="@+id/errorDialogCancel"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
@ -50,7 +88,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:text="@android:string/cancel" />
|
android:text="@android:string/cancel" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
@ -60,7 +97,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:text="@android:string/copy" />
|
android:text="@android:string/copy" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -421,5 +421,5 @@
|
|||||||
<string name="error_service_unavailable">Trwa przerwa techniczna dziennika UONET+. Spróbuj ponownie później</string>
|
<string name="error_service_unavailable">Trwa przerwa techniczna dziennika UONET+. Spróbuj ponownie później</string>
|
||||||
<string name="error_unknown">Wystąpił nieoczekiwany błąd</string>
|
<string name="error_unknown">Wystąpił nieoczekiwany błąd</string>
|
||||||
<string name="error_feature_disabled">Funkcja wyłączona przez szkołę</string>
|
<string name="error_feature_disabled">Funkcja wyłączona przez szkołę</string>
|
||||||
<string name="error_feature_not_available">Funkcja niedostępna. Zaloguj się w innym trybie niż Mobilne API</string>
|
<string name="error_feature_not_available">Funkcja niedostępna. Zaloguj się w trybie innym niż Mobilne API</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user