diff --git a/app/build.gradle b/app/build.gradle
index 9c121c79..1a65c84b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -21,7 +21,7 @@ android {
minSdkVersion 16
targetSdkVersion 30
versionCode 59
- versionName "5.0.2"
+ versionName "5.0.2-hotfix1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
diff --git a/app/libs/recyclerviewfastscroller-release.aar b/app/libs/recyclerviewfastscroller-release.aar
index 9b121127..d0f8ce00 100644
Binary files a/app/libs/recyclerviewfastscroller-release.aar and b/app/libs/recyclerviewfastscroller-release.aar differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index 003d2f82..54de8e06 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -12,7 +12,7 @@
"filters": [],
"properties": [],
"versionCode": 59,
- "versionName": "5.0.1-hotfix2",
+ "versionName": "5.0.2-hotfix1",
"enabled": true,
"outputFile": "app-release.apk"
}
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 c37d0003..99408289 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
@@ -80,8 +80,8 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
CoroutineScope(Dispatchers.Main).launch {
if (cache.metadata.reader == null || Preferences["cache_disable"]) {
- view.galleryblock_progressbar.visibility = View.GONE
- view.galleryblock_progress_complete.visibility = View.GONE
+ view.galleryblock_progressbar_layout.visibility = View.GONE
+ view.galleryblock_progress_complete.visibility = View.INVISIBLE
return@launch
}
@@ -91,8 +91,10 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
progress = imageList.filterNotNull().size
max = imageList.size
- if (visibility == View.GONE)
- visibility = View.VISIBLE
+ with(view.galleryblock_progressbar_layout) {
+ if (visibility == View.GONE)
+ visibility = View.VISIBLE
+ }
if (progress == max) {
val downloadManager = DownloadManager.getInstance(context)
@@ -126,8 +128,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
}
fun bind(galleryID: Int) {
- val time = System.currentTimeMillis()
-
val cache = Cache.getInstance(view.context, galleryID)
val galleryBlock = cache.metadata.galleryBlock ?: return
@@ -223,14 +223,14 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
galleryblock_tag_group.removeAllViews()
CoroutineScope(Dispatchers.Default).launch {
- galleryBlock.relatedTags.forEach {
+ galleryBlock.relatedTags.map {
TagChip(context, Tag.parse(it)).apply {
setOnClickListener { view ->
for (callback in onChipClickedHandler)
callback.invoke((view as TagChip).tag)
}
- }.let { launch(Dispatchers.Main) { galleryblock_tag_group.addView(it) } }
- }
+ }
+ }.let { launch(Dispatchers.Main) { it.forEach { galleryblock_tag_group.addView(it) } } }
}
galleryblock_id.text = galleryBlock.id.toString()
@@ -279,7 +279,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
galleryblock_tag_group.visibility = View.GONE
}
}
- Log.i("PUPILD", "${System.currentTimeMillis() - time}")
}
}
class NextViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
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 92d6a2ad..3b4eb8bc 100644
--- a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
+++ b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
@@ -28,6 +28,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.TaskStackBuilder
import androidx.core.content.ContextCompat
+import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -42,6 +43,7 @@ import xyz.quaver.pupil.R
import xyz.quaver.pupil.client
import xyz.quaver.pupil.interceptors
import xyz.quaver.pupil.ui.ReaderActivity
+import xyz.quaver.pupil.util.Preferences
import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.downloader.DownloadManager
import xyz.quaver.pupil.util.ellipsize
@@ -309,6 +311,18 @@ class DownloadService : Service() {
progress.put(galleryID, MutableList(reader.galleryInfo.files.size) { 0F })
+ FirebaseCrashlytics.getInstance().log(
+ """
+ GALLERYID: $galleryID
+ CACHE: ${cache.findFile(".metadata")}
+ PATTERN: ${Preferences["download_folder_name", ""]}
+ READER ID: ${reader.galleryInfo.id}
+ READER SIZE: ${reader.galleryInfo.files.size}
+ CACHE READER ID: ${cache.metadata.reader?.galleryInfo?.id}}
+ CACHE READER SIZE: ${cache.metadata.reader?.galleryInfo?.files?.size}
+ """.trimIndent()
+ )
+
cache.metadata.imageList?.let {
if (progress[galleryID]?.size != it.size) {
cache.metadata.imageList?.filterNotNull()?.forEach { file ->
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt
index e54ace31..6fe1b42a 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt
@@ -18,13 +18,13 @@
package xyz.quaver.pupil.ui.dialog
-import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout.LayoutParams
+import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -53,7 +53,7 @@ import xyz.quaver.pupil.util.ItemClickSupport
import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.wordCapitalize
-class GalleryDialog(context: Context, private val glide: RequestManager, private val galleryID: Int) : Dialog(context) {
+class GalleryDialog(context: Context, private val glide: RequestManager, private val galleryID: Int) : AlertDialog(context) {
val onChipClickedHandler = ArrayList<((Tag) -> (Unit))>()
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt
index cd79be1d..ef387396 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt
@@ -27,6 +27,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
+import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.dialog_proxy.view.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@@ -40,7 +41,7 @@ import xyz.quaver.pupil.util.getProxyInfo
import xyz.quaver.pupil.util.proxyInfo
import java.net.Proxy
-class ProxyDialog(context: Context) : Dialog(context) {
+class ProxyDialog(context: Context) : AlertDialog(context) {
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(build())
diff --git a/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt b/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
deleted file mode 100644
index 46e7b8e7..00000000
--- a/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Pupil, Hitomi.la viewer for Android
- * Copyright (C) 2020 tom5079
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package xyz.quaver.pupil.util.download
-
-import android.content.Context
-import android.content.ContextWrapper
-import android.util.Base64
-import android.util.SparseArray
-import androidx.preference.PreferenceManager
-import com.google.firebase.crashlytics.FirebaseCrashlytics
-import kotlinx.coroutines.*
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
-import xyz.quaver.Code
-import xyz.quaver.hitomi.GalleryBlock
-import xyz.quaver.hitomi.Reader
-import xyz.quaver.pupil.util.getCachedGallery
-import xyz.quaver.pupil.util.getDownloadDirectory
-import xyz.quaver.pupil.util.isParentOf
-import xyz.quaver.readBytes
-import java.io.BufferedInputStream
-import java.io.File
-import java.io.FileOutputStream
-import java.io.InputStream
-import java.net.URL
-
-@Suppress("DEPRECATION")
-@Deprecated("Use downloader.Cache instead")
-class Cache(context: Context) : ContextWrapper(context) {
-
- companion object {
- private val moving = mutableListOf()
- private val readers = SparseArray()
- }
-
- private val preference = PreferenceManager.getDefaultSharedPreferences(this)
-
- // Search in this order
- // Download -> Cache
- fun getCachedGallery(galleryID: Int) = getCachedGallery(this, galleryID).also {
- if (!it.exists())
- it.mkdirs()
- }
-
- fun getCachedMetadata(galleryID: Int) : Metadata? {
- val file = File(getCachedGallery(galleryID), ".metadata")
-
- if (!file.exists())
- return null
-
- return try {
- Json.decodeFromString(file.readText())
- } catch (e: Exception) {
- //File corrupted
- file.delete()
- null
- }
- }
-
- fun setCachedMetadata(galleryID: Int, metadata: Metadata) {
- if (preference.getBoolean("cache_disable", false))
- return
-
- val file = File(getCachedGallery(galleryID), ".metadata").also {
- if (!it.exists())
- it.createNewFile()
- }
-
- file.writeText(Json.encodeToString(metadata))
- }
-
- suspend fun getThumbnail(galleryID: Int): String? {
- val metadata = Cache(this).getCachedMetadata(galleryID)
-
- @Suppress("BlockingMethodInNonBlockingContext")
- val thumbnail = if (metadata?.thumbnail == null)
- withContext(Dispatchers.IO) {
- val thumbnail = getGalleryBlock(galleryID)?.thumbnails?.firstOrNull() ?: return@withContext null
- try {
- val data = URL(thumbnail).readBytes().apply {
- if (isEmpty()) return@withContext null
- }
- Base64.encodeToString(data, Base64.DEFAULT)
- } catch (e: Exception) {
- null
- }
- }
- else
- metadata.thumbnail
-
- setCachedMetadata(
- galleryID,
- Metadata(Cache(this).getCachedMetadata(galleryID), thumbnail = thumbnail)
- )
-
- return thumbnail
- }
-
- suspend fun getGalleryBlock(galleryID: Int): GalleryBlock? {
- val metadata = Cache(this).getCachedMetadata(galleryID)
-
- val sources = listOf(
- { xyz.quaver.hitomi.getGalleryBlock(galleryID) },
- { xyz.quaver.hiyobi.getGalleryBlock(galleryID) }
- )
-
- val galleryBlock = if (metadata?.galleryBlock == null) {
- withContext(Dispatchers.IO) {
- var galleryBlock: GalleryBlock? = null
-
- for (source in sources) {
- galleryBlock = try {
- source.invoke()
- } catch (e: Exception) {
- null
- }
-
- if (galleryBlock != null)
- break
- }
-
- galleryBlock
- } ?: return null
- }
- else
- metadata.galleryBlock
-
- setCachedMetadata(
- galleryID,
- Metadata(Cache(this).getCachedMetadata(galleryID), galleryBlock = galleryBlock)
- )
-
- return galleryBlock
- }
-
- fun getReaderOrNull(galleryID: Int): Reader? {
- return readers[galleryID] ?: getCachedMetadata(galleryID)?.reader
- }
-
- suspend fun getReader(galleryID: Int): Reader? {
- val metadata = getCachedMetadata(galleryID)
- val mirrors = preference.getString("mirrors", null)?.split('>') ?: listOf()
-
- val sources = mapOf(
- Code.HITOMI to { xyz.quaver.hitomi.getReader(galleryID) },
- Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) }
- ).let {
- if (mirrors.isNotEmpty())
- it.toSortedMap{ o1, o2 ->
- mirrors.indexOf(o1.name) - mirrors.indexOf(o2.name)
- }
- else
- it
- }
-
- val reader =
- if (readers[galleryID] != null)
- return readers[galleryID]
- else if (metadata?.reader == null) {
- var retval: Reader? = null
-
- for (source in sources) {
- retval = try {
- withContext(Dispatchers.IO) {
- withTimeoutOrNull(1000) {
- source.value.invoke()
- }
- }
- } catch (e: Exception) {
- FirebaseCrashlytics.getInstance().recordException(e)
- null
- }
-
- if (retval != null)
- break
- }
-
- retval
- } else
- metadata.reader
-
- readers.put(galleryID, reader)
-
- setCachedMetadata(
- galleryID,
- Metadata(Cache(this).getCachedMetadata(galleryID), readers = reader)
- )
-
- return reader
- }
-
- val imageNameRegex = Regex("""^\d+\..+$""")
- fun getImages(galleryID: Int): List? {
- val gallery = getCachedGallery(galleryID)
-
- return gallery.list { _, name ->
- imageNameRegex.matches(name)
- }?.map {
- File(gallery, it)
- }
- }
-
- val imageExtensions = listOf(
- "png",
- "jpg",
- "webp",
- "gif"
- )
- fun getImage(galleryID: Int, index: Int): File? {
- val gallery = getCachedGallery(galleryID)
-
- for (ext in imageExtensions) {
- File(gallery, "%05d.$ext".format(index)).let {
- if (it.exists())
- return it
- }
- }
-
- return null
- }
-
-
- fun putImage(galleryID: Int, index: Int, ext: String, data: InputStream) {
- if (preference.getBoolean("cache_disable", false))
- return
-
- val cache = File(getCachedGallery(galleryID), "%05d.$ext".format(index)).also {
- if (!it.exists())
- it.createNewFile()
- }
-
- try {
- BufferedInputStream(data).use { inputStream ->
- FileOutputStream(cache).use { outputStream ->
- inputStream.copyTo(outputStream)
- }
- }
- } catch (e: Exception) {
- cache.delete()
- }
- }
-
- fun moveToDownload(galleryID: Int) {
- if (preference.getBoolean("cache_disable", false))
- return
-
- if (moving.contains(galleryID))
- return
-
- CoroutineScope(Dispatchers.IO).launch {
- val cache = getCachedGallery(galleryID).also {
- if (!it.exists())
- return@launch
- }
- val download = File(getDownloadDirectory(this@Cache), galleryID.toString())
-
- if (download.isParentOf(cache))
- return@launch
-
- FirebaseCrashlytics.getInstance().log("MOVING ${cache.canonicalPath} --> ${download.canonicalPath}")
-
- cache.copyRecursively(download, true) { file, err ->
- FirebaseCrashlytics.getInstance().log("MOVING ERROR ${file.canonicalPath} ${err.message}")
- OnErrorAction.SKIP
- }
- FirebaseCrashlytics.getInstance().log("MOVED ${cache.canonicalPath}")
-
- FirebaseCrashlytics.getInstance().log("DELETING ${cache.canonicalPath}")
- cache.deleteRecursively()
- FirebaseCrashlytics.getInstance().log("DELETED ${cache.canonicalPath}")
- }
- }
-
- fun isDownloading(galleryID: Int) = getCachedMetadata(galleryID)?.isDownloading == true
-
- fun setDownloading(galleryID: Int, isDownloading: Boolean) {
- setCachedMetadata(galleryID, Metadata(getCachedMetadata(galleryID), isDownloading = isDownloading))
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt b/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt
deleted file mode 100644
index edd22251..00000000
--- a/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Pupil, Hitomi.la viewer for Android
- * Copyright (C) 2020 tom5079
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package xyz.quaver.pupil.util.download
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.ContextWrapper
-import android.content.Intent
-import android.content.SharedPreferences
-import android.util.Log
-import android.util.SparseArray
-import androidx.core.app.NotificationCompat
-import androidx.core.app.NotificationManagerCompat
-import androidx.core.app.TaskStackBuilder
-import androidx.preference.PreferenceManager
-import com.google.firebase.crashlytics.FirebaseCrashlytics
-import kotlinx.coroutines.*
-import okhttp3.*
-import okio.*
-import xyz.quaver.Code
-import xyz.quaver.hitomi.Reader
-import xyz.quaver.hitomi.getReferer
-import xyz.quaver.hitomi.imageUrlFromImage
-import xyz.quaver.hiyobi.createImgList
-import xyz.quaver.pupil.R
-import xyz.quaver.pupil.client
-import xyz.quaver.pupil.interceptors
-import xyz.quaver.pupil.ui.ReaderActivity
-import java.io.File
-import java.io.IOException
-import java.util.concurrent.LinkedBlockingQueue
-
-@Suppress("DEPRECATION")
-@Deprecated("Use DownloadService instead")
-@OptIn(ExperimentalCoroutinesApi::class)
-class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
-
- private val preferences : SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
-
- //region ProgressListener
- @Suppress("UNCHECKED_CAST")
- private val progressListener = object: ProgressListener {
- override fun update(tag: Any?, bytesRead: Long, contentLength: Long, done: Boolean) {
- val (galleryID, index) = (tag as? Pair) ?: return
-
- if (!done && progress[galleryID]?.get(index)?.isFinite() == true)
- progress[galleryID]?.set(index, bytesRead * 100F / contentLength)
- }
- }
-
- interface ProgressListener {
- fun update(tag: Any?, bytesRead : Long, contentLength: Long, done: Boolean)
- }
-
- class ProgressResponseBody(
- val tag: Any?,
- val responseBody: ResponseBody,
- val progressListener : ProgressListener
- ) : ResponseBody() {
- private var bufferedSource : BufferedSource? = null
-
- override fun contentLength() = responseBody.contentLength()
- override fun contentType() = responseBody.contentType()
-
- override fun source(): BufferedSource {
- if (bufferedSource == null)
- bufferedSource = Okio.buffer(source(responseBody.source()))
-
- return bufferedSource!!
- }
-
- private fun source(source: Source) = object: ForwardingSource(source) {
- var totalBytesRead = 0L
-
- override fun read(sink: Buffer, byteCount: Long): Long {
- val bytesRead = super.read(sink, byteCount)
-
- totalBytesRead += if (bytesRead == -1L) 0L else bytesRead
- progressListener.update(tag, totalBytesRead, responseBody.contentLength(), bytesRead == -1L)
-
- return bytesRead
- }
-
- }
- }
-
- init {
- interceptors[Pair::class] = { chain ->
- val request = chain.request()
- var response = chain.proceed(request)
-
- var retry = 5
- while (!response.isSuccessful && retry > 0) {
- response = chain.proceed(request)
- retry--
- }
-
- response.newBuilder()
- .body(response.body()?.let {
- ProgressResponseBody(request.tag(), it, progressListener)
- }).build()
- }
- }
- //endregion
-
- //region Singleton
- companion object {
-
- @Volatile private var instance: DownloadWorker? = null
-
- fun getInstance(context: Context) =
- instance ?: synchronized(this) {
- instance ?: DownloadWorker(context).also { instance = it }
- }
- }
- //endregion
-
- val notificationManager = NotificationManagerCompat.from(context)
-
- val queue = LinkedBlockingQueue()
-
- /*
- * KEY
- * primary galleryID
- * secondary index
- * PRIMARY VALUE
- * MutableList -> Download in progress
- * null -> Loading / Gallery doesn't exist
- * SECONDARY VALUE
- * 0 <= value < 100 -> Download in progress
- * Float.POSITIVE_INFINITY -> Download completed
- */
- val progress = SparseArray?>()
- val notification = SparseArray()
-
- private val loop = loop()
- private val worker = SparseArray()
-
- fun stop() {
- queue.clear()
-
- loop.cancel()
- for (i in 0 until worker.size()) {
- val galleryID = worker.keyAt(i)
-
- Cache(this@DownloadWorker).setDownloading(galleryID, false)
- worker[galleryID]?.cancel()
- }
-
- client.dispatcher().queuedCalls().filter {
- it.request().tag() is Pair<*, *>
- }.forEach {
- it.cancel()
- }
- client.dispatcher().runningCalls().filter {
- it.request().tag() is Pair<*, *>
- }.forEach {
- it.cancel()
- }
-
- progress.clear()
- notification.clear()
- notificationManager.cancelAll()
- }
-
- fun cancel(galleryID: Int) {
- queue.remove(galleryID)
- worker[galleryID]?.cancel()
-
- client.dispatcher().queuedCalls().filter {
- ((it.request().tag() as Pair<*, *>).first as Int) == galleryID
- }.forEach {
- it.cancel()
- }
- client.dispatcher().runningCalls().filter {
- ((it.request().tag() as Pair<*, *>).first as Int) == galleryID
- }.forEach {
- it.cancel()
- }
-
- progress.remove(galleryID)
- notification.remove(galleryID)
- notificationManager.cancel(galleryID)
- }
-
- fun isCompleted(galleryID: Int) = progress[galleryID]?.all { it.isInfinite() } == true
-
- private fun queueDownload(galleryID: Int, reader: Reader, index: Int, callback: Callback) {
- val lowQuality = preferences.getBoolean("low_quality", false)
-
- val request = Request.Builder().apply {
- when (reader.code) {
- Code.HITOMI -> {
- url(
- imageUrlFromImage(
- galleryID,
- reader.galleryInfo.files[index],
- !lowQuality
- )
- )
- addHeader("Referer", getReferer(galleryID))
- }
- Code.HIYOBI -> {
- url(createImgList(galleryID, reader, lowQuality)[index].path)
- }
- else -> {
- //shouldn't be called anyway
- }
- }
- tag(galleryID to index)
- }.build()
-
- client.newCall(request).enqueue(callback)
- }
-
- private fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
- val reader = Cache(this@DownloadWorker).getReader(galleryID)
-
- //gallery doesn't exist
- if (reader == null) {
- progress.put(galleryID, null)
-
- Cache(this@DownloadWorker).setDownloading(galleryID, false)
- return@launch
- }
-
- val cache = Cache(this@DownloadWorker).getImages(galleryID)
-
- progress.put(galleryID, reader.galleryInfo.files.indices.map { index ->
- if (cache?.firstOrNull { it?.nameWithoutExtension?.toIntOrNull() == index } != null)
- Float.POSITIVE_INFINITY
- else
- 0F
- }.toMutableList())
-
- if (notification[galleryID] == null)
- initNotification(galleryID)
-
- notification[galleryID]?.setContentTitle(reader.galleryInfo.title)
- notify(galleryID)
-
- if (isCompleted(galleryID)) {
- with(Cache(this@DownloadWorker)) {
- if (isDownloading(galleryID)) {
- moveToDownload(galleryID)
- setDownloading(galleryID, false)
- }
- }
-
- return@launch
- }
-
- for (i in reader.galleryInfo.files.indices) {
- val callback = object : Callback {
- override fun onFailure(call: Call, e: IOException) {
- if (e.message?.contains("cancel", true) != false)
- return
-
- cancel(galleryID)
- queue.add(galleryID)
- }
-
- override fun onResponse(call: Call, response: Response) {
- if (response.code() != 200) {
- response.close()
- onFailure(call, IOException())
- return
- }
-
- val ext = call.request().url().encodedPath().split('.').last()
-
- try {
- response.body()!!.use {
- Cache(this@DownloadWorker).putImage(galleryID, i, ext, it.byteStream())
- }
- progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
-
- notify(galleryID)
-
- CoroutineScope(Dispatchers.IO).launch {
- if (isCompleted(galleryID)) {
- with(Cache(this@DownloadWorker)) {
- if (isDownloading(galleryID)) {
- moveToDownload(galleryID)
- setDownloading(galleryID, false)
- }
- }
- }
- }
- } catch (e: Exception) {
- FirebaseCrashlytics.getInstance().apply {
- log("FAIL ON OK ${call.request().tag()} (${e.message})")
- setCustomKey("POS", "FAIL ON OK")
- recordException(e)
- }
-
- File(Cache(this@DownloadWorker).getCachedGallery(galleryID), "%05d.$ext".format(i)).delete()
-
- cancel(galleryID)
- queue.add(galleryID)
- }
- }
- }
-
- if (progress[galleryID]?.get(i)?.isFinite() == true)
- queueDownload(galleryID, reader, i, callback)
- }
- }
-
- private fun notify(galleryID: Int) {
- val max = progress[galleryID]?.size ?: 0
- val progress = progress[galleryID]?.count { it.isInfinite() } ?: 0
-
- if (isCompleted(galleryID)) {
- notification[galleryID]
- ?.setContentText(getString(R.string.reader_notification_complete))
- ?.setSmallIcon(android.R.drawable.stat_sys_download_done)
- ?.setProgress(0, 0, false)
- ?.setOngoing(false)
-
- notificationManager.cancel(galleryID)
- } else
- notification[galleryID]
- ?.setProgress(max, progress, false)
- ?.setContentText("$progress/$max")
-
- if (Cache(this).isDownloading(galleryID) && notification[galleryID] != null)
- notification[galleryID]?.let { notificationManager.notify(galleryID, it.build()) }
- else
- notificationManager.cancel(galleryID)
- }
-
- private fun initNotification(galleryID: Int) {
- val intent = Intent(this, ReaderActivity::class.java).apply {
- putExtra("galleryID", galleryID)
- }
- val pendingIntent = TaskStackBuilder.create(this).run {
- addNextIntentWithParentStack(intent)
- getPendingIntent(galleryID, PendingIntent.FLAG_UPDATE_CURRENT)
- }
-
- notification.put(galleryID, NotificationCompat.Builder(this, "download").apply {
- setContentTitle(getString(R.string.reader_loading))
- setContentText(getString(R.string.reader_notification_text))
- setSmallIcon(android.R.drawable.stat_sys_download) // had to use this because old android doesn't support VectorDrawable on Notification :P
- setContentIntent(pendingIntent)
- setProgress(0, 0, true)
- setOngoing(true)
- })
- }
-
- private fun loop() = CoroutineScope(Dispatchers.Default).launch {
- while (true) {
- if (queue.isEmpty())
- continue
-
- val galleryID = queue.peek() ?: continue
-
- if (progress.indexOfKey(galleryID) >= 0) // Gallery already downloading!
- cancel(galleryID)
-
- if (notification[galleryID] == null)
- initNotification(galleryID)
-
- if (Cache(this@DownloadWorker).isDownloading(galleryID))
- notification[galleryID]?.let { notificationManager.notify(galleryID, it.build()) }
-
- worker.put(galleryID, download(galleryID))
- queue.poll()
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/util/download/Metadata.kt b/app/src/main/java/xyz/quaver/pupil/util/download/Metadata.kt
deleted file mode 100644
index 8dead901..00000000
--- a/app/src/main/java/xyz/quaver/pupil/util/download/Metadata.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Pupil, Hitomi.la viewer for Android
- * Copyright (C) 2020 tom5079
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package xyz.quaver.pupil.util.download
-
-import kotlinx.serialization.Serializable
-import xyz.quaver.hitomi.GalleryBlock
-import xyz.quaver.hitomi.Reader
-
-@Suppress("DEPRECATION")
-@Deprecated("Use downloader.Cache.Metadata instead")
-@Serializable
-data class Metadata(
- var thumbnail: String? = null,
- var galleryBlock: GalleryBlock? = null,
- var reader: Reader? = null,
- var isDownloading: Boolean? = null
-) {
- constructor(
- metadata: Metadata?,
- thumbnail: String? = null,
- galleryBlock: GalleryBlock? = null,
- readers: Reader? = null,
- isDownloading: Boolean? = null
- ) : this(
- thumbnail ?: metadata?.thumbnail,
- galleryBlock ?: metadata?.galleryBlock,
- readers ?: metadata?.reader,
- isDownloading ?: metadata?.isDownloading
- )
-}
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_galleryblock.xml b/app/src/main/res/layout/item_galleryblock.xml
index efab2973..678208f9 100644
--- a/app/src/main/res/layout/item_galleryblock.xml
+++ b/app/src/main/res/layout/item_galleryblock.xml
@@ -49,7 +49,7 @@
android:background="@android:color/holo_blue_dark"
android:textColor="@android:color/white"
android:text="@string/main_download"
- android:foreground="?attr/selectableItemBackground"
+ android:foreground="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
tools:ignore="UnusedAttribute" />
@@ -64,7 +64,7 @@
android:background="@android:color/holo_red_dark"
android:textColor="@android:color/white"
android:text="@string/main_delete"
- android:foreground="?attr/selectableItemBackground"
+ android:foreground="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
tools:ignore="UnusedAttribute" />
@@ -74,24 +74,38 @@
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:focusable="true"
+ android:clickable="true">
-
+ app:layout_constraintTop_toTopOf="parent">
-
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/galleryblock_progressbar_layout"/>