From 59b627664f229c2de4b91800c134947fc08684b2 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Sat, 2 Apr 2022 16:15:18 +0200 Subject: [PATCH] Fix saving failed status to drafts (#2410) * fix saving failed statuses to drafts * use coroutine delay instead of timer --- .../tusky/service/SendStatusService.kt | 125 ++++++++---------- 1 file changed, 56 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt b/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt index 6d5c7a10b..a2709f975 100644 --- a/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt +++ b/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt @@ -30,13 +30,12 @@ import dagger.android.AndroidInjection import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import retrofit2.Call import retrofit2.Callback import retrofit2.Response -import java.util.Timer -import java.util.TimerTask import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -58,8 +57,6 @@ class SendStatusService : Service(), Injectable { private val statusesToSend = ConcurrentHashMap() private val sendCalls = ConcurrentHashMap>() - private val timer = Timer() - private val notificationManager by lazy { getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } override fun onCreate() { @@ -154,56 +151,56 @@ class SendStatusService : Service(), Injectable { val callback = object : Callback { override fun onResponse(call: Call, response: Response) { + serviceScope.launch { - val scheduled = !statusToSend.scheduledAt.isNullOrEmpty() - statusesToSend.remove(statusId) + val scheduled = !statusToSend.scheduledAt.isNullOrEmpty() + statusesToSend.remove(statusId) - if (response.isSuccessful) { - // If the status was loaded from a draft, delete the draft and associated media files. - if (statusToSend.draftId != 0) { - serviceScope.launch { + if (response.isSuccessful) { + // If the status was loaded from a draft, delete the draft and associated media files. + if (statusToSend.draftId != 0) { draftHelper.deleteDraftAndAttachments(statusToSend.draftId) } - } - if (scheduled) { - response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch) + if (scheduled) { + response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch) + } else { + response.body()?.let(::StatusComposedEvent)?.let(eventHub::dispatch) + } + + notificationManager.cancel(statusId) } else { - response.body()?.let(::StatusComposedEvent)?.let(eventHub::dispatch) + // the server refused to accept the status, save status & show error message + saveStatusToDrafts(statusToSend) + + val builder = NotificationCompat.Builder(this@SendStatusService, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notify) + .setContentTitle(getString(R.string.send_post_notification_error_title)) + .setContentText(getString(R.string.send_post_notification_saved_content)) + .setColor( + ContextCompat.getColor( + this@SendStatusService, + R.color.notification_color + ) + ) + + notificationManager.cancel(statusId) + notificationManager.notify(errorNotificationId--, builder.build()) } - - notificationManager.cancel(statusId) - } else { - // the server refused to accept the status, save status & show error message - saveStatusToDrafts(statusToSend) - - val builder = NotificationCompat.Builder(this@SendStatusService, CHANNEL_ID) - .setSmallIcon(R.drawable.ic_notify) - .setContentTitle(getString(R.string.send_post_notification_error_title)) - .setContentText(getString(R.string.send_post_notification_saved_content)) - .setColor(ContextCompat.getColor(this@SendStatusService, R.color.notification_color)) - - notificationManager.cancel(statusId) - notificationManager.notify(errorNotificationId--, builder.build()) + stopSelfWhenDone() } - - stopSelfWhenDone() } override fun onFailure(call: Call, t: Throwable) { - var backoff = TimeUnit.SECONDS.toMillis(statusToSend.retries.toLong()) - if (backoff > MAX_RETRY_INTERVAL) { - backoff = MAX_RETRY_INTERVAL - } + serviceScope.launch { + var backoff = TimeUnit.SECONDS.toMillis(statusToSend.retries.toLong()) + if (backoff > MAX_RETRY_INTERVAL) { + backoff = MAX_RETRY_INTERVAL + } - timer.schedule( - object : TimerTask() { - override fun run() { - sendStatus(statusId) - } - }, - backoff - ) + delay(backoff) + sendStatus(statusId) + } } } @@ -218,7 +215,7 @@ class SendStatusService : Service(), Injectable { } } - private fun cancelSending(statusId: Int) { + private fun cancelSending(statusId: Int) = serviceScope.launch { val statusToCancel = statusesToSend.remove(statusId) if (statusToCancel != null) { val sendCall = sendCalls.remove(statusId) @@ -230,38 +227,28 @@ class SendStatusService : Service(), Injectable { .setSmallIcon(R.drawable.ic_notify) .setContentTitle(getString(R.string.send_post_notification_cancel_title)) .setContentText(getString(R.string.send_post_notification_saved_content)) - .setColor(ContextCompat.getColor(this, R.color.notification_color)) + .setColor(ContextCompat.getColor(this@SendStatusService, R.color.notification_color)) notificationManager.notify(statusId, builder.build()) - timer.schedule( - object : TimerTask() { - override fun run() { - notificationManager.cancel(statusId) - stopSelfWhenDone() - } - }, - 5000 - ) + delay(5000) } } - private fun saveStatusToDrafts(status: StatusToSend) { - serviceScope.launch { - draftHelper.saveDraft( - draftId = status.draftId, - accountId = status.accountId, - inReplyToId = status.inReplyToId, - content = status.text, - contentWarning = status.warningText, - sensitive = status.sensitive, - visibility = Status.Visibility.byString(status.visibility), - mediaUris = status.mediaUris, - mediaDescriptions = status.mediaDescriptions, - poll = status.poll, - failedToSend = true - ) - } + private suspend fun saveStatusToDrafts(status: StatusToSend) { + draftHelper.saveDraft( + draftId = status.draftId, + accountId = status.accountId, + inReplyToId = status.inReplyToId, + content = status.text, + contentWarning = status.warningText, + sensitive = status.sensitive, + visibility = Status.Visibility.byString(status.visibility), + mediaUris = status.mediaUris, + mediaDescriptions = status.mediaDescriptions, + poll = status.poll, + failedToSend = true + ) } private fun cancelSendingIntent(statusId: Int): PendingIntent {