diff --git a/app/build.gradle b/app/build.gradle
index 3e89689a..3fef32d8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -29,6 +29,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.11.0"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8a646c94..766a3ca7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -25,7 +25,8 @@
+ android:parentActivityName=".MainActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize"/>
diff --git a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
index 6e9f18f7..951ff28a 100644
--- a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
@@ -218,7 +218,9 @@ class MainActivity : AppCompatActivity() {
private fun setupRecyclerView() {
with(main_recyclerview) {
- adapter = GalleryBlockAdapter(galleries)
+ adapter = GalleryBlockAdapter(galleries).apply {
+
+ }
addOnScrollListener(
object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -235,8 +237,7 @@ class MainActivity : AppCompatActivity() {
ItemClickSupport.addTo(this).setOnItemClickListener { _, position, _ ->
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
val gallery = galleries[position].first
- intent.putExtra("GALLERY_ID", gallery.id)
- intent.putExtra("GALLERY_TITLE", gallery.title)
+ intent.putExtra("galleryblock", Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), gallery))
//TODO: Maybe sprinke some transitions will be nice :D
startActivity(intent)
diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
index bf5d8b3b..8e1184dd 100644
--- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt
+++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
@@ -1,21 +1,40 @@
package xyz.quaver.pupil
-import android.content.Intent
-import android.os.Process
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+import android.os.Build
+import android.preference.PreferenceManager
+import android.util.SparseArray
import com.finotes.android.finotescore.Fn
import com.finotes.android.finotescore.ObservableApplication
import com.finotes.android.finotescore.Severity
+import kotlinx.coroutines.Job
class Pupil : ObservableApplication() {
override fun onCreate() {
+ val preference = PreferenceManager.getDefaultSharedPreferences(this)
+
super.onCreate()
Fn.init(this)
Fn.enableFrameDetection()
- Thread.setDefaultUncaughtExceptionHandler { t, e ->
- Fn.reportException(t, Exception(e), Severity.FATAL)
+ if (!preference.getBoolean("channel_created", false)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ val channel = NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_LOW).apply {
+ description = getString(R.string.channel_download_description)
+ enableLights(false)
+ enableVibration(false)
+ lockscreenVisibility = Notification.VISIBILITY_SECRET
+ }
+ manager.createNotificationChannel(channel)
+ }
+
+ preference.edit().putBoolean("channel_created", true).apply()
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
index 91e54659..039be0dc 100644
--- a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
@@ -1,7 +1,7 @@
package xyz.quaver.pupil
+import android.graphics.drawable.Drawable
import android.os.Bundle
-import android.util.Log
import android.view.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
@@ -10,37 +10,33 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
+import androidx.vectordrawable.graphics.drawable.Animatable2Compat
+import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import kotlinx.android.synthetic.main.activity_reader.*
import kotlinx.android.synthetic.main.activity_reader.view.*
import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
-import kotlinx.coroutines.*
-import kotlinx.io.IOException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
-import kotlinx.serialization.list
-import xyz.quaver.hitomi.Reader
-import xyz.quaver.hitomi.ReaderItem
-import xyz.quaver.hitomi.getReader
-import xyz.quaver.hitomi.getReferer
+import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.pupil.adapters.ReaderAdapter
+import xyz.quaver.pupil.util.GalleryDownloader
import xyz.quaver.pupil.util.ItemClickSupport
-import java.io.File
-import java.io.FileOutputStream
-import java.net.URL
-import javax.net.ssl.HttpsURLConnection
class ReaderActivity : AppCompatActivity() {
private val images = ArrayList()
- private var galleryID = 0
- private var gallerySize: Int = 0
- private var currentPage: Int = 0
- private lateinit var reader: Deferred
- private var loadJob: Job? = null
+ private lateinit var galleryBlock: GalleryBlock
+ private var gallerySize = 0
+ private var currentPage = 0
private var isScroll = true
private var isFullscreen = false
+ private lateinit var downloader: GalleryDownloader
+
private val snapHelper = PagerSnapHelper()
private var menu: Menu? = null
@@ -54,54 +50,20 @@ class ReaderActivity : AppCompatActivity() {
setContentView(R.layout.activity_reader)
- supportActionBar?.title = intent.getStringExtra("GALLERY_TITLE")
+ galleryBlock = Json(JsonConfiguration.Stable).parse(
+ GalleryBlock.serializer(),
+ intent.getStringExtra("galleryblock")
+ )
- galleryID = intent.getIntExtra("GALLERY_ID", 0)
- reader = CoroutineScope(Dispatchers.IO).async {
- val json = Json(JsonConfiguration.Stable)
- val serializer = ReaderItem.serializer().list
- val preference = PreferenceManager.getDefaultSharedPreferences(this@ReaderActivity)
- val isHiyobi = preference.getBoolean("use_hiyobi", false)
+ supportActionBar?.title = galleryBlock.title
+ supportActionBar?.setDisplayHomeAsUpEnabled(false)
- val cache = when {
- isHiyobi -> File(cacheDir, "imageCache/$galleryID/reader-hiyobi.json")
- else -> File(cacheDir, "imageCache/$galleryID/reader.json")
- }
-
- if (cache.exists()) {
- val cached = json.parse(serializer, cache.readText())
-
- if (cached.isNotEmpty())
- return@async cached
- }
-
- val reader = when {
- isHiyobi -> {
- xyz.quaver.hiyobi.getReader(galleryID).let {
- when {
- it.isEmpty() -> getReader(galleryID)
- else -> it
- }
- }
- }
- else -> {
- getReader(galleryID)
- }
- }
-
- if (reader.isEmpty())
- finish()
-
- if (!cache.parentFile.exists())
- cache.parentFile.mkdirs()
-
- cache.writeText(json.stringify(serializer, reader))
-
- reader
- }
+ initDownloader()
initView()
- loadImages()
+
+ if (!downloader.notify)
+ downloader.start()
}
override fun onResume() {
@@ -149,6 +111,9 @@ class ReaderActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
+
+ if (!downloader.notify)
+ downloader.cancel()
}
override fun onBackPressed() {
@@ -166,6 +131,85 @@ class ReaderActivity : AppCompatActivity() {
}
}
+ private fun initDownloader() {
+ var d: GalleryDownloader? = GalleryDownloader.get(galleryBlock.id)
+
+ if (d == null) {
+ d = GalleryDownloader(this, galleryBlock)
+ }
+
+ downloader = d.apply {
+ onReaderLoadedHandler = {
+ CoroutineScope(Dispatchers.Main).launch {
+ with(reader_progressbar) {
+ max = it.size
+ progress = 0
+
+ visibility = View.VISIBLE
+ }
+
+ gallerySize = it.size
+ menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/${it.size}"
+ }
+ }
+ onProgressHandler = {
+ CoroutineScope(Dispatchers.Main).launch {
+ reader_progressbar.progress = it
+ }
+ }
+ onDownloadedHandler = {
+ CoroutineScope(Dispatchers.Main).launch {
+ if (images.isEmpty()) {
+ images.addAll(it)
+ reader_recyclerview.adapter?.notifyDataSetChanged()
+ } else {
+ images.add(it.last())
+ reader_recyclerview.adapter?.notifyItemInserted(images.size-1)
+ }
+ }
+ }
+ onErrorHandler = {
+ downloader.notify = false
+ }
+ onCompleteHandler = {
+ CoroutineScope(Dispatchers.Main).launch {
+ reader_progressbar.visibility = View.GONE
+ }
+ }
+ onNotifyChangedHandler = { notify ->
+ val fab = reader_fab_download
+
+ if (notify) {
+ val icon = AnimatedVectorDrawableCompat.create(this, R.drawable.ic_downloading)
+ icon?.registerAnimationCallback(object: Animatable2Compat.AnimationCallback() {
+ override fun onAnimationEnd(drawable: Drawable?) {
+ if (downloader.notify)
+ fab.post {
+ icon.start()
+ fab.labelText = getString(R.string.reader_fab_download_cancel)
+ }
+ else
+ fab.post {
+ fab.setImageResource(R.drawable.ic_download)
+ fab.labelText = getString(R.string.reader_fab_download)
+ }
+ }
+ })
+
+ fab.setImageDrawable(icon)
+ icon?.start()
+ } else {
+ fab.setImageResource(R.drawable.ic_download)
+ }
+ }
+ }
+
+ if (downloader.notify) {
+ downloader.invokeOnReaderLoaded()
+ downloader.invokeOnNotifyChanged()
+ }
+ }
+
private fun initView() {
with(reader_recyclerview) {
adapter = ReaderAdapter(images)
@@ -208,6 +252,13 @@ class ReaderActivity : AppCompatActivity() {
reader_fab.close(true)
}
+
+ reader_fab_download.setOnClickListener {
+ downloader.notify = !downloader.notify
+
+ if (!downloader.notify)
+ downloader.clearNotification()
+ }
}
private fun fullscreen(isFullscreen: Boolean) {
@@ -237,68 +288,4 @@ class ReaderActivity : AppCompatActivity() {
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0)
}
-
- private fun loadImages() {
- fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp"
-
- loadJob = CoroutineScope(Dispatchers.Default).launch {
- val reader = reader.await()
-
- launch(Dispatchers.Main) {
- with(reader_progressbar) {
- max = reader.size
- progress = 0
-
- visibility = View.VISIBLE
- }
-
- gallerySize = reader.size
- menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/$gallerySize"
- }
-
- reader.chunked(4).forEach { chunked ->
- chunked.map {
- async(Dispatchers.IO) {
- val url = if (it.galleryInfo?.haswebp == 1) webpUrlFromUrl(it.url) else it.url
-
- val fileName: String
-
- with(url) {
- fileName = substring(lastIndexOf('/')+1)
- }
-
- val cache = File(cacheDir, "/imageCache/$galleryID/$fileName")
-
- if (!cache.exists())
- try {
- with(URL(url).openConnection() as HttpsURLConnection) {
- setRequestProperty("Referer", getReferer(galleryID))
-
- if (!cache.parentFile.exists())
- cache.parentFile.mkdirs()
-
- inputStream.copyTo(FileOutputStream(cache))
- }
- } catch (e: Exception) {
- cache.delete()
- }
-
- cache.absolutePath
- }
- }.forEach {
- val cache = it.await()
-
- launch(Dispatchers.Main) {
- images.add(cache)
- reader_recyclerview.adapter?.notifyItemInserted(images.size - 1)
- reader_progressbar.progress++
- }
- }
- }
-
- launch(Dispatchers.Main) {
- reader_progressbar.visibility = View.GONE
- }
- }
- }
}
\ No newline at end of file
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 c7c4f67e..54166f8e 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
@@ -1,6 +1,7 @@
package xyz.quaver.pupil.adapters
import android.graphics.BitmapFactory
+import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -14,9 +15,17 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonConfiguration
+import kotlinx.serialization.list
import xyz.quaver.hitomi.GalleryBlock
+import xyz.quaver.hitomi.ReaderItem
import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tag
+import java.io.File
+import java.util.*
+import kotlin.collections.ArrayList
+import kotlin.concurrent.schedule
class GalleryBlockAdapter(private val galleries: List>>) : RecyclerView.Adapter() {
@@ -35,9 +44,12 @@ class GalleryBlockAdapter(private val galleries: List()
- class ViewHolder(val view: CardView) : RecyclerView.ViewHolder(view)
- class ProgressViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
+ private var onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
+
+ class ViewHolder(val view: CardView, var galleryID: Int? = null) : RecyclerView.ViewHolder(view)
+ class ProgressViewHolder(val view: LinearLayout) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when(viewType) {
@@ -71,16 +83,62 @@ class GalleryBlockAdapter(private val galleries: List View.GONE
+ false -> View.VISIBLE
+ }
+ }
}
- override fun getItemCount() = if (galleries.isEmpty()) 0 else galleries.size+(if (noMore) 0 else 1)
+ override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
+ super.onViewDetachedFromWindow(holder)
+
+ if (holder is ViewHolder) {
+ val galleryID = holder.galleryID ?: return
+ val task = refreshTasks.get(galleryID) ?: return
+
+ refreshTasks.remove(galleryID)
+ task.cancel()
+ }
+ }
+
+ override fun getItemCount() = if (galleries.isEmpty()) 0 else galleries.size+1
override fun getItemViewType(position: Int): Int {
return when {
diff --git a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
new file mode 100644
index 00000000..ef36b282
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
@@ -0,0 +1,232 @@
+package xyz.quaver.pupil.util
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.util.SparseArray
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.app.TaskStackBuilder
+import androidx.preference.PreferenceManager
+import kotlinx.coroutines.*
+import kotlinx.io.IOException
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonConfiguration
+import kotlinx.serialization.list
+import xyz.quaver.hitomi.*
+import xyz.quaver.pupil.R
+import xyz.quaver.pupil.ReaderActivity
+import java.io.File
+import java.io.FileOutputStream
+import java.net.URL
+import javax.net.ssl.HttpsURLConnection
+
+class GalleryDownloader(
+ base: Context,
+ private val galleryBlock: GalleryBlock
+) : ContextWrapper(base) {
+
+ var notify: Boolean = false
+ set(value) {
+ if (value) {
+ field = true
+ notificationManager.notify(galleryBlock.id, notificationBuilder.build())
+
+ if (downloadJob?.isActive != true)
+ field = false
+ } else {
+ field = false
+ }
+
+ onNotifyChangedHandler?.invoke(value)
+ }
+
+ private val reader: Deferred
+ private var downloadJob: Job? = null
+
+ private lateinit var notificationBuilder: NotificationCompat.Builder
+ private lateinit var notificationManager: NotificationManagerCompat
+
+ var onReaderLoadedHandler: ((Reader) -> Unit)? = null
+ var onProgressHandler: ((Int) -> Unit)? = null
+ var onDownloadedHandler: ((List) -> Unit)? = null
+ var onErrorHandler: (() -> Unit)? = null
+ var onCompleteHandler: (() -> Unit)? = null
+ var onNotifyChangedHandler: ((Boolean) -> Unit)? = null
+
+ companion object : SparseArray()
+
+ init {
+ put(galleryBlock.id, this)
+
+ initNotification()
+
+ reader = CoroutineScope(Dispatchers.IO).async {
+ val json = Json(JsonConfiguration.Stable)
+ val serializer = ReaderItem.serializer().list
+ val preference = PreferenceManager.getDefaultSharedPreferences(this@GalleryDownloader)
+ val useHiyobi = preference.getBoolean("use_hiyobi", false)
+
+ //Check cache
+ val cache = File(cacheDir, "imageCache/${galleryBlock.id}/reader.json")
+
+ if (cache.exists()) {
+ val cached = json.parse(serializer, cache.readText())
+
+ if (cached.isNotEmpty())
+ return@async cached
+ }
+
+ //Cache doesn't exist. Load from internet
+ val reader = when {
+ useHiyobi -> {
+ xyz.quaver.hiyobi.getReader(galleryBlock.id).let {
+ when {
+ it.isEmpty() -> getReader(galleryBlock.id)
+ else -> it
+ }
+ }
+ }
+ else -> {
+ getReader(galleryBlock.id)
+ }
+ }
+
+ //Could not retrieve reader
+ if (reader.isEmpty())
+ throw IOException("Can't retrieve Reader")
+
+ //Save cache
+ if (!cache.parentFile.exists())
+ cache.parentFile.mkdirs()
+
+ cache.writeText(json.stringify(serializer, reader))
+
+ reader
+ }
+ }
+
+ private fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp"
+
+ fun start() {
+ downloadJob = CoroutineScope(Dispatchers.Default).launch {
+ val reader = reader.await()
+
+ val list = ArrayList()
+
+ onReaderLoadedHandler?.invoke(reader)
+
+ notificationBuilder
+ .setProgress(reader.size, 0, false)
+ .setContentText("0/${reader.size}")
+
+ reader.chunked(4).forEachIndexed { chunkIndex, chunked ->
+ chunked.mapIndexed { i, it ->
+ val index = chunkIndex*4+i
+
+ onProgressHandler?.invoke(index)
+
+ notificationBuilder
+ .setProgress(reader.size, index, false)
+ .setContentText("$index/${reader.size}")
+
+ if (notify)
+ notificationManager.notify(galleryBlock.id, notificationBuilder.build())
+
+ async(Dispatchers.IO) {
+ val url = if (it.galleryInfo?.haswebp == 1) webpUrlFromUrl(it.url) else it.url
+
+ val name = "$index".padStart(4, '0')
+ val ext = url.split('.').last()
+
+ val cache = File(cacheDir, "/imageCache/${galleryBlock.id}/images/$name.$ext")
+
+ if (!cache.exists())
+ try {
+ with(URL(url).openConnection() as HttpsURLConnection) {
+ setRequestProperty("Referer", getReferer(galleryBlock.id))
+
+ if (!cache.parentFile.exists())
+ cache.parentFile.mkdirs()
+
+ inputStream.copyTo(FileOutputStream(cache))
+ }
+ } catch (e: Exception) {
+ cache.delete()
+
+ onErrorHandler?.invoke()
+
+ notificationBuilder
+ .setContentTitle(galleryBlock.title)
+ .setContentText(getString(R.string.reader_notification_error))
+ .setProgress(0, 0, false)
+
+ notificationManager.notify(galleryBlock.id, notificationBuilder.build())
+ }
+
+ cache.absolutePath
+ }
+ }.forEach {
+ list.add(it.await())
+ onDownloadedHandler?.invoke(list)
+ }
+ }
+
+ onCompleteHandler?.invoke()
+
+ notificationBuilder
+ .setContentTitle(galleryBlock.title)
+ .setContentText(getString(R.string.reader_notification_complete))
+ .setProgress(0, 0, false)
+
+ if (notify)
+ notificationManager.notify(galleryBlock.id, notificationBuilder.build())
+
+ notify = false
+
+ remove(galleryBlock.id)
+ }
+ }
+
+ fun cancel() {
+ downloadJob?.cancel()
+
+ remove(galleryBlock.id)
+ }
+
+ fun invokeOnReaderLoaded() {
+ CoroutineScope(Dispatchers.Default).launch {
+ onReaderLoadedHandler?.invoke(reader.await())
+ }
+ }
+
+ fun clearNotification() {
+ notificationManager.cancel(galleryBlock.id)
+ }
+
+ fun invokeOnNotifyChanged() {
+ onNotifyChangedHandler?.invoke(notify)
+ }
+
+ private fun initNotification() {
+ val intent = Intent(this, ReaderActivity::class.java).apply {
+ putExtra("galleryblock", Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), galleryBlock))
+ }
+ val pendingIntent = TaskStackBuilder.create(this).run {
+ addNextIntentWithParentStack(intent)
+ getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
+
+ notificationBuilder = NotificationCompat.Builder(this, "download").apply {
+ setContentTitle(galleryBlock.title)
+ setContentText(getString(R.string.reader_notification_text))
+ setSmallIcon(R.drawable.ic_download)
+ setContentIntent(pendingIntent)
+ setProgress(0, 0, true)
+ priority = NotificationCompat.PRIORITY_LOW
+ }
+ notificationManager = NotificationManagerCompat.from(this)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/util/history.kt b/app/src/main/java/xyz/quaver/pupil/util/history.kt
index b0ad4395..a7fdce46 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/history.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/history.kt
@@ -1,6 +1,5 @@
package xyz.quaver.pupil.util
-import kotlinx.io.IOException
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
@@ -8,7 +7,6 @@ import kotlinx.serialization.parseList
import kotlinx.serialization.stringify
import java.io.File
-
class Histories(private val file: File) : ArrayList() {
init {
diff --git a/app/src/main/java/xyz/quaver/pupil/util/progress.kt b/app/src/main/java/xyz/quaver/pupil/util/progress.kt
deleted file mode 100644
index 554cfe05..00000000
--- a/app/src/main/java/xyz/quaver/pupil/util/progress.kt
+++ /dev/null
@@ -1,2 +0,0 @@
-package xyz.quaver.pupil.util
-
diff --git a/app/src/main/res/drawable-anydpi/ic_downloading.xml b/app/src/main/res/drawable-anydpi/ic_downloading.xml
new file mode 100644
index 00000000..9188c5f3
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi/ic_downloading.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml
new file mode 100644
index 00000000..c95797c1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_download.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml
index 0e0c6bd7..59ff93c1 100644
--- a/app/src/main/res/layout/activity_reader.xml
+++ b/app/src/main/res/layout/activity_reader.xml
@@ -41,6 +41,15 @@
android:layout_gravity="bottom|end"
app:menu_colorNormal="@color/colorAccent">
+
+
-
-
\ 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 69883a53..594363a9 100644
--- a/app/src/main/res/layout/item_galleryblock.xml
+++ b/app/src/main/res/layout/item_galleryblock.xml
@@ -18,6 +18,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+
+
-
-
-
\ No newline at end of file
+ app:chipCornerRadius="100dp"/>
\ No newline at end of file
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index a0018929..eff3b9be 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -44,4 +44,11 @@
準備中
準備中です。
フルスクリーン
+ ダウンロード
+ ダウンロードの進行を通知
+ バックグラウンドダウンロード
+ ダウンロード中…
+ ダウンロード完了
+ ダウンロードエラー
+ バックグラウンドダウンロード中止
\ 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 ed39440d..40800583 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -44,4 +44,11 @@
준비 중
준비중입니다.
전체 화면
+ 다운로드
+ 다운로드 상태 알림
+ 백그라운드 다운로드
+ 다운로드 중…
+ 다운로드 완료
+ 다운로드 오류
+ 백그라운드 다운로드 취소
\ 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 e004b06b..b137f139 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
-
- Pupil
+
+ Pupil
https://api.github.com/repos/tom5079/Pupil-issue/releases
Pupil-v(\\d+\\.)+\\d+\\.apk
@@ -22,6 +22,9 @@
Denying any permission can deactivate some functions
+ Download
+ Shows download status
+
Search
No result
@@ -49,6 +52,11 @@
Go to page
Fullscreen
+ Background download
+ Cancel background download
+ Downloading…
+ Download complete
+ Download error
Settings
Search Settings
diff --git a/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt b/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt
index fec18cac..c4a08536 100644
--- a/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt
+++ b/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt
@@ -12,7 +12,6 @@ import org.junit.Test
class ExampleUnitTest {
@Test
- @ImplicitReflectionSerializer
fun test() {
}
diff --git a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt
index b573e193..e85582af 100644
--- a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt
+++ b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt
@@ -7,9 +7,7 @@ import java.net.URL
class UnitTest {
@Test
fun test() {
- val f = File("C:/Users/tom50/Workspace/Pupil/nodir/nodir/asdf.txt")
-
- f.delete()
+ print(File("C:\\asdf").list()?.size ?: 0)
}
@Test