End service when completed
Auto redownload
This commit is contained in:
@@ -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'
|
||||||
|
|||||||
Binary file not shown.
@@ -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()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
@@ -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' }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user