diff --git a/.idea/misc.xml b/.idea/misc.xml index 7631aec3..84da703c 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 ea00135a..c7cfaa59 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,6 +41,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation "ru.noties.markwon:core:${markwonVersion}" implementation 'com.shawnlin:number-picker:2.4.8' + implementation 'com.github.clans:fab:1.6.4' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test:runner:1.1.1' diff --git a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt index 80471c11..f6e56537 100644 --- a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt @@ -1,19 +1,23 @@ package xyz.quaver.pupil import android.os.Bundle -import android.util.Log import android.view.* import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.PagerSnapHelper import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.android.synthetic.main.activity_reader.view.* import kotlinx.android.synthetic.main.dialog_numberpicker.view.* import kotlinx.coroutines.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonConfiguration +import kotlinx.serialization.list import xyz.quaver.hitomi.Reader +import xyz.quaver.hitomi.ReaderItem import xyz.quaver.hitomi.getReader import xyz.quaver.hitomi.getReferer import xyz.quaver.pupil.adapters.ReaderAdapter @@ -32,7 +36,10 @@ class ReaderActivity : AppCompatActivity() { private lateinit var reader: Deferred private var loadJob: Job? = null - private lateinit var snapHelper: PagerSnapHelper + private var isScroll = true + private var isFullscreen = false + + private val snapHelper = PagerSnapHelper() private var menu: Menu? = null @@ -48,44 +55,39 @@ class ReaderActivity : AppCompatActivity() { supportActionBar?.title = intent.getStringExtra("GALLERY_TITLE") galleryID = intent.getIntExtra("GALLERY_ID", 0) - CoroutineScope(Dispatchers.Unconfined).launch { - reader = async(Dispatchers.IO) { - val preference = PreferenceManager.getDefaultSharedPreferences(this@ReaderActivity) - if (preference.getBoolean("use_hiyobi", false)) { - try { - xyz.quaver.hiyobi.getReader(galleryID) - } catch (e: Exception) { + reader = CoroutineScope(Dispatchers.IO).async { + val json = Json(JsonConfiguration.Stable) + val serializer = ReaderItem.serializer().list + val preference = PreferenceManager.getDefaultSharedPreferences(this@ReaderActivity) + val isHiyobi = preference.getBoolean("use_hiyobi", false) + + val cache = when { + isHiyobi -> File(cacheDir, "imageCache/$galleryID/reader-hiyobi.json") + else -> File(cacheDir, "imageCache/$galleryID/reader.json") + } + + if (cache.exists()) + json.parse(serializer, cache.readText()) + else { + val reader = when { + isHiyobi -> { + try { + xyz.quaver.hiyobi.getReader(galleryID) + } catch (e: Exception) { + getReader(galleryID) + } + } + else -> { getReader(galleryID) } } - getReader(galleryID) + + cache.writeText(json.stringify(serializer, reader)) + + reader } } - snapHelper = PagerSnapHelper() - - val preferences = PreferenceManager.getDefaultSharedPreferences(this) - - val attrs = window.attributes - - if (preferences.getBoolean("reader_fullscreen", false)) { - attrs.flags = attrs.flags or WindowManager.LayoutParams.FLAG_FULLSCREEN - supportActionBar?.hide() - } else { - attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv() - supportActionBar?.show() - } - - window.attributes = attrs - - if (preferences.getBoolean("reader_one_by_one", false)) { - snapHelper.attachToRecyclerView(reader_recyclerview) - reader_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false) - } else { - snapHelper.attachToRecyclerView(null) - reader_recyclerview.layoutManager = LinearLayoutManager(this) - } - initView() loadImages() } @@ -138,6 +140,21 @@ class ReaderActivity : AppCompatActivity() { loadJob?.cancel() } + override fun onBackPressed() { + if (isScroll and !isFullscreen) + super.onBackPressed() + + if (isFullscreen) { + isFullscreen = false + fullscreen(false) + } + + if (!isScroll) { + isScroll = true + scrollMode(true) + } + } + private fun initView() { with(reader_recyclerview) { adapter = ReaderAdapter(images) @@ -155,45 +172,61 @@ class ReaderActivity : AppCompatActivity() { } }) - val preferences = PreferenceManager.getDefaultSharedPreferences(context) ItemClickSupport.addTo(this) .setOnItemClickListener { _, _, _ -> - val attrs = window.attributes - val fullscreen = preferences.getBoolean("reader_fullscreen", false) + if (isScroll) { + isScroll = false + isFullscreen = true - if (fullscreen) { - attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv() - supportActionBar?.show() + scrollMode(false) + fullscreen(true) } else { - attrs.flags = attrs.flags or WindowManager.LayoutParams.FLAG_FULLSCREEN - supportActionBar?.hide() + val smoothScroller = object : LinearSmoothScroller(context) { + override fun getVerticalSnapPreference() = SNAP_TO_START + }.apply { + targetPosition = currentPage + } + (reader_recyclerview.layoutManager as LinearLayoutManager?)?.startSmoothScroll(smoothScroller) } - - window.attributes = attrs - - preferences.edit().putBoolean("reader_fullscreen", !fullscreen).apply() - }.setOnItemLongClickListener { _, _, _ -> - val oneByOne = preferences.getBoolean("reader_one_by_one", false) - if (oneByOne) { - snapHelper.attachToRecyclerView(null) - reader_recyclerview.layoutManager = LinearLayoutManager(context) - } - else { - snapHelper.attachToRecyclerView(reader_recyclerview) - reader_recyclerview.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - } - - (reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0) - - preferences.edit().putBoolean("reader_one_by_one", !oneByOne).apply() - - true } } + + reader_fab_fullscreen.setOnClickListener { + isFullscreen = true + fullscreen(isFullscreen) + } + } + + private fun fullscreen(isFullscreen: Boolean) { + with(window.attributes) { + if (isFullscreen) { + flags = flags or WindowManager.LayoutParams.FLAG_FULLSCREEN + supportActionBar?.hide() + this@ReaderActivity.reader_fab.visibility = View.INVISIBLE + } else { + flags = flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv() + supportActionBar?.show() + this@ReaderActivity.reader_fab.visibility = View.VISIBLE + } + + window.attributes = this + } + } + + private fun scrollMode(isScroll: Boolean) { + if (isScroll) { + snapHelper.attachToRecyclerView(null) + reader_recyclerview.layoutManager = LinearLayoutManager(this) + } else { + snapHelper.attachToRecyclerView(reader_recyclerview) + reader_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false) + } + + (reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0) } private fun loadImages() { - fun webpUrlFromUrl(url: URL) = URL(url.toString().replace("/galleries/", "/webp/") + ".webp") + fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp" loadJob = CoroutineScope(Dispatchers.Default).launch { val reader = reader.await() @@ -213,18 +246,18 @@ class ReaderActivity : AppCompatActivity() { reader.chunked(8).forEach { chunked -> chunked.map { async(Dispatchers.IO) { - val url = if (it.second?.haswebp == 1) webpUrlFromUrl(it.first) else it.first + val url = if (it.galleryInfo?.haswebp == 1) webpUrlFromUrl(it.url) else it.url val fileName: String - with(url.path) { + with(url) { fileName = substring(lastIndexOf('/')+1) } val cache = File(cacheDir, "/imageCache/$galleryID/$fileName") if (!cache.exists()) - with(url.openConnection() as HttpsURLConnection) { + with(URL(url).openConnection() as HttpsURLConnection) { setRequestProperty("Referer", getReferer(galleryID)) if (!cache.parentFile.exists()) diff --git a/app/src/main/res/drawable-anydpi/ic_fullscreen.xml b/app/src/main/res/drawable-anydpi/ic_fullscreen.xml new file mode 100644 index 00000000..f9831623 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_fullscreen.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen.png b/app/src/main/res/drawable-hdpi/ic_fullscreen.png new file mode 100644 index 00000000..c72a9b9e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fullscreen.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen.png b/app/src/main/res/drawable-mdpi/ic_fullscreen.png new file mode 100644 index 00000000..f19ccbfa Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fullscreen.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png new file mode 100644 index 00000000..6caba05d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png new file mode 100644 index 00000000..4712c6c1 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png differ diff --git a/app/src/main/res/drawable/github_circle.xml b/app/src/main/res/drawable/github_circle.xml new file mode 100644 index 00000000..7df41959 --- /dev/null +++ b/app/src/main/res/drawable/github_circle.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index a77f48e5..f77b8d6b 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -6,12 +6,18 @@ android:layout_height="match_parent" tools:context=".ReaderActivity"> - + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"> + + + + + + + + + + \ 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 d9519336..a0018929 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -43,4 +43,5 @@ メールを送る 準備中 準備中です。 + フルスクリーン \ 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 1ecefb30..a4de07d9 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -43,4 +43,5 @@ 문의 준비 중 준비중입니다.\n만화 화면에서 사진을 길게 누르면 스크롤 방식이 바뀝니다. 알고 계셨나요? :) + 전체 화면 \ 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 551b9f54..97f25378 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -48,6 +48,7 @@ Language: %1$s Go to page + Fullscreen Settings Search Settings diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/readers.kt b/libpupil/src/main/java/xyz/quaver/hitomi/readers.kt index 5fee483d..f2a06ec1 100644 --- a/libpupil/src/main/java/xyz/quaver/hitomi/readers.kt +++ b/libpupil/src/main/java/xyz/quaver/hitomi/readers.kt @@ -16,7 +16,12 @@ data class GalleryInfo( val name: String, val height: Int ) -typealias Reader = List> +@Serializable +data class ReaderItem( + val url: String, + val galleryInfo: GalleryInfo? +) +typealias Reader = List //Set header `Referer` to reader url to avoid 403 error fun getReader(galleryID: Int) : Reader { val readerUrl = "https://hitomi.la/reader/$galleryID.html" @@ -25,7 +30,7 @@ fun getReader(galleryID: Int) : Reader { val doc = Jsoup.connect(readerUrl).get() val images = doc.select(".img-url").map { - URL(protocol + urlFromURL(it.text())) + protocol + urlFromURL(it.text()) } val galleryInfo = ArrayList() @@ -42,5 +47,7 @@ fun getReader(galleryID: Int) : Reader { if (images.size > galleryInfo.size) galleryInfo.addAll(arrayOfNulls(images.size - galleryInfo.size)) - return images zip galleryInfo + return (images zip galleryInfo).map { + ReaderItem(it.first, it.second) + } } \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt b/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt index dfd289bb..47f766b4 100644 --- a/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt +++ b/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt @@ -4,6 +4,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.json.content import xyz.quaver.hitomi.Reader +import xyz.quaver.hitomi.ReaderItem import java.net.URL import javax.net.ssl.HttpsURLConnection @@ -42,6 +43,6 @@ fun getReader(galleryId: Int) : Reader { return json.jsonArray.map { val name = it.jsonObject["name"]!!.content - Pair(URL("https://$hiyobi/data/$galleryId/$name"), null) + ReaderItem("https://$hiyobi/data/$galleryId/$name", null) } } \ No newline at end of file