diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 4fc02689..d694c394 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -61,5 +61,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4d59040d..5a64e6db 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,8 +20,8 @@ android {
applicationId "xyz.quaver.pupil"
minSdkVersion 16
targetSdkVersion 30
- versionCode 59
- versionName "5.0.3-hotfix2"
+ versionCode 60
+ versionName "5.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
@@ -64,7 +64,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
- //implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC"
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0-RC2"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation "androidx.activity:activity-ktx:1.2.0-alpha08"
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha08'
@@ -80,7 +80,6 @@ dependencies {
implementation 'com.google.firebase:firebase-perf:19.0.8'
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0'
implementation 'com.google.android.gms:play-services-mlkit-face-detection:16.1.1'
- implementation 'com.github.arimorty:floatingsearchview:2.1.1'
implementation 'com.github.clans:fab:1.6.4'
//implementation 'com.quiph.ui:recyclerviewfastscroller:0.2.1'
//noinspection GradleDependency
@@ -89,6 +88,9 @@ dependencies {
implementation ("com.github.bumptech.glide:okhttp3-integration:4.11.0") {
transitive = false
}
+ implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
+ transitive = false
+ }
implementation 'com.github.bumptech.glide:annotations:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
@@ -106,6 +108,7 @@ dependencies {
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
}
implementation "xyz.quaver:documentfilex:0.2.15"
+ implementation "xyz.quaver:floatingsearchview:1.0.4"
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test:rules:1.3.0'
diff --git a/app/libs/kotlinx-serialization-core-1.0.0-RC.jar b/app/libs/kotlinx-serialization-core-1.0.0-RC.jar
deleted file mode 100644
index f4abfe48..00000000
Binary files a/app/libs/kotlinx-serialization-core-1.0.0-RC.jar and /dev/null differ
diff --git a/app/libs/recyclerviewfastscroller-release.aar b/app/libs/recyclerviewfastscroller-release.aar
index d0f8ce00..896f7d6d 100644
Binary files a/app/libs/recyclerviewfastscroller-release.aar and b/app/libs/recyclerviewfastscroller-release.aar differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index 794f670a..3f844996 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"properties": [],
- "versionCode": 59,
- "versionName": "5.0.3-hotfix2",
+ "versionCode": 60,
+ "versionName": "5.1",
"enabled": true,
"outputFile": "app-release.apk"
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d96312dc..8161565b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -25,6 +25,7 @@
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config"
tools:replace="android:theme"
+ android:largeHeap="true"
tools:ignore="UnusedAttribute">
0
+ "male" -> 1
+ else -> 2
+ }
+ }.map {
TagChip(context, Tag.parse(it)).apply {
setOnClickListener { view ->
for (callback in onChipClickedHandler)
@@ -273,7 +285,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
// Make some views invisible to make it thinner
- if (isThin) {
+ if (thin) {
galleryblock_language.visibility = View.GONE
galleryblock_type.visibility = View.GONE
galleryblock_tag_group.visibility = View.GONE
diff --git a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
index d3055a8e..36755a49 100644
--- a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
+++ b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
@@ -43,13 +43,16 @@ import xyz.quaver.pupil.R
import xyz.quaver.pupil.client
import xyz.quaver.pupil.interceptors
import xyz.quaver.pupil.ui.ReaderActivity
-import xyz.quaver.pupil.util.Preferences
import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.downloader.DownloadManager
import xyz.quaver.pupil.util.ellipsize
import xyz.quaver.pupil.util.normalizeID
import xyz.quaver.pupil.util.requestBuilders
import java.io.IOException
+import kotlin.math.ceil
+import kotlin.math.floor
+import kotlin.math.log10
+import kotlin.math.roundToInt
private typealias ProgressListener = (DownloadService.Tag, Long, Long, Boolean) -> Unit
class DownloadService : Service() {
@@ -218,10 +221,11 @@ class DownloadService : Service() {
kotlin.runCatching {
val image = response.also { if (it.code() != 200) throw IOException() }.body()?.use { it.bytes() } ?: throw Exception()
+ val padding = ceil(progress[galleryID]?.size?.let { log10(it.toFloat()) } ?: 0F).toInt()
CoroutineScope(Dispatchers.IO).launch {
kotlin.runCatching {
- Cache.getInstance(this@DownloadService, galleryID).putImage(index, "$index.$ext", image)
+ Cache.getInstance(this@DownloadService, galleryID).putImage(index, "${index.toString().padStart(padding, '0')}.$ext", image)
}.onSuccess {
progress[galleryID]?.set(index, Float.POSITIVE_INFINITY)
notify(galleryID)
@@ -309,34 +313,26 @@ class DownloadService : Service() {
return@launch
}
- progress.put(galleryID, MutableList(reader.galleryInfo.files.size) { 0F })
-
- FirebaseCrashlytics.getInstance().log(
- """
- GALLERYID: $galleryID
- CACHE: ${cache.findFile(".metadata")}
- PATTERN: ${Preferences["download_folder_name", ""]}
- READER ID: ${reader.galleryInfo.id}
- READER SIZE: ${reader.galleryInfo.files.size}
- CACHE READER ID: ${cache.metadata.reader?.galleryInfo?.id}}
- CACHE READER SIZE: ${cache.metadata.reader?.galleryInfo?.files?.size}
- """.trimIndent()
- )
+ val list = MutableList(reader.galleryInfo.files.size) { 0F }
cache.metadata.imageList?.let {
- if (progress[galleryID]?.size != it.size) {
- cache.metadata.imageList?.filterNotNull()?.forEach { file ->
- cache.findFile(file)?.delete()
- }
- cache.metadata.imageList = MutableList(reader.galleryInfo.files.size) { null }
- return@let
+ if (list.size != it.size) {
+ FirebaseCrashlytics.getInstance().log(
+ """
+ GALLERYID: $galleryID
+ ${it.size} - ${list.size}
+ """.trimIndent()
+ )
+ error("ImageList Size does not match")
}
it.forEachIndexed { index, image ->
- progress[galleryID]?.set(index, if (image != null) Float.POSITIVE_INFINITY else 0F)
+ list[index] = if (image != null) Float.POSITIVE_INFINITY else 0F
}
}
+ progress.put(galleryID, list)
+
if (isCompleted(galleryID)) {
if (DownloadManager.getInstance(this@DownloadService)
.getDownloadFolder(galleryID) != null )
@@ -361,8 +357,18 @@ class DownloadService : Service() {
}
}
- reader.requestBuilders.forEachIndexed { index, it ->
- if (progress[galleryID]?.get(index)?.isInfinite() != true) {
+ reader.requestBuilders.also {
+ if (it.size != list.size) {
+ FirebaseCrashlytics.getInstance().log(
+ """
+ GALLERYID: $galleryID
+ ${it.size} - ${list.size}
+ """.trimIndent()
+ )
+ error("Requests Size does not match")
+ }
+ }.forEachIndexed { index, it ->
+ if (!list[index].isInfinite()) {
val request = it.tag(Tag(galleryID, index, startId)).build()
client.newCall(request).enqueue(callback)
}
diff --git a/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt b/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt
index e49391e4..54dccdab 100644
--- a/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt
+++ b/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt
@@ -18,36 +18,28 @@
package xyz.quaver.pupil.types
-import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
+import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize
+import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.hitomi.Suggestion
@Parcelize
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
- override fun getBody(): String {
- return s
- }
+ @IgnoredOnParcel
+ override val body = s
}
@Parcelize
-class Suggestion(val str: String) : SearchSuggestion {
- override fun getBody() = str
-}
+class Suggestion(override val body: String) : SearchSuggestion
@Parcelize
-class NoResultSuggestion(val str: String) : SearchSuggestion {
- override fun getBody() = str
-}
+class NoResultSuggestion(override val body: String) : SearchSuggestion
@Parcelize
-class LoadingSuggestion(val str: String) : SearchSuggestion {
- override fun getBody() = str
-}
+class LoadingSuggestion(override val body: String) : SearchSuggestion
@Parcelize
@Suppress("PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY")
-class FavoriteHistorySwitch(private val body: String) : SearchSuggestion {
- override fun getBody() = body
-}
\ No newline at end of file
+class FavoriteHistorySwitch(override val body: String) : SearchSuggestion
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt
index 5963073c..96d8b3b3 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt
@@ -23,6 +23,7 @@ import android.content.Intent
import android.os.Bundle
import android.os.PersistableBundle
import android.view.WindowManager
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import xyz.quaver.pupil.R
@@ -34,6 +35,13 @@ open class BaseActivity : AppCompatActivity() {
private var locked: Boolean = true
+ private val lockLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ if (it.resultCode == Activity.RESULT_OK)
+ locked = false
+ else
+ finish()
+ }
+
@CallSuper
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
@@ -53,20 +61,7 @@ open class BaseActivity : AppCompatActivity() {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
if (locked)
- startActivityForResult(Intent(this, LockActivity::class.java), R.id.request_lock.normalizeID())
- }
-
- @CallSuper
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- when(requestCode) {
- R.id.request_lock.normalizeID() -> {
- if (resultCode == Activity.RESULT_OK)
- locked = false
- else
- finish()
- }
- else -> super.onActivityResult(requestCode, resultCode, data)
- }
+ lockLauncher.launch(Intent(this, LockActivity::class.java))
}
}
\ No newline at end of file
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 8913ca8f..32f34979 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
@@ -23,16 +23,15 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.InputType
-import android.view.*
+import android.view.KeyEvent
+import android.view.MenuItem
+import android.view.MotionEvent
+import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.cardview.widget.CardView
import androidx.core.view.GravityCompat
-import com.arlib.floatingsearchview.FloatingSearchView
-import com.arlib.floatingsearchview.FloatingSearchViewDayNight
-import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
-import com.arlib.floatingsearchview.util.view.SearchInputView
import com.bumptech.glide.Glide
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.navigation.NavigationView
@@ -41,6 +40,10 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main_content.*
import kotlinx.coroutines.*
+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.doSearch
import xyz.quaver.hitomi.getGalleryIDsFromNozomi
import xyz.quaver.hitomi.getSuggestionsForQuery
@@ -50,9 +53,12 @@ import xyz.quaver.pupil.services.DownloadService
import xyz.quaver.pupil.types.*
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialogFragment
import xyz.quaver.pupil.ui.dialog.GalleryDialog
-import xyz.quaver.pupil.util.*
+import xyz.quaver.pupil.util.ItemClickSupport
+import xyz.quaver.pupil.util.Preferences
+import xyz.quaver.pupil.util.checkUpdate
import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.downloader.DownloadManager
+import xyz.quaver.pupil.util.restore
import kotlin.math.abs
import kotlin.math.ceil
import kotlin.math.min
@@ -60,7 +66,6 @@ import kotlin.math.roundToInt
class MainActivity :
BaseActivity(),
- FloatingSearchView.OnMenuItemClickListener,
NavigationView.OnNavigationItemSelectedListener
{
@@ -96,7 +101,6 @@ class MainActivity :
private var loadingJob: Job? = null
private var currentPage = 0
-
override fun onCreate(savedInstanceState: Bundle?) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
super.onCreate(savedInstanceState)
@@ -138,6 +142,17 @@ class MainActivity :
}
}
+ override fun onResume() {
+ super.onResume()
+
+ runOnUiThread {
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query, sortMode)
+ loadBlocks()
+ }
+ }
+
override fun onDestroy() {
super.onDestroy()
@@ -181,20 +196,6 @@ class MainActivity :
}
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- when(requestCode) {
- R.id.request_settings.normalizeID() -> {
- runOnUiThread {
- cancelFetch()
- clearGalleries()
- fetchGalleries(query, sortMode)
- loadBlocks()
- }
- }
- else -> super.onActivityResult(requestCode, resultCode, data)
- }
- }
-
private fun initView() {
var prevP1 = 0
main_appbar_layout.addOnOffsetChangedListener(
@@ -626,8 +627,8 @@ class MainActivity :
private var suggestionJob : Job? = null
private fun setupSearchBar() {
- with(main_searchview as FloatingSearchViewDayNight) {
- setOnLeftMenuClickListener(object: FloatingSearchView.OnLeftMenuClickListener {
+ with(main_searchview as xyz.quaver.pupil.ui.view.FloatingSearchView) {
+ onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
override fun onMenuOpened() {
(this@MainActivity.main_recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
}
@@ -635,7 +636,15 @@ class MainActivity :
override fun onMenuClosed() {
//Do Nothing
}
- })
+ }
+
+ 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)
@@ -646,9 +655,11 @@ class MainActivity :
swapSuggestions(defaultSuggestions)
}
- setOnMenuItemClickListener(this@MainActivity)
+ onMenuItemClickListener = {
+ onActionMenuItemSelected(it)
+ }
- setOnQueryChangeListener { _, query ->
+ onQueryChangeListener = lambda@{ _, query ->
this@MainActivity.query = query
suggestionJob?.cancel()
@@ -656,7 +667,7 @@ class MainActivity :
if (query.isEmpty() or query.endsWith(' ')) {
swapSuggestions(defaultSuggestions)
- return@setOnQueryChangeListener
+ return@lambda
}
swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString())))
@@ -682,7 +693,7 @@ class MainActivity :
}
}
- setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener {
+ onFocusChangeListener = object: FloatingSearchView.OnFocusChangeListener {
override fun onFocus() {
if (query.isEmpty() or query.endsWith(' '))
swapSuggestions(defaultSuggestions)
@@ -699,19 +710,24 @@ class MainActivity :
loadBlocks()
}
}
- })
+ }
attachNavigationDrawerToMenuButton(main_drawer_layout)
}
}
- override fun onActionMenuItemSelected(item: MenuItem?) {
+ fun onActionMenuItemSelected(item: MenuItem?) {
when(item?.itemId) {
- R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), R.id.request_settings.normalizeID())
+ R.id.main_menu_settings -> startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
R.id.main_menu_thin -> {
+ val thin = !item.isChecked
+
+ item.isChecked = thin
main_recyclerview.apply {
(adapter as GalleryBlockAdapter).apply {
- isThin = !isThin
+ this.thin = thin
+
+ Preferences["thin"] = thin
}
adapter = adapter // Force to redraw
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
index 3187b240..788f23c5 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
@@ -118,7 +118,6 @@ class ReaderActivity : BaseActivity() {
private var cameraEnabled = false
private var eyeType: Eye? = null
- private var eyeCount: Int = 0
private var eyeTime: Long = 0L
override fun onCreate(savedInstanceState: Bundle?) {
@@ -248,6 +247,8 @@ class ReaderActivity : BaseActivity() {
override fun onResume() {
super.onResume()
+ bindService(Intent(this, DownloadService::class.java), conn, BIND_AUTO_CREATE)
+
if (cameraEnabled)
startCamera(this, cameraCallback)
}
@@ -255,6 +256,9 @@ class ReaderActivity : BaseActivity() {
override fun onPause() {
super.onPause()
closeCamera()
+
+ if (downloader != null)
+ unbindService(conn)
}
override fun onDestroy() {
@@ -265,9 +269,6 @@ class ReaderActivity : BaseActivity() {
if (!DownloadManager.getInstance(this).isDownloading(galleryID))
DownloadService.cancel(this, galleryID)
-
- if (downloader != null)
- unbindService(conn)
}
override fun onBackPressed() {
@@ -304,7 +305,6 @@ class ReaderActivity : BaseActivity() {
private fun initDownloader() {
DownloadService.download(this, galleryID, true)
- bindService(Intent(this, DownloadService::class.java), conn, BIND_AUTO_CREATE)
timer.schedule(1000, 1000) {
val downloader = downloader ?: return@schedule
@@ -564,28 +564,23 @@ class ReaderActivity : BaseActivity() {
// Both closed / opened
!left.xor(right) -> {
eyeType = null
- eyeCount = 0
eyeTime = 0L
}
!left -> {
if (eyeType != Eye.LEFT) {
eyeType = Eye.LEFT
- eyeCount = 0
eyeTime = System.currentTimeMillis()
}
- eyeCount++
}
!right -> {
if (eyeType != Eye.RIGHT) {
eyeType = Eye.RIGHT
- eyeCount = 0
eyeTime = System.currentTimeMillis()
}
- eyeCount++
}
}
- if (eyeCount > 3 && System.currentTimeMillis() - eyeTime > 500) {
+ if (eyeType != null && System.currentTimeMillis() - eyeTime > 100) {
(this@ReaderActivity.reader_recyclerview.layoutManager as LinearLayoutManager).let {
it.scrollToPositionWithOffset(when(eyeType!!) {
Eye.RIGHT -> {
@@ -597,9 +592,7 @@ class ReaderActivity : BaseActivity() {
}, 0)
}
- eyeType = null
- eyeCount = 0
- eyeTime = 0L
+ eyeTime = System.currentTimeMillis() + 500
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt
index 7e797ac5..38685e4f 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt
@@ -18,24 +18,10 @@
package xyz.quaver.pupil.ui
-import android.annotation.SuppressLint
-import android.app.Activity
-import android.content.Intent
-import android.content.pm.PackageManager
import android.os.Bundle
import android.view.MenuItem
-import android.view.WindowManager
-import androidx.appcompat.app.AppCompatActivity
-import com.google.android.material.snackbar.Snackbar
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
import xyz.quaver.pupil.R
-import xyz.quaver.pupil.favorites
-import xyz.quaver.pupil.ui.fragment.LockSettingsFragment
import xyz.quaver.pupil.ui.fragment.SettingsFragment
-import xyz.quaver.pupil.util.Preferences
-import xyz.quaver.pupil.util.normalizeID
-import java.nio.charset.Charset
class SettingsActivity : BaseActivity() {
@@ -56,19 +42,4 @@ class SettingsActivity : BaseActivity() {
return true
}
-
- @SuppressLint("InlinedApi")
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
- when (requestCode) {
- R.id.request_write_permission_and_saf.normalizeID() -> {
- if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) {
- val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
- putExtra("android.content.extra.SHOW_ADVANCED", true)
- }
-
- startActivityForResult(intent, R.id.request_download_folder.normalizeID())
- }
- }
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt
index 042854e2..4708a470 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt
@@ -26,26 +26,87 @@ import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import com.google.android.material.snackbar.Snackbar
+import kotlinx.android.synthetic.main.dialog_download_folder_name.view.*
import kotlinx.android.synthetic.main.item_download_folder.view.*
import net.rdrei.android.dirchooser.DirectoryChooserActivity
import net.rdrei.android.dirchooser.DirectoryChooserConfig
import xyz.quaver.io.FileX
+import xyz.quaver.io.util.toFile
import xyz.quaver.pupil.R
import xyz.quaver.pupil.util.Preferences
import xyz.quaver.pupil.util.byteToString
import xyz.quaver.pupil.util.downloader.DownloadManager
import xyz.quaver.pupil.util.migrate
-import xyz.quaver.pupil.util.normalizeID
import java.io.File
class DownloadLocationDialogFragment : DialogFragment() {
private val entries = mutableMapOf()
+ private val requestDownloadFolderLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ val activity = activity ?: return@registerForActivityResult
+ val context = context ?: return@registerForActivityResult
+ val dialog = dialog ?: return@registerForActivityResult
+
+ it.data?.data?.also { uri ->
+ val takeFlags: Int =
+ activity.intent.flags and
+ (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
+ context.contentResolver.takePersistableUriPermission(uri, takeFlags)
+
+ if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) {
+ entries[null]?.location_available?.text = uri.toFile(context)?.canonicalPath
+ Preferences["download_folder"] = uri.toString()
+ } else {
+ Snackbar.make(
+ dialog.window!!.decorView.rootView,
+ R.string.settings_download_folder_not_writable,
+ Snackbar.LENGTH_LONG
+ ).show()
+
+ val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
+ val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
+ entries[key]!!.button.isChecked = true
+ if (key == null) entries[key]!!.location_available.text = downloadFolder
+ }
+ }
+ }
+ }
+
+ private val requestDownloadFolderOldLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ val context = context ?: return@registerForActivityResult
+ val dialog = dialog ?: return@registerForActivityResult
+
+ if (it.resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
+ val directory = it.data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!!
+
+ if (!File(directory).canWrite()) {
+ Snackbar.make(
+ dialog.window!!.decorView.rootView,
+ R.string.settings_download_folder_not_writable,
+ Snackbar.LENGTH_LONG
+ ).show()
+
+ val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
+ val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
+ entries[key]!!.button.isChecked = true
+ if (key == null) entries[key]!!.location_available.text = downloadFolder
+ }
+ else {
+ entries[null]?.location_available?.text = directory
+ Preferences["download_folder"] = File(directory).toURI().toString()
+ }
+ }
+ }
+
@SuppressLint("InflateParams")
private fun build() : View? {
val context = context ?: return null
@@ -90,7 +151,7 @@ class DownloadLocationDialogFragment : DialogFragment() {
putExtra("android.content.extra.SHOW_ADVANCED", true)
}
- startActivityForResult(intent, R.id.request_download_folder.normalizeID())
+ requestDownloadFolderLauncher.launch(intent)
} else { // Can't use SAF on old Androids!
val config = DirectoryChooserConfig.builder()
.newDirectoryName("Pupil")
@@ -101,7 +162,7 @@ class DownloadLocationDialogFragment : DialogFragment() {
putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config)
}
- startActivityForResult(intent, R.id.request_download_folder_old.normalizeID())
+ requestDownloadFolderOldLauncher.launch(intent)
}
}
entries[null] = this
@@ -132,65 +193,4 @@ class DownloadLocationDialogFragment : DialogFragment() {
return builder.create()
}
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- when (requestCode) {
- R.id.request_download_folder.normalizeID() -> {
- if (resultCode == Activity.RESULT_OK) {
- val activity = activity ?: return
- val context = context ?: return
- val dialog = dialog ?: return
-
- data?.data?.also { uri ->
- val takeFlags: Int =
- activity.intent.flags and
- (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
- context.contentResolver.takePersistableUriPermission(uri, takeFlags)
-
- if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false))
- Preferences["download_folder"] = uri.toString()
- else {
- Snackbar.make(
- dialog.window!!.decorView.rootView,
- R.string.settings_download_folder_not_writable,
- Snackbar.LENGTH_LONG
- ).show()
-
- val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
- val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
- entries[key]!!.button.isChecked = true
- if (key == null) entries[key]!!.location_available.text = downloadFolder
- }
- }
- }
- }
- R.id.request_download_folder_old.normalizeID() -> {
- val context = context ?: return
- val dialog = dialog ?: return
-
- if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
- val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!!
-
- if (!File(directory).canWrite()) {
- Snackbar.make(
- dialog.window!!.decorView.rootView,
- R.string.settings_download_folder_not_writable,
- Snackbar.LENGTH_LONG
- ).show()
-
- val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
- val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
- entries[key]!!.button.isChecked = true
- if (key == null) entries[key]!!.location_available.text = downloadFolder
- }
- else
- Preferences["download_folder"] = File(directory).toURI().toString()
- }
- }
- else -> super.onActivityResult(requestCode, resultCode, data)
- }
- }
-
}
\ No newline at end of file
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 6fe1b42a..76ef9827 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
@@ -45,6 +45,7 @@ import xyz.quaver.pupil.BuildConfig
import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
+import xyz.quaver.pupil.favoriteTags
import xyz.quaver.pupil.histories
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.ui.ReaderActivity
@@ -141,7 +142,18 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
listOf(gallery.language).map { Tag("language", it) },
gallery.series.map { Tag("series", it) },
gallery.characters.map { Tag("character", it) },
- gallery.tags.map {
+ gallery.tags.sortedBy {
+ val tag = Tag.parse(it)
+
+ if (favoriteTags.contains(tag))
+ -1
+ else
+ when(Tag.parse(it).area) {
+ "female" -> 0
+ "male" -> 1
+ else -> 2
+ }
+ }.map {
Tag.parse(it).let { tag ->
when {
tag.area != null -> tag
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt
index 3514ff42..8345dc45 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt
@@ -22,25 +22,21 @@ import android.app.Activity
import android.content.*
import android.os.Bundle
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
-import com.google.android.material.snackbar.Snackbar
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
import xyz.quaver.io.FileX
import xyz.quaver.io.util.getChild
import xyz.quaver.pupil.R
-import xyz.quaver.pupil.favorites
import xyz.quaver.pupil.ui.LockActivity
import xyz.quaver.pupil.ui.SettingsActivity
import xyz.quaver.pupil.ui.dialog.*
import xyz.quaver.pupil.util.*
import xyz.quaver.pupil.util.downloader.DownloadManager
-import java.nio.charset.Charset
class SettingsFragment :
PreferenceFragmentCompat(),
@@ -48,6 +44,16 @@ class SettingsFragment :
Preference.OnPreferenceChangeListener,
SharedPreferences.OnSharedPreferenceChangeListener {
+ private val lockLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ parentFragmentManager
+ .beginTransaction()
+ .replace(R.id.settings, LockSettingsFragment())
+ .addToBackStack("Lock")
+ .commitAllowingStateLoss()
+ }
+ }
+
override fun onResume() {
super.onResume()
@@ -89,7 +95,7 @@ class SettingsFragment :
val intent = Intent(requireContext(), LockActivity::class.java).apply {
putExtra("force", true)
}
- startActivityForResult(intent, R.id.request_lock.normalizeID())
+ lockLauncher.launch(intent)
}
"mirrors" -> {
MirrorDialog(requireContext())
@@ -267,19 +273,4 @@ class SettingsFragment :
}
}
}
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- when(requestCode) {
- R.id.request_lock.normalizeID() -> {
- if (resultCode == Activity.RESULT_OK) {
- parentFragmentManager
- .beginTransaction()
- .replace(R.id.settings, LockSettingsFragment())
- .addToBackStack("Lock")
- .commitAllowingStateLoss()
- }
- }
- else -> super.onActivityResult(requestCode, resultCode, data)
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/arlib/floatingsearchview/FloatingSearchViewDayNight.kt b/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt
similarity index 89%
rename from app/src/main/java/com/arlib/floatingsearchview/FloatingSearchViewDayNight.kt
rename to app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt
index 0792cac1..79b4b362 100644
--- a/app/src/main/java/com/arlib/floatingsearchview/FloatingSearchViewDayNight.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-package com.arlib.floatingsearchview
+package xyz.quaver.pupil.ui.view
import android.content.Context
import android.graphics.PorterDuff
@@ -36,21 +36,21 @@ import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
-import com.arlib.floatingsearchview.suggestions.SearchSuggestionsAdapter
-import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
-import com.arlib.floatingsearchview.util.view.SearchInputView
+import xyz.quaver.floatingsearchview.FloatingSearchView
+import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
+import xyz.quaver.floatingsearchview.util.MenuPopupHelper
+import xyz.quaver.floatingsearchview.util.view.MenuView
+import xyz.quaver.floatingsearchview.util.view.SearchInputView
import xyz.quaver.pupil.R
import xyz.quaver.pupil.favoriteTags
import xyz.quaver.pupil.types.*
import java.util.*
-class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
FloatingSearchView(context, attrs),
FloatingSearchView.OnSearchListener,
- SearchSuggestionsAdapter.OnBindSuggestionCallback,
TextWatcher
{
-
private val searchInputView = findViewById(R.id.search_bar_text)
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
@@ -60,8 +60,10 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
searchInputView.addTextChangedListener(this)
- setOnSearchListener(this)
- setOnBindSuggestionCallback(this)
+ onSearchListener = this
+ onBindSuggestionCallback = { a, b, c, d, e ->
+ onBindSuggestion(a, b, c, d, e)
+ }
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
@@ -83,7 +85,7 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
when (searchSuggestion) {
is TagSuggestion -> {
val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}"
- with(searchInputView.text) {
+ with(searchInputView.text!!) {
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length)
if (!this.contains(tag))
@@ -91,9 +93,9 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
}
}
is Suggestion -> {
- with(searchInputView.text) {
+ with(searchInputView.text!!) {
clear()
- append(searchSuggestion.str)
+ append(searchSuggestion.body)
}
}
is FavoriteHistorySwitch -> onFavoriteHistorySwitchClickListener?.invoke()
@@ -102,14 +104,14 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
override fun onSearchAction(currentQuery: String?) {}
- override fun onBindSuggestion(
+ fun onBindSuggestion(
suggestionView: View?,
leftIcon: ImageView?,
textView: TextView?,
item: SearchSuggestion?,
itemPosition: Int
) {
- when(item) {
+ when(item) {
is TagSuggestion -> {
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
@@ -199,7 +201,7 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
isClickable = true
setOnClickListener {
- onHistoryDeleteClickedListener?.invoke(item.str)
+ onHistoryDeleteClickedListener?.invoke(item.body)
}
}
}
@@ -215,10 +217,4 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
}
}
}
-
- // hack to remove color attributes which should not be reused
- override fun onSaveInstanceState(): Parcelable? {
- super.onSaveInstanceState()
- return null
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt b/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt
index 67904daf..81445b74 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt
@@ -23,6 +23,7 @@ import android.content.Context
import androidx.core.content.ContextCompat
import com.google.android.material.chip.Chip
import xyz.quaver.pupil.R
+import xyz.quaver.pupil.favoriteTags
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.wordCapitalize
@@ -56,6 +57,34 @@ class TagChip(context: Context, tag: Tag) : Chip(context) {
ContextCompat.getDrawable(context, R.drawable.gender_female_white)
}
else -> null
+ }.also {
+ if (favoriteTags.contains(tag))
+ setChipBackgroundColorResource(R.color.material_orange_500)
+ }
+
+ isCloseIconVisible = true
+ closeIcon = ContextCompat.getDrawable(context,
+ if (favoriteTags.contains(tag))
+ R.drawable.ic_star_filled
+ else
+ R.drawable.ic_star_empty
+ )
+
+ setOnCloseIconClickListener {
+ if (favoriteTags.contains(tag)) {
+ favoriteTags.remove(tag)
+ closeIcon = ContextCompat.getDrawable(context, R.drawable.ic_star_empty)
+
+ when(tag.area) {
+ "male" -> setChipBackgroundColorResource(R.color.material_blue_700)
+ "female" -> setChipBackgroundColorResource(R.color.material_pink_600)
+ else -> chipBackgroundColor = null
+ }
+ } else {
+ favoriteTags.add(tag)
+ closeIcon = ContextCompat.getDrawable(context, R.drawable.ic_star_filled)
+ setChipBackgroundColorResource(R.color.material_orange_500)
+ }
}
text = when (tag.area) {
diff --git a/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt b/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt
index ada9f18c..257a67d9 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt
@@ -200,22 +200,18 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
fun moveToDownload() = CoroutineScope(Dispatchers.IO).launch {
val downloadFolder = downloadFolder ?: return@launch
- if (downloadFolder.getChild(".metadata").exists())
- return@launch
-
- metadata.imageList?.forEach { imageName ->
- imageName ?: return@forEach
- val target = downloadFolder.getChild(imageName)
- val source = cacheFolder.getChild(imageName)
+ val cacheMetadata = cacheFolder.getChild(".metadata")
+ val downloadMetadata = downloadFolder.getChild(".metadata")
- if (!source.exists() || target.exists())
- return@forEach
+ if (downloadMetadata.exists() || !cacheMetadata.exists())
+ return@launch
+ if (cacheMetadata.exists()) {
kotlin.runCatching {
- target.createNewFile()
- target.outputStream()?.use { target -> source.inputStream()?.use { source ->
- source.copyTo(target)
- } }
+ downloadMetadata.createNewFile()
+ downloadMetadata.writeText(Json.encodeToString(metadata))
+
+ cacheMetadata.delete()
}
}
@@ -224,7 +220,9 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
if (cacheThumbnail.exists() && !downloadThumbnail.exists()) {
kotlin.runCatching {
- downloadThumbnail.createNewFile()
+ if (!downloadThumbnail.exists())
+ downloadThumbnail.createNewFile()
+
downloadThumbnail.outputStream()?.use { target -> cacheThumbnail.inputStream()?.use { source ->
source.copyTo(target)
} }
@@ -232,17 +230,22 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
}
}
- val cacheMetadata = cacheFolder.getChild(".metadata")
- val downloadMetadata = downloadFolder.getChild(".metadata")
+ metadata.imageList?.forEach { imageName ->
+ imageName ?: return@forEach
+ val target = downloadFolder.getChild(imageName)
+ val source = cacheFolder.getChild(imageName)
+
+ if (!source.exists() || target.exists())
+ return@forEach
- if (cacheMetadata.exists() && !downloadMetadata.exists()) {
kotlin.runCatching {
- downloadMetadata.createNewFile()
- downloadMetadata.writeText(Json.encodeToString(metadata))
- cacheMetadata.delete()
+ if (!target.exists())
+ target.createNewFile()
+
+ target.outputStream()?.use { target -> source.inputStream()?.use { source ->
+ source.copyTo(target)
+ } }
}
}
-
- cacheFolder.delete()
}
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/reader_item_boundary.xml b/app/src/main/res/drawable/reader_item_boundary.xml
index caff3bcf..18006135 100644
--- a/app/src/main/res/drawable/reader_item_boundary.xml
+++ b/app/src/main/res/drawable/reader_item_boundary.xml
@@ -4,7 +4,7 @@
-
-
+
diff --git a/app/src/main/res/drawable/sort_variant.xml b/app/src/main/res/drawable/sort_variant.xml
new file mode 100644
index 00000000..83d5e4cb
--- /dev/null
+++ b/app/src/main/res/drawable/sort_variant.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-v23/activity_main_content.xml b/app/src/main/res/layout-v23/activity_main_content.xml
deleted file mode 100644
index 78db4973..00000000
--- a/app/src/main/res/layout-v23/activity_main_content.xml
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml
index 210d502b..201e31c7 100644
--- a/app/src/main/res/layout/activity_main_content.xml
+++ b/app/src/main/res/layout/activity_main_content.xml
@@ -1,7 +1,7 @@