Added Download feature
This commit is contained in:
@@ -406,6 +406,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
worker.cancel(galleryID)
|
worker.cancel(galleryID)
|
||||||
else {
|
else {
|
||||||
Cache(context).moveToDownload(galleryID)
|
Cache(context).moveToDownload(galleryID)
|
||||||
|
Cache(context).setDownloading(galleryID, true)
|
||||||
|
|
||||||
if (!worker.queue.contains(galleryID))
|
if (!worker.queue.contains(galleryID))
|
||||||
worker.queue.add(galleryID)
|
worker.queue.add(galleryID)
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ import io.fabric.sdk.android.Fabric
|
|||||||
import kotlinx.android.synthetic.main.activity_reader.*
|
import kotlinx.android.synthetic.main.activity_reader.*
|
||||||
import kotlinx.android.synthetic.main.activity_reader.view.*
|
import kotlinx.android.synthetic.main.activity_reader.view.*
|
||||||
import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import xyz.quaver.hitomi.Reader
|
import xyz.quaver.hitomi.Reader
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
@@ -46,8 +49,6 @@ import xyz.quaver.pupil.adapters.ReaderAdapter
|
|||||||
import xyz.quaver.pupil.util.Histories
|
import xyz.quaver.pupil.util.Histories
|
||||||
import xyz.quaver.pupil.util.download.Cache
|
import xyz.quaver.pupil.util.download.Cache
|
||||||
import xyz.quaver.pupil.util.download.DownloadWorker
|
import xyz.quaver.pupil.util.download.DownloadWorker
|
||||||
import xyz.quaver.pupil.util.getDownloadDirectory
|
|
||||||
import xyz.quaver.pupil.util.isParentOf
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
|
|
||||||
@@ -199,8 +200,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
|
|
||||||
if (!getDownloadDirectory(this).isParentOf(Cache(this).getCachedGallery(galleryID)))
|
if (!Cache(this).isDownloading(galleryID))
|
||||||
DownloadWorker.getInstance(this).cancel(galleryID)
|
DownloadWorker.getInstance(this@ReaderActivity).cancel(galleryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
@@ -253,7 +254,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
reader_download_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
reader_download_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
||||||
reader_download_progressbar.progress = worker.progress[galleryID]!!.count { !it.isFinite() }
|
reader_download_progressbar.progress = worker.progress[galleryID]?.count { !it.isFinite() } ?: 0
|
||||||
reader_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
reader_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
||||||
|
|
||||||
if (title == getString(R.string.reader_loading)) {
|
if (title == getString(R.string.reader_loading)) {
|
||||||
@@ -272,7 +273,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worker.progress[galleryID]!!.all { !it.isFinite() }) { //Download finished
|
if (worker.progress[galleryID]?.all { !it.isFinite() } == true) { //Download finished
|
||||||
reader_download_progressbar.visibility = View.GONE
|
reader_download_progressbar.visibility = View.GONE
|
||||||
|
|
||||||
animateDownloadFAB(false)
|
animateDownloadFAB(false)
|
||||||
@@ -318,14 +319,23 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
with(reader_fab_download) {
|
with(reader_fab_download) {
|
||||||
animateDownloadFAB(getDownloadDirectory(context).isParentOf(Cache(context).getCachedGallery(galleryID))) //If download in progress, animate button
|
animateDownloadFAB(Cache(context).isDownloading(galleryID)) //If download in progress, animate button
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
Cache(context).moveToDownload(galleryID)
|
if (Cache(context).isDownloading(galleryID)) {
|
||||||
|
Cache(context).setDownloading(galleryID, false)
|
||||||
|
|
||||||
|
animateDownloadFAB(false)
|
||||||
|
} else {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
Cache(context).moveToDownload(galleryID)
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache(context).setDownloading(galleryID, true)
|
||||||
animateDownloadFAB(true)
|
animateDownloadFAB(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
with(reader_fab_fullscreen) {
|
with(reader_fab_fullscreen) {
|
||||||
setImageResource(R.drawable.ic_fullscreen)
|
setImageResource(R.drawable.ic_fullscreen)
|
||||||
@@ -379,7 +389,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
setImageResource(R.drawable.ic_download)
|
setImageResource(R.drawable.ic_download)
|
||||||
labelText = getString(R.string.reader_fab_download)
|
labelText = getString(R.string.reader_fab_download)
|
||||||
}
|
}
|
||||||
else // Or continue animating
|
else // Or continue animate
|
||||||
post {
|
post {
|
||||||
icon.start()
|
icon.start()
|
||||||
labelText = getString(R.string.reader_fab_download_cancel)
|
labelText = getString(R.string.reader_fab_download_cancel)
|
||||||
@@ -389,8 +399,10 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
setImageDrawable(icon)
|
setImageDrawable(icon)
|
||||||
icon?.start()
|
icon?.start()
|
||||||
} else
|
} else {
|
||||||
setImageResource(R.drawable.ic_download)
|
setImageResource(R.drawable.ic_download)
|
||||||
|
labelText = getString(R.string.reader_fab_download)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ package xyz.quaver.pupil.util.download
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
import android.util.Log
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
@@ -218,4 +219,11 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
File(getDownloadDirectory(this), galleryID.toString()).mkdirs()
|
File(getDownloadDirectory(this), galleryID.toString()).mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isDownloading(galleryID: Int) = getCachedMetadata(galleryID)?.isDownloading == true
|
||||||
|
|
||||||
|
fun setDownloading(galleryID: Int, isDownloading: Boolean) {
|
||||||
|
Log.i("PUPILD", "$galleryID $isDownloading")
|
||||||
|
setCachedMetadata(galleryID, Metadata(getCachedMetadata(galleryID), isDownloading = isDownloading))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
|
|
||||||
override fun source(): BufferedSource {
|
override fun source(): BufferedSource {
|
||||||
if (bufferedSource == null)
|
if (bufferedSource == null)
|
||||||
bufferedSource = source(responseBody.source()).buffer()
|
bufferedSource = Okio.buffer(source(responseBody.source()))
|
||||||
|
|
||||||
return bufferedSource!!
|
return bufferedSource!!
|
||||||
}
|
}
|
||||||
@@ -143,13 +143,12 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
|
|
||||||
var retry = preferences.getInt("retry", 3)
|
var retry = preferences.getInt("retry", 3)
|
||||||
while (!response.isSuccessful && retry > 0) {
|
while (!response.isSuccessful && retry > 0) {
|
||||||
response.close()
|
|
||||||
response = chain.proceed(request)
|
response = chain.proceed(request)
|
||||||
retry--
|
retry--
|
||||||
}
|
}
|
||||||
|
|
||||||
response.newBuilder()
|
response.newBuilder()
|
||||||
.body(ProgressResponseBody(request.tag(), response.body!!, progressListener))
|
.body(ProgressResponseBody(request.tag(), response.body(), progressListener))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
.dispatcher(Dispatcher(Executors.newSingleThreadExecutor()))
|
.dispatcher(Dispatcher(Executors.newSingleThreadExecutor()))
|
||||||
@@ -159,21 +158,31 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
queue.clear()
|
queue.clear()
|
||||||
|
|
||||||
loop.cancel()
|
loop.cancel()
|
||||||
for (i in 0..worker.size())
|
for (i in 0..worker.size()) {
|
||||||
worker[worker.keyAt(i)]?.cancel()
|
val galleryID = worker.keyAt(i)
|
||||||
|
|
||||||
client.dispatcher.cancelAll()
|
Cache(this@DownloadWorker).setDownloading(galleryID, false)
|
||||||
|
worker[galleryID]?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
client.dispatcher().cancelAll()
|
||||||
|
|
||||||
progress.clear()
|
progress.clear()
|
||||||
exception.clear()
|
exception.clear()
|
||||||
|
|
||||||
|
nRunners = 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancel(galleryID: Int) {
|
fun cancel(galleryID: Int) {
|
||||||
queue.remove(galleryID)
|
queue.remove(galleryID)
|
||||||
worker[galleryID]?.cancel()
|
worker[galleryID]?.cancel()
|
||||||
|
|
||||||
client.dispatcher.queuedCalls()
|
client.dispatcher().queuedCalls()
|
||||||
.filter { it.request().tag(Pair::class.java)?.first == galleryID }
|
.filter {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
(it.request().tag() as? Pair<Int, Int>)?.first == galleryID
|
||||||
|
}
|
||||||
.forEach {
|
.forEach {
|
||||||
it.cancel()
|
it.cancel()
|
||||||
}
|
}
|
||||||
@@ -182,6 +191,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
progress.remove(galleryID)
|
progress.remove(galleryID)
|
||||||
exception.remove(galleryID)
|
exception.remove(galleryID)
|
||||||
|
|
||||||
|
Cache(this@DownloadWorker).setDownloading(galleryID, false)
|
||||||
nRunners--
|
nRunners--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,6 +241,8 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
if (reader == null) {
|
if (reader == null) {
|
||||||
progress.put(galleryID, null)
|
progress.put(galleryID, null)
|
||||||
exception.put(galleryID, null)
|
exception.put(galleryID, null)
|
||||||
|
|
||||||
|
Cache(this@DownloadWorker).setDownloading(galleryID, false)
|
||||||
nRunners--
|
nRunners--
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
@@ -251,15 +263,16 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
progress.remove(galleryID)
|
progress.remove(galleryID)
|
||||||
exception.remove(galleryID)
|
exception.remove(galleryID)
|
||||||
|
|
||||||
|
Cache(this@DownloadWorker).setDownloading(galleryID, false)
|
||||||
nRunners--
|
nRunners--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
response.use {
|
response.body().use {
|
||||||
val res = it.body!!.bytes()
|
val res = it.bytes()
|
||||||
val ext =
|
val ext =
|
||||||
call.request().url.encodedPath.split('.').last()
|
call.request().url().encodedPath().split('.').last()
|
||||||
|
|
||||||
Cache(this@DownloadWorker).putImage(galleryID, "$i.$ext", res)
|
Cache(this@DownloadWorker).putImage(galleryID, "$i.$ext", res)
|
||||||
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
|
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
|
||||||
@@ -269,6 +282,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
progress.remove(galleryID)
|
progress.remove(galleryID)
|
||||||
exception.remove(galleryID)
|
exception.remove(galleryID)
|
||||||
|
|
||||||
|
Cache(this@DownloadWorker).setDownloading(galleryID, false)
|
||||||
nRunners--
|
nRunners--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,16 +26,19 @@ import xyz.quaver.hitomi.Reader
|
|||||||
data class Metadata(
|
data class Metadata(
|
||||||
val thumbnail: String? = null,
|
val thumbnail: String? = null,
|
||||||
val galleryBlock: GalleryBlock? = null,
|
val galleryBlock: GalleryBlock? = null,
|
||||||
val readers: List<Reader>? = null
|
val readers: List<Reader>? = null,
|
||||||
|
val isDownloading: Boolean? = null
|
||||||
) {
|
) {
|
||||||
constructor(
|
constructor(
|
||||||
metadata: Metadata?,
|
metadata: Metadata?,
|
||||||
thumbnail: String? = null,
|
thumbnail: String? = null,
|
||||||
galleryBlock: GalleryBlock? = null,
|
galleryBlock: GalleryBlock? = null,
|
||||||
readers: List<Reader>? = null
|
readers: List<Reader>? = null,
|
||||||
|
isDownloading: Boolean? = null
|
||||||
) : this(
|
) : this(
|
||||||
thumbnail ?: metadata?.thumbnail,
|
thumbnail ?: metadata?.thumbnail,
|
||||||
galleryBlock ?: metadata?.galleryBlock,
|
galleryBlock ?: metadata?.galleryBlock,
|
||||||
readers ?: metadata?.readers
|
readers ?: metadata?.readers,
|
||||||
|
isDownloading ?: metadata?.isDownloading
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user