Bug fix
Add paging
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8 (2)" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<List<Int>>? = 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<SearchInputView>(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<ImageView>(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<ImageView>(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<ImageView>(R.id.icon_prev)
|
||||
val text = prev.findViewById<TextView>(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<ImageView>(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<ImageView>(R.id.icon_next)
|
||||
val text = next.findViewById<TextView>(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<ImageView>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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<Pair<GalleryBlock, Deferred<String>>>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private enum class ViewType {
|
||||
VIEW_ITEM,
|
||||
VIEW_PROG
|
||||
enum class ViewType {
|
||||
NEXT,
|
||||
GALLERY,
|
||||
PREV
|
||||
}
|
||||
|
||||
private fun String.wordCapitalize() : String {
|
||||
val result = ArrayList<String>()
|
||||
|
||||
for (word in this.split(" "))
|
||||
result.add(word.capitalize())
|
||||
|
||||
return result.joinToString(" ")
|
||||
}
|
||||
|
||||
var noMore = false
|
||||
private val refreshTasks = SparseArray<TimerTask>()
|
||||
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<GalleryBlock, Deferred<String>>) {
|
||||
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<String>) = item
|
||||
|
||||
val artists = gallery.artists
|
||||
val series = gallery.series
|
||||
@@ -99,7 +62,7 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
|
||||
val bitmap = BitmapFactory.decodeFile(thumbnail.await())
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
post {
|
||||
galleryblock_thumbnail.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
@@ -122,10 +85,10 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
galleryblock_progressbar.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (refreshTasks.get(gallery.id) == null) {
|
||||
if (refreshTasks[this@GalleryViewHolder] == null) {
|
||||
val refresh = Timer(false).schedule(0, 1000) {
|
||||
post {
|
||||
with(galleryblock_progressbar) {
|
||||
with(view.galleryblock_progressbar) {
|
||||
progress = imageCache.list()?.size ?: 0
|
||||
|
||||
if (!readerCache.exists()) {
|
||||
@@ -133,7 +96,7 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
max = 0
|
||||
progress = 0
|
||||
|
||||
holder.view.galleryblock_progress_complete.visibility = View.INVISIBLE
|
||||
view.galleryblock_progress_complete.visibility = View.INVISIBLE
|
||||
} else {
|
||||
if (visibility == View.GONE) {
|
||||
val reader = Json(JsonConfiguration.Stable)
|
||||
@@ -144,24 +107,21 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
|
||||
if (progress == max) {
|
||||
if (completeFlag.get(gallery.id, false)) {
|
||||
with(holder.view.galleryblock_progress_complete) {
|
||||
with(view.galleryblock_progress_complete) {
|
||||
setImageResource(R.drawable.ic_progressbar)
|
||||
visibility = View.VISIBLE
|
||||
}
|
||||
} else {
|
||||
val drawable = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_progressbar_complete)
|
||||
with(holder.view.galleryblock_progress_complete) {
|
||||
with(view.galleryblock_progress_complete) {
|
||||
setImageDrawable(drawable)
|
||||
visibility = View.VISIBLE
|
||||
}
|
||||
drawable?.start()
|
||||
completeFlag.put(gallery.id, true)
|
||||
}
|
||||
} else {
|
||||
with(holder.view.galleryblock_progress_complete) {
|
||||
visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
} else
|
||||
view.galleryblock_progress_complete.visibility = View.INVISIBLE
|
||||
|
||||
null
|
||||
}
|
||||
@@ -169,7 +129,7 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
}
|
||||
}
|
||||
|
||||
refreshTasks.put(gallery.id, refresh)
|
||||
refreshTasks[this@GalleryViewHolder] = refresh
|
||||
}
|
||||
|
||||
galleryblock_title.text = gallery.title
|
||||
@@ -205,7 +165,7 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
val tag = Tag.parse(it)
|
||||
|
||||
val chip = LayoutInflater.from(context)
|
||||
.inflate(R.layout.tag_chip, holder.view, false) as Chip
|
||||
.inflate(R.layout.tag_chip, this, false) as Chip
|
||||
|
||||
val icon = when(tag.area) {
|
||||
"male" -> {
|
||||
@@ -232,32 +192,85 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
|
||||
}
|
||||
}
|
||||
}
|
||||
if (holder is ProgressViewHolder) {
|
||||
holder.view.visibility = when(noMore) {
|
||||
true -> 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<String>()
|
||||
|
||||
for (word in this.split(" "))
|
||||
result.add(word.capitalize())
|
||||
|
||||
return result.joinToString(" ")
|
||||
}
|
||||
|
||||
private val refreshTasks = HashMap<GalleryViewHolder, TimerTask>()
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ class GalleryDownloader(
|
||||
var onReaderLoadedHandler: ((Reader) -> Unit)? = null
|
||||
var onProgressHandler: ((Int) -> Unit)? = null
|
||||
var onDownloadedHandler: ((List<String>) -> 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<String>()
|
||||
|
||||
onReaderLoadedHandler?.invoke(reader)
|
||||
@@ -162,7 +163,7 @@ class GalleryDownloader(
|
||||
} catch (e: Exception) {
|
||||
cache.delete()
|
||||
|
||||
onErrorHandler?.invoke()
|
||||
onErrorHandler?.invoke(e)
|
||||
|
||||
notificationBuilder
|
||||
.setContentTitle(galleryBlock.title)
|
||||
|
||||
14
app/src/main/res/drawable/ic_jump.xml
Normal file
14
app/src/main/res/drawable/ic_jump.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:pathData="M18.4,10.6C16.55,8.99 14.15,8 11.5,8c-4.65,0 -8.58,3.03 -9.96,7.22L3.9,16c1.05,-3.19 4.05,-5.5 7.6,-5.5 1.95,0 3.73,0.72 5.12,1.88L13,16h9V7l-3.6,3.6z"/>
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:pathData="M8.5,15
|
||||
a1.5,1.5 0 1,1 1.5,1.5
|
||||
a1.5,1.5 0 0,1 -1.5,-1.5 Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
|
||||
</vector>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
android:id="@+id/main_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
@@ -22,7 +23,7 @@
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_height="64dp"
|
||||
android:visibility="invisible"
|
||||
android:background="@color/transparent"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
@@ -46,22 +47,14 @@
|
||||
android:text="@string/main_no_result"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/main_swipe_layout"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/main_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="-80dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/main_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="80dp"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
android:paddingTop="64dp"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/reader_layout"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
@@ -39,6 +40,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
app:menu_colorNormal="@color/colorAccent">
|
||||
|
||||
<com.github.clans.fab.FloatingActionButton
|
||||
@@ -46,7 +48,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_downloading"
|
||||
android:tint="@android:color/white"
|
||||
app:fab_label="@string/reader_fab_download"
|
||||
app:fab_size="mini"/>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceLarge"
|
||||
android:id="@+id/reader_dialog_title"
|
||||
android:id="@+id/dialog_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reader_go_to_page"
|
||||
@@ -15,20 +15,20 @@
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/reader_dialog_number_picker"
|
||||
android:id="@+id/dialog_number_picker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/reader_dialog_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/dialog_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/reader_dialog_ok"
|
||||
android:id="@+id/dialog_ok"
|
||||
style="?borderlessButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/ok"
|
||||
app:layout_constraintTop_toBottomOf="@id/reader_dialog_number_picker"
|
||||
app:layout_constraintTop_toBottomOf="@id/dialog_number_picker"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
|
||||
35
app/src/main/res/layout/item_next.xml
Normal file
35
app/src/main/res/layout/item_next.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_next"
|
||||
android:contentDescription="@string/page_indicator_placeholder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/ic_navigate_next_black_24dp"
|
||||
android:tint="@color/colorAccent"
|
||||
android:rotation="180"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_next"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
||||
35
app/src/main/res/layout/item_prev.xml
Normal file
35
app/src/main/res/layout/item_prev.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_prev"
|
||||
android:contentDescription="@string/page_indicator_placeholder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/ic_navigate_next_black_24dp"
|
||||
android:tint="@color/colorAccent"
|
||||
android:rotation="180"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_prev"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -2,10 +2,9 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/main_menu_search"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:title="@string/main_search"
|
||||
<item android:id="@+id/main_menu_page_indicator"
|
||||
android:icon="@drawable/ic_jump"
|
||||
android:title="@string/page_indicator_placeholder"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:id="@+id/reader_menu_page_indicator"
|
||||
android:title="@string/reader_page_indicator_placeholder"
|
||||
android:title="@string/page_indicator_placeholder"
|
||||
app:showAsAction="always|withText"/>
|
||||
|
||||
</menu>
|
||||
@@ -6,12 +6,12 @@
|
||||
<string name="main_no_result">結果なし</string>
|
||||
<string name="main_search">検索</string>
|
||||
<string name="search_hint">ギャラリー検索</string>
|
||||
<string name="search_hint_with_page">ギャラリー検索</string>
|
||||
<string name="settings_cache_title">キャッシュ</string>
|
||||
<string name="settings_clear_image_cache">イメージキャッシュクリア</string>
|
||||
<string name="settings_clear_cache_alert_message">キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?</string>
|
||||
<string name="settings_clear_cache_summary">キャッシュサイズ: %1$d%2$s</string>
|
||||
<string name="settings_default_query">デフォルトキーワード</string>
|
||||
<string name="permission_explain">権限を拒否すると一部の機能が利用できません</string>
|
||||
<string name="settings_galleries_per_page">一回にロードするギャラリー数</string>
|
||||
<string name="settings_search_title">検索設定</string>
|
||||
<string name="settings_title">設定</string>
|
||||
@@ -53,4 +53,10 @@
|
||||
<string name="reader_fab_download_cancel">バックグラウンドダウンロード中止</string>
|
||||
<string name="main_dialog_delete">このギャラリーを削除</string>
|
||||
<string name="main_drawer_downloads">ダウンロード</string>
|
||||
<string name="main_jump_title">ページ移動</string>
|
||||
<string name="main_jump_message">現ページ番号: %1$d\nページ数: %2$d</string>
|
||||
<string name="unable_to_connect">hitomi.laに接続できません</string>
|
||||
<string name="main_move">%1$dページへ移動</string>
|
||||
<string name="https_block_alert_title">(Korean only)</string>
|
||||
<string name="https_block_alert">(Korean only)</string>
|
||||
</resources>
|
||||
@@ -3,8 +3,8 @@
|
||||
<string name="galleryblock_language">언어: %1$s</string>
|
||||
<string name="galleryblock_series">시리즈: %1$s</string>
|
||||
<string name="galleryblock_type">종류: %1$s</string>
|
||||
<string name="permission_explain">권한을 거부하면 일부 기능이 작동하지 않을 수 있습니다</string>
|
||||
<string name="search_hint">갤러리 검색</string>
|
||||
<string name="search_hint_with_page">갤러리 검색</string>
|
||||
<string name="settings_default_query">기본 검색어</string>
|
||||
<string name="settings_clear_image_cache">이미지 캐시 정리하기</string>
|
||||
<string name="settings_clear_cache_alert_message">캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?</string>
|
||||
@@ -53,4 +53,10 @@
|
||||
<string name="reader_fab_download_cancel">백그라운드 다운로드 취소</string>
|
||||
<string name="main_dialog_delete">갤러리 삭제</string>
|
||||
<string name="main_drawer_downloads">다운로드</string>
|
||||
<string name="main_jump_title">페이지 이동</string>
|
||||
<string name="main_jump_message">현재 페이지: %1$d\n페이지 수: %2$d</string>
|
||||
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
|
||||
<string name="main_move">%1$d 페이지로 이동</string>
|
||||
<string name="https_block_alert_title">접속 불가 현상 안내</string>
|
||||
<string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다\n이 경우 플레이스토어에서 SNIper앱을 이용하시면 정상이용이 가능합니다.</string>
|
||||
</resources>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="NoActionBarAppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -12,7 +12,7 @@
|
||||
<string name="galleryblock_thumbnail_description" translatable="false">Thumbnail</string>
|
||||
|
||||
<string name="reader_imageview_description" translatable="false">Content ImageView</string>
|
||||
<string name="reader_page_indicator_placeholder" translatable="false">-/-</string>
|
||||
<string name="page_indicator_placeholder" translatable="false">-/-</string>
|
||||
|
||||
<string name="plus_to_close" translatable="false">Fab</string>
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
|
||||
<string name="warning">Warning</string>
|
||||
|
||||
<string name="permission_explain">Denying any permission can deactivate some functions</string>
|
||||
<string name="https_block_alert_title">(Korean only)</string>
|
||||
<string name="https_block_alert">(Korean only)</string>
|
||||
|
||||
<string name="channel_download">Download</string>
|
||||
<string name="channel_download_description">Shows download status</string>
|
||||
|
||||
<string name="unable_to_connect">Unable to connect to hitomi.la</string>
|
||||
|
||||
<string name="main_search">Search</string>
|
||||
<string name="main_no_result">No result</string>
|
||||
|
||||
@@ -37,6 +40,11 @@
|
||||
<string name="main_drawer_group_contact_github">Visit github</string>
|
||||
<string name="main_drawer_group_contact_email">Email me!</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_move">Move to page %1$d</string>
|
||||
|
||||
<string name="main_dialog_delete">Delete this gallery</string>
|
||||
|
||||
<string name="help_dialog_title">WIP</string>
|
||||
@@ -48,6 +56,7 @@
|
||||
<string name="update_release_note"># Release Note(v%1$s)\n%2$s</string>
|
||||
|
||||
<string name="search_hint">Search galleries</string>
|
||||
<string name="search_hint_with_page">Search galleries</string>
|
||||
|
||||
<string name="galleryblock_series">Series: %1$s</string>
|
||||
<string name="galleryblock_type">Type: %1$s</string>
|
||||
|
||||
@@ -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<Int> {
|
||||
fun fetchNozomi(area: String? = null, tag: String = "index", language: String = "all", start: Int = -1, count: Int = -1) : Pair<List<Int>, 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<Int>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user