Fix saving failed status to drafts (#2410)

* fix saving failed statuses to drafts

* use coroutine delay instead of timer
This commit is contained in:
Konrad Pozniak 2022-04-02 16:15:18 +02:00 committed by GitHub
parent 3d2ae4dcbb
commit 59b627664f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -30,13 +30,12 @@ import dagger.android.AndroidInjection
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
@ -58,8 +57,6 @@ class SendStatusService : Service(), Injectable {
private val statusesToSend = ConcurrentHashMap<Int, StatusToSend>() private val statusesToSend = ConcurrentHashMap<Int, StatusToSend>()
private val sendCalls = ConcurrentHashMap<Int, Call<Status>>() private val sendCalls = ConcurrentHashMap<Int, Call<Status>>()
private val timer = Timer()
private val notificationManager by lazy { getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } private val notificationManager by lazy { getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
override fun onCreate() { override fun onCreate() {
@ -154,56 +151,56 @@ class SendStatusService : Service(), Injectable {
val callback = object : Callback<Status> { val callback = object : Callback<Status> {
override fun onResponse(call: Call<Status>, response: Response<Status>) { override fun onResponse(call: Call<Status>, response: Response<Status>) {
serviceScope.launch {
val scheduled = !statusToSend.scheduledAt.isNullOrEmpty() val scheduled = !statusToSend.scheduledAt.isNullOrEmpty()
statusesToSend.remove(statusId) statusesToSend.remove(statusId)
if (response.isSuccessful) { if (response.isSuccessful) {
// If the status was loaded from a draft, delete the draft and associated media files. // If the status was loaded from a draft, delete the draft and associated media files.
if (statusToSend.draftId != 0) { if (statusToSend.draftId != 0) {
serviceScope.launch {
draftHelper.deleteDraftAndAttachments(statusToSend.draftId) draftHelper.deleteDraftAndAttachments(statusToSend.draftId)
} }
}
if (scheduled) { if (scheduled) {
response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch) response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch)
} else {
response.body()?.let(::StatusComposedEvent)?.let(eventHub::dispatch)
}
notificationManager.cancel(statusId)
} else { } 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())
} }
stopSelfWhenDone()
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()
} }
override fun onFailure(call: Call<Status>, t: Throwable) { override fun onFailure(call: Call<Status>, t: Throwable) {
var backoff = TimeUnit.SECONDS.toMillis(statusToSend.retries.toLong()) serviceScope.launch {
if (backoff > MAX_RETRY_INTERVAL) { var backoff = TimeUnit.SECONDS.toMillis(statusToSend.retries.toLong())
backoff = MAX_RETRY_INTERVAL if (backoff > MAX_RETRY_INTERVAL) {
} backoff = MAX_RETRY_INTERVAL
}
timer.schedule( delay(backoff)
object : TimerTask() { sendStatus(statusId)
override fun run() { }
sendStatus(statusId)
}
},
backoff
)
} }
} }
@ -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) val statusToCancel = statusesToSend.remove(statusId)
if (statusToCancel != null) { if (statusToCancel != null) {
val sendCall = sendCalls.remove(statusId) val sendCall = sendCalls.remove(statusId)
@ -230,38 +227,28 @@ class SendStatusService : Service(), Injectable {
.setSmallIcon(R.drawable.ic_notify) .setSmallIcon(R.drawable.ic_notify)
.setContentTitle(getString(R.string.send_post_notification_cancel_title)) .setContentTitle(getString(R.string.send_post_notification_cancel_title))
.setContentText(getString(R.string.send_post_notification_saved_content)) .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()) notificationManager.notify(statusId, builder.build())
timer.schedule( delay(5000)
object : TimerTask() {
override fun run() {
notificationManager.cancel(statusId)
stopSelfWhenDone()
}
},
5000
)
} }
} }
private fun saveStatusToDrafts(status: StatusToSend) { private suspend fun saveStatusToDrafts(status: StatusToSend) {
serviceScope.launch { draftHelper.saveDraft(
draftHelper.saveDraft( draftId = status.draftId,
draftId = status.draftId, accountId = status.accountId,
accountId = status.accountId, inReplyToId = status.inReplyToId,
inReplyToId = status.inReplyToId, content = status.text,
content = status.text, contentWarning = status.warningText,
contentWarning = status.warningText, sensitive = status.sensitive,
sensitive = status.sensitive, visibility = Status.Visibility.byString(status.visibility),
visibility = Status.Visibility.byString(status.visibility), mediaUris = status.mediaUris,
mediaUris = status.mediaUris, mediaDescriptions = status.mediaDescriptions,
mediaDescriptions = status.mediaDescriptions, poll = status.poll,
poll = status.poll, failedToSend = true
failedToSend = true )
)
}
} }
private fun cancelSendingIntent(statusId: Int): PendingIntent { private fun cancelSendingIntent(statusId: Int): PendingIntent {