diff --git a/app/build.gradle b/app/build.gradle index 35a8584c..814f6d93 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ android { compileSdk 34 targetSdkVersion 34 versionCode 69 - versionName "5.3.10" + versionName "6.0.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } @@ -87,7 +87,7 @@ dependencies { implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.ui:ui-tooling-preview' debugImplementation 'androidx.compose.ui:ui-tooling' - androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.6.1' + androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.6.2' debugImplementation 'androidx.compose.ui:ui-test-manifest' implementation 'androidx.compose.material:material-icons-extended' implementation 'androidx.activity:activity-compose:1.8.2' @@ -103,8 +103,6 @@ dependencies { implementation "io.ktor:ktor-client-core:2.3.8" implementation "io.ktor:ktor-client-okhttp:2.3.8" - implementation "com.daimajia.swipelayout:library:1.2.0@aar" - implementation "com.google.android.material:material:1.11.0" implementation platform('com.google.firebase:firebase-bom:32.7.0') @@ -117,8 +115,6 @@ dependencies { implementation "com.github.clans:fab:1.6.4" - //implementation "com.quiph.ui:recyclerviewfastscroller:0.2.1" - implementation 'com.github.piasy:BigImageViewer:1.8.1' implementation 'com.github.piasy:FrescoImageLoader:1.8.1' implementation 'com.github.piasy:FrescoImageViewFactory:1.8.1' @@ -127,18 +123,10 @@ dependencies { //noinspection GradleDependency implementation "com.squareup.okhttp3:okhttp:4.12.0" - implementation "com.tbuonomo.andrui:viewpagerdotsindicator:4.1.2" - - implementation "net.rdrei.android.dirchooser:library:3.2@aar" - implementation "com.gu:option:1.3" - implementation "com.andrognito.patternlockview:patternlockview:1.0.0" - //implementation "com.andrognito.pinlockview:pinlockview:2.1.0" implementation "ru.noties.markwon:core:3.1.0" - implementation "org.jsoup:jsoup:1.14.3" - implementation "xyz.quaver:documentfilex:0.7.2" implementation "xyz.quaver:floatingsearchview:1.1.7" diff --git a/app/src/main/java/xyz/quaver/pupil/hitomi/galleryblock.kt b/app/src/main/java/xyz/quaver/pupil/hitomi/galleryblock.kt index eb52a8d7..dbe19b53 100644 --- a/app/src/main/java/xyz/quaver/pupil/hitomi/galleryblock.kt +++ b/app/src/main/java/xyz/quaver/pupil/hitomi/galleryblock.kt @@ -17,13 +17,11 @@ package xyz.quaver.pupil.hitomi import kotlinx.serialization.Serializable -import org.jsoup.Jsoup import java.net.URL import java.net.URLDecoder import java.nio.ByteBuffer import java.nio.ByteOrder import javax.net.ssl.HttpsURLConnection -import kotlin.io.readText //galleryblock.js fun fetchNozomi(area: String? = null, tag: String = "index", language: String = "all", start: Int = -1, count: Int = -1) : Pair, Int> { diff --git a/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt b/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt index bc3ad347..930fd554 100644 --- a/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt +++ b/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt @@ -45,7 +45,7 @@ fun IntBuffer.toSet(): Set { return result } -class HitomiHttpClient { +object HitomiHttpClient { private val httpClient = HttpClient(OkHttp) private var _tagIndexVersion: String? = null @@ -186,7 +186,7 @@ class HitomiHttpClient { suspend fun getSuggestionsForQuery(query: SearchQuery.Tag): Result> = runCatching { val field = query.namespace ?: "global" - val key = Node.Key(field) + val key = Node.Key(query.tag) val node = getNodeAtAddress(field, 0) val data = bSearch(field, key, node) diff --git a/app/src/main/java/xyz/quaver/pupil/networking/Node.kt b/app/src/main/java/xyz/quaver/pupil/networking/Node.kt index 6e90284b..47775bfd 100644 --- a/app/src/main/java/xyz/quaver/pupil/networking/Node.kt +++ b/app/src/main/java/xyz/quaver/pupil/networking/Node.kt @@ -95,7 +95,7 @@ data class Node( val isLeaf: Boolean = subNodeAddresses.all { it == 0L } fun locateKey(target: Key): Pair { - val index = keys.indexOfFirst { key -> key <= target } + val index = keys.indexOfFirst { key -> target <= key } if (index == -1) { return Pair(false, keys.size) diff --git a/app/src/main/java/xyz/quaver/pupil/ui/composable/QueryEditor.kt b/app/src/main/java/xyz/quaver/pupil/ui/composable/QueryEditor.kt index 998ec4b7..e62a2de1 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/composable/QueryEditor.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/composable/QueryEditor.kt @@ -1,5 +1,6 @@ package xyz.quaver.pupil.ui.composable +import android.util.Log import androidx.compose.animation.AnimatedContent import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Spring @@ -9,6 +10,7 @@ import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer @@ -69,7 +71,9 @@ import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay import kotlinx.coroutines.launch import xyz.quaver.pupil.R +import xyz.quaver.pupil.networking.HitomiHttpClient import xyz.quaver.pupil.networking.SearchQuery +import xyz.quaver.pupil.networking.Suggestion import xyz.quaver.pupil.networking.validNamespace import xyz.quaver.pupil.ui.theme.Blue300 import xyz.quaver.pupil.ui.theme.Blue600 @@ -146,6 +150,45 @@ sealed interface EditableSearchQueryState { } +@Composable +fun TagSuggestionList( + state: EditableSearchQueryState.Tag +) { + var suggestionList: List? by remember { mutableStateOf(null) } + + var namespace by state.namespace + var tag by state.tag + var expanded by state.expanded + + LaunchedEffect(namespace, tag) { + suggestionList = null + suggestionList = HitomiHttpClient.getSuggestionsForQuery(SearchQuery.Tag(namespace, tag)) + .getOrDefault(emptyList()) + .filterNot { it.tag == SearchQuery.Tag(namespace, tag) } + } + + val suggestionListSnapshot = suggestionList + if (suggestionListSnapshot == null) { + Text("Loading") + } else if (suggestionListSnapshot.isNotEmpty()) { + Column( + modifier = Modifier.padding(8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + suggestionListSnapshot.forEach { suggestion -> + TagChip( + tag = suggestion.tag, + onClick = { + namespace = it.namespace + tag = it.tag + expanded = false + } + ) + } + } + } +} + @Composable fun EditableTagChip( state: EditableSearchQueryState.Tag, @@ -244,7 +287,7 @@ fun EditableTagChip( ) } - var selection by remember { mutableStateOf(TextRange(tag.length)) } + var selection by remember(tag) { mutableStateOf(TextRange(tag.length)) } var composition by remember { mutableStateOf(null) } val focusRequester = remember { FocusRequester() } @@ -311,6 +354,8 @@ fun EditableTagChip( } ) } + + TagSuggestionList(state) } } } 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 e6a03cff..c2f59642 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 @@ -29,8 +29,6 @@ import androidx.core.content.ContextCompat import androidx.core.net.toUri import androidx.fragment.app.DialogFragment import com.google.android.material.snackbar.Snackbar -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 @@ -56,8 +54,7 @@ class DownloadLocationDialogFragment : DialogFragment() { it.data?.data?.also { uri -> val takeFlags: Int = 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) + context.contentResolver.takePersistableUriPermission(uri, takeFlags) if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) { entries[null]?.locationAvailable?.text = uri.toFile(context)?.canonicalPath @@ -72,14 +69,14 @@ class DownloadLocationDialogFragment : DialogFragment() { 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]!!.locationAvailable.text = downloadFolder + if (key == null) entries[null]!!.locationAvailable.text = downloadFolder } } } else { val downloadFolder = DownloadManager.getInstance(context ?: return@registerForActivityResult).downloadFolder.canonicalPath val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder } if (key == null) - entries[key]!!.locationAvailable.text = downloadFolder + entries[null]!!.locationAvailable.text = downloadFolder else { entries[null]!!.button.isChecked = false entries[key]!!.button.isChecked = true @@ -87,32 +84,6 @@ class DownloadLocationDialogFragment : DialogFragment() { } } - 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]!!.locationAvailable.text = downloadFolder - } - else { - entries[null]?.locationAvailable?.text = directory - Preferences["download_folder"] = File(directory).toURI().toString() - } - } - } - private fun initView() { val externalFilesDirs = ContextCompat.getExternalFilesDirs(requireContext(), null) @@ -147,24 +118,11 @@ class DownloadLocationDialogFragment : DialogFragment() { } button.performClick() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { - putExtra("android.content.extra.SHOW_ADVANCED", true) - } - - requestDownloadFolderLauncher.launch(intent) - } else { // Can't use SAF on old Androids! - val config = DirectoryChooserConfig.builder() - .newDirectoryName("Pupil") - .allowNewDirectoryNameModification(true) - .build() - - val intent = Intent(context, DirectoryChooserActivity::class.java).apply { - putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) - } - - requestDownloadFolderOldLauncher.launch(intent) + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { + putExtra("android.content.extra.SHOW_ADVANCED", true) } + + requestDownloadFolderLauncher.launch(intent) } entries[null] = this } diff --git a/app/src/main/res/layout/progress_card_view.xml b/app/src/main/res/layout/progress_card_view.xml deleted file mode 100644 index 671a789f..00000000 --- a/app/src/main/res/layout/progress_card_view.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/suggestion_count.xml b/app/src/main/res/layout/suggestion_count.xml deleted file mode 100644 index 6957609a..00000000 --- a/app/src/main/res/layout/suggestion_count.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - \ No newline at end of file