Backup restorng fixes
This commit is contained in:
@@ -20,7 +20,7 @@ class BookmarkBackup(
|
|||||||
@SerialName("chapter_id") val chapterId: Long,
|
@SerialName("chapter_id") val chapterId: Long,
|
||||||
@SerialName("page") val page: Int,
|
@SerialName("page") val page: Int,
|
||||||
@SerialName("scroll") val scroll: Int,
|
@SerialName("scroll") val scroll: Int,
|
||||||
@SerialName("image") val imageUrl: String,
|
@SerialName("image_url") val imageUrl: String,
|
||||||
@SerialName("created_at") val createdAt: Long,
|
@SerialName("created_at") val createdAt: Long,
|
||||||
@SerialName("percent") val percent: Float,
|
@SerialName("percent") val percent: Float,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
package org.koitharu.kotatsu.backups.ui
|
package org.koitharu.kotatsu.backups.ui
|
||||||
|
|
||||||
import android.app.Notification
|
import android.net.Uri
|
||||||
import androidx.core.app.NotificationChannelCompat
|
import androidx.core.app.NotificationChannelCompat
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.app.PendingIntentCompat
|
import androidx.core.app.PendingIntentCompat
|
||||||
|
import androidx.core.app.ShareCompat
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.ErrorReporterReceiver
|
import org.koitharu.kotatsu.core.ErrorReporterReceiver
|
||||||
import org.koitharu.kotatsu.core.nav.AppRouter
|
import org.koitharu.kotatsu.core.nav.AppRouter
|
||||||
import org.koitharu.kotatsu.core.ui.CoroutineIntentService
|
import org.koitharu.kotatsu.core.ui.CoroutineIntentService
|
||||||
|
import org.koitharu.kotatsu.core.util.CompositeResult
|
||||||
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.getFileDisplayName
|
||||||
|
import androidx.appcompat.R as appcompatR
|
||||||
|
|
||||||
abstract class BaseBackupRestoreService : CoroutineIntentService() {
|
abstract class BaseBackupRestoreService : CoroutineIntentService() {
|
||||||
|
|
||||||
protected abstract val notificationTag: String
|
protected abstract val notificationTag: String
|
||||||
|
protected abstract val isRestoreService: Boolean
|
||||||
|
|
||||||
protected lateinit var notificationManager: NotificationManagerCompat
|
protected lateinit var notificationManager: NotificationManagerCompat
|
||||||
private set
|
private set
|
||||||
@@ -26,10 +31,7 @@ abstract class BaseBackupRestoreService : CoroutineIntentService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun IntentJobContext.onError(error: Throwable) {
|
override fun IntentJobContext.onError(error: Throwable) {
|
||||||
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
|
showResultNotification(null, CompositeResult.failure(error))
|
||||||
val notification = createErrorNotification(error)
|
|
||||||
notificationManager.notify(notificationTag, startId, notification)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
@@ -43,33 +45,93 @@ abstract class BaseBackupRestoreService : CoroutineIntentService() {
|
|||||||
notificationManager.createNotificationChannel(channel)
|
notificationManager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createErrorNotification(error: Throwable): Notification {
|
protected fun IntentJobContext.showResultNotification(
|
||||||
|
fileUri: Uri?,
|
||||||
|
result: CompositeResult,
|
||||||
|
) {
|
||||||
|
if (!applicationContext.checkNotificationPermission(CHANNEL_ID)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
.setDefaults(0)
|
.setDefaults(0)
|
||||||
.setSilent(true)
|
.setSilent(true)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentText(error.getDisplayMessage(resources))
|
.setSubText(fileUri?.let { contentResolver.getFileDisplayName(it) })
|
||||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
when {
|
||||||
ErrorReporterReceiver.getPendingIntent(applicationContext, error)?.let { reportIntent ->
|
result.isAllSuccess -> {
|
||||||
notification.addAction(
|
if (isRestoreService) {
|
||||||
R.drawable.ic_alert_outline,
|
notification
|
||||||
applicationContext.getString(R.string.report),
|
.setContentTitle(getString(R.string.restoring_backup))
|
||||||
reportIntent,
|
.setContentText(getString(R.string.data_restored_success))
|
||||||
)
|
} else {
|
||||||
|
notification
|
||||||
|
.setContentTitle(getString(R.string.backup_saved))
|
||||||
|
.setContentText(fileUri?.let { contentResolver.getFileDisplayName(it) })
|
||||||
|
.setSubText(null)
|
||||||
|
|
||||||
|
}
|
||||||
|
notification.setSmallIcon(R.drawable.ic_stat_done)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.isAllFailed || !isRestoreService -> {
|
||||||
|
val title = getString(if (isRestoreService) R.string.data_not_restored else R.string.error_occurred)
|
||||||
|
val message = result.failures.joinToString("\n") {
|
||||||
|
it.getDisplayMessage(applicationContext.resources)
|
||||||
|
}
|
||||||
|
notification
|
||||||
|
.setContentText(if (isRestoreService) getString(R.string.data_not_restored_text) else message)
|
||||||
|
.setBigText(title, message)
|
||||||
|
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||||
|
result.failures.firstNotNullOfOrNull { error ->
|
||||||
|
ErrorReporterReceiver.getPendingIntent(applicationContext, error)
|
||||||
|
}?.let { reportIntent ->
|
||||||
|
notification.addAction(
|
||||||
|
R.drawable.ic_alert_outline,
|
||||||
|
applicationContext.getString(R.string.report),
|
||||||
|
reportIntent,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
notification
|
||||||
|
.setContentTitle(getString(R.string.restoring_backup))
|
||||||
|
.setContentText(getString(R.string.data_restored_with_errors))
|
||||||
|
.setSmallIcon(R.drawable.ic_stat_done)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notification.setContentIntent(
|
notification.setContentIntent(
|
||||||
PendingIntentCompat.getActivity(
|
PendingIntentCompat.getActivity(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
0,
|
0,
|
||||||
AppRouter.homeIntent(this),
|
AppRouter.homeIntent(this@BaseBackupRestoreService),
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return notification.build()
|
if (!isRestoreService && fileUri != null) {
|
||||||
|
val shareIntent = ShareCompat.IntentBuilder(this@BaseBackupRestoreService)
|
||||||
|
.setStream(fileUri)
|
||||||
|
.setType("application/zip")
|
||||||
|
.setChooserTitle(R.string.share_backup)
|
||||||
|
.createChooserIntent()
|
||||||
|
notification.addAction(
|
||||||
|
appcompatR.drawable.abc_ic_menu_share_mtrl_alpha,
|
||||||
|
getString(R.string.share),
|
||||||
|
PendingIntentCompat.getActivity(this@BaseBackupRestoreService, 0, shareIntent, 0, false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
notificationManager.notify(notificationTag, startId, notification.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun NotificationCompat.Builder.setBigText(title: String, text: CharSequence) = setStyle(
|
||||||
|
NotificationCompat.BigTextStyle()
|
||||||
|
.bigText(text)
|
||||||
|
.setSummaryText(text)
|
||||||
|
.setBigContentTitle(title),
|
||||||
|
)
|
||||||
|
|
||||||
protected companion object {
|
protected companion object {
|
||||||
|
|
||||||
const val CHANNEL_ID = "backup_restore"
|
const val CHANNEL_ID = "backup_restore"
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import android.content.pm.ServiceInfo
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.annotation.CheckResult
|
import androidx.annotation.CheckResult
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.PendingIntentCompat
|
|
||||||
import androidx.core.app.ShareCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
@@ -19,6 +17,7 @@ import org.koitharu.kotatsu.R
|
|||||||
import org.koitharu.kotatsu.backups.data.BackupRepository
|
import org.koitharu.kotatsu.backups.data.BackupRepository
|
||||||
import org.koitharu.kotatsu.backups.ui.BaseBackupRestoreService
|
import org.koitharu.kotatsu.backups.ui.BaseBackupRestoreService
|
||||||
import org.koitharu.kotatsu.core.nav.AppRouter
|
import org.koitharu.kotatsu.core.nav.AppRouter
|
||||||
|
import org.koitharu.kotatsu.core.util.CompositeResult
|
||||||
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
||||||
import org.koitharu.kotatsu.core.util.ext.powerManager
|
import org.koitharu.kotatsu.core.util.ext.powerManager
|
||||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||||
@@ -35,6 +34,7 @@ import androidx.appcompat.R as appcompatR
|
|||||||
class BackupService : BaseBackupRestoreService() {
|
class BackupService : BaseBackupRestoreService() {
|
||||||
|
|
||||||
override val notificationTag = TAG
|
override val notificationTag = TAG
|
||||||
|
override val isRestoreService = false
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var repository: BackupRepository
|
lateinit var repository: BackupRepository
|
||||||
@@ -63,9 +63,7 @@ class BackupService : BaseBackupRestoreService() {
|
|||||||
}
|
}
|
||||||
progressUpdateJob?.cancelAndJoin()
|
progressUpdateJob?.cancelAndJoin()
|
||||||
contentResolver.notifyChange(destination, null)
|
contentResolver.notifyChange(destination, null)
|
||||||
if (checkNotificationPermission(CHANNEL_ID)) {
|
showResultNotification(destination, CompositeResult.success())
|
||||||
notificationManager.notify(notificationTag, startId, createResultNotification(destination))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,31 +96,6 @@ class BackupService : BaseBackupRestoreService() {
|
|||||||
).build()
|
).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createResultNotification(uri: Uri): Notification {
|
|
||||||
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setDefaults(0)
|
|
||||||
.setSilent(true)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentText(getString(R.string.backup_saved))
|
|
||||||
.setSmallIcon(R.drawable.ic_stat_done)
|
|
||||||
val shareIntent = ShareCompat.IntentBuilder(this)
|
|
||||||
.setStream(uri)
|
|
||||||
.setType(contentResolver.getType(uri) ?: "application/zip")
|
|
||||||
.setChooserTitle(R.string.share_backup)
|
|
||||||
.createChooserIntent()
|
|
||||||
notification.setContentIntent(
|
|
||||||
PendingIntentCompat.getActivity(
|
|
||||||
applicationContext,
|
|
||||||
0,
|
|
||||||
shareIntent,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return notification.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val TAG = "BACKUP"
|
private const val TAG = "BACKUP"
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import android.content.pm.ServiceInfo
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.annotation.CheckResult
|
import androidx.annotation.CheckResult
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.PendingIntentCompat
|
|
||||||
import androidx.core.app.ShareCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
@@ -37,6 +35,7 @@ import androidx.appcompat.R as appcompatR
|
|||||||
class RestoreService : BaseBackupRestoreService() {
|
class RestoreService : BaseBackupRestoreService() {
|
||||||
|
|
||||||
override val notificationTag = TAG
|
override val notificationTag = TAG
|
||||||
|
override val isRestoreService = true
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var repository: BackupRepository
|
lateinit var repository: BackupRepository
|
||||||
@@ -62,13 +61,11 @@ class RestoreService : BaseBackupRestoreService() {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
ZipInputStream(contentResolver.openInputStream(source)).use { input ->
|
val result = ZipInputStream(contentResolver.openInputStream(source)).use { input ->
|
||||||
repository.restoreBackup(input, sections, progress)
|
repository.restoreBackup(input, sections, progress)
|
||||||
}
|
}
|
||||||
progressUpdateJob?.cancelAndJoin()
|
progressUpdateJob?.cancelAndJoin()
|
||||||
if (checkNotificationPermission(CHANNEL_ID)) {
|
showResultNotification(source, result)
|
||||||
notificationManager.notify(notificationTag, startId, createResultNotification(source))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,31 +98,6 @@ class RestoreService : BaseBackupRestoreService() {
|
|||||||
).build()
|
).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createResultNotification(uri: Uri): Notification {
|
|
||||||
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setDefaults(0)
|
|
||||||
.setSilent(true)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentText(getString(R.string.backup_saved))
|
|
||||||
.setSmallIcon(R.drawable.ic_stat_done)
|
|
||||||
val shareIntent = ShareCompat.IntentBuilder(this)
|
|
||||||
.setStream(uri)
|
|
||||||
.setType(contentResolver.getType(uri) ?: "application/zip")
|
|
||||||
.setChooserTitle(R.string.share_backup)
|
|
||||||
.createChooserIntent()
|
|
||||||
notification.setContentIntent(
|
|
||||||
PendingIntentCompat.getActivity(
|
|
||||||
applicationContext,
|
|
||||||
0,
|
|
||||||
shareIntent,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return notification.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val TAG = "RESTORE"
|
private const val TAG = "RESTORE"
|
||||||
|
|||||||
Reference in New Issue
Block a user