End service when completed

Auto redownload
This commit is contained in:
tom5079
2020-09-02 11:03:46 +09:00
parent 9583897ada
commit 2b8facfb97
7 changed files with 66 additions and 31 deletions

View File

@@ -63,7 +63,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
//implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC-HOTFIX1"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.preference:preference:1.1.1'

View File

@@ -144,6 +144,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
galleryblock_thumbnail.layoutParams.width = context.resources.getDimensionPixelSize(
R.dimen.galleryblock_thumbnail_thin
)
galleryblock_thumbnail.setImageDrawable(CircularProgressDrawable(context).also {
it.start()
})

View File

@@ -18,15 +18,20 @@
package xyz.quaver.pupil.adapters
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.LazyHeaders
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import kotlinx.android.synthetic.main.item_reader.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -40,6 +45,7 @@ import xyz.quaver.hiyobi.createImgList
import xyz.quaver.hiyobi.user_agent
import xyz.quaver.io.util.readBytes
import xyz.quaver.pupil.R
import xyz.quaver.pupil.services.DownloadService
import xyz.quaver.pupil.ui.ReaderActivity
import xyz.quaver.pupil.util.Preferences
import xyz.quaver.pupil.util.downloader.Cache
@@ -139,6 +145,23 @@ class ReaderAdapter(private val activity: ReaderActivity,
.skipMemoryCache(true)
.fitCenter()
.error(R.drawable.image_broken_variant)
.listener(object: RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
cache!!.metadata.imageList?.set(position, null)
image.delete()
DownloadService.cancel(holder.view.context, galleryID)
DownloadService.delete(holder.view.context, galleryID)
return true
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean) =
false
})
.into(holder.view.image)
}

View File

@@ -18,6 +18,7 @@
package xyz.quaver.pupil.services
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.app.Service
import android.content.Context
@@ -44,13 +45,14 @@ import xyz.quaver.pupil.ui.ReaderActivity
import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.downloader.DownloadFolderManager
import xyz.quaver.pupil.util.ellipsize
import xyz.quaver.pupil.util.normalizeID
import xyz.quaver.pupil.util.requestBuilders
import xyz.quaver.pupil.util.startForegroundServiceCompat
import java.io.IOException
private typealias ProgressListener = (DownloadService.Tag, Long, Long, Boolean) -> Unit
class DownloadService : Service() {
data class Tag(val galleryID: Int, val index: Int)
data class Tag(val galleryID: Int, val index: Int, val startId: Int? = null)
//region Notification
private val notificationManager by lazy {
@@ -68,19 +70,30 @@ class DownloadService : Service() {
private val notification = SparseArray<NotificationCompat.Builder?>()
private fun initNotification(galleryID: Int) {
val intent = Intent(this, ReaderActivity::class.java).apply {
putExtra("galleryID", galleryID)
}
val intent = Intent(this, ReaderActivity::class.java)
.putExtra("galleryID", galleryID)
val pendingIntent = TaskStackBuilder.create(this).run {
addNextIntentWithParentStack(intent)
getPendingIntent(galleryID, PendingIntent.FLAG_UPDATE_CURRENT)
}
val action =
NotificationCompat.Action.Builder(0, getText(android.R.string.cancel),
PendingIntent.getService(
this,
R.id.notification_download_cancel_action.normalizeID(),
Intent(this, DownloadService::class.java)
.putExtra(KEY_COMMAND, COMMAND_CANCEL)
.putExtra(KEY_ID, galleryID),
PendingIntent.FLAG_UPDATE_CURRENT),
).build()
notification.put(galleryID, NotificationCompat.Builder(this, "download").apply {
setContentTitle(getString(R.string.reader_loading))
setContentText(getString(R.string.reader_notification_text))
setSmallIcon(R.drawable.ic_notification) // had to use this because old android doesn't support VectorDrawable on Notification :P
setSmallIcon(R.drawable.ic_notification)
setContentIntent(pendingIntent)
addAction(action)
setProgress(0, 0, true)
setOngoing(true)
})
@@ -88,6 +101,7 @@ class DownloadService : Service() {
notify(galleryID)
}
@SuppressLint("RestrictedApi")
private fun notify(galleryID: Int) {
val max = progress[galleryID]?.size ?: 0
val progress = progress[galleryID]?.count { it.isInfinite() } ?: 0
@@ -99,6 +113,7 @@ class DownloadService : Service() {
.setContentText(getString(R.string.reader_notification_complete))
.setProgress(0, 0, false)
.setOngoing(false)
.mActions.clear()
notificationManager.cancel(galleryID)
} else
@@ -190,8 +205,6 @@ class DownloadService : Service() {
if (e.message?.contains("cancel", true) == false) {
val galleryID = (call.request().tag() as Tag).galleryID
Log.i("PUPILD", "$galleryID ERR-RETRYING $e ${e.message}")
// Retry
cancel(galleryID)
download(galleryID)
@@ -199,7 +212,7 @@ class DownloadService : Service() {
}
override fun onResponse(call: Call, response: Response) {
val (galleryID, index) = call.request().tag() as Tag
val (galleryID, index, startId) = call.request().tag() as Tag
val ext = call.request().url().encodedPath().split('.').last()
kotlin.runCatching {
@@ -212,12 +225,14 @@ class DownloadService : Service() {
progress[galleryID]?.set(index, Float.POSITIVE_INFINITY)
notify(galleryID)
if (isCompleted(galleryID))
if (DownloadFolderManager.getInstance(this@DownloadService).getDownloadFolder(galleryID) != null)
if (isCompleted(galleryID)) {
if (DownloadFolderManager.getInstance(this@DownloadService)
.getDownloadFolder(galleryID) != null)
Cache.getInstance(this@DownloadService, galleryID).moveToDownload()
}.onFailure {
Log.i("PUPILD", "$galleryID-$index DLERR-RETRYING $it ${it.message}")
startId?.let { stopSelf(it) }
}
}.onFailure {
cancel(galleryID)
download(galleryID)
}
@@ -243,7 +258,7 @@ class DownloadService : Service() {
notificationManager.cancelAll()
}
fun cancel(galleryID: Int) {
fun cancel(galleryID: Int, startId: Int? = null) {
client.dispatcher().queuedCalls().filter {
(it.request().tag() as? Tag)?.galleryID == galleryID
}.forEach {
@@ -258,15 +273,19 @@ class DownloadService : Service() {
progress.remove(galleryID)
notification.remove(galleryID)
notificationManager.cancel(galleryID)
startId?.let { stopSelf(it) }
}
fun delete(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
fun delete(galleryID: Int, startId: Int? = null) = CoroutineScope(Dispatchers.IO).launch {
cancel(galleryID)
DownloadFolderManager.getInstance(this@DownloadService).deleteDownloadFolder(galleryID)
Cache.delete(galleryID)
startId?.let { stopSelf(it) }
}
fun download(galleryID: Int, priority: Boolean = false): Job = CoroutineScope(Dispatchers.IO).launch {
fun download(galleryID: Int, priority: Boolean = false, startId: Int? = null): Job = CoroutineScope(Dispatchers.IO).launch {
if (progress.indexOfKey(galleryID) >= 0)
cancel(galleryID)
@@ -276,8 +295,6 @@ class DownloadService : Service() {
val reader = cache.getReader()
Log.i("PUPILD", "READER")
// Gallery doesn't exist
if (reader == null) {
delete(galleryID)
@@ -285,8 +302,6 @@ class DownloadService : Service() {
return@launch
}
Log.i("PUPILD", "READER OK")
if (progress.indexOfKey(galleryID) < 0)
progress.put(galleryID, mutableListOf())
@@ -294,13 +309,9 @@ class DownloadService : Service() {
progress[galleryID]?.add(if (it != null) Float.POSITIVE_INFINITY else 0F)
}
Log.i("PUPILD", "LOADED")
notification[galleryID]?.setContentTitle(reader.galleryInfo.title?.ellipsize(30))
notify(galleryID)
Log.i("PUPILD", "NOTIFY")
val queued = mutableSetOf<Int>()
if (priority) {
@@ -313,13 +324,11 @@ class DownloadService : Service() {
}
reader.requestBuilders.filterIndexed { index, _ -> !progress[galleryID]!![index].isInfinite() }.forEachIndexed { index, it ->
val request = it.tag(Tag(galleryID, index)).build()
val request = it.tag(Tag(galleryID, index, startId)).build()
client.newCall(request).enqueue(callback)
}
queued.forEach { download(it) }
Log.i("PUPILD", "OK")
}
//endregion
@@ -362,10 +371,10 @@ class DownloadService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.getStringExtra(KEY_COMMAND)) {
COMMAND_DOWNLOAD -> intent.getIntExtra(KEY_ID, -1).let { if (it > 0)
download(it, intent.getBooleanExtra(KEY_PRIORITY, false))
download(it, intent.getBooleanExtra(KEY_PRIORITY, false), startId)
}
COMMAND_CANCEL -> intent.getIntExtra(KEY_ID, -1).let { if (it > 0) cancel(it) else cancel() }
COMMAND_DELETE -> intent.getIntExtra(KEY_ID, -1).let { if (it > 0) delete(it) }
COMMAND_CANCEL -> intent.getIntExtra(KEY_ID, -1).let { if (it > 0) cancel(it, startId) else cancel() }
COMMAND_DELETE -> intent.getIntExtra(KEY_ID, -1).let { if (it > 0) delete(it, startId) }
}
return START_NOT_STICKY
@@ -385,6 +394,5 @@ class DownloadService : Service() {
override fun onDestroy() {
interceptors.remove(Tag::class)
cancel()
}
}

View File

@@ -13,4 +13,6 @@
<item name="downloader_notification_id" type="id" />
<item name="downloader_notification_request" type="id" />
<item name="notification_download_cancel_action" type="id" />
</resources>

View File

@@ -22,6 +22,7 @@ allprojects {
repositories {
google()
jcenter()
mavenLocal()
maven { url "https://jitpack.io" }
maven { url 'https://guardian.github.com/maven/repo-releases' }
}