diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7631aec3..fb8c126a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index d34d7924..76304c9d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,8 +9,8 @@ android {
applicationId "xyz.quaver.pupil"
minSdkVersion 16
targetSdkVersion 28
- versionCode 7
- versionName "2.1"
+ versionCode 8
+ versionName "2.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
diff --git a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
index 94470e8f..bbe0c7d3 100644
--- a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
@@ -6,16 +6,17 @@ import android.os.Bundle
import android.preference.PreferenceManager
import android.text.*
import android.text.style.AlignmentSpan
-import android.view.LayoutInflater
-import android.view.View
-import android.view.WindowManager
+import android.util.Log
+import android.view.*
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
+import androidx.cardview.widget.CardView
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.GravityCompat
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import com.arlib.floatingsearchview.FloatingSearchView
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
import com.arlib.floatingsearchview.util.view.SearchInputView
@@ -39,6 +40,7 @@ import java.net.URL
import java.util.*
import javax.net.ssl.HttpsURLConnection
import kotlin.collections.ArrayList
+import kotlin.math.roundToInt
class MainActivity : AppCompatActivity() {
@@ -56,7 +58,9 @@ class MainActivity : AppCompatActivity() {
private val SETTINGS = 45162
private var galleryIDs: Deferred>? = null
+ private var totalItems = 0
private var loadingJob: Job? = null
+ private var currentPage = 0
private lateinit var histories: Histories
private lateinit var downloads: Histories
@@ -64,16 +68,25 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ val preference = PreferenceManager.getDefaultSharedPreferences(this)
+
+ if (Locale.getDefault().language == "ko") {
+ if (!preference.getBoolean("https_block_alert", false)) {
+ android.app.AlertDialog.Builder(this).apply {
+ setTitle(R.string.https_block_alert_title)
+ setMessage(R.string.https_block_alert)
+ setPositiveButton(android.R.string.ok) { _, _ -> }
+ }.show()
+
+ preference.edit().putBoolean("https_block_alert", true).apply()
+ }
+ }
+
with(application as Pupil) {
this@MainActivity.histories = histories
this@MainActivity.downloads = downloads
}
- window.setFlags(
- WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
- WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- )
-
setContentView(R.layout.activity_main)
checkUpdate()
@@ -109,6 +122,44 @@ class MainActivity : AppCompatActivity() {
super.onResume()
}
+ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
+ val preference = PreferenceManager.getDefaultSharedPreferences(this)
+ val perPage = preference.getString("per_page", "25")!!.toInt()
+ val maxPage = Math.ceil(totalItems / perPage.toDouble()).roundToInt()
+
+ return when(keyCode) {
+ KeyEvent.KEYCODE_VOLUME_DOWN -> {
+ if (currentPage < maxPage) {
+ runOnUiThread {
+ currentPage++
+
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query)
+ loadBlocks()
+ }
+ }
+
+ true
+ }
+ KeyEvent.KEYCODE_VOLUME_UP -> {
+ if (currentPage > 0) {
+ runOnUiThread {
+ currentPage--
+
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query)
+ loadBlocks()
+ }
+ }
+
+ true
+ }
+ else -> super.onKeyDown(keyCode, event)
+ }
+ }
+
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode) {
@@ -188,31 +239,16 @@ class MainActivity : AppCompatActivity() {
}
private fun initView() {
+ var prevP1 = 0
main_appbar_layout.addOnOffsetChangedListener(
AppBarLayout.OnOffsetChangedListener { _, p1 ->
main_searchview.translationY = p1.toFloat()
- main_recyclerview.translationY = p1.toFloat()
+ main_recyclerview.scrollBy(0, prevP1 - p1)
+
+ prevP1 = p1
}
)
- //SwipeRefreshLayout
- with(main_swipe_layout) {
- setProgressViewOffset(
- false,
- resources.getDimensionPixelSize(R.dimen.progress_view_start),
- resources.getDimensionPixelSize(R.dimen.progress_view_offset)
- )
-
- setOnRefreshListener {
- post {
- cancelFetch()
- clearGalleries()
- fetchGalleries(query)
- loadBlocks()
- }
- }
- }
-
//NavigationView
main_nav_view.setNavigationItemSelectedListener {
runOnUiThread {
@@ -276,7 +312,7 @@ class MainActivity : AppCompatActivity() {
with(main_recyclerview) {
adapter = GalleryBlockAdapter(galleries).apply {
onChipClickedHandler.add {
- post {
+ runOnUiThread {
query = it.toQuery()
this@MainActivity.findViewById(R.id.search_bar_text)
.setText(query, TextView.BufferType.EDITABLE)
@@ -288,21 +324,12 @@ class MainActivity : AppCompatActivity() {
}
}
}
- addOnScrollListener(
- object: RecyclerView.OnScrollListener() {
- override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
- super.onScrolled(recyclerView, dx, dy)
-
- val layoutManager = recyclerView.layoutManager as LinearLayoutManager
-
- if (loadingJob?.isActive != true)
- if (layoutManager.findLastCompletelyVisibleItemPosition() == galleries.size)
- loadBlocks()
- }
- }
- )
ItemClickSupport.addTo(this)
- .setOnItemClickListener { _, position, _ ->
+ .setOnItemClickListener { _, position, v ->
+
+ if (v !is CardView)
+ return@setOnItemClickListener
+
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
val gallery = galleries[position].first
intent.putExtra("galleryblock", Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), gallery))
@@ -311,7 +338,11 @@ class MainActivity : AppCompatActivity() {
startActivity(intent)
histories.add(gallery.id)
- }.setOnItemLongClickListener { recyclerView, position, _ ->
+ }.setOnItemLongClickListener { recyclerView, position, v ->
+
+ if (v !is CardView)
+ return@setOnItemLongClickListener true
+
val galleryBlock = galleries[position].first
val view = LayoutInflater.from(this@MainActivity)
.inflate(R.layout.dialog_galleryblock, recyclerView, false)
@@ -358,6 +389,210 @@ class MainActivity : AppCompatActivity() {
true
}
+
+ var origin = 0f
+ var target = -1
+ val preferences = PreferenceManager.getDefaultSharedPreferences(context)
+ val perPage = preferences.getString("per_page", "25")!!.toInt()
+ setOnTouchListener { _, event ->
+ when(event.action) {
+ MotionEvent.ACTION_UP -> {
+ origin = 0f
+
+ with(main_recyclerview.adapter as GalleryBlockAdapter) {
+ if(showPrev) {
+ showPrev = false
+
+ val prev = main_recyclerview.layoutManager?.getChildAt(0)
+
+ if (prev is LinearLayout) {
+ val icon = prev.findViewById(R.id.icon_prev)
+ prev.layoutParams.height = 1
+ icon.layoutParams.height = 1
+ icon.rotation = 180f
+ }
+
+ prev?.requestLayout()
+
+ notifyItemRemoved(0)
+ }
+
+ if(showNext) {
+ showNext = false
+
+ val next = main_recyclerview.layoutManager?.let {
+ getChildAt(childCount-1)
+ }
+
+ if (next is LinearLayout) {
+ val icon = next.findViewById(R.id.icon_next)
+ next.layoutParams.height = 1
+ icon.layoutParams.height = 1
+ icon.rotation = 0f
+ }
+
+ next?.requestLayout()
+
+ notifyItemRemoved(itemCount)
+ }
+ }
+
+ if (target != -1) {
+ currentPage = target
+
+ runOnUiThread {
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query)
+ loadBlocks()
+ }
+
+ target = -1
+ }
+ }
+ MotionEvent.ACTION_DOWN -> origin = event.y
+ MotionEvent.ACTION_MOVE -> {
+ if (origin == 0f)
+ origin = event.y
+
+ val dist = event.y - origin
+
+ when {
+ !canScrollVertically(-1) -> {
+ //TOP
+
+ //Scrolling UP
+ if (dist > 0 && currentPage != 0) {
+ with(main_recyclerview.adapter as GalleryBlockAdapter) {
+ if(!showPrev) {
+ showPrev = true
+ notifyItemInserted(0)
+ }
+ }
+
+ val prev = main_recyclerview.layoutManager?.getChildAt(0)
+
+ if (prev is LinearLayout) {
+ val icon = prev.findViewById(R.id.icon_prev)
+ val text = prev.findViewById(R.id.text_prev).apply {
+ text = getString(R.string.main_move, currentPage)
+ }
+ if (dist < 360) {
+ prev.layoutParams.height = (dist/2).roundToInt()
+ icon.layoutParams.height = (dist/2).roundToInt()
+ icon.rotation = dist+180
+ text.layoutParams.width = dist.roundToInt()
+
+ target = -1
+ }
+ else {
+ prev.layoutParams.height = 180
+ icon.layoutParams.height = 180
+ icon.rotation = 180f
+ text.layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT
+
+ target = currentPage-1
+ }
+ }
+
+ prev?.requestLayout()
+
+ return@setOnTouchListener true
+ } else {
+ with(main_recyclerview.adapter as GalleryBlockAdapter) {
+ if(showPrev) {
+ showPrev = false
+
+ val prev = main_recyclerview.layoutManager?.getChildAt(0)
+
+ if (prev is LinearLayout) {
+ val icon = prev.findViewById(R.id.icon_prev)
+ prev.layoutParams.height = 1
+ icon.layoutParams.height = 1
+ icon.rotation = 180f
+ }
+
+ prev?.requestLayout()
+
+ notifyItemRemoved(0)
+ }
+ }
+ }
+ }
+ !canScrollVertically(1) -> {
+ //BOTTOM
+
+ //Scrolling DOWN
+ if (dist < 0 && currentPage != Math.ceil(totalItems.toDouble()/perPage).roundToInt()-1) {
+ with(main_recyclerview.adapter as GalleryBlockAdapter) {
+ if(!showNext) {
+ showNext = true
+ notifyItemInserted(itemCount-1)
+ }
+ }
+
+ val next = main_recyclerview.layoutManager?.let {
+ getChildAt(childCount-1)
+ }
+
+ val absDist = Math.abs(dist)
+
+ if (next is LinearLayout) {
+ val icon = next.findViewById(R.id.icon_next)
+ val text = next.findViewById(R.id.text_next).apply {
+ text = getString(R.string.main_move, currentPage+2)
+ }
+ if (absDist < 360) {
+ next.layoutParams.height = (absDist/2).roundToInt()
+ icon.layoutParams.height = (absDist/2).roundToInt()
+ icon.rotation = -absDist
+ text.layoutParams.width = absDist.roundToInt()
+
+ target = -1
+ }
+ else {
+ next.layoutParams.height = 180
+ icon.layoutParams.height = 180
+ icon.rotation = 0f
+ text.layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT
+
+ target = currentPage+1
+ }
+ }
+
+ next?.requestLayout()
+
+ return@setOnTouchListener true
+ } else {
+ with(main_recyclerview.adapter as GalleryBlockAdapter) {
+ if(showNext) {
+ showNext = false
+
+ val next = main_recyclerview.layoutManager?.let {
+ getChildAt(childCount-1)
+ }
+
+ if (next is LinearLayout) {
+ Log.d("Pupil", "hmm...")
+ val icon = next.findViewById(R.id.icon_next)
+ next.layoutParams.height = 1
+ icon.layoutParams.height = 1
+ icon.rotation = 180f
+ }
+
+ next?.requestLayout()
+
+ notifyItemRemoved(itemCount)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ false
+ }
}
}
@@ -386,7 +621,33 @@ class MainActivity : AppCompatActivity() {
setOnMenuItemClickListener {
when(it.itemId) {
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), SETTINGS)
- R.id.main_menu_search -> setSearchFocused(true)
+ R.id.main_menu_page_indicator -> {
+ val preference = PreferenceManager.getDefaultSharedPreferences(context)
+ val perPage = preference.getString("per_page", "25")!!.toInt()
+ val editText = EditText(context)
+
+ AlertDialog.Builder(context).apply {
+ title = getString(R.string.reader_go_to_page)
+ setView(editText)
+ setTitle(R.string.main_jump_title)
+ setMessage(getString(
+ R.string.main_jump_message,
+ currentPage+1,
+ Math.ceil(totalItems / perPage.toDouble()).roundToInt()
+ ))
+
+ setPositiveButton(android.R.string.ok) { _, _ ->
+ currentPage = (editText.text.toString().toIntOrNull() ?: return@setPositiveButton)-1
+
+ runOnUiThread {
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query)
+ loadBlocks()
+ }
+ }
+ }.show()
+ }
}
}
@@ -471,7 +732,7 @@ class MainActivity : AppCompatActivity() {
if (query != this@MainActivity.query) {
this@MainActivity.query = query
- CoroutineScope(Dispatchers.Main).launch {
+ runOnUiThread {
cancelFetch()
clearGalleries()
fetchGalleries(query)
@@ -502,12 +763,12 @@ class MainActivity : AppCompatActivity() {
this.notifyDataSetChanged()
}
+ main_appbar_layout.setExpanded(true)
main_noresult.visibility = View.INVISIBLE
main_progressbar.show()
- main_swipe_layout.isRefreshing = false
}
- private fun fetchGalleries(query: String, from: Int = 0) {
+ private fun fetchGalleries(query: String) {
val preference = PreferenceManager.getDefaultSharedPreferences(this)
val perPage = preference.getString("per_page", "25")?.toInt() ?: 25
val defaultQuery = preference.getString("default_query", "")!!
@@ -521,27 +782,42 @@ class MainActivity : AppCompatActivity() {
when(mode) {
Mode.SEARCH -> {
when {
- query.isEmpty() and defaultQuery.isEmpty() ->
- fetchNozomi(start = from, count = perPage)
- else ->
- doSearch("$defaultQuery $query")
+ query.isEmpty() and defaultQuery.isEmpty() -> {
+ fetchNozomi(start = currentPage*perPage, count = perPage).let {
+ totalItems = it.second
+ it.first
+ }
+ }
+ else -> doSearch("$defaultQuery $query").apply {
+ totalItems = size
+ }
}
}
Mode.HISTORY -> {
when {
- query.isEmpty() -> histories.toList()
+ query.isEmpty() -> {
+ histories.toList().apply {
+ totalItems = size
+ }
+ }
else -> {
val result = doSearch(query).sorted()
- histories.filter { result.binarySearch(it) >= 0 }
+ histories.filter { result.binarySearch(it) >= 0 }.apply {
+ totalItems = size
+ }
}
}
}
Mode.DOWNLOAD -> {
when {
- query.isEmpty() -> downloads.toList()
+ query.isEmpty() -> downloads.toList().apply {
+ totalItems = size
+ }
else -> {
val result = doSearch(query).sorted()
- downloads.filter { result.binarySearch(it) >= 0 }
+ downloads.filter { result.binarySearch(it) >= 0 }.apply {
+ totalItems = size
+ }
}
}
}
@@ -566,18 +842,11 @@ class MainActivity : AppCompatActivity() {
return@launch
}
- if (query.isEmpty() and defaultQuery.isEmpty())
- fetchGalleries("", galleries.size+perPage)
- else
- with(main_recyclerview.adapter as GalleryBlockAdapter) {
- noMore = galleries.size + perPage >= galleryIDs.size
- }
-
when {
- query.isEmpty() and defaultQuery.isEmpty() ->
+ query.isEmpty() and defaultQuery.isEmpty() and (mode == Mode.SEARCH) ->
galleryIDs
else ->
- galleryIDs.slice(galleries.size until Math.min(galleries.size+perPage, galleryIDs.size))
+ galleryIDs.slice(currentPage*perPage until Math.min(currentPage*perPage+perPage, galleryIDs.size))
}.chunked(5).let { chunks ->
for (chunk in chunks)
chunk.map {
@@ -635,8 +904,7 @@ class MainActivity : AppCompatActivity() {
if (galleryBlock != null) {
galleries.add(galleryBlock)
-
- main_recyclerview.adapter?.notifyItemInserted(galleries.size - 1)
+ main_recyclerview.adapter!!.notifyItemInserted(galleries.size - 1)
}
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
index 542921f5..a6cd8cc3 100644
--- a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
@@ -12,12 +12,14 @@ import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
+import com.google.android.material.snackbar.Snackbar
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.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.io.IOException
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import xyz.quaver.hitomi.GalleryBlock
@@ -89,7 +91,7 @@ class ReaderActivity : AppCompatActivity() {
when(item?.itemId) {
R.id.reader_menu_page_indicator -> {
val view = LayoutInflater.from(this).inflate(R.layout.dialog_numberpicker, findViewById(android.R.id.content), false)
- with(view.reader_dialog_number_picker) {
+ with(view.dialog_number_picker) {
minValue=1
maxValue=gallerySize
value=currentPage
@@ -97,8 +99,8 @@ class ReaderActivity : AppCompatActivity() {
val dialog = AlertDialog.Builder(this).apply {
setView(view)
}.create()
- view.reader_dialog_ok.setOnClickListener {
- (reader_recyclerview.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(view.reader_dialog_number_picker.value-1, 0)
+ view.dialog_ok.setOnClickListener {
+ (reader_recyclerview.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(view.dialog_number_picker.value-1, 0)
dialog.dismiss()
}
@@ -135,7 +137,13 @@ class ReaderActivity : AppCompatActivity() {
var d: GalleryDownloader? = GalleryDownloader.get(galleryBlock.id)
if (d == null) {
- d = GalleryDownloader(this, galleryBlock)
+ try {
+ d = GalleryDownloader(this, galleryBlock)
+ } catch (e: IOException) {
+ Snackbar.make(reader_layout, R.string.unable_to_connect, Snackbar.LENGTH_LONG).show()
+ finish()
+ return
+ }
}
downloader = d.apply {
@@ -170,6 +178,8 @@ class ReaderActivity : AppCompatActivity() {
}
}
onErrorHandler = {
+ if (it is IOException)
+ Snackbar.make(reader_layout, R.string.unable_to_connect, Snackbar.LENGTH_LONG).show()
downloader.download = false
}
onCompleteHandler = {
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 06ccd862..c75529b7 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
@@ -1,12 +1,13 @@
package xyz.quaver.pupil.adapters
import android.graphics.BitmapFactory
-import android.util.SparseArray
+import android.util.Log
import android.util.SparseBooleanArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
+import android.widget.RelativeLayout
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
@@ -27,66 +28,28 @@ import xyz.quaver.pupil.types.Tag
import java.io.File
import java.util.*
import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
import kotlin.concurrent.schedule
class GalleryBlockAdapter(private val galleries: List>>) : RecyclerView.Adapter() {
- private enum class ViewType {
- VIEW_ITEM,
- VIEW_PROG
+ enum class ViewType {
+ NEXT,
+ GALLERY,
+ PREV
}
- private fun String.wordCapitalize() : String {
- val result = ArrayList()
-
- for (word in this.split(" "))
- result.add(word.capitalize())
-
- return result.joinToString(" ")
- }
-
- var noMore = false
- private val refreshTasks = SparseArray()
- val completeFlag = SparseBooleanArray()
-
- val 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) {
- ViewType.VIEW_ITEM.ordinal -> {
- val view = LayoutInflater.from(parent.context).inflate(
- R.layout.item_galleryblock, parent, false
- ) as CardView
-
- return ViewHolder(view)
- }
- ViewType.VIEW_PROG.ordinal -> {
- val view = LayoutInflater.from(parent.context).inflate(
- R.layout.item_progressbar, parent, false
- ) as LinearLayout
-
- return ProgressViewHolder(view)
- }
- }
-
- throw Exception("Unexpected ViewType")
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- if (holder is ViewHolder) {
- with(holder.view) {
+ inner class GalleryViewHolder(private val view: CardView) : RecyclerView.ViewHolder(view) {
+ fun bind(item: Pair>) {
+ with(view) {
val resources = context.resources
val languages = resources.getStringArray(R.array.languages).map {
it.split("|").let { split ->
Pair(split[0], split[1])
}
}.toMap()
- val (gallery, thumbnail) = galleries[position]
- holder.galleryID = gallery.id
+ val (gallery: GalleryBlock, thumbnail: Deferred) = item
val artists = gallery.artists
val series = gallery.series
@@ -99,7 +62,7 @@ class GalleryBlockAdapter(private val galleries: List {
@@ -232,32 +192,85 @@ class GalleryBlockAdapter(private val galleries: List View.GONE
- false -> View.VISIBLE
+ }
+ class NextViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
+ class PrevViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
+
+ class ViewHolderFactory {
+ companion object {
+ fun getLayoutID(type: Int): Int {
+ return when(ViewType.values()[type]) {
+ ViewType.NEXT -> R.layout.item_next
+ ViewType.PREV -> R.layout.item_prev
+ ViewType.GALLERY -> R.layout.item_galleryblock
+ }
}
}
}
+ private fun String.wordCapitalize() : String {
+ val result = ArrayList()
+
+ for (word in this.split(" "))
+ result.add(word.capitalize())
+
+ return result.joinToString(" ")
+ }
+
+ private val refreshTasks = HashMap()
+ val completeFlag = SparseBooleanArray()
+
+ val onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
+
+ var showNext = false
+ var showPrev = false
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+
+ fun getViewHolder(type: Int, view: View): RecyclerView.ViewHolder {
+ return when(ViewType.values()[type]) {
+ ViewType.NEXT -> NextViewHolder(view as LinearLayout)
+ ViewType.PREV -> PrevViewHolder(view as LinearLayout)
+ ViewType.GALLERY -> GalleryViewHolder(view as CardView)
+ }
+ }
+
+ return getViewHolder(
+ viewType,
+ LayoutInflater.from(parent.context).inflate(
+ ViewHolderFactory.getLayoutID(viewType),
+ parent,
+ false
+ )
+ )
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is GalleryViewHolder)
+ holder.bind(galleries[position-(if (showPrev) 1 else 0)])
+ }
+
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
- if (holder is ViewHolder) {
- val galleryID = holder.galleryID ?: return
- val task = refreshTasks.get(galleryID) ?: return
+ if (holder is GalleryViewHolder) {
+ val task = refreshTasks[holder] ?: return
- refreshTasks.remove(galleryID)
task.cancel()
+ refreshTasks.remove(holder)
}
}
- override fun getItemCount() = if (galleries.isEmpty()) 0 else galleries.size+1
+ override fun getItemCount() =
+ (if (galleries.isEmpty()) 0 else galleries.size)+
+ (if (showNext) 1 else 0)+
+ (if (showPrev) 1 else 0)
override fun getItemViewType(position: Int): Int {
return when {
- galleries.getOrNull(position) == null -> ViewType.VIEW_PROG.ordinal
- else -> ViewType.VIEW_ITEM.ordinal
- }
+ showPrev && position == 0 -> ViewType.PREV
+ showNext && position == galleries.size+(if (showPrev) 1 else 0) -> ViewType.NEXT
+ else -> ViewType.GALLERY
+ }.ordinal
}
}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
index a557d222..b3657ed9 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
@@ -55,7 +55,7 @@ class GalleryDownloader(
var onReaderLoadedHandler: ((Reader) -> Unit)? = null
var onProgressHandler: ((Int) -> Unit)? = null
var onDownloadedHandler: ((List) -> Unit)? = null
- var onErrorHandler: (() -> Unit)? = null
+ var onErrorHandler: ((Exception) -> Unit)? = null
var onCompleteHandler: (() -> Unit)? = null
var onNotifyChangedHandler: ((Boolean) -> Unit)? = null
@@ -100,15 +100,13 @@ class GalleryDownloader(
}
}
- //Could not retrieve reader
- if (reader.isEmpty())
- throw IOException("Can't retrieve Reader")
+ if (reader.isNotEmpty()) {
+ //Save cache
+ if (!cache.parentFile.exists())
+ cache.parentFile.mkdirs()
- //Save cache
- if (!cache.parentFile.exists())
- cache.parentFile.mkdirs()
-
- cache.writeText(json.stringify(serializer, reader))
+ cache.writeText(json.stringify(serializer, reader))
+ }
reader
}
@@ -120,6 +118,9 @@ class GalleryDownloader(
downloadJob = CoroutineScope(Dispatchers.Default).launch {
val reader = reader.await()
+ if (reader.isEmpty())
+ onErrorHandler?.invoke(IOException("Couldn't retrieve Reader"))
+
val list = ArrayList()
onReaderLoadedHandler?.invoke(reader)
@@ -162,7 +163,7 @@ class GalleryDownloader(
} catch (e: Exception) {
cache.delete()
- onErrorHandler?.invoke()
+ onErrorHandler?.invoke(e)
notificationBuilder
.setContentTitle(galleryBlock.title)
diff --git a/app/src/main/res/drawable/ic_jump.xml b/app/src/main/res/drawable/ic_jump.xml
new file mode 100644
index 00000000..e59a1a2a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_jump.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_navigate_before_black_24dp.xml b/app/src/main/res/drawable/ic_navigate_before_black_24dp.xml
new file mode 100644
index 00000000..e6bb3ca9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_navigate_before_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml b/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml
new file mode 100644
index 00000000..24835127
--- /dev/null
+++ b/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml
index ffebabe9..a5b3b266 100644
--- a/app/src/main/res/layout/activity_main_content.xml
+++ b/app/src/main/res/layout/activity_main_content.xml
@@ -1,5 +1,6 @@
-
-
-
-
-
+ android:paddingTop="64dp"
+ android:clipToPadding="false"
+ android:scrollbars="vertical"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
@@ -71,7 +64,7 @@
android:layout_height="match_parent"
app:floatingSearch_searchBarMarginLeft="8dp"
app:floatingSearch_searchBarMarginRight="8dp"
- app:floatingSearch_searchBarMarginTop="24dp"
+ app:floatingSearch_searchBarMarginTop="8dp"
app:floatingSearch_searchHint="@string/search_hint"
app:floatingSearch_suggestionsListAnimDuration="250"
app:floatingSearch_showSearchKey="true"
diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml
index 59ff93c1..9e49df68 100644
--- a/app/src/main/res/layout/activity_reader.xml
+++ b/app/src/main/res/layout/activity_reader.xml
@@ -1,5 +1,6 @@
diff --git a/app/src/main/res/layout/dialog_numberpicker.xml b/app/src/main/res/layout/dialog_numberpicker.xml
index d9167359..943ab6ac 100644
--- a/app/src/main/res/layout/dialog_numberpicker.xml
+++ b/app/src/main/res/layout/dialog_numberpicker.xml
@@ -7,7 +7,7 @@
diff --git a/app/src/main/res/layout/item_next.xml b/app/src/main/res/layout/item_next.xml
new file mode 100644
index 00000000..ec429ad8
--- /dev/null
+++ b/app/src/main/res/layout/item_next.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_prev.xml b/app/src/main/res/layout/item_prev.xml
new file mode 100644
index 00000000..c01cc5da
--- /dev/null
+++ b/app/src/main/res/layout/item_prev.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
index a204ac61..5272419e 100644
--- a/app/src/main/res/menu/main.xml
+++ b/app/src/main/res/menu/main.xml
@@ -2,10 +2,9 @@
\ 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 a625b88c..24689f50 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -6,12 +6,12 @@
結果なし
検索
ギャラリー検索
+ ギャラリー検索
キャッシュ
イメージキャッシュクリア
キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?
キャッシュサイズ: %1$d%2$s
デフォルトキーワード
- 権限を拒否すると一部の機能が利用できません
一回にロードするギャラリー数
検索設定
設定
@@ -53,4 +53,10 @@
バックグラウンドダウンロード中止
このギャラリーを削除
ダウンロード
+ ページ移動
+ 現ページ番号: %1$d\nページ数: %2$d
+ hitomi.laに接続できません
+ %1$dページへ移動
+ (Korean only)
+ (Korean only)
\ 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 b46801e1..003f882c 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -3,8 +3,8 @@
언어: %1$s
시리즈: %1$s
종류: %1$s
- 권한을 거부하면 일부 기능이 작동하지 않을 수 있습니다
갤러리 검색
+ 갤러리 검색
기본 검색어
이미지 캐시 정리하기
캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?
@@ -53,4 +53,10 @@
백그라운드 다운로드 취소
갤러리 삭제
다운로드
+ 페이지 이동
+ 현재 페이지: %1$d\n페이지 수: %2$d
+ hitomi.la에 연결할 수 없습니다
+ %1$d 페이지로 이동
+ 접속 불가 현상 안내
+ 최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다\n이 경우 플레이스토어에서 SNIper앱을 이용하시면 정상이용이 가능합니다.
\ No newline at end of file
diff --git a/app/src/main/res/values-v23/styles.xml b/app/src/main/res/values-v23/styles.xml
deleted file mode 100644
index 1c4f0c38..00000000
--- a/app/src/main/res/values-v23/styles.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
\ 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 8b5eb247..1a4abd09 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -12,7 +12,7 @@
Thumbnail
Content ImageView
- -/-
+ -/-
Fab
@@ -20,11 +20,14 @@
Warning
- Denying any permission can deactivate some functions
+ (Korean only)
+ (Korean only)
Download
Shows download status
+ Unable to connect to hitomi.la
+
Search
No result
@@ -37,6 +40,11 @@
Visit github
Email me!
+ Jump to page
+ Current page: %1$d\nMaximum page: %2$d
+
+ Move to page %1$d
+
Delete this gallery
WIP
@@ -48,6 +56,7 @@
# Release Note(v%1$s)\n%2$s
Search galleries
+ Search galleries
Series: %1$s
Type: %1$s
diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt b/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt
index cd4859b0..42aece05 100644
--- a/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt
+++ b/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt
@@ -10,7 +10,7 @@ import java.util.*
import javax.net.ssl.HttpsURLConnection
//galleryblock.js
-fun fetchNozomi(area: String? = null, tag: String = "index", language: String = "all", start: Int = -1, count: Int = -1) : List {
+fun fetchNozomi(area: String? = null, tag: String = "index", language: String = "all", start: Int = -1, count: Int = -1) : Pair, Int> {
val url =
when(area) {
null -> "$protocol//$domain/$tag-$language$nozomiextension"
@@ -28,6 +28,11 @@ fun fetchNozomi(area: String? = null, tag: String = "index", language: String =
setRequestProperty("Range", "bytes=$startByte-$endByte")
}
+ connect()
+
+ val totalItems = getHeaderField("Content-Range")
+ .replace(Regex("^[Bb]ytes \\d+-\\d+/"), "").toInt() / 4
+
val nozomi = ArrayList()
val arrayBuffer = ByteBuffer
@@ -37,10 +42,10 @@ fun fetchNozomi(area: String? = null, tag: String = "index", language: String =
while (arrayBuffer.hasRemaining())
nozomi.add(arrayBuffer.int)
- return nozomi
+ return Pair(nozomi, totalItems)
}
} catch (e: Exception) {
- return emptyList()
+ return Pair(emptyList(), 0)
}
}