Add error reporting to import local manga
This commit is contained in:
@@ -337,6 +337,13 @@
|
|||||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
<receiver
|
||||||
|
android:name="org.koitharu.kotatsu.core.ErrorReporterReceiver"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="${applicationId}.action.REPORT_ERROR" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.webkit.WebView.EnableSafeBrowsing"
|
android:name="android.webkit.WebView.EnableSafeBrowsing"
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.koitharu.kotatsu.core
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.core.app.PendingIntentCompat
|
||||||
|
import org.koitharu.kotatsu.BuildConfig
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.report
|
||||||
|
|
||||||
|
class ErrorReporterReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
val e = intent?.getSerializableExtraCompat<Throwable>(EXTRA_ERROR) ?: return
|
||||||
|
e.report()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val EXTRA_ERROR = "err"
|
||||||
|
private const val ACTION_REPORT = "${BuildConfig.APPLICATION_ID}.action.REPORT_ERROR"
|
||||||
|
|
||||||
|
fun getPendingIntent(context: Context, e: Throwable): PendingIntent {
|
||||||
|
val intent = Intent(context, ErrorReporterReceiver::class.java)
|
||||||
|
intent.setAction(ACTION_REPORT)
|
||||||
|
intent.setData(Uri.parse("err://${e.hashCode()}"))
|
||||||
|
intent.putExtra(EXTRA_ERROR, e)
|
||||||
|
return checkNotNull(PendingIntentCompat.getBroadcast(context, 0, intent, 0, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import coil.request.ImageRequest
|
|||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.ErrorReporterReceiver
|
||||||
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
||||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||||
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
|
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
|
||||||
@@ -91,6 +92,7 @@ class ImportWorker @AssistedInject constructor(
|
|||||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
.setDefaults(0)
|
.setDefaults(0)
|
||||||
.setSilent(true)
|
.setSilent(true)
|
||||||
|
.setAutoCancel(true)
|
||||||
result.onSuccess { manga ->
|
result.onSuccess { manga ->
|
||||||
notification.setLargeIcon(
|
notification.setLargeIcon(
|
||||||
coil.execute(
|
coil.execute(
|
||||||
@@ -110,10 +112,9 @@ class ImportWorker @AssistedInject constructor(
|
|||||||
PendingIntent.FLAG_UPDATE_CURRENT,
|
PendingIntent.FLAG_UPDATE_CURRENT,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
).setAutoCancel(true)
|
).setVisibility(
|
||||||
.setVisibility(
|
if (manga.isNsfw) NotificationCompat.VISIBILITY_SECRET else NotificationCompat.VISIBILITY_PUBLIC,
|
||||||
if (manga.isNsfw) NotificationCompat.VISIBILITY_SECRET else NotificationCompat.VISIBILITY_PUBLIC,
|
)
|
||||||
)
|
|
||||||
notification.setContentTitle(applicationContext.getString(R.string.import_completed))
|
notification.setContentTitle(applicationContext.getString(R.string.import_completed))
|
||||||
.setContentText(applicationContext.getString(R.string.import_completed_hint))
|
.setContentText(applicationContext.getString(R.string.import_completed_hint))
|
||||||
.setSmallIcon(R.drawable.ic_stat_done)
|
.setSmallIcon(R.drawable.ic_stat_done)
|
||||||
@@ -123,6 +124,11 @@ class ImportWorker @AssistedInject constructor(
|
|||||||
notification.setContentTitle(applicationContext.getString(R.string.error_occurred))
|
notification.setContentTitle(applicationContext.getString(R.string.error_occurred))
|
||||||
.setContentText(error.getDisplayMessage(applicationContext.resources))
|
.setContentText(error.getDisplayMessage(applicationContext.resources))
|
||||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||||
|
.addAction(
|
||||||
|
R.drawable.ic_alert_outline,
|
||||||
|
applicationContext.getString(R.string.report),
|
||||||
|
ErrorReporterReceiver.getPendingIntent(applicationContext, error),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return notification.build()
|
return notification.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
@@ -18,6 +19,7 @@ import org.koitharu.kotatsu.core.parser.MangaIntent
|
|||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||||
import org.koitharu.kotatsu.core.util.ext.call
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||||
import org.koitharu.kotatsu.core.util.ext.require
|
import org.koitharu.kotatsu.core.util.ext.require
|
||||||
import org.koitharu.kotatsu.core.util.ext.requireValue
|
import org.koitharu.kotatsu.core.util.ext.requireValue
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
@@ -27,7 +29,6 @@ import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
|||||||
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
|
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
|
||||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
||||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
|
import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
|
||||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@@ -53,7 +54,7 @@ class ScrobblingSelectorViewModel @Inject constructor(
|
|||||||
get() = availableScrobblers[selectedScrobblerIndex.requireValue()]
|
get() = availableScrobblers[selectedScrobblerIndex.requireValue()]
|
||||||
|
|
||||||
val content: StateFlow<List<ListModel>> = combine(
|
val content: StateFlow<List<ListModel>> = combine(
|
||||||
scrobblerMangaList,
|
scrobblerMangaList.map { it.distinctBy { x -> x.id } },
|
||||||
listError,
|
listError,
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
) { list, error, isHasNextPage ->
|
) { list, error, isHasNextPage ->
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ class MALRepository @Inject constructor(
|
|||||||
.build()
|
.build()
|
||||||
val request = Request.Builder().url(url).get().build()
|
val request = Request.Builder().url(url).get().build()
|
||||||
val response = okHttp.newCall(request).await().parseJson()
|
val response = okHttp.newCall(request).await().parseJson()
|
||||||
|
check(response.has("data")) { "Invalid response: \"$response\"" }
|
||||||
val data = response.getJSONArray("data")
|
val data = response.getJSONArray("data")
|
||||||
return data.mapJSONNotNull { jsonToManga(it) }
|
return data.mapJSONNotNull { jsonToManga(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
<?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/action_import"
|
|
||||||
android:orderInCategory="50"
|
|
||||||
android:title="@string/_import"
|
|
||||||
app:showAsAction="never" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_categories"
|
|
||||||
android:orderInCategory="50"
|
|
||||||
android:title="@string/settings"
|
|
||||||
app:showAsAction="never" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_grid_size"
|
|
||||||
android:orderInCategory="50"
|
|
||||||
android:title="@string/grid_size"
|
|
||||||
app:showAsAction="never" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_clear_history"
|
|
||||||
android:orderInCategory="50"
|
|
||||||
android:title="@string/clear_history"
|
|
||||||
app:showAsAction="never" />
|
|
||||||
|
|
||||||
</menu>
|
|
||||||
Reference in New Issue
Block a user