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.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9" 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-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.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.preference:preference:1.1.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( galleryblock_thumbnail.layoutParams.width = context.resources.getDimensionPixelSize(
R.dimen.galleryblock_thumbnail_thin R.dimen.galleryblock_thumbnail_thin
) )
galleryblock_thumbnail.setImageDrawable(CircularProgressDrawable(context).also { galleryblock_thumbnail.setImageDrawable(CircularProgressDrawable(context).also {
it.start() it.start()
}) })

View File

@@ -18,15 +18,20 @@
package xyz.quaver.pupil.adapters package xyz.quaver.pupil.adapters
import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy 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.GlideUrl
import com.bumptech.glide.load.model.LazyHeaders 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.android.synthetic.main.item_reader.view.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -40,6 +45,7 @@ import xyz.quaver.hiyobi.createImgList
import xyz.quaver.hiyobi.user_agent import xyz.quaver.hiyobi.user_agent
import xyz.quaver.io.util.readBytes import xyz.quaver.io.util.readBytes
import xyz.quaver.pupil.R import xyz.quaver.pupil.R
import xyz.quaver.pupil.services.DownloadService
import xyz.quaver.pupil.ui.ReaderActivity import xyz.quaver.pupil.ui.ReaderActivity
import xyz.quaver.pupil.util.Preferences import xyz.quaver.pupil.util.Preferences
import xyz.quaver.pupil.util.downloader.Cache import xyz.quaver.pupil.util.downloader.Cache
@@ -139,6 +145,23 @@ class ReaderAdapter(private val activity: ReaderActivity,
.skipMemoryCache(true) .skipMemoryCache(true)
.fitCenter() .fitCenter()
.error(R.drawable.image_broken_variant) .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) .into(holder.view.image)
} }

View File

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

View File

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

View File

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