diff --git a/app/build.gradle b/app/build.gradle
index 0f0316d4..7c9bf7f8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -74,14 +74,12 @@ dependencies {
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
implementation 'com.github.clans:fab:1.6.4'
-
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
transitive = false
}
-
implementation 'net.rdrei.android.dirchooser:library:3.2@aar'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
diff --git a/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt b/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt
index 92c22553..2d73549c 100644
--- a/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt
@@ -105,9 +105,9 @@ class ExampleInstrumentedTest {
val galleryID = 1561552
runBlocking {
- Log.i("PUPILD", Cache(context).getReader(galleryID)?.title ?: "null")
+ Log.i("PUPILD", Cache(context).getReader(galleryID)?.galleryInfo?.title ?: "null")
}
- Log.i("PUPILD", Cache(context).getReaderOrNull(galleryID)?.title ?: "null")
+ Log.i("PUPILD", Cache(context).getReaderOrNull(galleryID)?.galleryInfo?.title ?: "null")
}
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f9bf5296..addcb73f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
+
) : RecyclerSwipeAdapter(), SwipeAdapterInterface {
+class GalleryBlockAdapter(private val context: Context, private val galleries: List) : RecyclerSwipeAdapter(), SwipeAdapterInterface {
enum class ViewType {
NEXT,
@@ -68,11 +67,12 @@ class GalleryBlockAdapter(context: Context, private val galleries: List
- Regex("^[0-9]+.+\$").matches(file.name)
- } ?: 0
+ progress = Cache(context).getImages(galleryID)?.size ?: 0
if (visibility == View.GONE) {
visibility = View.VISIBLE
@@ -126,6 +124,10 @@ class GalleryBlockAdapter(context: Context, private val galleries: List= 0) //download in progress
+ if (Cache(context).isDownloading(galleryID)) //download in progress
worker.cancel(galleryID)
else {
Cache(context).setDownloading(galleryID, true)
@@ -724,6 +731,15 @@ class MainActivity : AppCompatActivity() {
setOnMenuItemClickListener {
when(it.itemId) {
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS)
+ R.id.main_menu_thin -> {
+ main_recyclerview.apply {
+ (adapter as GalleryBlockAdapter).apply {
+ isThin = !isThin
+ }
+
+ adapter = adapter // Force to redraw
+ }
+ }
R.id.main_menu_sort_newest -> {
sortMode = SortMode.NEWEST
it.isChecked = true
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
index 5caf8770..f4a6c22e 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
@@ -362,7 +362,7 @@ class ReaderActivity : AppCompatActivity() {
window.attributes = this
}
- reader_recyclerview.adapter?.notifyDataSetChanged() // Force to redraw
+ reader_recyclerview.adapter = reader_recyclerview.adapter // Force to redraw
}
private fun scrollMode(isScroll: Boolean) {
@@ -388,7 +388,7 @@ class ReaderActivity : AppCompatActivity() {
if (worker.progress[galleryID]?.all { !it.isFinite() } == true) // If download is finished, stop animating
post {
setImageResource(R.drawable.ic_download)
- labelText = getString(R.string.reader_fab_download)
+ labelText = getString(R.string.reader_fab_download_cancel)
}
else // Or continue animate
post {
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
index 757dbf9a..14a0e7a1 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
@@ -21,21 +21,19 @@ package xyz.quaver.pupil.util.download
import android.content.Context
import android.content.ContextWrapper
import android.util.Base64
+import android.util.Log
import android.util.SparseArray
import androidx.preference.PreferenceManager
import com.crashlytics.android.Crashlytics
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.*
import kotlinx.io.InputStream
import xyz.quaver.Code
import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.Reader
import xyz.quaver.proxy
-import xyz.quaver.pupil.util.copyRecursively
import xyz.quaver.pupil.util.getCachedGallery
import xyz.quaver.pupil.util.getDownloadDirectory
+import xyz.quaver.pupil.util.isParentOf
import xyz.quaver.pupil.util.json
import java.io.File
import java.io.FileOutputStream
@@ -247,15 +245,27 @@ class Cache(context: Context) : ContextWrapper(context) {
}
}
- fun moveToDownload(galleryID: Int) {
+ fun moveToDownload(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
val cache = getCachedGallery(galleryID).also {
if (!it.exists())
- return
+ return@launch
}
- val download = File(getDownloadDirectory(this), galleryID.toString())
+ val download = File(getDownloadDirectory(this@Cache), galleryID.toString())
- cache.copyRecursively(download, true) { _, _ -> OnErrorAction.SKIP }
+ if (download.isParentOf(cache))
+ return@launch
+
+ Log.i("PUPILD", "MOVING ${cache.canonicalPath} --> ${download.canonicalPath}")
+
+ cache.copyRecursively(download, true) { file, err ->
+ Log.i("PUPILD", "MOVING ERROR ${file.canonicalPath} ${err.message}")
+ OnErrorAction.SKIP
+ }
+ Log.i("PUPILD", "MOVED ${cache.canonicalPath}")
+
+ Log.i("PUPILD", "DELETING ${cache.canonicalPath}")
cache.deleteRecursively()
+ Log.i("PUPILD", "DELETED ${cache.canonicalPath}")
}
fun isDownloading(galleryID: Int) = getCachedMetadata(galleryID)?.isDownloading == true
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
index 2d54ef0c..cd957af8 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt
@@ -149,7 +149,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
private val loop = loop()
private val worker = SparseArray()
- val clients = SparseArray()
val interceptor = Interceptor { chain ->
val request = chain.request()
@@ -159,7 +158,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
.body(ProgressResponseBody(request.tag(), response.body(), progressListener))
.build()
}
- fun buildClient() =
+ val client =
OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(0, TimeUnit.SECONDS)
@@ -172,17 +171,14 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
queue.clear()
loop.cancel()
- for (i in 0..worker.size()) {
+ for (i in 0 until worker.size()) {
val galleryID = worker.keyAt(i)
Cache(this@DownloadWorker).setDownloading(galleryID, false)
worker[galleryID]?.cancel()
}
- for (i in 0 until clients.size()) {
- clients.valueAt(i).dispatcher().cancelAll()
- }
- clients.clear()
+ client.dispatcher().cancelAll()
progress.clear()
exception.clear()
@@ -194,17 +190,19 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
queue.remove(galleryID)
worker[galleryID]?.cancel()
- clients[galleryID]?.dispatcher()?.cancelAll()
- clients.remove(galleryID)
+ client.dispatcher().queuedCalls().filter {
+ ((it.request().tag() as Pair<*, *>).first as Int) == galleryID
+ }.forEach {
+ it.cancel()
+ }
progress.remove(galleryID)
exception.remove(galleryID)
notification.remove(galleryID)
notificationManager.cancel(galleryID)
- if (progress.indexOfKey(galleryID) >= 0) {
+ if (progress.indexOfKey(galleryID) >= 0)
Cache(this@DownloadWorker).setDownloading(galleryID, false)
- }
}
fun isCompleted(galleryID: Int) = progress[galleryID]?.all { !it.isFinite() } == true
@@ -236,10 +234,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
tag(galleryID to index)
}.build()
- if (clients.get(galleryID) == null)
- clients.put(galleryID, buildClient())
-
- clients[galleryID]?.newCall(request)?.enqueue(callback)
+ client.newCall(request).enqueue(callback)
}
private fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
@@ -294,8 +289,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
notify(galleryID)
CoroutineScope(Dispatchers.IO).launch {
- if (isCompleted(galleryID) && clients.indexOfKey(galleryID) >= 0) {
- clients.remove(galleryID)
+ if (isCompleted(galleryID)) {
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
@@ -320,8 +314,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
notify(galleryID)
CoroutineScope(Dispatchers.IO).launch {
- if (isCompleted(galleryID) && clients.indexOfKey(galleryID) >= 0) {
- clients.remove(galleryID)
+ if (isCompleted(galleryID)) {
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
@@ -340,8 +333,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
notify(galleryID)
CoroutineScope(Dispatchers.IO).launch {
- if (isCompleted(galleryID) && clients.indexOfKey(galleryID) >= 0) {
- clients.remove(galleryID)
+ if (isCompleted(galleryID)) {
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
@@ -418,7 +410,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
val galleryID = queue.peek() ?: continue
- if (clients.indexOfKey(galleryID) >= 0) // Gallery already downloading!
+ if (progress.indexOfKey(galleryID) >= 0) // Gallery already downloading!
continue
if (notification[galleryID] == null)
@@ -427,10 +419,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
if (Cache(this@DownloadWorker).isDownloading(galleryID))
notificationManager.notify(galleryID, notification[galleryID].build())
- if (clients.size() >= preferences.getInt("max_download", 4))
- continue
-
- Log.i("PUPILD", "QUEUED $galleryID #${clients.size()+1}")
+ Log.i("PUPILD", "QUEUED $galleryID")
worker.put(galleryID, download(galleryID))
queue.poll()
diff --git a/app/src/main/java/xyz/quaver/pupil/util/file.kt b/app/src/main/java/xyz/quaver/pupil/util/file.kt
index 497424c1..4ed014e2 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/file.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/file.kt
@@ -26,7 +26,6 @@ import android.os.storage.StorageManager
import android.provider.DocumentsContract
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
-import kotlinx.io.IOException
import java.io.File
import java.io.FileOutputStream
import java.lang.reflect.Array
@@ -214,64 +213,5 @@ fun Uri.toFile(context: Context): File? {
return File(context.getExternalFilesDir(null)?.canonicalPath?.substringBeforeLast("/Android/data") ?: return null, folderName)
}
-fun File.copyRecursively(
- target: File,
- overwrite: Boolean = false,
- onError: (File, IOException) -> OnErrorAction = { _, exception -> throw exception }
-): Boolean {
- if (!exists()) {
- return onError(this, NoSuchFileException(file = this, reason = "The source file doesn't exist.")) !=
- OnErrorAction.TERMINATE
- }
- try {
- // We cannot break for loop from inside a lambda, so we have to use an exception here
- for (src in walkTopDown().onFail { f, e -> if (onError(f, e) == OnErrorAction.TERMINATE) throw IOException("Walk failed") }) {
- if (!src.exists()) {
- if (onError(src, NoSuchFileException(file = src, reason = "The source file doesn't exist.")) ==
- OnErrorAction.TERMINATE)
- return false
- } else {
- val relPath = src.toRelativeString(this)
- val dstFile = File(target, relPath)
- if (dstFile.exists() && !(src.isDirectory && dstFile.isDirectory)) {
- val stillExists = if (!overwrite) true else {
- if (dstFile.isDirectory)
- !dstFile.deleteRecursively()
- else
- !dstFile.delete()
- }
-
- if (stillExists) {
- if (onError(dstFile, FileAlreadyExistsException(file = src,
- other = dstFile,
- reason = "The destination file already exists.")) == OnErrorAction.TERMINATE)
- return false
-
- continue
- }
- }
-
- if (src.isDirectory) {
- dstFile.mkdirs()
- } else {
- val length = try {
- src.copyTo(dstFile, overwrite).length()
- } catch (e: IOException) {
- if (onError(src, e) == OnErrorAction.TERMINATE)
- return false
- else
- -1
- }
-
- if (length != src.length()) {
- if (onError(src, IOException("Source file wasn't copied completely, length of destination file differs.")) == OnErrorAction.TERMINATE)
- return false
- }
- }
- }
- }
- return true
- } catch (e: IOException) {
- return false
- }
-}
\ No newline at end of file
+fun File.isParentOf(another: File) =
+ another.absolutePath.startsWith(this.absolutePath)
\ No newline at end of file
diff --git a/app/src/main/res/drawable/cancel.xml b/app/src/main/res/drawable/cancel.xml
new file mode 100644
index 00000000..cad57ac3
--- /dev/null
+++ b/app/src/main/res/drawable/cancel.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/img_thumbnail.jpg b/app/src/main/res/drawable/img_thumbnail.jpg
deleted file mode 100644
index c6959911..00000000
Binary files a/app/src/main/res/drawable/img_thumbnail.jpg and /dev/null differ
diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml
index 3041a890..aa8350ee 100644
--- a/app/src/main/res/layout/activity_main_content.xml
+++ b/app/src/main/res/layout/activity_main_content.xml
@@ -82,6 +82,13 @@
android:layout_margin="16dp"
app:menu_colorNormal="@color/colorAccent">
+
+
+
+
-
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 5cb0d9a4..5c54d534 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -130,4 +130,6 @@
エラー
サーバーアドレス
サーバー
+ 簡単モード
+ すべてのダウンロード取り消し
\ No newline at end of file
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 05c173f1..99ebfe1f 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -130,4 +130,6 @@
잘못된 값
서버 주소
서버
+ 간단히 보기 모드
+ 다운로드 모두 취소
\ No newline at end of file
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
index 68307f90..64a437a1 100644
--- a/app/src/main/res/values/dimen.xml
+++ b/app/src/main/res/values/dimen.xml
@@ -11,6 +11,6 @@
8dp
- 50dp
+ 100dp
150dp
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c79b2143..fd51625d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -53,6 +53,8 @@
Email me!
Discord
+ Toggle Thin Mode
+
Sort
Newest
Popular
@@ -61,6 +63,7 @@
Current page: %1$d\nMaximum page: %2$d
Open Gallery by ID
Failed to open gallery
+ Cancel all downloads
Move to page %1$d