Applying changed Download routines
This commit is contained in:
1
.idea/codeStyles/Project.xml
generated
1
.idea/codeStyles/Project.xml
generated
@@ -1,5 +1,6 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="RIGHT_MARGIN" value="120" />
|
||||||
<AndroidXmlCodeStyleSettings>
|
<AndroidXmlCodeStyleSettings>
|
||||||
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
|
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
|
||||||
</AndroidXmlCodeStyleSettings>
|
</AndroidXmlCodeStyleSettings>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.rule.ActivityTestRule
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
@@ -37,6 +38,7 @@ import xyz.quaver.hiyobi.createImgList
|
|||||||
import xyz.quaver.hiyobi.getReader
|
import xyz.quaver.hiyobi.getReader
|
||||||
import xyz.quaver.hiyobi.user_agent
|
import xyz.quaver.hiyobi.user_agent
|
||||||
import xyz.quaver.pupil.ui.LockActivity
|
import xyz.quaver.pupil.ui.LockActivity
|
||||||
|
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.getDownloadDirectory
|
||||||
import xyz.quaver.pupil.util.updateOldReaderGalleries
|
import xyz.quaver.pupil.util.updateOldReaderGalleries
|
||||||
@@ -139,4 +141,17 @@ class ExampleInstrumentedTest {
|
|||||||
|
|
||||||
Log.i("PUPILD", "DONE!!")
|
Log.i("PUPILD", "DONE!!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_getReaderOrNull() {
|
||||||
|
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
|
||||||
|
val galleryID = 1561552
|
||||||
|
|
||||||
|
runBlocking {
|
||||||
|
Log.i("PUPILD", Cache(context).getReader(galleryID)?.title ?: "null")
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i("PUPILD", Cache(context).getReaderOrNull(galleryID)?.title ?: "null")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,9 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.adapters
|
package xyz.quaver.pupil.adapters
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.Base64
|
||||||
import android.util.SparseBooleanArray
|
import android.util.SparseBooleanArray
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -29,7 +31,7 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
import com.bumptech.glide.RequestManager
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.daimajia.swipe.SwipeLayout
|
import com.daimajia.swipe.SwipeLayout
|
||||||
import com.daimajia.swipe.adapters.RecyclerSwipeAdapter
|
import com.daimajia.swipe.adapters.RecyclerSwipeAdapter
|
||||||
@@ -37,28 +39,22 @@ import com.daimajia.swipe.interfaces.SwipeAdapterInterface
|
|||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import kotlinx.android.synthetic.main.item_galleryblock.view.*
|
import kotlinx.android.synthetic.main.item_galleryblock.view.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
|
||||||
import xyz.quaver.hitomi.GalleryBlock
|
import xyz.quaver.hitomi.GalleryBlock
|
||||||
import xyz.quaver.hitomi.Reader
|
|
||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.BuildConfig
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.util.GalleryDownloader
|
|
||||||
import xyz.quaver.pupil.util.Histories
|
import xyz.quaver.pupil.util.Histories
|
||||||
import xyz.quaver.pupil.util.getCachedGallery
|
import xyz.quaver.pupil.util.download.Cache
|
||||||
|
import xyz.quaver.pupil.util.download.DownloadWorker
|
||||||
import xyz.quaver.pupil.util.wordCapitalize
|
import xyz.quaver.pupil.util.wordCapitalize
|
||||||
import java.io.File
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.HashMap
|
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
|
|
||||||
class GalleryBlockAdapter(private val glide: RequestManager, private val galleries: List<Pair<GalleryBlock, Deferred<String>>>) : RecyclerSwipeAdapter<RecyclerView.ViewHolder>(), SwipeAdapterInterface {
|
class GalleryBlockAdapter(context: Context, private val galleries: List<GalleryBlock>) : RecyclerSwipeAdapter<RecyclerView.ViewHolder>(), SwipeAdapterInterface {
|
||||||
|
|
||||||
enum class ViewType {
|
enum class ViewType {
|
||||||
NEXT,
|
NEXT,
|
||||||
@@ -66,10 +62,13 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
PREV
|
PREV
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val glide = Glide.with(context)
|
||||||
private lateinit var favorites: Histories
|
private lateinit var favorites: Histories
|
||||||
|
|
||||||
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
fun bind(item: Pair<GalleryBlock, Deferred<String>>) {
|
var timerTask: TimerTask? = null
|
||||||
|
|
||||||
|
fun bind(galleryBlock: GalleryBlock) {
|
||||||
with(view) {
|
with(view) {
|
||||||
val resources = context.resources
|
val resources = context.resources
|
||||||
val languages = resources.getStringArray(R.array.languages).map {
|
val languages = resources.getStringArray(R.array.languages).map {
|
||||||
@@ -78,16 +77,14 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
}
|
}
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
val (galleryBlock: GalleryBlock, thumbnail: Deferred<String>) = item
|
|
||||||
|
|
||||||
val artists = galleryBlock.artists
|
val artists = galleryBlock.artists
|
||||||
val series = galleryBlock.series
|
val series = galleryBlock.series
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
val cache = thumbnail.await()
|
val thumbnail = Base64.decode(Cache(context).getThumbnail(galleryBlock.id), Base64.DEFAULT)
|
||||||
|
|
||||||
glide
|
glide
|
||||||
.load(cache)
|
.load(thumbnail)
|
||||||
.skipMemoryCache(true)
|
.skipMemoryCache(true)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.error(R.drawable.image_broken_variant)
|
.error(R.drawable.image_broken_variant)
|
||||||
@@ -99,48 +96,44 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Check cache
|
//Check cache
|
||||||
val readerCache = { File(getCachedGallery(context, galleryBlock.id), "reader.json") }
|
val cache = Cache(context).getCachedGallery(galleryBlock.id)
|
||||||
val imageCache = { File(getCachedGallery(context, galleryBlock.id), "images") }
|
val reader = Cache(context).getReaderOrNull(galleryBlock.id)
|
||||||
|
|
||||||
try {
|
if (cache != null && reader != null) {
|
||||||
Json(JsonConfiguration.Stable)
|
val count = cache.listFiles { file ->
|
||||||
.parse(Reader.serializer(), readerCache.invoke().readText())
|
file.nameWithoutExtension.toIntOrNull() != null
|
||||||
} catch(e: Exception) {
|
}?.size ?: 0
|
||||||
readerCache.invoke().delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readerCache.invoke().exists()) {
|
|
||||||
val reader = Json(JsonConfiguration.Stable)
|
|
||||||
.parse(Reader.serializer(), readerCache.invoke().readText())
|
|
||||||
|
|
||||||
with(galleryblock_progressbar) {
|
with(galleryblock_progressbar) {
|
||||||
max = reader.galleryInfo.size
|
max = reader.galleryInfo.size
|
||||||
progress = imageCache.invoke().list()?.size ?: 0
|
progress = count
|
||||||
|
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
galleryblock_progressbar.visibility = View.GONE
|
galleryblock_progressbar.visibility = View.GONE
|
||||||
|
|
||||||
|
if (timerTask == null)
|
||||||
|
timerTask = Timer().schedule(0, 1000) {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
val _cache = Cache(context).getCachedGallery(galleryBlock.id)
|
||||||
|
val _reader = Cache(context).getReaderOrNull(galleryBlock.id)
|
||||||
|
|
||||||
|
if (_reader == null) {
|
||||||
|
view.galleryblock_progressbar.visibility = View.GONE
|
||||||
|
view.galleryblock_progress_complete.visibility = View.GONE
|
||||||
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refreshTasks[this@GalleryViewHolder] == null) {
|
|
||||||
val refresh = Timer(false).schedule(0, 1000) {
|
|
||||||
post {
|
|
||||||
with(view.galleryblock_progressbar) {
|
with(view.galleryblock_progressbar) {
|
||||||
progress = imageCache.invoke().list()?.size ?: 0
|
|
||||||
|
|
||||||
if (!readerCache.invoke().exists()) {
|
progress = _cache?.listFiles { file ->
|
||||||
visibility = View.GONE
|
file.nameWithoutExtension.toIntOrNull() != null
|
||||||
max = 0
|
}?.size ?: 0
|
||||||
progress = 0
|
|
||||||
|
|
||||||
view.galleryblock_progress_complete.visibility = View.INVISIBLE
|
|
||||||
} else {
|
|
||||||
if (visibility == View.GONE) {
|
if (visibility == View.GONE) {
|
||||||
val reader = Json(JsonConfiguration.Stable)
|
|
||||||
.parse(Reader.serializer(), readerCache.invoke().readText())
|
|
||||||
max = reader.galleryInfo.size
|
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
|
max = _reader.galleryInfo.size
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress == max) {
|
if (progress == max) {
|
||||||
@@ -163,10 +156,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
refreshTasks[this@GalleryViewHolder] = refresh
|
|
||||||
}
|
|
||||||
|
|
||||||
galleryblock_title.text = galleryBlock.title
|
galleryblock_title.text = galleryBlock.title
|
||||||
with(galleryblock_artist) {
|
with(galleryblock_artist) {
|
||||||
@@ -277,7 +266,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val refreshTasks = HashMap<GalleryViewHolder, TimerTask>()
|
|
||||||
val completeFlag = SparseBooleanArray()
|
val completeFlag = SparseBooleanArray()
|
||||||
|
|
||||||
val onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
|
val onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
|
||||||
@@ -336,10 +324,11 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
override fun onStartOpen(layout: SwipeLayout?) {
|
override fun onStartOpen(layout: SwipeLayout?) {
|
||||||
mItemManger.closeAllExcept(layout)
|
mItemManger.closeAllExcept(layout)
|
||||||
|
|
||||||
holder.view.galleryblock_download.text = when(GalleryDownloader.get(gallery.first.id)) {
|
holder.view.galleryblock_download.text =
|
||||||
null -> holder.view.context.getString(R.string.main_download)
|
if (DownloadWorker.getInstance(holder.view.context).progress.indexOfKey(gallery.id) < 0)
|
||||||
else -> holder.view.context.getString(android.R.string.cancel)
|
holder.view.context.getString(R.string.main_download)
|
||||||
}
|
else
|
||||||
|
holder.view.context.getString(android.R.string.cancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClose(layout: SwipeLayout?) {}
|
override fun onClose(layout: SwipeLayout?) {}
|
||||||
@@ -354,12 +343,8 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
|
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
|
||||||
super.onViewDetachedFromWindow(holder)
|
super.onViewDetachedFromWindow(holder)
|
||||||
|
|
||||||
if (holder is GalleryViewHolder) {
|
if (holder is GalleryViewHolder)
|
||||||
val task = refreshTasks[holder] ?: return
|
holder.timerTask?.cancel()
|
||||||
|
|
||||||
task.cancel()
|
|
||||||
refreshTasks.remove(holder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() =
|
override fun getItemCount() =
|
||||||
|
|||||||
@@ -18,30 +18,47 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.adapters
|
package xyz.quaver.pupil.adapters
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.RequestManager
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.item_reader.view.*
|
import kotlinx.android.synthetic.main.item_reader.view.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import xyz.quaver.hitomi.Reader
|
import xyz.quaver.hitomi.Reader
|
||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.BuildConfig
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.util.GalleryDownloader
|
import xyz.quaver.pupil.util.download.Cache
|
||||||
import xyz.quaver.pupil.util.getCachedGallery
|
import xyz.quaver.pupil.util.download.DownloadWorker
|
||||||
import java.io.File
|
import java.util.*
|
||||||
|
import kotlin.concurrent.schedule
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class ReaderAdapter(private val glide: RequestManager,
|
class ReaderAdapter(private val context: Context,
|
||||||
private val galleryID: Int,
|
private val galleryID: Int) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
||||||
private val images: List<String>) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
var isFullScreen = false
|
var isFullScreen = false
|
||||||
|
|
||||||
|
var reader: Reader? = null
|
||||||
|
private val glide = Glide.with(context)
|
||||||
|
|
||||||
var onItemClickListener : ((Int) -> (Unit))? = null
|
var onItemClickListener : ((Int) -> (Unit))? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
reader = Cache(context).getReader(galleryID)
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view)
|
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
@@ -60,38 +77,62 @@ class ReaderAdapter(private val glide: RequestManager,
|
|||||||
else
|
else
|
||||||
holder.view.layoutParams.height = RecyclerView.LayoutParams.WRAP_CONTENT
|
holder.view.layoutParams.height = RecyclerView.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
var reader: Reader? = null
|
|
||||||
with (GalleryDownloader[galleryID]?.reader) {
|
|
||||||
if (reader == null && this?.isCompleted == true)
|
|
||||||
runBlocking {
|
|
||||||
reader = await()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.view.image.setOnPhotoTapListener { _, _, _ ->
|
holder.view.image.setOnPhotoTapListener { _, _, _ ->
|
||||||
onItemClickListener?.invoke(position)
|
onItemClickListener?.invoke(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(holder.view.container.layoutParams as ConstraintLayout.LayoutParams)
|
||||||
|
.dimensionRatio = "${reader!!.galleryInfo[position].width}:${reader!!.galleryInfo[position].height}"
|
||||||
|
|
||||||
|
holder.view.reader_item_progressbar.progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position)?.roundToInt() ?: 0
|
||||||
|
holder.view.reader_index.text = (position+1).toString()
|
||||||
|
|
||||||
|
val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position)
|
||||||
|
if (progress?.isFinite() == false) {
|
||||||
|
when {
|
||||||
|
progress.isInfinite() -> {
|
||||||
|
var image = Cache(context).getImages(galleryID)
|
||||||
|
|
||||||
|
while (image?.get(position) == null)
|
||||||
|
image = Cache(context).getImages(galleryID)
|
||||||
|
|
||||||
glide
|
glide
|
||||||
.load(File(getCachedGallery(holder.view.context, galleryID), images[position]))
|
.load(image[position])
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.skipMemoryCache(true)
|
.skipMemoryCache(true)
|
||||||
.error(R.drawable.image_broken_variant)
|
.error(R.drawable.image_broken_variant)
|
||||||
.apply {
|
.apply {
|
||||||
if (BuildConfig.CENSOR)
|
if (BuildConfig.CENSOR)
|
||||||
override(5, 8)
|
override(5, 8)
|
||||||
else {
|
|
||||||
val galleryInfo = reader?.galleryInfo?.get(position)
|
|
||||||
|
|
||||||
if (galleryInfo != null) {
|
|
||||||
(holder.view.image.layoutParams as ConstraintLayout.LayoutParams)
|
|
||||||
.dimensionRatio = "${galleryInfo.width}:${galleryInfo.height}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.into(holder.view.image)
|
.into(holder.view.image)
|
||||||
}
|
}
|
||||||
|
progress.isNaN() -> {
|
||||||
|
glide
|
||||||
|
.load(R.drawable.image_broken_variant)
|
||||||
|
.into(holder.view.image)
|
||||||
|
Snackbar
|
||||||
|
.make(
|
||||||
|
holder.view,
|
||||||
|
DownloadWorker.getInstance(context).exception[galleryID]!![position]?.message
|
||||||
|
?: context.getText(R.string.default_error_msg),
|
||||||
|
Snackbar.LENGTH_INDEFINITE
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getItemCount() = images.size
|
} else {
|
||||||
|
holder.view.image.setImageDrawable(null)
|
||||||
|
|
||||||
|
Timer().schedule(1000) {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = reader?.galleryInfo?.size ?: 0
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,6 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
|||||||
import com.arlib.floatingsearchview.FloatingSearchView
|
import com.arlib.floatingsearchview.FloatingSearchView
|
||||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import com.arlib.floatingsearchview.util.view.SearchInputView
|
import com.arlib.floatingsearchview.util.view.SearchInputView
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.activity_main_content.*
|
import kotlinx.android.synthetic.main.activity_main_content.*
|
||||||
@@ -64,11 +63,10 @@ import xyz.quaver.pupil.types.TagSuggestion
|
|||||||
import xyz.quaver.pupil.types.Tags
|
import xyz.quaver.pupil.types.Tags
|
||||||
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
||||||
import xyz.quaver.pupil.util.*
|
import xyz.quaver.pupil.util.*
|
||||||
|
import xyz.quaver.pupil.util.download.Cache
|
||||||
|
import xyz.quaver.pupil.util.download.DownloadWorker
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.net.ssl.HttpsURLConnection
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
@@ -89,7 +87,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
POPULAR
|
POPULAR
|
||||||
}
|
}
|
||||||
|
|
||||||
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
|
private val galleries = ArrayList<GalleryBlock>()
|
||||||
|
|
||||||
private var query = ""
|
private var query = ""
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -386,7 +384,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
with(main_recyclerview) {
|
with(main_recyclerview) {
|
||||||
adapter = GalleryBlockAdapter(Glide.with(this@MainActivity), galleries).apply {
|
adapter = GalleryBlockAdapter(this@MainActivity, galleries).apply {
|
||||||
onChipClickedHandler.add {
|
onChipClickedHandler.add {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
query = it.toQuery()
|
query = it.toQuery()
|
||||||
@@ -399,20 +397,18 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onDownloadClickedHandler = { position ->
|
onDownloadClickedHandler = { position ->
|
||||||
val galleryID = galleries[position].first.id
|
val galleryID = galleries[position].id
|
||||||
|
|
||||||
if (!completeFlag.get(galleryID, false)) {
|
if (!completeFlag.get(galleryID, false)) {
|
||||||
val downloader = GalleryDownloader.get(galleryID)
|
val worker = DownloadWorker.getInstance(context)
|
||||||
|
|
||||||
if (downloader == null)
|
if (worker.progress.indexOfKey(galleryID) >= 0) //download in progress
|
||||||
GalleryDownloader(
|
worker.cancel(galleryID)
|
||||||
context,
|
|
||||||
galleryID,
|
|
||||||
true
|
|
||||||
).start()
|
|
||||||
else {
|
else {
|
||||||
downloader.cancel()
|
Cache(context).moveToDownload(galleryID)
|
||||||
downloader.clearNotification()
|
|
||||||
|
if (!worker.queue.contains(galleryID))
|
||||||
|
worker.queue.add(galleryID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,39 +416,28 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDeleteClickedHandler = { position ->
|
onDeleteClickedHandler = { position ->
|
||||||
val galleryID = galleries[position].first.id
|
val galleryID = galleries[position].id
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
with(GalleryDownloader[galleryID]) {
|
DownloadWorker.getInstance(context).cancel(galleryID)
|
||||||
this?.cancelAndJoin()
|
|
||||||
this?.clearNotification()
|
var cache = Cache(context).getCachedGallery(galleryID)
|
||||||
}
|
|
||||||
val cache = File(cacheDir, "imageCache/${galleryID}")
|
while (cache != null) {
|
||||||
val data = getCachedGallery(context, galleryID)
|
|
||||||
cache.deleteRecursively()
|
cache.deleteRecursively()
|
||||||
data.deleteRecursively()
|
cache = Cache(context).getCachedGallery(galleryID)
|
||||||
|
}
|
||||||
|
|
||||||
downloads.remove(galleryID)
|
downloads.remove(galleryID)
|
||||||
|
|
||||||
if (this@MainActivity.mode == Mode.DOWNLOAD) {
|
|
||||||
runOnUiThread {
|
|
||||||
cancelFetch()
|
|
||||||
clearGalleries()
|
|
||||||
fetchGalleries(query, sortMode)
|
|
||||||
loadBlocks()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
histories.remove(galleryID)
|
histories.remove(galleryID)
|
||||||
|
|
||||||
if (this@MainActivity.mode == Mode.HISTORY) {
|
if (this@MainActivity.mode != Mode.SEARCH)
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query, sortMode)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
completeFlag.put(galleryID, false)
|
completeFlag.put(galleryID, false)
|
||||||
}
|
}
|
||||||
@@ -466,7 +451,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
return@setOnItemClickListener
|
return@setOnItemClickListener
|
||||||
|
|
||||||
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
||||||
val gallery = galleries[position].first
|
val gallery = galleries[position]
|
||||||
intent.putExtra("galleryID", gallery.id)
|
intent.putExtra("galleryID", gallery.id)
|
||||||
|
|
||||||
//TODO: Maybe sprinkling some transitions will be nice :D
|
//TODO: Maybe sprinkling some transitions will be nice :D
|
||||||
@@ -478,7 +463,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (v !is CardView)
|
if (v !is CardView)
|
||||||
return@setOnItemLongClickListener true
|
return@setOnItemLongClickListener true
|
||||||
|
|
||||||
val galleryID = galleries[position].first.id
|
val galleryID = galleries[position].id
|
||||||
|
|
||||||
GalleryDialog(
|
GalleryDialog(
|
||||||
this@MainActivity,
|
this@MainActivity,
|
||||||
@@ -1030,7 +1015,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val json = Json(JsonConfiguration.Stable)
|
val json = Json(JsonConfiguration.Stable)
|
||||||
val serializer = GalleryBlock.serializer()
|
val serializer = GalleryBlock.serializer()
|
||||||
|
|
||||||
val galleryBlock =
|
|
||||||
File(getCachedGallery(this@MainActivity, galleryID), "galleryBlock.json").let { cache ->
|
File(getCachedGallery(this@MainActivity, galleryID), "galleryBlock.json").let { cache ->
|
||||||
when {
|
when {
|
||||||
cache.exists() -> json.parse(serializer, cache.readText())
|
cache.exists() -> json.parse(serializer, cache.readText())
|
||||||
@@ -1046,25 +1030,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: return@async null
|
} ?: return@async null
|
||||||
|
|
||||||
val thumbnail = async {
|
|
||||||
val ext = galleryBlock.thumbnails[0].split('.').last()
|
|
||||||
File(getCachedGallery(this@MainActivity, galleryBlock.id), "thumbnail.$ext").apply {
|
|
||||||
if (!exists())
|
|
||||||
try {
|
|
||||||
with(URL(galleryBlock.thumbnails[0]).openConnection() as HttpsURLConnection) {
|
|
||||||
if (this@apply.parentFile?.exists() == false)
|
|
||||||
this@apply.parentFile!!.mkdirs()
|
|
||||||
|
|
||||||
inputStream.copyTo(FileOutputStream(this@apply))
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
delete()
|
|
||||||
}
|
|
||||||
}.absolutePath
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair(galleryBlock, thumbnail)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,39 +21,39 @@ package xyz.quaver.pupil.ui
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.PagerSnapHelper
|
import androidx.recyclerview.widget.PagerSnapHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import io.fabric.sdk.android.Fabric
|
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.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.ReaderAdapter
|
import xyz.quaver.pupil.adapters.ReaderAdapter
|
||||||
import xyz.quaver.pupil.util.GalleryDownloader
|
|
||||||
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.DownloadWorker
|
||||||
|
import xyz.quaver.pupil.util.getDownloadDirectory
|
||||||
|
import xyz.quaver.pupil.util.isParentOf
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.concurrent.schedule
|
||||||
|
|
||||||
class ReaderActivity : AppCompatActivity() {
|
class ReaderActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private var galleryID = 0
|
private var galleryID = 0
|
||||||
private val images = ArrayList<String>()
|
|
||||||
private var gallerySize = 0
|
|
||||||
private var currentPage = 0
|
private var currentPage = 0
|
||||||
|
|
||||||
private var isScroll = true
|
private var isScroll = true
|
||||||
@@ -69,7 +69,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var downloader: GalleryDownloader
|
private val timer = Timer()
|
||||||
|
|
||||||
private val snapHelper = PagerSnapHelper()
|
private val snapHelper = PagerSnapHelper()
|
||||||
|
|
||||||
@@ -101,12 +101,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
initDownloader()
|
|
||||||
|
|
||||||
initView()
|
initView()
|
||||||
|
initDownloader()
|
||||||
if (!downloader.download)
|
|
||||||
downloader.start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
@@ -168,7 +164,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
val view = LayoutInflater.from(this).inflate(R.layout.dialog_numberpicker, findViewById(android.R.id.content), false)
|
val view = LayoutInflater.from(this).inflate(R.layout.dialog_numberpicker, findViewById(android.R.id.content), false)
|
||||||
with(view.dialog_number_picker) {
|
with(view.dialog_number_picker) {
|
||||||
minValue=1
|
minValue=1
|
||||||
maxValue=gallerySize
|
maxValue=reader_recyclerview.adapter?.itemCount ?: 0
|
||||||
value=currentPage
|
value=currentPage
|
||||||
}
|
}
|
||||||
val dialog = AlertDialog.Builder(this).apply {
|
val dialog = AlertDialog.Builder(this).apply {
|
||||||
@@ -201,8 +197,10 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
||||||
if (::downloader.isInitialized && !downloader.download)
|
timer.cancel()
|
||||||
downloader.cancel()
|
|
||||||
|
if (!getDownloadDirectory(this).isParentOf(Cache(this).getCachedGallery(galleryID)))
|
||||||
|
DownloadWorker.getInstance(this).cancel(galleryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
@@ -238,101 +236,54 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initDownloader() {
|
private fun initDownloader() {
|
||||||
var d: GalleryDownloader? = GalleryDownloader.get(galleryID)
|
val worker = DownloadWorker.getInstance(this).apply {
|
||||||
|
queue.add(galleryID)
|
||||||
if (d == null)
|
|
||||||
d = GalleryDownloader(this, galleryID)
|
|
||||||
|
|
||||||
downloader = d.apply {
|
|
||||||
onReaderLoadedHandler = {
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
title = it.title
|
|
||||||
with(reader_download_progressbar) {
|
|
||||||
max = it.galleryInfo.size
|
|
||||||
progress = 0
|
|
||||||
}
|
|
||||||
with(reader_progressbar) {
|
|
||||||
max = it.galleryInfo.size
|
|
||||||
progress = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gallerySize = it.galleryInfo.size
|
timer.schedule(0, 1000) {
|
||||||
menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/${it.galleryInfo.size}"
|
if (worker.progress.indexOfKey(galleryID) < 0) //loading
|
||||||
}
|
return@schedule
|
||||||
}
|
|
||||||
onProgressHandler = {
|
if (worker.progress[galleryID] == null) { //Gallery not found
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
timer.cancel()
|
||||||
reader_download_progressbar.progress = it
|
|
||||||
menu?.findItem(R.id.reader_menu_use_hiyobi)?.isVisible = downloader.useHiyobi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onDownloadedHandler = {
|
|
||||||
val item = it.toList()
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
if (images.isEmpty()) {
|
|
||||||
images.addAll(item)
|
|
||||||
reader_recyclerview.adapter?.notifyDataSetChanged()
|
|
||||||
} else {
|
|
||||||
images.add(item.last())
|
|
||||||
reader_recyclerview.adapter?.notifyItemInserted(images.size-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onErrorHandler = {
|
|
||||||
Snackbar
|
Snackbar
|
||||||
.make(reader_layout, it.message ?: it.javaClass.name, Snackbar.LENGTH_INDEFINITE)
|
.make(reader_layout, R.string.reader_failed_to_find_gallery, Snackbar.LENGTH_INDEFINITE)
|
||||||
.setAction(R.string.reader_help) {
|
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.error_help))))
|
|
||||||
}
|
|
||||||
.show()
|
.show()
|
||||||
downloader.download = false
|
|
||||||
}
|
}
|
||||||
onCompleteHandler = {
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
reader_download_progressbar.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onNotifyChangedHandler = { notify ->
|
|
||||||
val fab = reader_fab_download
|
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
if (notify) {
|
reader_download_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
||||||
val icon = AnimatedVectorDrawableCompat.create(this, R.drawable.ic_downloading)
|
reader_download_progressbar.progress = worker.progress[galleryID]!!.count { !it.isFinite() }
|
||||||
icon?.registerAnimationCallback(object: Animatable2Compat.AnimationCallback() {
|
reader_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
||||||
override fun onAnimationEnd(drawable: Drawable?) {
|
|
||||||
if (downloader.download)
|
if (title == getString(R.string.reader_loading)) {
|
||||||
fab.post {
|
val reader = (reader_recyclerview.adapter as ReaderAdapter).reader
|
||||||
icon.start()
|
|
||||||
fab.labelText = getString(R.string.reader_fab_download_cancel)
|
if (reader != null) {
|
||||||
}
|
title = reader.title
|
||||||
else
|
menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/${reader.galleryInfo.size}"
|
||||||
fab.post {
|
|
||||||
fab.setImageResource(R.drawable.ic_download)
|
menu?.findItem(R.id.reader_type)?.icon = ContextCompat.getDrawable(this@ReaderActivity,
|
||||||
fab.labelText = getString(R.string.reader_fab_download)
|
when (reader.code) {
|
||||||
}
|
Reader.Code.HITOMI -> R.drawable.hitomi
|
||||||
}
|
Reader.Code.HIYOBI -> R.drawable.ic_hiyobi
|
||||||
|
else -> android.R.color.transparent
|
||||||
})
|
})
|
||||||
|
|
||||||
fab.setImageDrawable(icon)
|
|
||||||
icon?.start()
|
|
||||||
} else {
|
|
||||||
runOnUiThread {
|
|
||||||
fab.setImageResource(R.drawable.ic_download)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloader.download) {
|
if (worker.progress[galleryID]!!.all { !it.isFinite() }) { //Download finished
|
||||||
downloader.invokeOnReaderLoaded()
|
reader_download_progressbar.visibility = View.GONE
|
||||||
downloader.invokeOnNotifyChanged()
|
|
||||||
|
animateDownloadFAB(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
with(reader_recyclerview) {
|
with(reader_recyclerview) {
|
||||||
adapter = ReaderAdapter(Glide.with(this@ReaderActivity), galleryID, images).apply {
|
adapter = ReaderAdapter(this@ReaderActivity, galleryID).apply {
|
||||||
onItemClickListener = {
|
onItemClickListener = {
|
||||||
if (isScroll) {
|
if (isScroll) {
|
||||||
isScroll = false
|
isScroll = false
|
||||||
@@ -360,19 +311,19 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
if (layoutManager.findFirstVisibleItemPosition() == -1)
|
if (layoutManager.findFirstVisibleItemPosition() == -1)
|
||||||
return
|
return
|
||||||
currentPage = layoutManager.findFirstVisibleItemPosition()+1
|
currentPage = layoutManager.findFirstVisibleItemPosition()+1
|
||||||
menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/$gallerySize"
|
menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/${recyclerView.adapter!!.itemCount}"
|
||||||
this@ReaderActivity.reader_progressbar.progress = currentPage
|
this@ReaderActivity.reader_progressbar.progress = currentPage
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
with(reader_fab_download) {
|
with(reader_fab_download) {
|
||||||
setImageResource(R.drawable.ic_download)
|
animateDownloadFAB(getDownloadDirectory(context).isParentOf(Cache(context).getCachedGallery(galleryID))) //If download in progress, animate button
|
||||||
setOnClickListener {
|
|
||||||
downloader.download = !downloader.download
|
|
||||||
|
|
||||||
if (!downloader.download)
|
setOnClickListener {
|
||||||
downloader.clearNotification()
|
Cache(context).moveToDownload(galleryID)
|
||||||
|
|
||||||
|
animateDownloadFAB(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,4 +365,32 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0)
|
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun animateDownloadFAB(animate: Boolean) {
|
||||||
|
with(reader_fab_download) {
|
||||||
|
if (animate) {
|
||||||
|
val icon = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_downloading)
|
||||||
|
|
||||||
|
icon?.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
|
||||||
|
override fun onAnimationEnd(drawable: Drawable?) {
|
||||||
|
val worker = DownloadWorker.getInstance(context)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
else // Or continue animating
|
||||||
|
post {
|
||||||
|
icon.start()
|
||||||
|
labelText = getString(R.string.reader_fab_download_cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setImageDrawable(icon)
|
||||||
|
icon?.start()
|
||||||
|
} else
|
||||||
|
setImageResource(R.drawable.ic_download)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,10 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import kotlinx.android.synthetic.main.dialog_gallery.*
|
import kotlinx.android.synthetic.main.dialog_gallery.*
|
||||||
import kotlinx.android.synthetic.main.gallery_details.view.*
|
import kotlinx.android.synthetic.main.gallery_details.view.*
|
||||||
import kotlinx.android.synthetic.main.item_gallery_details.view.*
|
import kotlinx.android.synthetic.main.item_gallery_details.view.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import xyz.quaver.hitomi.Gallery
|
import xyz.quaver.hitomi.Gallery
|
||||||
import xyz.quaver.hitomi.GalleryBlock
|
import xyz.quaver.hitomi.GalleryBlock
|
||||||
import xyz.quaver.hitomi.getGallery
|
import xyz.quaver.hitomi.getGallery
|
||||||
@@ -221,9 +224,9 @@ class GalleryDialog(context: Context, private val galleryID: Int) : Dialog(conte
|
|||||||
|
|
||||||
private fun addRelated(gallery: Gallery) {
|
private fun addRelated(gallery: Gallery) {
|
||||||
val inflater = LayoutInflater.from(context)
|
val inflater = LayoutInflater.from(context)
|
||||||
val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
|
val galleries = ArrayList<GalleryBlock>()
|
||||||
|
|
||||||
val adapter = GalleryBlockAdapter(glide, galleries).apply {
|
val adapter = GalleryBlockAdapter(context, galleries).apply {
|
||||||
onChipClickedHandler.add { tag ->
|
onChipClickedHandler.add { tag ->
|
||||||
this@GalleryDialog.onChipClickedHandler.forEach { handler ->
|
this@GalleryDialog.onChipClickedHandler.forEach { handler ->
|
||||||
handler.invoke(tag)
|
handler.invoke(tag)
|
||||||
@@ -238,7 +241,7 @@ class GalleryDialog(context: Context, private val galleryID: Int) : Dialog(conte
|
|||||||
}.let {
|
}.let {
|
||||||
val galleryBlock = it.await() ?: return@let
|
val galleryBlock = it.await() ?: return@let
|
||||||
|
|
||||||
galleries.add(Pair(galleryBlock, GlobalScope.async { galleryBlock.thumbnails.first() }))
|
galleries.add(galleryBlock)
|
||||||
adapter.notifyItemInserted(i)
|
adapter.notifyItemInserted(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,14 +257,14 @@ class GalleryDialog(context: Context, private val galleryID: Int) : Dialog(conte
|
|||||||
ItemClickSupport.addTo(this)
|
ItemClickSupport.addTo(this)
|
||||||
.setOnItemClickListener { _, position, _ ->
|
.setOnItemClickListener { _, position, _ ->
|
||||||
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
||||||
putExtra("galleryID", galleries[position].first.id)
|
putExtra("galleryID", galleries[position].id)
|
||||||
})
|
})
|
||||||
(context.applicationContext as Pupil).histories.add(galleries[position].first.id)
|
(context.applicationContext as Pupil).histories.add(galleries[position].id)
|
||||||
}
|
}
|
||||||
.setOnItemLongClickListener { _, position, _ ->
|
.setOnItemLongClickListener { _, position, _ ->
|
||||||
GalleryDialog(
|
GalleryDialog(
|
||||||
context,
|
context,
|
||||||
galleries[position].first.id
|
galleries[position].id
|
||||||
).apply {
|
).apply {
|
||||||
onChipClickedHandler.add { tag ->
|
onChipClickedHandler.add { tag ->
|
||||||
this@GalleryDialog.onChipClickedHandler.forEach { it.invoke(tag) }
|
this@GalleryDialog.onChipClickedHandler.forEach { it.invoke(tag) }
|
||||||
|
|||||||
@@ -78,16 +78,14 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
|
|
||||||
@UseExperimental(ImplicitReflectionSerializer::class)
|
@UseExperimental(ImplicitReflectionSerializer::class)
|
||||||
fun setCachedMetadata(galleryID: Int, metadata: Metadata) {
|
fun setCachedMetadata(galleryID: Int, metadata: Metadata) {
|
||||||
val file = File(getCachedGallery(galleryID), ".metadata")
|
val file = File(getCachedGallery(galleryID) ?: File(cacheDir, "imageCache/$galleryID"), ".metadata")
|
||||||
|
|
||||||
if (!file.exists())
|
if (file.parentFile?.exists() != true)
|
||||||
return
|
file.parentFile?.mkdirs()
|
||||||
|
|
||||||
|
file.createNewFile()
|
||||||
|
|
||||||
try {
|
|
||||||
file.writeText(Json.stringify(metadata))
|
file.writeText(Json.stringify(metadata))
|
||||||
} catch (e: Exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getThumbnail(galleryID: Int): String? {
|
suspend fun getThumbnail(galleryID: Int): String? {
|
||||||
@@ -135,6 +133,16 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
return galleryBlock
|
return galleryBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getReaderOrNull(galleryID: Int): Reader? {
|
||||||
|
val metadata = getCachedMetadata(galleryID)
|
||||||
|
|
||||||
|
val mirrors = preference.getString("mirrors", "")!!.split('>')
|
||||||
|
|
||||||
|
return metadata?.readers?.firstOrNull {
|
||||||
|
mirrors.contains(it.code.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getReader(galleryID: Int): Reader? {
|
suspend fun getReader(galleryID: Int): Reader? {
|
||||||
val metadata = getCachedMetadata(galleryID)
|
val metadata = getCachedMetadata(galleryID)
|
||||||
|
|
||||||
@@ -173,7 +181,7 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
gallery.listFiles { file ->
|
gallery.listFiles { file ->
|
||||||
file.nameWithoutExtension.toIntOrNull() != null
|
file.nameWithoutExtension.toIntOrNull() != null
|
||||||
}?.forEach {
|
}?.forEach {
|
||||||
append(it.nameWithoutExtension.toInt(), it)
|
put(it.nameWithoutExtension.toInt(), it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,14 +205,17 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun moveToDownload(galleryID: Int) {
|
fun moveToDownload(galleryID: Int) {
|
||||||
val cache = getCachedGallery(galleryID) ?: File(cacheDir, "imageCache/$galleryID")
|
val cache = getCachedGallery(galleryID)
|
||||||
|
|
||||||
|
if (cache != null) {
|
||||||
val download = getDownloadDirectory(this)
|
val download = getDownloadDirectory(this)
|
||||||
|
|
||||||
if (!download.isParentOf(cache)) {
|
if (!download.isParentOf(cache)) {
|
||||||
cache.copyRecursively(download)
|
cache.copyRecursively(download, true)
|
||||||
cache.deleteRecursively()
|
cache.deleteRecursively()
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
File(getDownloadDirectory(this), galleryID.toString()).mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,8 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
override fun update(tag: Any?, bytesRead: Long, contentLength: Long, done: Boolean) {
|
override fun update(tag: Any?, bytesRead: Long, contentLength: Long, done: Boolean) {
|
||||||
val (galleryID, index) = (tag as? Pair<Int, Int>) ?: return
|
val (galleryID, index) = (tag as? Pair<Int, Int>) ?: return
|
||||||
|
|
||||||
if (!done && progress[galleryID]!![index] != Float.POSITIVE_INFINITY)
|
if (!done && progress[galleryID]?.get(index)?.isFinite() == true)
|
||||||
progress[galleryID]!![index] = bytesRead * 100F / contentLength
|
progress[galleryID]?.set(index, bytesRead * 100F / contentLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,14 +156,20 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
|
queue.clear()
|
||||||
|
|
||||||
loop.cancel()
|
loop.cancel()
|
||||||
for (i in 0..worker.size())
|
for (i in 0..worker.size())
|
||||||
worker[worker.keyAt(i)]?.cancel()
|
worker[worker.keyAt(i)]?.cancel()
|
||||||
|
|
||||||
client.dispatcher.cancelAll()
|
client.dispatcher.cancelAll()
|
||||||
|
|
||||||
|
progress.clear()
|
||||||
|
exception.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancel(galleryID: Int) {
|
fun cancel(galleryID: Int) {
|
||||||
|
queue.remove(galleryID)
|
||||||
worker[galleryID]?.cancel()
|
worker[galleryID]?.cancel()
|
||||||
|
|
||||||
client.dispatcher.queuedCalls()
|
client.dispatcher.queuedCalls()
|
||||||
@@ -171,6 +177,13 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
.forEach {
|
.forEach {
|
||||||
it.cancel()
|
it.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (progress.indexOfKey(galleryID) >= 0) {
|
||||||
|
progress.remove(galleryID)
|
||||||
|
exception.remove(galleryID)
|
||||||
|
|
||||||
|
nRunners--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun queueDownload(galleryID: Int, reader: Reader, index: Int, callback: Callback) {
|
private fun queueDownload(galleryID: Int, reader: Reader, index: Int, callback: Callback) {
|
||||||
@@ -179,7 +192,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
|
|
||||||
//Cache exists :P
|
//Cache exists :P
|
||||||
cache?.get(index)?.let {
|
cache?.get(index)?.let {
|
||||||
progress[galleryID]!![index] = Float.POSITIVE_INFINITY
|
progress[galleryID]?.set(index, Float.POSITIVE_INFINITY)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -231,12 +244,16 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
if (Fabric.isInitialized())
|
if (Fabric.isInitialized())
|
||||||
Crashlytics.logException(e)
|
Crashlytics.logException(e)
|
||||||
|
|
||||||
progress[galleryID]!![i] = Float.NaN
|
progress[galleryID]?.set(i, Float.NaN)
|
||||||
exception[galleryID]!![i] = e
|
exception[galleryID]?.set(i, e)
|
||||||
|
|
||||||
|
if (progress[galleryID]?.all { !it.isFinite() } == true) {
|
||||||
|
progress.remove(galleryID)
|
||||||
|
exception.remove(galleryID)
|
||||||
|
|
||||||
if (progress[galleryID]!!.all { !it.isFinite() })
|
|
||||||
nRunners--
|
nRunners--
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
response.use {
|
response.use {
|
||||||
@@ -245,13 +262,17 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
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]!![i] = Float.POSITIVE_INFINITY
|
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress[galleryID]!!.all { !it.isFinite() })
|
if (progress[galleryID]?.all { !it.isFinite() } == true) {
|
||||||
|
progress.remove(galleryID)
|
||||||
|
exception.remove(galleryID)
|
||||||
|
|
||||||
nRunners--
|
nRunners--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
queueDownload(galleryID, reader, i, callback)
|
queueDownload(galleryID, reader, i, callback)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,4 +64,4 @@ fun URL.download(to: File, onDownloadProgress: ((Long, Long) -> Unit)? = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun File.isParentOf(file: File) = file.absolutePath.startsWith(this.absolutePath)
|
fun File.isParentOf(file: File?) = file?.absolutePath?.startsWith(this.absolutePath) ?: false
|
||||||
BIN
app/src/main/res/drawable/hitomi.png
Normal file
BIN
app/src/main/res/drawable/hitomi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
34
app/src/main/res/drawable/reader_item_boundary.xml
Normal file
34
app/src/main/res/drawable/reader_item_boundary.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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 <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:bottom="1dp"
|
||||||
|
android:left="1dp"
|
||||||
|
android:right="1dp"
|
||||||
|
android:top="1dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="#555555" />
|
||||||
|
|
||||||
|
<solid android:color="@color/transparent" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
@@ -23,15 +23,49 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:background="@drawable/reader_item_boundary">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/reader_item_progressbar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="?android:progressBarStyleHorizontal"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:progress="0"
|
||||||
|
android:max="100"
|
||||||
|
android:visibility="visible"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reader_index"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TextAppearance.AppCompat.Caption"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<com.github.chrisbanes.photoview.PhotoView
|
<com.github.chrisbanes.photoview.PhotoView
|
||||||
android:id="@+id/image"
|
android:id="@+id/image"
|
||||||
android:contentDescription="@string/reader_imageview_description"
|
android:contentDescription="@string/reader_imageview_description"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:paddingBottom="8dp"/>
|
android:paddingBottom="8dp"/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -25,9 +25,8 @@
|
|||||||
android:icon="@drawable/avd_star"
|
android:icon="@drawable/avd_star"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
<item android:id="@+id/reader_menu_use_hiyobi"
|
<item android:id="@+id/reader_type"
|
||||||
android:title=""
|
android:title=""
|
||||||
android:icon="@drawable/ic_hiyobi"
|
|
||||||
app:showAsAction="ifRoom"
|
app:showAsAction="ifRoom"
|
||||||
android:visible="false"/>
|
android:visible="false"/>
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="settings_mirror_summary">ミラーサーバからイメージをロード</string>
|
<string name="settings_mirror_summary">ミラーサーバからイメージをロード</string>
|
||||||
<string name="main_drawer_favorite">お気に入り</string>
|
<string name="main_drawer_favorite">お気に入り</string>
|
||||||
<string name="main_open_gallery_by_id">ギャラリー番号で見る</string>
|
<string name="main_open_gallery_by_id">ギャラリー番号で見る</string>
|
||||||
<string name="main_open_gallery_by_id_error">エラーが発生しました</string>
|
<string name="reader_failed_to_find_gallery">エラーが発生しました</string>
|
||||||
<string name="settings_storage">ストレージ</string>
|
<string name="settings_storage">ストレージ</string>
|
||||||
<string name="main_drawer_grouop_contact_discord">ディスコード</string>
|
<string name="main_drawer_grouop_contact_discord">ディスコード</string>
|
||||||
<string name="settings_app_lock">アプリロック</string>
|
<string name="settings_app_lock">アプリロック</string>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
|
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
|
||||||
<string name="main_drawer_favorite">즐겨찾기</string>
|
<string name="main_drawer_favorite">즐겨찾기</string>
|
||||||
<string name="main_open_gallery_by_id">갤러리 번호로 열기</string>
|
<string name="main_open_gallery_by_id">갤러리 번호로 열기</string>
|
||||||
<string name="main_open_gallery_by_id_error">갤러리를 찾지 못했습니다</string>
|
<string name="reader_failed_to_find_gallery">갤러리를 찾지 못했습니다</string>
|
||||||
<string name="settings_storage">저장 공간</string>
|
<string name="settings_storage">저장 공간</string>
|
||||||
<string name="main_drawer_grouop_contact_discord">디스코드</string>
|
<string name="main_drawer_grouop_contact_discord">디스코드</string>
|
||||||
<string name="settings_app_lock">앱 잠금</string>
|
<string name="settings_app_lock">앱 잠금</string>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
<string name="main_jump_title">Jump to page</string>
|
<string name="main_jump_title">Jump to page</string>
|
||||||
<string name="main_jump_message">Current page: %1$d\nMaximum page: %2$d</string>
|
<string name="main_jump_message">Current page: %1$d\nMaximum page: %2$d</string>
|
||||||
<string name="main_open_gallery_by_id">Open Gallery by ID</string>
|
<string name="main_open_gallery_by_id">Open Gallery by ID</string>
|
||||||
<string name="main_open_gallery_by_id_error">Failed to open gallery</string>
|
<string name="reader_failed_to_find_gallery">Failed to open gallery</string>
|
||||||
|
|
||||||
<string name="main_move">Move to page %1$d</string>
|
<string name="main_move">Move to page %1$d</string>
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
# Project-wide Gradle settings.
|
## For more details on how to configure your build environment visit
|
||||||
# IDE (e.g. Android Studio) users:
|
|
||||||
# Gradle settings configured through the IDE *will override*
|
|
||||||
# any settings specified in this file.
|
|
||||||
# For more details on how to configure your build environment visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
#
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
org.gradle.jvmargs=-Xmx1536m
|
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
||||||
|
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||||
|
#
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
# org.gradle.parallel=true
|
# org.gradle.parallel=true
|
||||||
# Kotlin code style for this project: "official" or "obsolete":
|
#Thu Jan 30 12:29:48 KST 2020
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
|
||||||
android.useAndroidX=true
|
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
org.gradle.jvmargs=-Xmx1024M -Dkotlin.daemon.jvm.options\="-Xmx1024M"
|
||||||
|
android.useAndroidX=true
|
||||||
|
|||||||
Reference in New Issue
Block a user