From b708437a16d963da546f018d3b90fd5b21fa218b Mon Sep 17 00:00:00 2001 From: tom5079 Date: Sat, 25 Dec 2021 23:33:13 +0900 Subject: [PATCH] Fixed a few things... Can't really write them all down :v --- .idea/deploymentTargetDropDown.xml | 2 +- app/src/main/java/xyz/quaver/pupil/Pupil.kt | 1 - .../sources/composable/FloatingSearchBar.kt | 5 +-- .../sources/composable/ListSearchResult.kt | 41 ----------------- .../sources/composable/OverscrollPager.kt | 15 ++++--- .../pupil/sources/composable/SearchBase.kt | 6 ++- .../xyz/quaver/pupil/sources/hitomi/Hitomi.kt | 34 ++++++++------ .../hitomi/HitomiSearchResultViewModel.kt | 44 +++++++++++++++---- .../hitomi/composable/SearchResultEntry.kt | 3 +- .../pupil/sources/hitomi/lib/galleryblock.kt | 2 +- .../quaver/pupil/sources/hitomi/lib/search.kt | 29 ++++++++---- 11 files changed, 95 insertions(+), 87 deletions(-) delete mode 100644 app/src/main/java/xyz/quaver/pupil/sources/composable/ListSearchResult.kt diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 144bcc60..538b1cb5 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -12,6 +12,6 @@ - + \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index 05278bde..80761d6d 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -74,7 +74,6 @@ class Pupil : Application(), DIAware { socketTimeoutMillis = HttpTimeout.INFINITE_TIMEOUT_MS connectTimeoutMillis = HttpTimeout.INFINITE_TIMEOUT_MS } - install(HttpCache) BrowserUserAgent() } diff --git a/app/src/main/java/xyz/quaver/pupil/sources/composable/FloatingSearchBar.kt b/app/src/main/java/xyz/quaver/pupil/sources/composable/FloatingSearchBar.kt index 57a7f027..2eee3d82 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/composable/FloatingSearchBar.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/composable/FloatingSearchBar.kt @@ -50,6 +50,7 @@ fun FloatingSearchBar( onQueryChange: (String) -> Unit = { }, navigationIcon: @Composable () -> Unit = { }, actions: @Composable RowScope.() -> Unit = { }, + onSearch: () -> Unit = { }, onTextFieldFocused: () -> Unit = { }, onTextFieldUnfocused: () -> Unit = { } ) { @@ -100,9 +101,7 @@ fun FloatingSearchBar( cursorBrush = SolidColor(MaterialTheme.colors.secondary), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), keyboardActions = KeyboardActions( - onSearch = { - focusManager.clearFocus() - } + onSearch = { onSearch() } ), decorationBox = { innerTextField -> Row( diff --git a/app/src/main/java/xyz/quaver/pupil/sources/composable/ListSearchResult.kt b/app/src/main/java/xyz/quaver/pupil/sources/composable/ListSearchResult.kt deleted file mode 100644 index 2c118053..00000000 --- a/app/src/main/java/xyz/quaver/pupil/sources/composable/ListSearchResult.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2021 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.sources.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp - -@Composable -fun ListSearchResult(searchResults: List, contentPadding: PaddingValues = PaddingValues(0.dp), content: @Composable (T) -> Unit) { - LazyColumn( - Modifier.fillMaxSize(), - contentPadding = contentPadding, - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - items(searchResults) { itemInfo -> - content(itemInfo) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/sources/composable/OverscrollPager.kt b/app/src/main/java/xyz/quaver/pupil/sources/composable/OverscrollPager.kt index 23f5c499..2463d2ee 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/composable/OverscrollPager.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/composable/OverscrollPager.kt @@ -18,7 +18,6 @@ package xyz.quaver.pupil.sources.composable -import android.util.Log import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.Canvas import androidx.compose.foundation.gestures.awaitFirstDown @@ -41,17 +40,19 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed import androidx.compose.ui.input.pointer.consumePositionChange import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastFirstOrNull -import com.google.accompanist.insets.LocalWindowInsets -import com.google.accompanist.insets.rememberInsetsPaddingValues import xyz.quaver.pupil.R import xyz.quaver.pupil.ui.theme.LightBlue300 -import kotlin.math.* +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min +import kotlin.math.sign @Composable fun OverscrollPager( @@ -68,8 +69,10 @@ fun OverscrollPager( var overscroll: Float? by remember { mutableStateOf(null) } - val topCircleRadius by animateFloatAsState(if (overscroll?.let { it >= pageTurnIndicatorHeight } == true) 1000f else 0f) - val bottomCircleRadius by animateFloatAsState(if (overscroll?.let { it <= -pageTurnIndicatorHeight } == true) 1000f else 0f) + val screenWidth = LocalConfiguration.current.screenWidthDp + + val topCircleRadius by animateFloatAsState(if (overscroll?.let { it >= pageTurnIndicatorHeight } == true) screenWidth.toFloat() else 0f) + val bottomCircleRadius by animateFloatAsState(if (overscroll?.let { it <= -pageTurnIndicatorHeight } == true) screenWidth.toFloat() else 0f) val prevPageTurnIndicatorOffsetPx = LocalDensity.current.run { prevPageTurnIndicatorOffset.toPx() } val nextPageTurnIndicatorOffsetPx = LocalDensity.current.run { nextPageTurnIndicatorOffset.toPx() } diff --git a/app/src/main/java/xyz/quaver/pupil/sources/composable/SearchBase.kt b/app/src/main/java/xyz/quaver/pupil/sources/composable/SearchBase.kt index 95c5b46e..bb149da6 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/composable/SearchBase.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/composable/SearchBase.kt @@ -85,6 +85,7 @@ open class SearchBaseViewModel(app: Application) : AndroidViewModel(app) { var query by mutableStateOf("") var loading by mutableStateOf(false) + var error by mutableStateOf(false) //region UI var isFabVisible by mutableStateOf(true) @@ -139,7 +140,7 @@ fun SearchBase( ) } ) { contentPadding -> - Box(Modifier.padding(contentPadding)) { + Box(Modifier.padding(contentPadding).fillMaxSize()) { OverscrollPager( currentPage = model.currentPage, prevPageAvailable = model.prevPageAvailable, @@ -191,8 +192,9 @@ fun SearchBase( } }, actions = actions, + onSearch = { onSearch(); focusManager.clearFocus() }, onTextFieldFocused = { navigationIconState = NavigationIconState.ARROW }, - onTextFieldUnfocused = { navigationIconState = NavigationIconState.MENU; onSearch() } + onTextFieldUnfocused = { navigationIconState = NavigationIconState.MENU } ) } } 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 6f30a53c..8dbd6b5e 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 @@ -26,6 +26,9 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.GridCells +import androidx.compose.foundation.lazy.LazyVerticalGrid +import androidx.compose.foundation.lazy.items import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -187,21 +190,26 @@ class Hitomi(app: Application) : Source(), DIAware { }, onSearch = { model.search() } ) { contentPadding -> - ListSearchResult(model.searchResults, contentPadding = contentPadding) { - DetailedSearchResult( - it, - bookmarks = bookmarkSet, - onBookmarkToggle = { - coroutineScope.launch { - if (it in bookmarkSet) bookmarkDao.delete(name, it) - else bookmarkDao.insert(name, it) + LazyVerticalGrid( + cells = GridCells.Adaptive(minSize = 500.dp), + contentPadding = contentPadding + ) { + items(model.searchResults) { + DetailedSearchResult( + it, + bookmarks = bookmarkSet, + onBookmarkToggle = { + coroutineScope.launch { + if (it in bookmarkSet) bookmarkDao.delete(name, it) + else bookmarkDao.insert(name, it) + } } + ) { result -> + logger.info { + result.toString() + } + navController.navigate("hitomi.la/reader/${result.itemID}") } - ) { result -> - logger.info { - result.toString() - } - navController.navigate("hitomi.la/reader/${result.itemID}") } } } diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/HitomiSearchResultViewModel.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/HitomiSearchResultViewModel.kt index 0212ad7f..bff10ab0 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/HitomiSearchResultViewModel.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/HitomiSearchResultViewModel.kt @@ -19,6 +19,7 @@ package xyz.quaver.pupil.sources.hitomi import android.app.Application +import android.util.LruCache import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -39,6 +40,8 @@ import xyz.quaver.pupil.sources.hitomi.lib.GalleryBlock import xyz.quaver.pupil.sources.hitomi.lib.doSearch import xyz.quaver.pupil.sources.hitomi.lib.getGalleryBlock import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min class HitomiSearchResultViewModel(app: Application) : SearchBaseViewModel(app), DIAware { override val di by closestDI(app) @@ -54,6 +57,8 @@ class HitomiSearchResultViewModel(app: Application) : SearchBaseViewModel() + private val galleryBlockCache = LruCache(100) + var sortByPopularity by mutableStateOf(false) private var searchJob: Job? = null @@ -66,6 +71,7 @@ class HitomiSearchResultViewModel(app: Application) : SearchBaseViewModel - yield() - loading = false - searchResults.add(transform(getGalleryBlock(client, galleryID))) - } + yield() + + val range = max((currentPage-1)*resultsPerPage, 0) until min(currentPage*resultsPerPage, totalItems) + + cache.slice(range) + .forEach { galleryID -> + yield() + loading = false + kotlin.runCatching { + galleryBlockCache.get(galleryID) ?: getGalleryBlock(client, galleryID).also { + galleryBlockCache.put(galleryID, it) + } + }.onFailure { + error = true + }.getOrNull()?.let { + searchResults.add(transform(it)) + } + + } } viewModelScope.launch { diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/composable/SearchResultEntry.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/composable/SearchResultEntry.kt index 64e3a909..f1e6f702 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/composable/SearchResultEntry.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/composable/SearchResultEntry.kt @@ -19,6 +19,7 @@ package xyz.quaver.pupil.sources.hitomi.composable import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape @@ -107,7 +108,7 @@ fun DetailedSearchResult( Card( modifier = Modifier - .padding(8.dp, 0.dp) + .padding(8.dp) .fillMaxWidth() .clickable { onClick(result) }, elevation = 4.dp diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/galleryblock.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/galleryblock.kt index e7ccb3cb..bc4e1a9a 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/galleryblock.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/galleryblock.kt @@ -48,7 +48,7 @@ suspend fun fetchNozomi( val startByte = start*4 val endByte = (start+count)*4-1 - append("Range", "bytes=$startByte-$endByte") + set("Range", "bytes=$startByte-$endByte") } } } diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/search.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/search.kt index fc5d9ccc..07f836db 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/search.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/lib/search.kt @@ -18,8 +18,12 @@ package xyz.quaver.pupil.sources.hitomi.lib +import android.util.Log import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.util.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.nio.ByteBuffer @@ -36,8 +40,15 @@ const val max_node_size = 464 const val B = 16 const val compressed_nozomi_prefix = "n" -var tag_index_version: String? = null -var galleries_index_version: String? = null +var _tag_index_version: String? = null +suspend fun getTagIndexVersion(client: HttpClient): String = _tag_index_version ?: getIndexVersion(client, "tagindex").also { + _tag_index_version = it +} + +var _galleries_index_version: String? = null +suspend fun getGalleriesIndexVersion(client: HttpClient): String = _galleries_index_version ?: getIndexVersion(client, "galleriesindex").also { + _galleries_index_version = it +} fun sha256(data: ByteArray) : ByteArray { return MessageDigest.getInstance("SHA-256").digest(data) @@ -118,7 +129,7 @@ suspend fun getSuggestionsForQuery(client: HttpClient, query: String) : List) : List { - val url = "$protocol//$domain/$index_dir/$field.$tag_index_version.data" + val url = "$protocol//$domain/$index_dir/$field.${getTagIndexVersion(client)}.data" val (offset, length) = data if (length > 10000 || length <= 0) throw Exception("length $length is too long") @@ -188,7 +199,7 @@ suspend fun getGalleryIDsFromNozomi(client: HttpClient, area: String?, tag: Stri } suspend fun getGalleryIDsFromData(client: HttpClient, data: Pair) : Set { - val url = "$protocol//$domain/$galleries_index_dir/galleries.$galleries_index_version.data" + val url = "$protocol//$domain/$galleries_index_dir/galleries.${getGalleriesIndexVersion(client)}.data" val (offset, length) = data if (length > 100000000 || length <= 0) throw Exception("length $length is too long") @@ -219,10 +230,10 @@ suspend fun getGalleryIDsFromData(client: HttpClient, data: Pair) : S suspend fun getNodeAtAddress(client: HttpClient, field: String, address: Long) : Node? { val url = when(field) { - "galleries" -> "$protocol//$domain/$galleries_index_dir/galleries.$galleries_index_version.index" - "languages" -> "$protocol//$domain/$galleries_index_dir/languages.$galleries_index_version.index" - "nozomiurl" -> "$protocol//$domain/$galleries_index_dir/nozomiurl.$galleries_index_version.index" - else -> "$protocol//$domain/$index_dir/$field.$tag_index_version.index" + "galleries" -> "$protocol//$domain/$galleries_index_dir/galleries.${getGalleriesIndexVersion(client)}.index" + "languages" -> "$protocol//$domain/$galleries_index_dir/languages.${getGalleriesIndexVersion(client)}.index" + "nozomiurl" -> "$protocol//$domain/$galleries_index_dir/nozomiurl.${getGalleriesIndexVersion(client)}.index" + else -> "$protocol//$domain/$index_dir/$field.${getTagIndexVersion(client)}.index" } val nodedata = getURLAtRange(client, url, address.until(address+max_node_size)) @@ -233,7 +244,7 @@ suspend fun getNodeAtAddress(client: HttpClient, field: String, address: Long) : suspend fun getURLAtRange(client: HttpClient, url: String, range: LongRange) : ByteArray = withContext(Dispatchers.IO) { client.get(url) { headers { - append("Range", "bytes=${range.first}-${range.last}") + set("Range", "bytes=${range.first}-${range.last}") } } }