Merge pull request #8 from tom5079/development

Version 2.7
This commit is contained in:
tom5079
2019-06-08 15:33:19 +09:00
committed by GitHub
22 changed files with 416 additions and 114 deletions

View File

@@ -9,8 +9,8 @@ android {
applicationId "xyz.quaver.pupil" applicationId "xyz.quaver.pupil"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
versionCode 11 versionCode 14
versionName "2.5.2" versionName "2.7"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {

View File

@@ -3,6 +3,7 @@ package xyz.quaver.pupil
import android.Manifest import android.Manifest
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
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.os.Environment
@@ -21,6 +22,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.arlib.floatingsearchview.FloatingSearchView import com.arlib.floatingsearchview.FloatingSearchView
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
import com.arlib.floatingsearchview.util.view.SearchInputView import com.arlib.floatingsearchview.util.view.SearchInputView
@@ -31,14 +33,20 @@ import kotlinx.android.synthetic.main.activity_main_content.*
import kotlinx.android.synthetic.main.dialog_galleryblock.view.* import kotlinx.android.synthetic.main.dialog_galleryblock.view.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.io.IOException import kotlinx.io.IOException
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.content import kotlinx.serialization.json.content
import kotlinx.serialization.list
import kotlinx.serialization.parseList
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.adapters.GalleryBlockAdapter import xyz.quaver.pupil.adapters.GalleryBlockAdapter
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.util.* import xyz.quaver.pupil.util.*
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
@@ -56,7 +64,8 @@ class MainActivity : AppCompatActivity() {
enum class Mode { enum class Mode {
SEARCH, SEARCH,
HISTORY, HISTORY,
DOWNLOAD DOWNLOAD,
FAVORITE
} }
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>() private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
@@ -73,6 +82,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var histories: Histories private lateinit var histories: Histories
private lateinit var downloads: Histories private lateinit var downloads: Histories
private lateinit var favorites: Histories
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -96,6 +106,7 @@ class MainActivity : AppCompatActivity() {
with(application as Pupil) { with(application as Pupil) {
this@MainActivity.histories = histories this@MainActivity.histories = histories
this@MainActivity.downloads = downloads this@MainActivity.downloads = downloads
this@MainActivity.favorites = favorites
} }
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
@@ -274,6 +285,7 @@ class MainActivity : AppCompatActivity() {
R.id.main_drawer_home -> { R.id.main_drawer_home -> {
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
currentPage = 0
query = "" query = ""
mode = Mode.SEARCH mode = Mode.SEARCH
fetchGalleries(query) fetchGalleries(query)
@@ -282,6 +294,7 @@ class MainActivity : AppCompatActivity() {
R.id.main_drawer_history -> { R.id.main_drawer_history -> {
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
currentPage = 0
query = "" query = ""
mode = Mode.HISTORY mode = Mode.HISTORY
fetchGalleries(query) fetchGalleries(query)
@@ -290,11 +303,21 @@ class MainActivity : AppCompatActivity() {
R.id.main_drawer_downloads -> { R.id.main_drawer_downloads -> {
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
currentPage = 0
query = "" query = ""
mode = Mode.DOWNLOAD mode = Mode.DOWNLOAD
fetchGalleries(query) fetchGalleries(query)
loadBlocks() loadBlocks()
} }
R.id.main_drawer_favorite -> {
cancelFetch()
clearGalleries()
currentPage = 0
query = ""
mode = Mode.FAVORITE
fetchGalleries(query)
loadBlocks()
}
R.id.main_drawer_help -> { R.id.main_drawer_help -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help)))) startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help))))
} }
@@ -686,6 +709,7 @@ class MainActivity : AppCompatActivity() {
} }
private var suggestionJob : Job? = null private var suggestionJob : Job? = null
@UseExperimental(ImplicitReflectionSerializer::class)
private fun setupSearchBar() { private fun setupSearchBar() {
val searchInputView = findViewById<SearchInputView>(R.id.search_bar_text) val searchInputView = findViewById<SearchInputView>(R.id.search_bar_text)
//Change upper case letters to lower case //Change upper case letters to lower case
@@ -707,16 +731,24 @@ class MainActivity : AppCompatActivity() {
}) })
with(main_searchview as FloatingSearchView) { with(main_searchview as FloatingSearchView) {
val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json")
val json = Json(JsonConfiguration.Stable)
val serializer = Tag.serializer().list
if (!favoritesFile.exists()) {
favoritesFile.createNewFile()
favoritesFile.writeText(json.stringify(Tags(listOf())))
}
setOnMenuItemClickListener { setOnMenuItemClickListener {
when(it.itemId) { when(it.itemId) {
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), SETTINGS) R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), SETTINGS)
R.id.main_menu_page_indicator -> { R.id.main_menu_jump -> {
val preference = PreferenceManager.getDefaultSharedPreferences(context) val preference = PreferenceManager.getDefaultSharedPreferences(context)
val perPage = preference.getString("per_page", "25")!!.toInt() val perPage = preference.getString("per_page", "25")!!.toInt()
val editText = EditText(context) val editText = EditText(context)
AlertDialog.Builder(context).apply { AlertDialog.Builder(context).apply {
title = getString(R.string.reader_go_to_page)
setView(editText) setView(editText)
setTitle(R.string.main_jump_title) setTitle(R.string.main_jump_title)
setMessage(getString( setMessage(getString(
@@ -737,6 +769,32 @@ class MainActivity : AppCompatActivity() {
} }
}.show() }.show()
} }
R.id.main_menu_id -> {
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(
"galleryblock",
Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), gallery)
)
startActivity(intent)
} catch (e: Exception) {
Snackbar.make(main_layout, R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
}
}
}
}.show()
}
} }
} }
@@ -751,7 +809,15 @@ class MainActivity : AppCompatActivity() {
suggestionJob?.cancel() suggestionJob?.cancel()
suggestionJob = CoroutineScope(Dispatchers.IO).launch { suggestionJob = CoroutineScope(Dispatchers.IO).launch {
val suggestions = getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) } val suggestions = ArrayList(getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) })
suggestions.filter {
val tag = "${it.n}:${it.s.replace(Regex("\\s"), "_")}"
Tags(json.parse(serializer, favoritesFile.readText())).contains(tag)
}.reversed().forEach {
suggestions.remove(it)
suggestions.add(0, it)
}
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
swapSuggestions(suggestions) swapSuggestions(suggestions)
@@ -759,8 +825,9 @@ class MainActivity : AppCompatActivity() {
} }
} }
setOnBindSuggestionCallback { _, leftIcon, textView, item, _ -> setOnBindSuggestionCallback { suggestionView, leftIcon, textView, item, _ ->
val suggestion = item as TagSuggestion val suggestion = item as TagSuggestion
val tag = "${suggestion.n}:${suggestion.s.replace(Regex("\\s"), "_")}"
leftIcon.setImageDrawable( leftIcon.setImageDrawable(
ResourcesCompat.getDrawable( ResourcesCompat.getDrawable(
@@ -778,16 +845,52 @@ class MainActivity : AppCompatActivity() {
null) null)
) )
val text = "${suggestion.s}\n ${suggestion.t}" with(suggestionView.findViewById<ImageView>(R.id.right_icon)) {
val len = text.length if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag))
val left = suggestion.s.length setImageResource(R.drawable.ic_star_filled)
else
setImageResource(R.drawable.ic_star_empty)
textView.text = SpannableString(text).apply { visibility = View.VISIBLE
val s = AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE) rotation = 0f
setSpan(s, left, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) isEnabled = true
setSpan(SetLineOverlap(true), 1, len-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
setSpan(SetLineOverlap(false), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) 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))
}
}
if (suggestion.t == -1) {
textView.text = suggestion.s
} else {
val text = "${suggestion.s}\n ${suggestion.t}"
val len = text.length
val left = suggestion.s.length
textView.text = SpannableString(text).apply {
val s = AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE)
setSpan(s, left, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
setSpan(SetLineOverlap(true), 1, len-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
setSpan(SetLineOverlap(false), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
} }
} }
@@ -810,7 +913,10 @@ class MainActivity : AppCompatActivity() {
setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener { setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener {
override fun onFocus() { override fun onFocus() {
//Do Nothing if (searchInputView.text.isEmpty())
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
})
} }
override fun onFocusCleared() { override fun onFocusCleared() {
@@ -824,6 +930,7 @@ class MainActivity : AppCompatActivity() {
runOnUiThread { runOnUiThread {
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
currentPage = 0
fetchGalleries(query) fetchGalleries(query)
loadBlocks() loadBlocks()
} }
@@ -910,6 +1017,19 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
Mode.FAVORITE -> {
when {
query.isEmpty() -> favorites.toList().apply {
totalItems = size
}
else -> {
val result = doSearch(query).sorted()
favorites.filter { result.binarySearch(it) >= 0 }.apply {
totalItems = size
}
}
}
}
} }
} }
} }

View File

@@ -16,12 +16,14 @@ class Pupil : ObservableApplication() {
lateinit var histories: Histories lateinit var histories: Histories
lateinit var downloads: Histories lateinit var downloads: Histories
lateinit var favorites: Histories
override fun onCreate() { override fun onCreate() {
val preference = PreferenceManager.getDefaultSharedPreferences(this) val preference = PreferenceManager.getDefaultSharedPreferences(this)
histories = Histories(File(ContextCompat.getDataDir(this), "histories.json")) histories = Histories(File(ContextCompat.getDataDir(this), "histories.json"))
downloads = Histories(File(ContextCompat.getDataDir(this), "downloads.json")) downloads = Histories(File(ContextCompat.getDataDir(this), "downloads.json"))
favorites = Histories(File(ContextCompat.getDataDir(this), "favorites.json"))
super.onCreate() super.onCreate()
Fn.init(this) Fn.init(this)

View File

@@ -1,10 +1,12 @@
package xyz.quaver.pupil package xyz.quaver.pupil
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.LinearSmoothScroller
@@ -20,12 +22,19 @@ 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.io.IOException
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.list
import kotlinx.serialization.stringify
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.pupil.adapters.ReaderAdapter import xyz.quaver.pupil.adapters.ReaderAdapter
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.types.Tags
import xyz.quaver.pupil.util.GalleryDownloader import xyz.quaver.pupil.util.GalleryDownloader
import xyz.quaver.pupil.util.Histories
import xyz.quaver.pupil.util.ItemClickSupport import xyz.quaver.pupil.util.ItemClickSupport
import java.io.File
class ReaderActivity : AppCompatActivity() { class ReaderActivity : AppCompatActivity() {
@@ -43,9 +52,13 @@ class ReaderActivity : AppCompatActivity() {
private var menu: Menu? = null private var menu: Menu? = null
private lateinit var favorites: Histories
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
favorites = (application as Pupil).favorites
window.setFlags( window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE) WindowManager.LayoutParams.FLAG_SECURE)
@@ -81,8 +94,17 @@ class ReaderActivity : AppCompatActivity() {
super.onResume() super.onResume()
} }
@UseExperimental(ImplicitReflectionSerializer::class)
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.reader, menu) menuInflater.inflate(R.menu.reader, menu)
with(menu?.findItem(R.id.reader_menu_favorite)) {
this ?: return@with
if (favorites.contains(galleryBlock.id))
(icon as Animatable).start()
}
this.menu = menu this.menu = menu
return true return true
} }
@@ -106,6 +128,18 @@ class ReaderActivity : AppCompatActivity() {
dialog.show() dialog.show()
} }
R.id.reader_menu_favorite -> {
val id = galleryBlock.id
val favorite = menu?.findItem(R.id.reader_menu_favorite) ?: return true
if (favorites.contains(id)) {
favorites.remove(id)
favorite.icon = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_star)
} else {
favorites.add(id)
(favorite.icon as Animatable).start()
}
}
} }
return true return true

View File

@@ -1,6 +1,8 @@
package xyz.quaver.pupil.adapters package xyz.quaver.pupil.adapters
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.drawable.Animatable
import android.util.Log
import android.util.SparseBooleanArray import android.util.SparseBooleanArray
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -21,8 +23,10 @@ import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.list import kotlinx.serialization.list
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.ReaderItem import xyz.quaver.hitomi.ReaderItem
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tag import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.Histories
import java.io.File import java.io.File
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@@ -37,6 +41,8 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
PREV PREV
} }
private lateinit var favorites: Histories
inner class GalleryViewHolder(private val view: CardView) : RecyclerView.ViewHolder(view) { inner class GalleryViewHolder(private val view: CardView) : RecyclerView.ViewHolder(view) {
fun bind(item: Pair<GalleryBlock, Deferred<String>>) { fun bind(item: Pair<GalleryBlock, Deferred<String>>) {
with(view) { with(view) {
@@ -202,6 +208,27 @@ class GalleryBlockAdapter(private val galleries: List<Pair<GalleryBlock, Deferre
galleryblock_tag_group.addView(chip) galleryblock_tag_group.addView(chip)
} }
if (!::favorites.isInitialized)
favorites = (context.applicationContext as Pupil).favorites
with(galleryblock_favorite) {
post {
isChecked = favorites.contains(gallery.id)
}
setOnClickListener {
when {
isChecked -> favorites.add(gallery.id)
else -> favorites.remove(gallery.id)
}
}
setOnCheckedChangeListener { _, isChecked ->
when {
isChecked -> (background as Animatable).start()
else -> background = AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star)
}
}
}
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package xyz.quaver.pupil.adapters package xyz.quaver.pupil.adapters
import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View

View File

@@ -1,5 +1,8 @@
package xyz.quaver.pupil.types package xyz.quaver.pupil.types
import kotlinx.serialization.Serializable
@Serializable
data class Tag(val area: String?, val tag: String, val isNegative: Boolean = false) { data class Tag(val area: String?, val tag: String, val isNegative: Boolean = false) {
companion object { companion object {
fun parse(tag: String) : Tag { fun parse(tag: String) : Tag {

View File

@@ -104,7 +104,13 @@ class GalleryDownloader(
val cached = json.parse(serializer, cache.readText()) val cached = json.parse(serializer, cache.readText())
if (cached.isNotEmpty()) { if (cached.isNotEmpty()) {
useHiyobi = when {
cached.first().url.contains("hitomi.la") -> false
else -> true
}
onReaderLoadedHandler?.invoke(cached) onReaderLoadedHandler?.invoke(cached)
return@async cached return@async cached
} }
} }

View File

@@ -0,0 +1,37 @@
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="newApi">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:name="path"
android:pathData="M 12 15.39 L 8.24 17.66 L 9.23 13.38 L 5.91 10.5 L 10.29 10.13 L 12 6.09 L 13.71 10.13 L 18.09 10.5 L 14.77 13.38 L 15.76 17.66 M 22 9.24 L 14.81 8.63 L 12 2 L 9.19 8.63 L 2 9.24 L 7.45 13.97 L 5.82 21 L 12 17.27 L 18.18 21 L 16.54 13.97 L 22 9.24 Z"
android:fillColor="#000"/>
<clip-path
android:name="clip"
android:pathData="M 2 21 L 2 21 L 22 21 L 22 21 Z"/>
<path
android:name="path_1"
android:pathData="M 12 17.27 L 18.18 21 L 16.54 13.97 L 22 9.24 L 14.81 8.62 L 12 2 L 9.19 8.62 L 2 9.24 L 7.45 13.97 L 5.82 21 L 12 17.27 Z"
android:fillColor="#000"/>
</vector>
</aapt:attr>
<target android:name="clip">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="pathData"
android:duration="500"
android:valueFrom="M 2 21 L 2 21 L 22 21 L 22 21 Z"
android:valueTo="M 2 2 L 2 21 L 22 21 L 22 2 Z"
android:valueType="pathType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</aapt:attr>
</target>
</animated-vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

View File

@@ -0,0 +1,4 @@
<vector android:height="24dp" android:width="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000" android:pathData="M 12 15.39 L 8.24 17.66 L 9.23 13.38 L 5.91 10.5 L 10.29 10.13 L 12 6.09 L 13.71 10.13 L 18.09 10.5 L 14.77 13.38 L 15.76 17.66 M 22 9.24 L 14.81 8.63 L 12 2 L 9.19 8.63 L 2 9.24 L 7.45 13.97 L 5.82 21 L 12 17.27 L 18.18 21 L 16.54 13.97 L 22 9.24 Z"/>
</vector>

View File

@@ -0,0 +1,4 @@
<vector android:height="24dp" android:width="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000" android:pathData="M 12 17.27 L 18.18 21 L 16.54 13.97 L 22 9.24 L 14.81 8.62 L 12 2 L 9.19 8.62 L 2 9.24 L 7.45 13.97 L 5.82 21 L 12 17.27 Z"/>
</vector>

View File

@@ -14,111 +14,145 @@
android:focusable="true" android:focusable="true"
android:clickable="true"> android:clickable="true">
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="wrap_content"
android:orientation="vertical">
<ProgressBar <androidx.constraintlayout.widget.ConstraintLayout
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:id="@+id/galleryblock_progressbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="4dp" android:layout_height="wrap_content">
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView <ProgressBar
android:id="@+id/galleryblock_progress_complete" style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent" android:id="@+id/galleryblock_progressbar"
android:layout_height="4dp" android:layout_width="match_parent"
android:visibility="invisible" android:layout_height="4dp"
android:scaleType="fitXY" android:visibility="gone"
android:contentDescription="@string/reader_imageview_description" app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintTop_toTopOf="parent"/>
<ImageView <ImageView
android:id="@+id/galleryblock_thumbnail" android:id="@+id/galleryblock_progress_complete"
android:layout_width="150dp" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="4dp"
android:contentDescription="@string/galleryblock_thumbnail_description" android:visibility="invisible"
android:adjustViewBounds="true" android:scaleType="fitXY"
app:layout_constraintLeft_toLeftOf="parent" android:contentDescription="@string/reader_imageview_description"
app:layout_constraintTop_toBottomOf="@id/galleryblock_progressbar" app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView <ImageView
style="@style/TextAppearance.AppCompat.Headline" android:id="@+id/galleryblock_thumbnail"
android:id="@+id/galleryblock_title" android:layout_width="150dp"
android:layout_width="0dp" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:contentDescription="@string/galleryblock_thumbnail_description"
android:layout_marginTop="8dp" android:adjustViewBounds="true"
android:layout_marginStart="8dp" app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="8dp" app:layout_constraintTop_toBottomOf="@id/galleryblock_progressbar"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" app:layout_constraintBottom_toBottomOf="parent"/>
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView <TextView
style="@style/TextAppearance.AppCompat.Medium" style="@style/TextAppearance.AppCompat.Headline"
android:id="@+id/galleryblock_artist" android:id="@+id/galleryblock_title"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginTop="8dp"
android:layout_marginLeft="8dp" android:layout_marginStart="8dp"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" android:layout_marginLeft="8dp"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintTop_toBottomOf="@id/galleryblock_title"/> app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView <TextView
android:id="@+id/galleryblock_series" style="@style/TextAppearance.AppCompat.Medium"
android:layout_width="0dp" android:id="@+id/galleryblock_artist"
android:layout_height="wrap_content" android:layout_width="0dp"
android:layout_marginStart="8dp" android:layout_height="wrap_content"
android:layout_marginLeft="8dp" android:layout_marginStart="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_artist" android:layout_marginLeft="8dp"
app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail" app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintEnd_toEndOf="parent"/> app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/galleryblock_title"/>
<TextView <TextView
android:id="@+id/galleryblock_type" android:id="@+id/galleryblock_series"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_series" app:layout_constraintTop_toBottomOf="@id/galleryblock_artist"
app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail" /> app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView <TextView
android:id="@+id/galleryblock_language" android:id="@+id/galleryblock_type"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginBottom="8dp" app:layout_constraintTop_toBottomOf="@id/galleryblock_series"
app:layout_constraintTop_toBottomOf="@id/galleryblock_type" app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail" />
app:layout_constraintBottom_toTopOf="@id/galleryblock_padding"
app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail" /> <TextView
android:id="@+id/galleryblock_language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
app:layout_constraintBottom_toTopOf="@id/galleryblock_padding"
app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail" />
<View
android:id="@+id/galleryblock_padding"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
app:layout_constraintBottom_toTopOf="@id/galleryblock_tag_group"/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/galleryblock_tag_group"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_padding"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<View <View
android:id="@+id/galleryblock_padding" android:layout_width="match_parent"
android:layout_width="0dp" android:layout_height="1dp"
android:layout_height="0dp" android:layout_margin="8dp"
app:layout_constraintStart_toEndOf="@id/galleryblock_thumbnail" android:background="@android:color/darker_gray"/>
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
app:layout_constraintBottom_toTopOf="@id/galleryblock_tag_group"/>
<com.google.android.material.chip.ChipGroup <LinearLayout
android:id="@+id/galleryblock_tag_group" android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="8dp" android:orientation="horizontal"
android:layout_marginStart="8dp" android:gravity="end">
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/galleryblock_padding"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> <ToggleButton
android:id="@+id/galleryblock_favorite"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/avd_star"
android:backgroundTint="@color/material_orange_500"
android:text=""
android:textOn=""
android:textOff=""/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View File

@@ -14,6 +14,10 @@
<item android:id="@+id/main_drawer_downloads" <item android:id="@+id/main_drawer_downloads"
android:title="@string/main_drawer_downloads" android:title="@string/main_drawer_downloads"
android:icon="@drawable/ic_download"/> android:icon="@drawable/ic_download"/>
<item android:id="@+id/main_drawer_favorite"
android:title="@string/main_drawer_favorite"
android:icon="@drawable/ic_star_filled"/>
</group> </group>
<item android:title="@string/main_drawer_group_contact_title"> <item android:title="@string/main_drawer_group_contact_title">

View File

@@ -2,9 +2,14 @@
<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_page_indicator" <item android:id="@+id/main_menu_jump"
android:icon="@drawable/ic_jump" android:icon="@drawable/ic_jump"
android:title="@string/page_indicator_placeholder" android:title="@string/main_jump_title"
app:showAsAction="ifRoom"/>
<item android:id="@+id/main_menu_id"
android:icon="@drawable/ic_numeric"
android:title="@string/main_open_gallery_by_id"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item <item

View File

@@ -2,6 +2,12 @@
<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/reader_menu_favorite"
android:title=""
android:iconTint="@color/material_orange_500"
android:icon="@drawable/avd_star"
app:showAsAction="always"/>
<item android:id="@+id/reader_menu_use_hiyobi" <item android:id="@+id/reader_menu_use_hiyobi"
android:title="" android:title=""
android:icon="@drawable/ic_hiyobi" android:icon="@drawable/ic_hiyobi"

View File

@@ -67,4 +67,7 @@
<string name="settings_clear_downloads">ダウンロード削除</string> <string name="settings_clear_downloads">ダウンロード削除</string>
<string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか</string> <string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか</string>
<string name="settings_use_hiyobi_summary">ロード速度を向上させるため可能であればhiyobi.meからイメージロード</string> <string name="settings_use_hiyobi_summary">ロード速度を向上させるため可能であればhiyobi.meからイメージロード</string>
<string name="main_drawer_favorite">お気に入り</string>
<string name="main_open_gallery_by_id">ギャラリー番号で見る</string>
<string name="main_open_gallery_by_id_error">エラーが発生しました</string>
</resources> </resources>

View File

@@ -67,4 +67,7 @@
<string name="settings_clear_downloads">다운로드 삭제</string> <string name="settings_clear_downloads">다운로드 삭제</string>
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string> <string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
<string name="settings_use_hiyobi_summary">속도 향상을 위해 가능하면 hiyobi.me에서 이미지 로드</string> <string name="settings_use_hiyobi_summary">속도 향상을 위해 가능하면 hiyobi.me에서 이미지 로드</string>
<string name="main_drawer_favorite">즐겨찾기</string>
<string name="main_open_gallery_by_id">갤러리 번호로 열기</string>
<string name="main_open_gallery_by_id_error">갤러리를 찾지 못했습니다</string>
</resources> </resources>

View File

@@ -8,4 +8,5 @@
<color name="material_pink_600">#d81b60</color> <color name="material_pink_600">#d81b60</color>
<color name="material_blue_700">#1976d2</color> <color name="material_blue_700">#1976d2</color>
<color name="material_green_a700">#00c853</color> <color name="material_green_a700">#00c853</color>
<color name="material_orange_500">#ff9800</color>
</resources> </resources>

View File

@@ -4,8 +4,8 @@
<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-issue/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">https://tom5079.github.io/Pupil</string> <string name="home_page" translatable="false">http://bit.ly/2ZlOjXJ</string>
<string name="help" translatable="false">https://tom5079.github.io/Pupil/2019/06/06/manual-kr.html</string> <string name="help" translatable="false">http://bit.ly/2Z7lNZE</string>
<string name="github" translatable="false">https://github.com/tom5079/Pupil-issue/issues/new/choose</string> <string name="github" translatable="false">https://github.com/tom5079/Pupil-issue/issues/new/choose</string>
<string name="email" translatable="false">mailto:pupil.hentai@gmail.com</string> <string name="email" translatable="false">mailto:pupil.hentai@gmail.com</string>
@@ -35,6 +35,7 @@
<string name="main_drawer_home">Home</string> <string name="main_drawer_home">Home</string>
<string name="main_drawer_history">History</string> <string name="main_drawer_history">History</string>
<string name="main_drawer_downloads">Downloads</string> <string name="main_drawer_downloads">Downloads</string>
<string name="main_drawer_favorite">Favorites</string>
<string name="main_drawer_group_contact_title">Contact</string> <string name="main_drawer_group_contact_title">Contact</string>
<string name="main_drawer_group_contact_help">Help</string> <string name="main_drawer_group_contact_help">Help</string>
<string name="main_drawer_group_contact_homepage">Visit homepage</string> <string name="main_drawer_group_contact_homepage">Visit homepage</string>
@@ -43,6 +44,8 @@
<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_error">Failed to open gallery</string>
<string name="main_move">Move to page %1$d</string> <string name="main_move">Move to page %1$d</string>

View File

@@ -11,9 +11,11 @@ fun doSearch(query: String) : List<Int> {
val terms = query val terms = query
.trim() .trim()
.replace(Regex("""^\?"""), "") .replace(Regex("""^\?"""), "")
.replace('_', ' ')
.toLowerCase() .toLowerCase()
.split(Regex("\\s+")) .split(Regex("\\s+"))
.map {
it.replace('_', ' ')
}
val positiveTerms = LinkedList<String>() val positiveTerms = LinkedList<String>()
val negativeTerms = LinkedList<String>() val negativeTerms = LinkedList<String>()
@@ -42,7 +44,8 @@ fun doSearch(query: String) : List<Int> {
//positive results //positive results
positiveTerms.map { positiveTerms.map {
launch(searchDispatcher) { launch(searchDispatcher) {
filterPositive(getGalleryIDsForQuery(it).sorted()) val newResults = getGalleryIDsForQuery(it)
filterPositive(newResults.sorted())
} }
}.forEach { }.forEach {
it.join() it.join()

View File

@@ -7,7 +7,9 @@ import java.net.URL
class UnitTest { class UnitTest {
@Test @Test
fun test() { fun test() {
print(File("C:\\asdf").list()?.size ?: 0) val galleries = getGalleryIDsForQuery("series:touhou_project")
println(galleries.size)
} }
@Test @Test