UI update
Added sort by popularity functionality Added auto update
This commit is contained in:
112
.idea/codeStyles/Project.xml
generated
112
.idea/codeStyles/Project.xml
generated
@@ -1,8 +1,120 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
|
<AndroidXmlCodeStyleSettings>
|
||||||
|
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
||||||
|
</AndroidXmlCodeStyleSettings>
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
|
<XML>
|
||||||
|
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
||||||
|
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
||||||
|
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||||
|
</XML>
|
||||||
|
<codeStyleSettings language="XML">
|
||||||
|
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
<arrangement>
|
||||||
|
<rules>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:android</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:.*</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:id</NAME>
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:name</NAME>
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>name</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>style</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
</rules>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
<codeStyleSettings language="kotlin">
|
<codeStyleSettings language="kotlin">
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ android {
|
|||||||
applicationId "xyz.quaver.pupil"
|
applicationId "xyz.quaver.pupil"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 20
|
versionCode 21
|
||||||
versionName "2.12"
|
versionName "2.12"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
@@ -24,6 +24,9 @@ android {
|
|||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
|
buildTypes.each {
|
||||||
|
it.buildConfigField('boolean', 'PRERELEASE', 'true')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental'
|
freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental'
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":20,"versionName":"2.11.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":21,"versionName":"2.12","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
||||||
@@ -3,7 +3,9 @@
|
|||||||
package="xyz.quaver.pupil">
|
package="xyz.quaver.pupil">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="28"/>
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".Pupil"
|
android:name=".Pupil"
|
||||||
@@ -14,6 +16,7 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
<activity android:name=".ui.LockActivity"/>
|
<activity android:name=".ui.LockActivity"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ReaderActivity"
|
android:name=".ui.ReaderActivity"
|
||||||
|
|||||||
@@ -18,10 +18,13 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil
|
package xyz.quaver.pupil
|
||||||
|
|
||||||
|
import android.app.DownloadManager
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Pupil, Hitomi.la viewer for Android
|
|
||||||
* Copyright (C) 2019 tom5079
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package xyz.quaver.pupil.types
|
|
||||||
|
|
||||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
|
||||||
import xyz.quaver.hitomi.Suggestion
|
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
class SelectorSuggestion : SearchSuggestion {
|
|
||||||
|
|
||||||
override fun getBody(): String {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,11 +20,16 @@ package xyz.quaver.pupil.ui
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.DownloadManager
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
import android.text.*
|
import android.text.*
|
||||||
import android.text.style.AlignmentSpan
|
import android.text.style.AlignmentSpan
|
||||||
import android.view.*
|
import android.view.*
|
||||||
@@ -35,9 +40,9 @@ import android.widget.TextView
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
@@ -60,11 +65,9 @@ import kotlinx.serialization.list
|
|||||||
import kotlinx.serialization.stringify
|
import kotlinx.serialization.stringify
|
||||||
import ru.noties.markwon.Markwon
|
import ru.noties.markwon.Markwon
|
||||||
import xyz.quaver.hitomi.*
|
import xyz.quaver.hitomi.*
|
||||||
import xyz.quaver.pupil.BuildConfig
|
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||||
import xyz.quaver.pupil.types.SelectorSuggestion
|
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.types.TagSuggestion
|
import xyz.quaver.pupil.types.TagSuggestion
|
||||||
import xyz.quaver.pupil.types.Tags
|
import xyz.quaver.pupil.types.Tags
|
||||||
@@ -88,6 +91,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
DOWNLOAD,
|
DOWNLOAD,
|
||||||
FAVORITE
|
FAVORITE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SortMode {
|
||||||
|
NEWEST,
|
||||||
|
POPULAR
|
||||||
|
}
|
||||||
|
|
||||||
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
|
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
|
||||||
|
|
||||||
@@ -101,6 +109,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var mode = Mode.SEARCH
|
private var mode = Mode.SEARCH
|
||||||
|
private var sortMode = SortMode.NEWEST
|
||||||
|
|
||||||
private val REQUEST_SETTINGS = 45162
|
private val REQUEST_SETTINGS = 45162
|
||||||
private val REQUEST_LOCK = 561
|
private val REQUEST_LOCK = 561
|
||||||
@@ -156,7 +165,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
else -> super.onBackPressed()
|
else -> super.onBackPressed()
|
||||||
@@ -189,7 +198,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +212,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +230,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,14 +287,36 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
val update =
|
val update =
|
||||||
checkUpdate(getString(R.string.release_url), BuildConfig.VERSION_NAME) ?: return@launch
|
checkUpdate(getString(R.string.release_url)) ?: return@launch
|
||||||
|
|
||||||
|
val (url, fileName) = getApkUrl(update) ?: return@launch
|
||||||
|
fileName ?: return@launch
|
||||||
|
|
||||||
val dialog = AlertDialog.Builder(this@MainActivity).apply {
|
val dialog = AlertDialog.Builder(this@MainActivity).apply {
|
||||||
setTitle(R.string.update_title)
|
setTitle(R.string.update_title)
|
||||||
val msg = extractReleaseNote(update, Locale.getDefault().language)
|
val msg = extractReleaseNote(update, Locale.getDefault().language)
|
||||||
setMessage(Markwon.create(context).toMarkdown(msg))
|
setMessage(Markwon.create(context).toMarkdown(msg))
|
||||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.update))))
|
val request = DownloadManager.Request(Uri.parse(url)).apply {
|
||||||
|
setDescription(getString(R.string.update_notification_description))
|
||||||
|
setTitle(getString(R.string.app_name))
|
||||||
|
setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
val id = manager.enqueue(request)
|
||||||
|
|
||||||
|
registerReceiver(object: BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
val install = Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
setDataAndType(manager.getUriForDownloadedFile(id), manager.getMimeTypeForDownloadedFile(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivity(install)
|
||||||
|
unregisterReceiver(this)
|
||||||
|
}
|
||||||
|
}, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
||||||
}
|
}
|
||||||
setNegativeButton(android.R.string.no) { _, _ ->}
|
setNegativeButton(android.R.string.no) { _, _ ->}
|
||||||
}
|
}
|
||||||
@@ -308,6 +339,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
main_searchview.translationY = p1.toFloat()
|
main_searchview.translationY = p1.toFloat()
|
||||||
main_recyclerview.scrollBy(0, prevP1 - p1)
|
main_recyclerview.scrollBy(0, prevP1 - p1)
|
||||||
|
|
||||||
|
with(main_fab) {
|
||||||
|
if (prevP1 > p1)
|
||||||
|
hideMenuButton(true)
|
||||||
|
else if (prevP1 < p1)
|
||||||
|
showMenuButton(true)
|
||||||
|
}
|
||||||
|
|
||||||
prevP1 = p1
|
prevP1 = p1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -324,7 +362,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
currentPage = 0
|
currentPage = 0
|
||||||
query = ""
|
query = ""
|
||||||
mode = Mode.SEARCH
|
mode = Mode.SEARCH
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
R.id.main_drawer_history -> {
|
R.id.main_drawer_history -> {
|
||||||
@@ -333,7 +371,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
currentPage = 0
|
currentPage = 0
|
||||||
query = ""
|
query = ""
|
||||||
mode = Mode.HISTORY
|
mode = Mode.HISTORY
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
R.id.main_drawer_downloads -> {
|
R.id.main_drawer_downloads -> {
|
||||||
@@ -342,7 +380,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
currentPage = 0
|
currentPage = 0
|
||||||
query = ""
|
query = ""
|
||||||
mode = Mode.DOWNLOAD
|
mode = Mode.DOWNLOAD
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
R.id.main_drawer_favorite -> {
|
R.id.main_drawer_favorite -> {
|
||||||
@@ -351,7 +389,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
currentPage = 0
|
currentPage = 0
|
||||||
query = ""
|
query = ""
|
||||||
mode = Mode.FAVORITE
|
mode = Mode.FAVORITE
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
R.id.main_drawer_help -> {
|
R.id.main_drawer_help -> {
|
||||||
@@ -375,9 +413,67 @@ class MainActivity : AppCompatActivity() {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with(main_fab_jump) {
|
||||||
|
setImageResource(R.drawable.ic_jump)
|
||||||
|
setOnClickListener {
|
||||||
|
val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val perPage = preference.getString("per_page", "25")!!.toInt()
|
||||||
|
val editText = EditText(context)
|
||||||
|
|
||||||
|
AlertDialog.Builder(context).apply {
|
||||||
|
setView(editText)
|
||||||
|
setTitle(R.string.main_jump_title)
|
||||||
|
setMessage(getString(
|
||||||
|
R.string.main_jump_message,
|
||||||
|
currentPage+1,
|
||||||
|
ceil(totalItems / perPage.toDouble()).roundToInt()
|
||||||
|
))
|
||||||
|
|
||||||
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
currentPage = (editText.text.toString().toIntOrNull() ?: return@setPositiveButton)-1
|
||||||
|
|
||||||
|
runOnUiThread {
|
||||||
|
cancelFetch()
|
||||||
|
clearGalleries()
|
||||||
|
fetchGalleries(query, sortMode)
|
||||||
|
loadBlocks()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(main_fab_id) {
|
||||||
|
setImageResource(R.drawable.numeric)
|
||||||
|
setOnClickListener {
|
||||||
|
val editText = EditText(context)
|
||||||
|
|
||||||
|
AlertDialog.Builder(context).apply {
|
||||||
|
setView(editText)
|
||||||
|
setTitle(R.string.main_open_gallery_by_id)
|
||||||
|
|
||||||
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
try {
|
||||||
|
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
||||||
|
val gallery =
|
||||||
|
getGalleryBlock(editText.text.toString().toInt()) ?: throw Exception()
|
||||||
|
intent.putExtra("galleryID", gallery.id)
|
||||||
|
|
||||||
|
startActivity(intent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Snackbar.make(main_layout,
|
||||||
|
R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setupSearchBar()
|
setupSearchBar()
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +487,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,7 +555,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
fetchGalleries(query, sortMode)
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,7 +623,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
fetchGalleries(query)
|
|
||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,55 +809,31 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
when(it.itemId) {
|
when(it.itemId) {
|
||||||
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS)
|
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS)
|
||||||
R.id.main_menu_jump -> {
|
R.id.main_menu_sort_newest -> {
|
||||||
val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
sortMode = SortMode.NEWEST
|
||||||
val perPage = preference.getString("per_page", "25")!!.toInt()
|
it.isChecked = true
|
||||||
val editText = EditText(context)
|
|
||||||
|
|
||||||
AlertDialog.Builder(context).apply {
|
runOnUiThread {
|
||||||
setView(editText)
|
currentPage = 0
|
||||||
setTitle(R.string.main_jump_title)
|
|
||||||
setMessage(getString(
|
|
||||||
R.string.main_jump_message,
|
|
||||||
currentPage+1,
|
|
||||||
ceil(totalItems / perPage.toDouble()).roundToInt()
|
|
||||||
))
|
|
||||||
|
|
||||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
cancelFetch()
|
||||||
currentPage = (editText.text.toString().toIntOrNull() ?: return@setPositiveButton)-1
|
clearGalleries()
|
||||||
|
fetchGalleries(query, sortMode)
|
||||||
runOnUiThread {
|
loadBlocks()
|
||||||
cancelFetch()
|
}
|
||||||
clearGalleries()
|
|
||||||
fetchGalleries(query)
|
|
||||||
loadBlocks()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
}
|
||||||
R.id.main_menu_id -> {
|
R.id.main_menu_sort_popular -> {
|
||||||
val editText = EditText(context)
|
sortMode = SortMode.POPULAR
|
||||||
|
it.isChecked = true
|
||||||
|
|
||||||
AlertDialog.Builder(context).apply {
|
runOnUiThread {
|
||||||
setView(editText)
|
currentPage = 0
|
||||||
setTitle(R.string.main_open_gallery_by_id)
|
|
||||||
|
|
||||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
cancelFetch()
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
clearGalleries()
|
||||||
try {
|
fetchGalleries(query, sortMode)
|
||||||
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
loadBlocks()
|
||||||
val gallery =
|
}
|
||||||
getGalleryBlock(editText.text.toString().toInt()) ?: throw Exception()
|
|
||||||
intent.putExtra("galleryID", gallery.id)
|
|
||||||
|
|
||||||
startActivity(intent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Snackbar.make(main_layout,
|
|
||||||
R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,20 +841,20 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setOnQueryChangeListener { _, query ->
|
setOnQueryChangeListener { _, query ->
|
||||||
this@MainActivity.query = query
|
this@MainActivity.query = query
|
||||||
|
|
||||||
|
suggestionJob?.cancel()
|
||||||
|
|
||||||
clearSuggestions()
|
clearSuggestions()
|
||||||
|
|
||||||
if (query.isEmpty() or query.endsWith(' ')) {
|
if (query.isEmpty() or query.endsWith(' ')) {
|
||||||
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
|
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
|
||||||
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
|
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
|
||||||
} + SelectorSuggestion())
|
})
|
||||||
|
|
||||||
return@setOnQueryChangeListener
|
return@setOnQueryChangeListener
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentQuery = query.split(" ").last().replace('_', ' ')
|
val currentQuery = query.split(" ").last().replace('_', ' ')
|
||||||
|
|
||||||
suggestionJob?.cancel()
|
|
||||||
|
|
||||||
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val suggestions = ArrayList(getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) })
|
val suggestions = ArrayList(getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) })
|
||||||
|
|
||||||
@@ -802,103 +873,72 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setOnBindSuggestionCallback { suggestionView, leftIcon, textView, item, _ ->
|
setOnBindSuggestionCallback { suggestionView, leftIcon, textView, item, _ ->
|
||||||
if (item is SelectorSuggestion) {
|
item as TagSuggestion
|
||||||
var hasSelector = false
|
|
||||||
|
|
||||||
with(suggestionView as LinearLayout) {
|
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
||||||
for (i in 0 until childCount) {
|
|
||||||
val child = getChildAt(i)
|
|
||||||
if (child is ConstraintLayout) {
|
|
||||||
child.visibility = View.VISIBLE
|
|
||||||
hasSelector = true
|
|
||||||
}
|
|
||||||
else
|
|
||||||
child.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasSelector) {
|
leftIcon.setImageDrawable(
|
||||||
val view = LayoutInflater.from(context)
|
ResourcesCompat.getDrawable(
|
||||||
.inflate(R.layout.item_selector_suggestion, suggestionView, false)
|
resources,
|
||||||
|
when(item.n) {
|
||||||
|
"female" -> R.drawable.ic_gender_female
|
||||||
|
"male" -> R.drawable.ic_gender_male
|
||||||
|
"language" -> R.drawable.ic_translate
|
||||||
|
"group" -> R.drawable.ic_account_group
|
||||||
|
"character" -> R.drawable.ic_account_star
|
||||||
|
"series" -> R.drawable.ic_book_open
|
||||||
|
"artist" -> R.drawable.ic_brush
|
||||||
|
else -> R.drawable.ic_tag
|
||||||
|
},
|
||||||
|
null)
|
||||||
|
)
|
||||||
|
|
||||||
suggestionView.addView(view)
|
with(suggestionView.findViewById<ImageView>(R.id.right_icon)) {
|
||||||
}
|
|
||||||
} else if(item is TagSuggestion) {
|
|
||||||
with(suggestionView as LinearLayout) {
|
|
||||||
for (i in 0 until childCount) {
|
|
||||||
val child = getChildAt(i)
|
|
||||||
if (child is ConstraintLayout) {
|
|
||||||
child.visibility = View.GONE
|
|
||||||
}
|
|
||||||
else
|
|
||||||
child.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
|
||||||
|
|
||||||
leftIcon.setImageDrawable(
|
if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag))
|
||||||
ResourcesCompat.getDrawable(
|
setImageResource(R.drawable.ic_star_filled)
|
||||||
resources,
|
else
|
||||||
when(item.n) {
|
setImageResource(R.drawable.ic_star_empty)
|
||||||
"female" -> R.drawable.ic_gender_female
|
|
||||||
"male" -> R.drawable.ic_gender_male
|
|
||||||
"language" -> R.drawable.ic_translate
|
|
||||||
"group" -> R.drawable.ic_account_group
|
|
||||||
"character" -> R.drawable.ic_account_star
|
|
||||||
"series" -> R.drawable.ic_book_open
|
|
||||||
"artist" -> R.drawable.ic_brush
|
|
||||||
else -> R.drawable.ic_tag
|
|
||||||
},
|
|
||||||
null)
|
|
||||||
)
|
|
||||||
|
|
||||||
with(suggestionView.findViewById<ImageView>(R.id.right_icon)) {
|
rotation = 0f
|
||||||
|
isEnabled = true
|
||||||
|
|
||||||
if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag))
|
setColorFilter(ContextCompat.getColor(context, R.color.material_orange_500))
|
||||||
setImageResource(R.drawable.ic_star_filled)
|
|
||||||
else
|
isClickable = true
|
||||||
|
setOnClickListener {
|
||||||
|
val favorites = Tags(json.parse(serializer, favoritesFile.readText()))
|
||||||
|
|
||||||
|
if (favorites.contains(tag)) {
|
||||||
setImageResource(R.drawable.ic_star_empty)
|
setImageResource(R.drawable.ic_star_empty)
|
||||||
|
favorites.remove(tag)
|
||||||
rotation = 0f
|
|
||||||
isEnabled = true
|
|
||||||
|
|
||||||
setColorFilter(ContextCompat.getColor(context, R.color.material_orange_500))
|
|
||||||
|
|
||||||
isClickable = true
|
|
||||||
setOnClickListener {
|
|
||||||
val favorites = Tags(json.parse(serializer, favoritesFile.readText()))
|
|
||||||
|
|
||||||
if (favorites.contains(tag)) {
|
|
||||||
setImageResource(R.drawable.ic_star_empty)
|
|
||||||
favorites.remove(tag)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setImageDrawable(AnimatedVectorDrawableCompat.create(context,
|
|
||||||
R.drawable.avd_star
|
|
||||||
))
|
|
||||||
(drawable as Animatable).start()
|
|
||||||
|
|
||||||
favorites.add(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
favoritesFile.writeText(json.stringify(favorites))
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
setImageDrawable(AnimatedVectorDrawableCompat.create(context,
|
||||||
|
R.drawable.avd_star
|
||||||
|
))
|
||||||
|
(drawable as Animatable).start()
|
||||||
|
|
||||||
|
favorites.add(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
favoritesFile.writeText(json.stringify(favorites))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (item.t == -1) {
|
if (item.t == -1) {
|
||||||
textView.text = item.s
|
textView.text = item.s
|
||||||
} else {
|
} else {
|
||||||
val text = "${item.s}\n ${item.t}"
|
val text = "${item.s}\n ${item.t}"
|
||||||
|
|
||||||
val len = text.length
|
val len = text.length
|
||||||
val left = item.s.length
|
val left = item.s.length
|
||||||
|
|
||||||
textView.text = SpannableString(text).apply {
|
textView.text = SpannableString(text).apply {
|
||||||
val s = AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE)
|
val s = AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE)
|
||||||
setSpan(s, left, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
setSpan(s, left, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
setSpan(SetLineOverlap(true), 1, len-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
setSpan(SetLineOverlap(true), 1, len-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
setSpan(SetLineOverlap(false), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
setSpan(SetLineOverlap(false), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -924,24 +964,18 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (query.isEmpty() or query.endsWith(' '))
|
if (query.isEmpty() or query.endsWith(' '))
|
||||||
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
|
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
|
||||||
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
|
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
|
||||||
} + SelectorSuggestion())
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFocusCleared() {
|
override fun onFocusCleared() {
|
||||||
suggestionJob?.cancel()
|
suggestionJob?.cancel()
|
||||||
|
|
||||||
val query = searchInputView.text.toString()
|
runOnUiThread {
|
||||||
|
cancelFetch()
|
||||||
if (query != this@MainActivity.query) {
|
clearGalleries()
|
||||||
this@MainActivity.query = query
|
currentPage = 0
|
||||||
|
fetchGalleries(query, sortMode)
|
||||||
runOnUiThread {
|
loadBlocks()
|
||||||
cancelFetch()
|
|
||||||
clearGalleries()
|
|
||||||
currentPage = 0
|
|
||||||
fetchGalleries(query)
|
|
||||||
loadBlocks()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -970,9 +1004,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
main_progressbar.show()
|
main_progressbar.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchGalleries(query: String) {
|
private fun fetchGalleries(query: String, sortMode: SortMode) {
|
||||||
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
val perPage = preference.getString("per_page", "25")?.toInt() ?: 25
|
|
||||||
val defaultQuery = preference.getString("default_query", "")!!
|
val defaultQuery = preference.getString("default_query", "")!!
|
||||||
|
|
||||||
galleryIDs = null
|
galleryIDs = null
|
||||||
@@ -985,12 +1018,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
Mode.SEARCH -> {
|
Mode.SEARCH -> {
|
||||||
when {
|
when {
|
||||||
query.isEmpty() and defaultQuery.isEmpty() -> {
|
query.isEmpty() and defaultQuery.isEmpty() -> {
|
||||||
fetchNozomi(start = currentPage*perPage, count = perPage).let {
|
when(sortMode) {
|
||||||
totalItems = it.second
|
SortMode.POPULAR -> getGalleryIDsFromNozomi(null, "popular", "all")
|
||||||
it.first
|
else -> getGalleryIDsFromNozomi(null, "index", "all")
|
||||||
|
}.apply {
|
||||||
|
totalItems = size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> doSearch("$defaultQuery $query").apply {
|
else -> doSearch("$defaultQuery $query", sortMode == SortMode.POPULAR).apply {
|
||||||
totalItems = size
|
totalItems = size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1043,7 +1078,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private fun loadBlocks() {
|
private fun loadBlocks() {
|
||||||
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
val perPage = preference.getString("per_page", "25")?.toInt() ?: 25
|
val perPage = preference.getString("per_page", "25")?.toInt() ?: 25
|
||||||
val defaultQuery = preference.getString("default_query", "")!!
|
|
||||||
|
|
||||||
loadingJob = CoroutineScope(Dispatchers.IO).launch {
|
loadingJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val galleryIDs = galleryIDs?.await()
|
val galleryIDs = galleryIDs?.await()
|
||||||
@@ -1057,12 +1091,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size)).chunked(5).let { chunks ->
|
||||||
query.isEmpty() and defaultQuery.isEmpty() and (mode == Mode.SEARCH) ->
|
|
||||||
galleryIDs
|
|
||||||
else ->
|
|
||||||
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size))
|
|
||||||
}.chunked(5).let { chunks ->
|
|
||||||
for (chunk in chunks)
|
for (chunk in chunks)
|
||||||
chunk.map { galleryID ->
|
chunk.map { galleryID ->
|
||||||
async {
|
async {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import android.os.Bundle
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.PagerSnapHelper
|
import androidx.recyclerview.widget.PagerSnapHelper
|
||||||
@@ -40,7 +39,6 @@ import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.io.IOException
|
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
@@ -222,15 +220,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
private fun initDownloader() {
|
private fun initDownloader() {
|
||||||
var d: GalleryDownloader? = GalleryDownloader.get(galleryID)
|
var d: GalleryDownloader? = GalleryDownloader.get(galleryID)
|
||||||
|
|
||||||
if (d == null) {
|
if (d == null)
|
||||||
try {
|
d = GalleryDownloader(this, galleryID)
|
||||||
d = GalleryDownloader(this, galleryID)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Snackbar.make(reader_layout, R.string.unable_to_connect, Snackbar.LENGTH_LONG).show()
|
|
||||||
finish()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloader = d.apply {
|
downloader = d.apply {
|
||||||
onReaderLoadedHandler = {
|
onReaderLoadedHandler = {
|
||||||
@@ -268,8 +259,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onErrorHandler = {
|
onErrorHandler = {
|
||||||
if (it is IOException)
|
Snackbar.make(reader_layout, it.message ?: it.javaClass.name, Snackbar.LENGTH_INDEFINITE).show()
|
||||||
Snackbar.make(reader_layout, R.string.unable_to_connect, Snackbar.LENGTH_LONG).show()
|
|
||||||
downloader.download = false
|
downloader.download = false
|
||||||
}
|
}
|
||||||
onCompleteHandler = {
|
onCompleteHandler = {
|
||||||
@@ -323,6 +313,11 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
super.onScrolled(recyclerView, dx, dy)
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
|
||||||
|
if (dy < 0)
|
||||||
|
this@ReaderActivity.reader_fab.showMenuButton(true)
|
||||||
|
else if (dy > 0)
|
||||||
|
this@ReaderActivity.reader_fab.hideMenuButton(true)
|
||||||
|
|
||||||
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
||||||
|
|
||||||
if (layoutManager.findFirstVisibleItemPosition() == -1)
|
if (layoutManager.findFirstVisibleItemPosition() == -1)
|
||||||
|
|||||||
@@ -102,55 +102,59 @@ class GalleryDownloader(
|
|||||||
initNotification()
|
initNotification()
|
||||||
|
|
||||||
reader = CoroutineScope(Dispatchers.IO).async {
|
reader = CoroutineScope(Dispatchers.IO).async {
|
||||||
download = _notify
|
try {
|
||||||
val json = Json(JsonConfiguration.Stable)
|
download = _notify
|
||||||
val serializer = Reader.serializer()
|
val json = Json(JsonConfiguration.Stable)
|
||||||
|
val serializer = Reader.serializer()
|
||||||
|
|
||||||
//Check cache
|
//Check cache
|
||||||
val cache = File(getCachedGallery(this@GalleryDownloader, galleryID), "reader.json")
|
val cache = File(getCachedGallery(this@GalleryDownloader, galleryID), "reader.json")
|
||||||
|
|
||||||
if (cache.exists()) {
|
if (cache.exists()) {
|
||||||
val cached = json.parse(serializer, cache.readText())
|
val cached = json.parse(serializer, cache.readText())
|
||||||
|
|
||||||
if (cached.readerItems.isNotEmpty()) {
|
if (cached.readerItems.isNotEmpty()) {
|
||||||
useHiyobi = when {
|
useHiyobi = when {
|
||||||
cached.readerItems[0].url.contains("hitomi.la") -> false
|
cached.readerItems[0].url.contains("hitomi.la") -> false
|
||||||
else -> true
|
else -> true
|
||||||
|
}
|
||||||
|
|
||||||
|
onReaderLoadedHandler?.invoke(cached)
|
||||||
|
|
||||||
|
return@async cached
|
||||||
}
|
}
|
||||||
|
|
||||||
onReaderLoadedHandler?.invoke(cached)
|
|
||||||
|
|
||||||
return@async cached
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//Cache doesn't exist. Load from internet
|
//Cache doesn't exist. Load from internet
|
||||||
val reader = when {
|
val reader = when {
|
||||||
useHiyobi -> {
|
useHiyobi -> {
|
||||||
xyz.quaver.hiyobi.getReader(galleryID).let {
|
xyz.quaver.hiyobi.getReader(galleryID).let {
|
||||||
when {
|
when {
|
||||||
it.readerItems.isEmpty() -> {
|
it.readerItems.isEmpty() -> {
|
||||||
useHiyobi = false
|
useHiyobi = false
|
||||||
getReader(galleryID)
|
getReader(galleryID)
|
||||||
|
}
|
||||||
|
else -> it
|
||||||
}
|
}
|
||||||
else -> it
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> {
|
||||||
|
getReader(galleryID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
|
||||||
getReader(galleryID)
|
if (reader.readerItems.isNotEmpty()) {
|
||||||
|
//Save cache
|
||||||
|
if (cache.parentFile?.exists() == false)
|
||||||
|
cache.parentFile!!.mkdirs()
|
||||||
|
|
||||||
|
cache.writeText(json.stringify(serializer, reader))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Reader("", listOf())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader.readerItems.isNotEmpty()) {
|
|
||||||
//Save cache
|
|
||||||
if (cache.parentFile?.exists() == false)
|
|
||||||
cache.parentFile!!.mkdirs()
|
|
||||||
|
|
||||||
cache.writeText(json.stringify(serializer, reader))
|
|
||||||
}
|
|
||||||
|
|
||||||
reader
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,8 +164,10 @@ class GalleryDownloader(
|
|||||||
downloadJob = CoroutineScope(Dispatchers.Default).launch {
|
downloadJob = CoroutineScope(Dispatchers.Default).launch {
|
||||||
val reader = reader!!.await()
|
val reader = reader!!.await()
|
||||||
|
|
||||||
if (reader.readerItems.isEmpty())
|
if (reader.readerItems.isEmpty()) {
|
||||||
onErrorHandler?.invoke(IOException("Couldn't retrieve Reader"))
|
onErrorHandler?.invoke(IOException(getString(R.string.unable_to_connect)))
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
val list = ArrayList<String>()
|
val list = ArrayList<String>()
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
|
import xyz.quaver.pupil.BuildConfig
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
fun getReleases(url: String) : JsonArray {
|
fun getReleases(url: String) : JsonArray {
|
||||||
@@ -31,26 +32,27 @@ fun getReleases(url: String) : JsonArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkUpdate(url: String, currentVersion: String) : JsonObject? {
|
fun checkUpdate(url: String) : JsonObject? {
|
||||||
val releases = getReleases(url)
|
val releases = getReleases(url)
|
||||||
|
|
||||||
if (releases.isEmpty())
|
if (releases.isEmpty())
|
||||||
return null
|
return null
|
||||||
|
|
||||||
val latestVersion = releases[0].jsonObject["tag_name"]?.content
|
return releases.firstOrNull {
|
||||||
|
if (BuildConfig.PRERELEASE) {
|
||||||
|
BuildConfig.VERSION_NAME != it.jsonObject["tag_name"]?.content
|
||||||
|
} else {
|
||||||
|
it.jsonObject["prerelease"]?.boolean == false &&
|
||||||
|
BuildConfig.VERSION_NAME != (it.jsonObject["tag_name"]?.content ?: "")
|
||||||
|
}
|
||||||
|
}?.jsonObject
|
||||||
|
}
|
||||||
|
|
||||||
return when {
|
fun getApkUrl(releases: JsonObject) : Pair<String?, String?>? {
|
||||||
currentVersion.split('-').size == 1 -> {
|
releases["assets"]?.jsonArray?.forEach {
|
||||||
when {
|
if (Regex("Pupil-v(\\d+\\.)+\\d+\\.apk").matches(it.jsonObject["name"]?.content ?: ""))
|
||||||
currentVersion != latestVersion -> releases[0].jsonObject
|
return Pair(it.jsonObject["browser_download_url"]?.content, it.jsonObject["name"]?.content)
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
when {
|
|
||||||
(currentVersion.split('-')[0] == latestVersion) -> releases[0].jsonObject
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<vector android:height="24dp" android:tint="#fff"
|
<vector android:height="24dp" android:tint="#fff"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="#ff000000" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
|
<path android:fillColor="#fff" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<!-- drawable/numeric.xml -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:height="24dp"
|
|
||||||
android:width="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path android:fillColor="#000" android:pathData="M4,17V9H2V7H6V17H4M22,15C22,16.11 21.1,17 20,17H16V15H20V13H18V11H20V9H16V7H20A2,2 0 0,1 22,9V10.5A1.5,1.5 0 0,1 20.5,12A1.5,1.5 0 0,1 22,13.5V15M14,15V17H8V13C8,11.89 8.9,11 10,11H12V9H8V7H12A2,2 0 0,1 14,9V11C14,12.11 13.1,13 12,13H10V15H14Z" />
|
|
||||||
</vector>
|
|
||||||
8
app/src/main/res/drawable/image_broken_variant.xml
Normal file
8
app/src/main/res/drawable/image_broken_variant.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!-- drawable/image_broken_variant.xml -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#000" android:pathData="M21,5V11.59L18,8.58L14,12.59L10,8.59L6,12.59L3,9.58V5A2,2 0 0,1 5,3H19A2,2 0 0,1 21,5M18,11.42L21,14.43V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V12.42L6,15.41L10,11.41L14,15.41" />
|
||||||
|
</vector>
|
||||||
@@ -4,5 +4,5 @@
|
|||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path android:fillColor="#000" android:pathData="M4,17V9H2V7H6V17H4M22,15C22,16.11 21.1,17 20,17H16V15H20V13H18V11H20V9H16V7H20A2,2 0 0,1 22,9V10.5A1.5,1.5 0 0,1 20.5,12A1.5,1.5 0 0,1 22,13.5V15M14,15V17H8V13C8,11.89 8.9,11 10,11H12V9H8V7H12A2,2 0 0,1 14,9V11C14,12.11 13.1,13 12,13H10V15H14Z" />
|
<path android:fillColor="#fff" android:pathData="M4,17V9H2V7H6V17H4M22,15C22,16.11 21.1,17 20,17H16V15H20V13H18V11H20V9H16V7H20A2,2 0 0,1 22,9V10.5A1.5,1.5 0 0,1 20.5,12A1.5,1.5 0 0,1 22,13.5V15M14,15V17H8V13C8,11.89 8.9,11 10,11H12V9H8V7H12A2,2 0 0,1 14,9V11C14,12.11 13.1,13 12,13H10V15H14Z" />
|
||||||
</vector>
|
</vector>
|
||||||
8
app/src/main/res/drawable/sort_variant.xml
Normal file
8
app/src/main/res/drawable/sort_variant.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!-- drawable/sort_variant.xml -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#fff" android:pathData="M3,13H15V11H3M3,6V8H21V6M3,18H9V16H3V18Z" />
|
||||||
|
</vector>
|
||||||
@@ -56,6 +56,30 @@
|
|||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||||
|
|
||||||
|
<com.github.clans.fab.FloatingActionMenu
|
||||||
|
android:id="@+id/main_fab"
|
||||||
|
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
|
||||||
|
android:id="@+id/main_fab_jump"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:fab_label="@string/main_jump_title"
|
||||||
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
|
<com.github.clans.fab.FloatingActionButton
|
||||||
|
android:id="@+id/main_fab_id"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:fab_label="@string/main_open_gallery_by_id"
|
||||||
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
|
</com.github.clans.fab.FloatingActionMenu>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.arlib.floatingsearchview.FloatingSearchView
|
<com.arlib.floatingsearchview.FloatingSearchView
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="4dp"
|
android:layout_height="4dp"
|
||||||
android:progressTint="@color/material_green_a700"
|
android:progressTint="@color/material_green_a700"
|
||||||
|
tools:ignore="UnusedAttribute"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -55,7 +56,6 @@
|
|||||||
android:id="@+id/reader_fab_download"
|
android:id="@+id/reader_fab_download"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/ic_downloading"
|
|
||||||
app:fab_label="@string/reader_fab_download"
|
app:fab_label="@string/reader_fab_download"
|
||||||
app:fab_size="mini"/>
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
@@ -63,7 +63,6 @@
|
|||||||
android:id="@+id/reader_fab_fullscreen"
|
android:id="@+id/reader_fab_fullscreen"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/ic_fullscreen"
|
|
||||||
app:fab_label="@string/reader_fab_fullscreen"
|
app:fab_label="@string/reader_fab_fullscreen"
|
||||||
app:fab_size="mini"/>
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="@color/dark_gray"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style="?borderlessButtonStyle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="favorite" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style="?borderlessButtonStyle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="history" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -2,15 +2,19 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<item android:id="@+id/main_menu_jump"
|
<item
|
||||||
android:icon="@drawable/ic_jump"
|
android:id="@+id/main_menu_sort"
|
||||||
android:title="@string/main_jump_title"
|
android:title="@string/main_menu_sort">
|
||||||
app:showAsAction="ifRoom"/>
|
<menu>
|
||||||
|
<group android:checkableBehavior="single">
|
||||||
<item android:id="@+id/main_menu_id"
|
<item android:id="@+id/main_menu_sort_newest"
|
||||||
android:icon="@drawable/ic_numeric"
|
android:title="@string/main_menu_sort_newest"
|
||||||
android:title="@string/main_open_gallery_by_id"
|
android:checked="true"/>
|
||||||
app:showAsAction="ifRoom"/>
|
<item android:id="@+id/main_menu_sort_popular"
|
||||||
|
android:title="@string/main_menu_sort_popular"/>
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/main_menu_settings"
|
android:id="@+id/main_menu_settings"
|
||||||
|
|||||||
@@ -80,4 +80,7 @@
|
|||||||
<string name="settings_lock_none">なし</string>
|
<string name="settings_lock_none">なし</string>
|
||||||
<string name="settings_lock_remove_message">ロックを無効にしますか?</string>
|
<string name="settings_lock_remove_message">ロックを無効にしますか?</string>
|
||||||
<string name="reader_loading">ロード中</string>
|
<string name="reader_loading">ロード中</string>
|
||||||
|
<string name="main_menu_sort">ソート</string>
|
||||||
|
<string name="main_menu_sort_newest">投稿日時順</string>
|
||||||
|
<string name="main_menu_sort_popular">人気順</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
|
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
|
||||||
<string name="main_move">%1$d 페이지로 이동</string>
|
<string name="main_move">%1$d 페이지로 이동</string>
|
||||||
<string name="https_block_alert_title">접속 불가 현상 안내</string>
|
<string name="https_block_alert_title">접속 불가 현상 안내</string>
|
||||||
<string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다\n이 경우 플레이스토어에서 SNIper앱을 이용하시면 정상이용이 가능합니다.</string>
|
<string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다 이 경우 플레이스토어에서 Intra앱을 이용하시면 정상이용이 가능합니다.</string>
|
||||||
<string name="main_dialog_export">갤러리 내보내기</string>
|
<string name="main_dialog_export">갤러리 내보내기</string>
|
||||||
<string name="main_export_complete">내보내기 완료</string>
|
<string name="main_export_complete">내보내기 완료</string>
|
||||||
<string name="main_export_open_folder">폴더 열기</string>
|
<string name="main_export_open_folder">폴더 열기</string>
|
||||||
@@ -80,4 +80,7 @@
|
|||||||
<string name="settings_lock_none">없음</string>
|
<string name="settings_lock_none">없음</string>
|
||||||
<string name="settings_lock_remove_message">잠금을 해제할까요?</string>
|
<string name="settings_lock_remove_message">잠금을 해제할까요?</string>
|
||||||
<string name="reader_loading">로딩중</string>
|
<string name="reader_loading">로딩중</string>
|
||||||
|
<string name="main_menu_sort">정렬</string>
|
||||||
|
<string name="main_menu_sort_popular">인기순</string>
|
||||||
|
<string name="main_menu_sort_newest">시간순</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<string name="app_name" translatable="false" tools:override="true">Pupil</string>
|
<string name="app_name" translatable="false" tools:override="true">Pupil</string>
|
||||||
|
|
||||||
<string name="release_url" translatable="false">https://api.github.com/repos/tom5079/Pupil-issue/releases</string>
|
<string name="release_url" translatable="false">https://api.github.com/repos/tom5079/Pupil/releases</string>
|
||||||
<string name="release_name" translatable="false">Pupil-v(\\d+\\.)+\\d+\\.apk</string>
|
<string name="release_name" translatable="false">Pupil-v(\\d+\\.)+\\d+\\.apk</string>
|
||||||
|
|
||||||
<string name="home_page" translatable="false">http://bit.ly/2EZDClw</string>
|
<string name="home_page" translatable="false">http://bit.ly/2EZDClw</string>
|
||||||
@@ -45,6 +45,10 @@
|
|||||||
<string name="main_drawer_group_contact_email">Email me!</string>
|
<string name="main_drawer_group_contact_email">Email me!</string>
|
||||||
<string name="main_drawer_grouop_contact_kakaotalk">Kakaotalk</string>
|
<string name="main_drawer_grouop_contact_kakaotalk">Kakaotalk</string>
|
||||||
|
|
||||||
|
<string name="main_menu_sort">Sort</string>
|
||||||
|
<string name="main_menu_sort_newest">Newest</string>
|
||||||
|
<string name="main_menu_sort_popular">Popular</string>
|
||||||
|
|
||||||
<string name="main_jump_title">Jump to page</string>
|
<string name="main_jump_title">Jump to page</string>
|
||||||
<string name="main_jump_message">Current page: %1$d\nMaximum page: %2$d</string>
|
<string name="main_jump_message">Current page: %1$d\nMaximum page: %2$d</string>
|
||||||
<string name="main_open_gallery_by_id">Open Gallery by ID</string>
|
<string name="main_open_gallery_by_id">Open Gallery by ID</string>
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ class ExampleUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test() {
|
fun test() {
|
||||||
|
val current = "0.1"
|
||||||
|
val latest = "0.2"
|
||||||
|
|
||||||
|
print(current < latest)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.40'
|
ext.kotlin_version = '1.3.41'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package xyz.quaver.hitomi
|
package xyz.quaver.hitomi
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Executors
|
|
||||||
|
|
||||||
fun doSearch(query: String) : List<Int> {
|
|
||||||
val time = System.currentTimeMillis()
|
|
||||||
|
|
||||||
|
fun doSearch(query: String, sortByPopularity: Boolean = false) : List<Int> {
|
||||||
val terms = query
|
val terms = query
|
||||||
.trim()
|
.trim()
|
||||||
.replace(Regex("""^\?"""), "")
|
.replace(Regex("""^\?"""), "")
|
||||||
@@ -42,7 +42,20 @@ fun doSearch(query: String) : List<Int> {
|
|||||||
positiveTerms.push(term)
|
positiveTerms.push(term)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val positiveResults = positiveTerms.map {
|
||||||
|
CoroutineScope(Dispatchers.IO).async {
|
||||||
|
getGalleryIDsForQuery(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val negativeResults = negativeTerms.map {
|
||||||
|
CoroutineScope(Dispatchers.IO).async {
|
||||||
|
getGalleryIDsForQuery(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var results = when {
|
var results = when {
|
||||||
|
sortByPopularity -> getGalleryIDsFromNozomi(null, "popular", "all")
|
||||||
positiveTerms.isEmpty() -> getGalleryIDsFromNozomi(null, "index", "all")
|
positiveTerms.isEmpty() -> getGalleryIDsFromNozomi(null, "index", "all")
|
||||||
else -> getGalleryIDsForQuery(positiveTerms.poll())
|
else -> getGalleryIDsForQuery(positiveTerms.poll())
|
||||||
}
|
}
|
||||||
@@ -57,25 +70,19 @@ fun doSearch(query: String) : List<Int> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//positive results
|
//positive results
|
||||||
positiveTerms.map {
|
positiveResults.forEach {
|
||||||
async(Dispatchers.IO) {
|
val result = it.await()
|
||||||
Pair(getGalleryIDsForQuery(it), true)
|
|
||||||
}
|
|
||||||
}+negativeTerms.map {
|
|
||||||
async(Dispatchers.IO) {
|
|
||||||
Pair(getGalleryIDsForQuery(it), false)
|
|
||||||
}
|
|
||||||
}.forEach {
|
|
||||||
val (result, isPositive) = it.await()
|
|
||||||
|
|
||||||
when {
|
filterPositive(result.sorted())
|
||||||
isPositive -> filterPositive(result.sorted())
|
}
|
||||||
else -> filterNegative(result.sorted())
|
|
||||||
}
|
//negative results
|
||||||
|
negativeResults.forEach {
|
||||||
|
val result = it.await()
|
||||||
|
|
||||||
|
filterNegative(result.sorted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("PUPIL/SEARCH TIME ${System.currentTimeMillis() - time}ms")
|
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package xyz.quaver.hitomi
|
package xyz.quaver.hitomi
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
@@ -179,8 +180,10 @@ fun getGalleryIDsFromNozomi(area: String?, tag: String, language: String) : List
|
|||||||
|
|
||||||
val nozomi = ArrayList<Int>()
|
val nozomi = ArrayList<Int>()
|
||||||
|
|
||||||
|
val bytes = inputStream.readBytes()
|
||||||
|
|
||||||
val arrayBuffer = ByteBuffer
|
val arrayBuffer = ByteBuffer
|
||||||
.wrap(inputStream.readBytes())
|
.wrap(bytes)
|
||||||
.order(ByteOrder.BIG_ENDIAN)
|
.order(ByteOrder.BIG_ENDIAN)
|
||||||
|
|
||||||
while (arrayBuffer.hasRemaining())
|
while (arrayBuffer.hasRemaining())
|
||||||
|
|||||||
@@ -19,9 +19,6 @@
|
|||||||
package xyz.quaver.hitomi
|
package xyz.quaver.hitomi
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.UnknownHostException
|
|
||||||
|
|
||||||
|
|
||||||
class UnitTest {
|
class UnitTest {
|
||||||
@Test
|
@Test
|
||||||
@@ -31,9 +28,9 @@ class UnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_nozomi() {
|
fun test_nozomi() {
|
||||||
val nozomi = fetchNozomi(start = 0, count = 5)
|
val nozomi = getGalleryIDsFromNozomi(null, "popular", "all")
|
||||||
|
|
||||||
nozomi.first
|
print(nozomi.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -52,7 +49,7 @@ class UnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_doSearch() {
|
fun test_doSearch() {
|
||||||
val r = doSearch("female:loli female:bondage language:korean -male:yaoi -male:guro -female:guro")
|
val r = doSearch("female:loli female:bondage language:korean -male:yaoi -male:guro -female:guro", true)
|
||||||
|
|
||||||
print(r.size)
|
print(r.size)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user