diff --git a/app/build.gradle b/app/build.gradle index f9b707a2..594ef7fb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/libs/kotlinx-serialization-core-jvm-1.0.0-RC.jar b/app/libs/kotlinx-serialization-core-jvm-1.0.0-RC.jar deleted file mode 100644 index 02e866d4..00000000 Binary files a/app/libs/kotlinx-serialization-core-jvm-1.0.0-RC.jar and /dev/null differ diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt index f775243c..2636430b 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt @@ -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() }) diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt index 6924238a..5e53a6f0 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt @@ -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 { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + 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?, dataSource: DataSource?, isFirstResource: Boolean) = + false + }) .into(holder.view.image) } diff --git a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt index 0ff43a82..aebc9a67 100644 --- a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt +++ b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt @@ -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() 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() 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() } } \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 7e73441a..3ccc0e9e 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -13,4 +13,6 @@ + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index f7c2c182..7d4c79b7 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ allprojects { repositories { google() jcenter() + mavenLocal() maven { url "https://jitpack.io" } maven { url 'https://guardian.github.com/maven/repo-releases' } }