diff --git a/app/build.gradle b/app/build.gradle
index 9b296214..4c84cc84 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -124,7 +124,7 @@ dependencies {
implementation "xyz.quaver:libpupil:1.9.7"
implementation "xyz.quaver:documentfilex:0.4-alpha02"
- implementation "xyz.quaver:floatingsearchview:1.0.7"
+ implementation "xyz.quaver:floatingsearchview:1.0.9"
testImplementation "junit:junit:4.13.1"
androidTestImplementation "androidx.test.ext:junit:1.1.2"
diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
index 75776794..0a6d2b4d 100644
--- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt
+++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
@@ -42,6 +42,7 @@ import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import xyz.quaver.io.FileX
+import xyz.quaver.pupil.sources.initSources
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.*
import xyz.quaver.setClient
@@ -89,6 +90,8 @@ class Pupil : Application() {
firebaseAnalytics = Firebase.analytics
FirebaseCrashlytics.getInstance().setUserId(userID)
+ initSources(this)
+
val proxyInfo = getProxyInfo()
clientBuilder = OkHttpClient.Builder()
diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt
new file mode 100644
index 00000000..3010eb4d
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt
@@ -0,0 +1,59 @@
+/*
+ * Pupil, Hitomi.la viewer for Android
+ * Copyright (C) 2020 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 .
+ */
+
+package xyz.quaver.pupil.adapters
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.graphics.drawable.DrawableCompat
+import androidx.recyclerview.widget.RecyclerView
+import xyz.quaver.pupil.databinding.SourceSelectDialogItemBinding
+import xyz.quaver.pupil.sources.Source
+import xyz.quaver.pupil.sources.sourceIcons
+
+class SourceAdapter(private val sources: List>) : RecyclerView.Adapter() {
+
+ var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
+
+ inner class ViewHolder(private val binding: SourceSelectDialogItemBinding) : RecyclerView.ViewHolder(binding.root) {
+ lateinit var source: Source<*>
+
+ init {
+ binding.go.setOnClickListener {
+ onSourceSelectedListener?.invoke(source)
+ }
+ }
+
+ fun bind(source: Source<*>) {
+ this.source = source
+
+ binding.icon.setImageDrawable(sourceIcons[source.name])
+ binding.name.text = source.name
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return ViewHolder(SourceSelectDialogItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.bind(sources[position])
+ }
+
+ override fun getItemCount(): Int = sources.size
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt
index e1a5f0fb..cbe3c8ab 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt
@@ -18,9 +18,13 @@
package xyz.quaver.pupil.sources
+import android.content.Context
+import android.graphics.drawable.Drawable
+import androidx.core.content.ContextCompat
import kotlinx.coroutines.channels.Channel
import xyz.quaver.pupil.R
-import kotlin.reflect.KClass
+import xyz.quaver.pupil.sources.hitomi.Hitomi
+import xyz.quaver.pupil.sources.hitomi.Hiyobi
data class SearchResult(
val id: String,
@@ -49,8 +53,28 @@ data class SearchResult(
}
}
-interface Source> {
- val querySortModeClass: KClass?
+enum class DefaultSortMode {
+ DEFAULT
+}
+interface Source> {
+ val name: String
+ val iconResID: Int
+ val availableSortMode: Array
- suspend fun query(query: String, range: IntRange, sortMode: Query_SortMode? = null) : Pair, Int>
+ suspend fun query(query: String, range: IntRange, sortMode: Enum<*>) : Pair, Int>
+}
+
+val sources = mutableMapOf>()
+val sourceIcons = mutableMapOf()
+
+@Suppress("UNCHECKED_CAST")
+fun initSources(context: Context) {
+ // Add Default Sources
+ listOf(
+ Hitomi(),
+ Hiyobi()
+ ).forEach {
+ sources[it.name] = it
+ sourceIcons[it.name] = ContextCompat.getDrawable(context, it.iconResID)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt
index 98d9b097..d73fbb8e 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt
@@ -21,6 +21,7 @@ package xyz.quaver.pupil.sources.hitomi
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import xyz.quaver.hitomi.*
+import xyz.quaver.pupil.R
import xyz.quaver.pupil.sources.SearchResult
import xyz.quaver.pupil.sources.SearchResult.ExtraType
import xyz.quaver.pupil.sources.Source
@@ -30,18 +31,20 @@ import kotlin.math.min
class Hitomi : Source {
- override val querySortModeClass = SortMode::class
-
enum class SortMode {
NEWEST,
POPULAR
}
+ override val name: String = "hitomi.la"
+ override val iconResID: Int = R.drawable.hitomi
+ override val availableSortMode: Array = SortMode.values()
+
var cachedQuery: String? = null
var cachedSortMode: SortMode? = null
val cache = mutableListOf()
- override suspend fun query(query: String, range: IntRange, sortMode: SortMode?): Pair, Int> {
+ override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> {
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
cachedQuery = null
cache.clear()
diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt
index cd62be61..8da782de 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt
@@ -23,14 +23,19 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import xyz.quaver.hiyobi.*
+import xyz.quaver.pupil.R
+import xyz.quaver.pupil.sources.DefaultSortMode
import xyz.quaver.pupil.sources.SearchResult
import xyz.quaver.pupil.sources.Source
import xyz.quaver.pupil.util.wordCapitalize
-class Hiyobi : Source> {
- override val querySortModeClass = null
+class Hiyobi : Source {
- override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>?): Pair, Int> {
+ override val name: String = "hiyobi.me"
+ override val iconResID: Int = R.drawable.ic_hiyobi
+ override val availableSortMode: Array = DefaultSortMode.values()
+
+ override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> {
val channel = Channel()
val (results, total) = if (query.isEmpty())
@@ -59,7 +64,7 @@ class Hiyobi : Source> {
mapOf(
SearchResult.ExtraType.CHARACTER to { galleryBlock.characters.joinToString { it.value.wordCapitalize() } },
SearchResult.ExtraType.SERIES to { galleryBlock.parodys.joinToString { it.value.wordCapitalize() } },
- SearchResult.ExtraType.TYPE to { galleryBlock.type.name.wordCapitalize() },
+ SearchResult.ExtraType.TYPE to { galleryBlock.type.name.replace('_', ' ').wordCapitalize() },
SearchResult.ExtraType.PAGECOUNT to { getGalleryInfo(galleryBlock.id).files.size.toString() }
),
galleryBlock.tags.map { it.value }
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
index 2b04d51c..dcc885df 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
@@ -25,23 +25,27 @@ import android.os.Bundle
import android.text.InputType
import android.text.util.Linkify
import android.view.KeyEvent
+import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.EditText
+import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
-import androidx.cardview.widget.CardView
import androidx.core.view.GravityCompat
import androidx.core.view.ViewCompat
+import androidx.core.view.children
+import androidx.core.widget.ImageViewCompat
import androidx.recyclerview.widget.RecyclerView
+import androidx.swiperefreshlayout.widget.CircularProgressDrawable
+import com.daimajia.swipe.adapters.RecyclerSwipeAdapter
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import xyz.quaver.floatingsearchview.FloatingSearchView
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
-import xyz.quaver.floatingsearchview.util.view.MenuView
import xyz.quaver.floatingsearchview.util.view.SearchInputView
import xyz.quaver.hitomi.getSuggestionsForQuery
import xyz.quaver.pupil.*
@@ -50,18 +54,16 @@ import xyz.quaver.pupil.databinding.MainActivityBinding
import xyz.quaver.pupil.services.DownloadService
import xyz.quaver.pupil.sources.SearchResult
import xyz.quaver.pupil.sources.Source
-import xyz.quaver.pupil.sources.hitomi.Hitomi
-import xyz.quaver.pupil.sources.hitomi.Hiyobi
+import xyz.quaver.pupil.sources.sourceIcons
+import xyz.quaver.pupil.sources.sources
import xyz.quaver.pupil.types.*
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialogFragment
import xyz.quaver.pupil.ui.dialog.GalleryDialog
+import xyz.quaver.pupil.ui.dialog.SourceSelectDialog
import xyz.quaver.pupil.ui.view.ProgressCardView
import xyz.quaver.pupil.ui.view.SwipePageTurnView
-import xyz.quaver.pupil.util.ItemClickSupport
-import xyz.quaver.pupil.util.Preferences
-import xyz.quaver.pupil.util.checkUpdate
+import xyz.quaver.pupil.util.*
import xyz.quaver.pupil.util.downloader.DownloadManager
-import xyz.quaver.pupil.util.restore
import java.util.regex.Pattern
import kotlin.math.*
import kotlin.random.Random
@@ -82,9 +84,8 @@ class MainActivity :
}
private var queryStack = mutableListOf()
- @Suppress("UNCHECKED_CAST")
- private var source: Source> = Hiyobi() as Source>
- private var sortMode = Hitomi.SortMode.NEWEST
+ private lateinit var source: Source<*>
+ private lateinit var sortMode: Enum<*>
private var searchJob: Deferred, Int>>? = null
private var totalItems = 0
@@ -97,6 +98,8 @@ class MainActivity :
binding = MainActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
+ setSource(sources.values.first())
+
if (intent.action == Intent.ACTION_VIEW) {
intent.dataString?.let { url ->
restore(url,
@@ -167,6 +170,34 @@ class MainActivity :
}
}
+ private fun setSource(source: Source<*>) {
+ this.source = source
+ sortMode = source.availableSortMode.first()
+
+ query = ""
+ currentPage = 1
+
+ with (binding.contents.searchview.binding.querySection.menuView) {
+ post {
+ menuItems.findMenu(R.id.sort).subMenu.apply {
+ clear()
+
+ source.availableSortMode.forEach {
+ add(R.id.sort_mode_group_id, it.ordinal, Menu.NONE, it.name)
+ }
+
+ setGroupCheckable(R.id.sort_mode_group_id, true, true)
+
+ children.first().isChecked = true
+ }
+ with (getChildAt(1) as ImageView) {
+ ImageViewCompat.setImageTintList(this, null)
+ setImageDrawable(sourceIcons[source.name])
+ }
+ }
+ }
+ }
+
private fun initView() {
binding.contents.recyclerview.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -175,7 +206,7 @@ class MainActivity :
min(
max(
binding.contents.searchview.translationY - dy,
- -binding.contents.searchview.findViewById(R.id.search_query_section).height.toFloat()
+ -binding.contents.searchview.binding.querySection.root.height.toFloat()
), 0F)
if (dy > 0)
@@ -224,6 +255,7 @@ class MainActivity :
with(binding.contents.randomFab) {
setImageResource(R.drawable.shuffle_variant)
setOnClickListener {
+ setImageDrawable(CircularProgressDrawable(context))
if (totalItems > 0)
CoroutineScope(Dispatchers.IO).launch {
val random = Random.Default.nextInt(totalItems)
@@ -236,6 +268,7 @@ class MainActivity :
).first.receive()
launch(Dispatchers.Main) {
+ setImageResource(R.drawable.shuffle_variant)
GalleryDialog(this@MainActivity, randomResult.id).apply {
onChipClickedHandler.add {
query = it.toQuery()
@@ -394,7 +427,7 @@ class MainActivity :
with(binding.contents.searchview) {
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
override fun onMenuOpened() {
- (binding.contents.recyclerview.adapter as SearchResultsAdapter).closeAllItems()
+ (this@MainActivity.binding.contents.recyclerview.adapter as SearchResultsAdapter).closeAllItems()
}
override fun onMenuClosed() {
@@ -402,14 +435,6 @@ class MainActivity :
}
}
- post {
- findViewById(R.id.menu_view).menuItems.firstOrNull {
- (it as MenuItem).itemId == R.id.main_menu_thin
- }?.let {
- (it as MenuItem).isChecked = Preferences["thin"]
- }
- }
-
onHistoryDeleteClickedListener = {
searchHistory.remove(it)
swapSuggestions(defaultSuggestions)
@@ -473,37 +498,32 @@ class MainActivity :
}
}
- attachNavigationDrawerToMenuButton(binding.drawer)
+ attachNavigationDrawerToMenuButton(this@MainActivity.binding.drawer)
}
}
- fun onActionMenuItemSelected(item: MenuItem?) {
- when(item?.itemId) {
- R.id.main_menu_settings -> startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
- R.id.main_menu_thin -> {
- // TODO
+ private fun onActionMenuItemSelected(item: MenuItem?) {
+ if (item?.groupId == R.id.sort_mode_group_id) {
+ currentPage = 1
+ sortMode = source.availableSortMode.let { availableSortMode ->
+ availableSortMode.getOrElse(item.itemId) { availableSortMode.first() }
}
- R.id.main_menu_sort_newest -> {
- sortMode = Hitomi.SortMode.NEWEST
- item.isChecked = true
- runOnUiThread {
- currentPage = 1
-
- query()
- }
- }
- R.id.main_menu_sort_popular -> {
- sortMode = Hitomi.SortMode.POPULAR
- item.isChecked = true
-
- runOnUiThread {
- currentPage = 1
-
- query()
- }
- }
+ query()
}
+ else
+ when(item?.itemId) {
+ R.id.main_menu_settings -> startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
+ R.id.source -> SourceSelectDialog().apply {
+ onSourceSelectedListener = {
+ setSource(it)
+
+ query()
+
+ dismiss()
+ }
+ }.show(supportFragmentManager, null)
+ }
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
@@ -539,6 +559,7 @@ class MainActivity :
private fun clearGalleries() = CoroutineScope(Dispatchers.Main).launch {
searchResults.clear()
+ (binding.contents.recyclerview.adapter as RecyclerSwipeAdapter).mItemManger.closeAllItems()
binding.contents.recyclerview.adapter?.notifyDataSetChanged()
binding.contents.noresult.visibility = View.INVISIBLE
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt
index c4249c85..f30dff14 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt
@@ -64,12 +64,7 @@ class GalleryDialog(context: Context, private val galleryID: String) : AlertDial
binding = GalleryDialogBinding.inflate(layoutInflater)
setContentView(binding.root)
- window?.attributes.apply {
- this ?: return@apply
-
- width = LayoutParams.MATCH_PARENT
- height = LayoutParams.MATCH_PARENT
- }
+ window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
with(binding.fab) {
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right))
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt
new file mode 100644
index 00000000..1ca45b79
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt
@@ -0,0 +1,50 @@
+/*
+ * Pupil, Hitomi.la viewer for Android
+ * Copyright (C) 2020 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 .
+ */
+
+package xyz.quaver.pupil.ui.dialog
+
+import android.app.Dialog
+import android.os.Bundle
+import android.view.ViewGroup.LayoutParams
+import android.view.Window
+import androidx.fragment.app.DialogFragment
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import xyz.quaver.pupil.adapters.SourceAdapter
+import xyz.quaver.pupil.sources.Source
+import xyz.quaver.pupil.sources.sources
+
+class SourceSelectDialog : DialogFragment() {
+
+ var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ return Dialog(requireContext()).apply {
+ window?.requestFeature(Window.FEATURE_NO_TITLE)
+ window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
+
+ setContentView(RecyclerView(context).apply {
+ layoutManager = LinearLayoutManager(context)
+ adapter = SourceAdapter(sources.values.toList()).apply {
+ onSourceSelectedListener = this@SourceSelectDialog.onSourceSelectedListener
+ }
+ })
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/SwipePageTurnView.java b/app/src/main/java/xyz/quaver/pupil/ui/view/SwipePageTurnView.java
index fe42c007..da5065cf 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/view/SwipePageTurnView.java
+++ b/app/src/main/java/xyz/quaver/pupil/ui/view/SwipePageTurnView.java
@@ -407,6 +407,16 @@ public class SwipePageTurnView extends ViewGroup implements NestedScrollingChild
stopNestedScroll();
}
+ @Override
+ public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
+ return dispatchNestedPreFling(velocityX, velocityY);
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+ return dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
// NestedScrollingChild
@Override
diff --git a/app/src/main/java/xyz/quaver/pupil/util/misc.kt b/app/src/main/java/xyz/quaver/pupil/util/misc.kt
index c4272cff..32531c34 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/misc.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/misc.kt
@@ -22,6 +22,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
+import android.view.MenuItem
import androidx.core.content.ContextCompat
import kotlinx.serialization.json.*
import okhttp3.OkHttpClient
@@ -142,4 +143,8 @@ operator fun JsonElement.get(tag: String) =
this.jsonObject[tag]
val JsonElement.content
- get() = this.jsonPrimitive.contentOrNull
\ No newline at end of file
+ get() = this.jsonPrimitive.contentOrNull
+
+fun List