diff --git a/.idea/misc.xml b/.idea/misc.xml
index fb8c126a..6de32e1d 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index ec998b34..9300b3f3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,8 +9,8 @@ android {
applicationId "xyz.quaver.pupil"
minSdkVersion 16
targetSdkVersion 28
- versionCode 12
- versionName "2.5.3"
+ versionCode 13
+ versionName "2.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
diff --git a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
index 28079aaf..93a96b25 100644
--- a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
@@ -3,6 +3,7 @@ package xyz.quaver.pupil
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
+import android.graphics.drawable.Animatable
import android.net.Uri
import android.os.Bundle
import android.os.Environment
@@ -21,6 +22,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.GravityCompat
+import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.arlib.floatingsearchview.FloatingSearchView
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
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.coroutines.*
import kotlinx.io.IOException
+import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.content
+import kotlinx.serialization.list
+import kotlinx.serialization.parseList
+import kotlinx.serialization.stringify
import ru.noties.markwon.Markwon
import xyz.quaver.hitomi.*
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
+import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.types.TagSuggestion
+import xyz.quaver.pupil.types.Tags
import xyz.quaver.pupil.util.*
import java.io.File
import java.io.FileInputStream
@@ -56,7 +64,8 @@ class MainActivity : AppCompatActivity() {
enum class Mode {
SEARCH,
HISTORY,
- DOWNLOAD
+ DOWNLOAD,
+ FAVORITE
}
private val galleries = ArrayList>>()
@@ -73,6 +82,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var histories: Histories
private lateinit var downloads: Histories
+ private lateinit var favorites: Histories
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -96,6 +106,7 @@ class MainActivity : AppCompatActivity() {
with(application as Pupil) {
this@MainActivity.histories = histories
this@MainActivity.downloads = downloads
+ this@MainActivity.favorites = favorites
}
setContentView(R.layout.activity_main)
@@ -274,6 +285,7 @@ class MainActivity : AppCompatActivity() {
R.id.main_drawer_home -> {
cancelFetch()
clearGalleries()
+ currentPage = 0
query = ""
mode = Mode.SEARCH
fetchGalleries(query)
@@ -282,6 +294,7 @@ class MainActivity : AppCompatActivity() {
R.id.main_drawer_history -> {
cancelFetch()
clearGalleries()
+ currentPage = 0
query = ""
mode = Mode.HISTORY
fetchGalleries(query)
@@ -290,11 +303,21 @@ class MainActivity : AppCompatActivity() {
R.id.main_drawer_downloads -> {
cancelFetch()
clearGalleries()
+ currentPage = 0
query = ""
mode = Mode.DOWNLOAD
fetchGalleries(query)
loadBlocks()
}
+ R.id.main_drawer_favorite -> {
+ cancelFetch()
+ clearGalleries()
+ currentPage = 0
+ query = ""
+ mode = Mode.FAVORITE
+ fetchGalleries(query)
+ loadBlocks()
+ }
R.id.main_drawer_help -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help))))
}
@@ -686,6 +709,7 @@ class MainActivity : AppCompatActivity() {
}
private var suggestionJob : Job? = null
+ @UseExperimental(ImplicitReflectionSerializer::class)
private fun setupSearchBar() {
val searchInputView = findViewById(R.id.search_bar_text)
//Change upper case letters to lower case
@@ -707,6 +731,15 @@ class MainActivity : AppCompatActivity() {
})
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 {
when(it.itemId) {
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), SETTINGS)
@@ -759,8 +792,9 @@ class MainActivity : AppCompatActivity() {
}
}
- setOnBindSuggestionCallback { _, leftIcon, textView, item, _ ->
+ setOnBindSuggestionCallback { suggestionView, leftIcon, textView, item, _ ->
val suggestion = item as TagSuggestion
+ val tag = "${suggestion.n}:${suggestion.s.replace(Regex("\\s"), "_")}"
leftIcon.setImageDrawable(
ResourcesCompat.getDrawable(
@@ -778,16 +812,49 @@ class MainActivity : AppCompatActivity() {
null)
)
- val text = "${suggestion.s}\n ${suggestion.t}"
+ with(suggestionView.findViewById(R.id.right_icon)) {
+ setImageDrawable(AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star))
- val len = text.length
- val left = suggestion.s.length
+ if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag))
+ (drawable as Animatable).start()
- 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)
+ visibility = View.VISIBLE
+ 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)) {
+ setImageDrawable(AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star))
+ favorites.remove(tag)
+ }
+ else {
+ (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 +877,10 @@ class MainActivity : AppCompatActivity() {
setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener {
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() {
@@ -824,6 +894,7 @@ class MainActivity : AppCompatActivity() {
runOnUiThread {
cancelFetch()
clearGalleries()
+ currentPage = 0
fetchGalleries(query)
loadBlocks()
}
@@ -910,6 +981,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
+ }
+ }
+ }
+ }
}
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
index c4115c85..368b183a 100644
--- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt
+++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
@@ -16,12 +16,14 @@ class Pupil : ObservableApplication() {
lateinit var histories: Histories
lateinit var downloads: Histories
+ lateinit var favorites: Histories
override fun onCreate() {
val preference = PreferenceManager.getDefaultSharedPreferences(this)
histories = Histories(File(ContextCompat.getDataDir(this), "histories.json"))
downloads = Histories(File(ContextCompat.getDataDir(this), "downloads.json"))
+ favorites = Histories(File(ContextCompat.getDataDir(this), "favorites.json"))
super.onCreate()
Fn.init(this)
diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
index 183c90d9..96f5b609 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
@@ -1,6 +1,8 @@
package xyz.quaver.pupil.adapters
import android.graphics.BitmapFactory
+import android.graphics.drawable.Animatable
+import android.util.Log
import android.util.SparseBooleanArray
import android.view.LayoutInflater
import android.view.View
@@ -21,8 +23,10 @@ import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.list
import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.ReaderItem
+import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tag
+import xyz.quaver.pupil.util.Histories
import java.io.File
import java.util.*
import kotlin.collections.ArrayList
@@ -37,6 +41,8 @@ class GalleryBlockAdapter(private val galleries: List>) {
with(view) {
@@ -202,6 +208,27 @@ class GalleryBlockAdapter(private val galleries: List 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)
+ }
+ }
+ }
}
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/types/Tags.kt b/app/src/main/java/xyz/quaver/pupil/types/Tags.kt
index b7e8039b..70d0a119 100644
--- a/app/src/main/java/xyz/quaver/pupil/types/Tags.kt
+++ b/app/src/main/java/xyz/quaver/pupil/types/Tags.kt
@@ -1,5 +1,8 @@
package xyz.quaver.pupil.types
+import kotlinx.serialization.Serializable
+
+@Serializable
data class Tag(val area: String?, val tag: String, val isNegative: Boolean = false) {
companion object {
fun parse(tag: String) : Tag {
diff --git a/app/src/main/res/drawable/avd_star.xml b/app/src/main/res/drawable/avd_star.xml
new file mode 100644
index 00000000..6ae49f20
--- /dev/null
+++ b/app/src/main/res/drawable/avd_star.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_hiyobi.png b/app/src/main/res/drawable/ic_hiyobi.png
new file mode 100644
index 00000000..2af60c05
Binary files /dev/null and b/app/src/main/res/drawable/ic_hiyobi.png differ
diff --git a/app/src/main/res/drawable/ic_star_empty.xml b/app/src/main/res/drawable/ic_star_empty.xml
new file mode 100644
index 00000000..2231c7f8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_star_empty.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_star_filled.xml b/app/src/main/res/drawable/ic_star_filled.xml
new file mode 100644
index 00000000..ae9a8278
--- /dev/null
+++ b/app/src/main/res/drawable/ic_star_filled.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_galleryblock.xml b/app/src/main/res/layout/item_galleryblock.xml
index c4184f3d..8186c6a5 100644
--- a/app/src/main/res/layout/item_galleryblock.xml
+++ b/app/src/main/res/layout/item_galleryblock.xml
@@ -14,111 +14,145 @@
android:focusable="true"
android:clickable="true">
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
-
+ android:layout_height="wrap_content">
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_margin="8dp"
+ android:background="@android:color/darker_gray"/>
-
+ android:orientation="horizontal"
+ android:gravity="end">
-
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
index 4185cf90..3959e386 100644
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ b/app/src/main/res/menu/activity_main_drawer.xml
@@ -14,6 +14,10 @@
+
+
-
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 81f0d436..6bbd36f7 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -67,4 +67,5 @@
ダウンロード削除
ダウンロードしたギャラリーを全て削除します。\n実行しますか?
ロード速度を向上させるため可能であればhiyobi.meからイメージロード
+ お気に入り
\ No newline at end of file
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 7cfc9b9b..ef0c2380 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -67,4 +67,5 @@
다운로드 삭제
다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?
속도 향상을 위해 가능하면 hiyobi.me에서 이미지 로드
+ 즐겨찾기
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index efe64a23..efa2ab65 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -8,4 +8,5 @@
#d81b60
#1976d2
#00c853
+ #ff9800
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f925497f..0dffc533 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -35,6 +35,7 @@
Home
History
Downloads
+ Favorites
Contact
Help
Visit homepage