From 2a92d287af56913be5b7f31a05f729499c53a868 Mon Sep 17 00:00:00 2001 From: tom5079 Date: Fri, 25 Jun 2021 14:45:10 +0900 Subject: [PATCH] Download tab --- .../quaver/pupil/adapters/ReaderAdapter.kt | 4 +- .../java/xyz/quaver/pupil/sources/Common.kt | 8 ++-- .../xyz/quaver/pupil/sources/Downloads.kt | 47 +++++++++--------- .../pupil/ui/dialog/SourceSelectDialog.kt | 15 +++--- .../ui/fragment/SourceSettingsFragment.kt | 4 +- .../pupil/ui/viewmodel/MainViewModel.kt | 11 +++-- .../pupil/ui/viewmodel/ReaderViewModel.kt | 48 ++++++++++++------- .../main/res/layout/search_result_item.xml | 3 ++ app/src/main/res/xml/download_preferences.xml | 21 ++++++++ app/src/main/res/xml/history_preferences.xml | 21 ++++++++ 10 files changed, 123 insertions(+), 59 deletions(-) create mode 100644 app/src/main/res/xml/download_preferences.xml create mode 100644 app/src/main/res/xml/history_preferences.xml diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt index 88c6cceb..ac9504d7 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt @@ -48,7 +48,7 @@ import kotlin.math.roundToInt data class ReaderItem( val progress: Float, - val image: File? + val image: Uri? ) class ReaderAdapter : ListAdapter(ReaderItemDiffCallback()) { @@ -107,7 +107,7 @@ class ReaderAdapter : ListAdapter(ReaderIt if (image != null) { binding.root.background = null - binding.image.showImage(Uri.fromFile(image)) + binding.image.showImage(image) } else { binding.root.setBackgroundResource(R.drawable.reader_item_boundary) 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 35e9028d..b3092996 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt @@ -136,12 +136,12 @@ abstract class Source, Suggestion: SearchSu typealias SourceEntry = Pair typealias SourceEntries = Set -typealias PreferenceID = Pair -typealias PreferenceIDs = Set +typealias SourcePreferenceID = Pair +typealias SourcePreferenceIDs = Set @Suppress("UNCHECKED_CAST") val sourceModule = DI.Module(name = "source") { bindSet() - bindSet() + bindSet() listOf( Hitomi() @@ -151,5 +151,5 @@ val sourceModule = DI.Module(name = "source") { } bind { factory { source: String -> History(di, source) } } - bind { singleton { Downloads(di) } } + inSet { singleton { Downloads(di).let { it.name to (it as AnySource) } } } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/sources/Downloads.kt b/app/src/main/java/xyz/quaver/pupil/sources/Downloads.kt index e5f57669..5264c7ed 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/Downloads.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/Downloads.kt @@ -18,11 +18,8 @@ package xyz.quaver.pupil.sources -import android.app.Application -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.launch import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import org.kodein.di.DI @@ -39,17 +36,15 @@ import kotlin.math.min class Downloads(override val di: DI) : Source(), DIAware { override val name: String - get() = "Downloads" + get() = "downloads" override val iconResID: Int get() = R.drawable.ic_download override val preferenceID: Int - get() = -1 + get() = R.xml.download_preferences override val availableSortMode: Array = DefaultSortMode.values() private val downloadManager: DownloadManager by instance() - private val applicationContext: Application by instance() - override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> { val downloads = downloadManager.downloads.toList() @@ -74,30 +69,38 @@ class Downloads(override val di: DI) : Source } override suspend fun images(itemID: String): List { - TODO("Not yet implemented") + return downloadManager.downloadFolder.getChild(itemID).let { + if (!it.exists()) null else images(it) + }!! } override suspend fun info(itemID: String): ItemInfo { - TODO("Not yet implemented") + return transform(downloadManager.downloadFolder.getChild(itemID)) } companion object { - private fun firstImage(folder: FileX): String? = + private fun images(folder: FileX): List? = folder.list { _, name -> - name.takeLastWhile { it != '.' } !in listOf("jpg", "png", "gif", "webp") - }?.firstOrNull() + name.takeLastWhile { it != '.' } in listOf("jpg", "png", "gif", "webp") + }?.toList() - fun transform(folder: FileX): ItemInfo = + suspend fun transform(folder: FileX): ItemInfo = withContext(Dispatchers.Unconfined) { kotlin.runCatching { Json.decodeFromString(folder.getChild(".metadata").readText()) - }.getOrNull() ?: - ItemInfo( - "Downloads", - "", - folder.name, - firstImage(folder) ?: "", - "" - ) + }.getOrNull() ?: run { + val images = images(folder) + ItemInfo( + "Downloads", + folder.name, + folder.name, + images?.firstOrNull() ?: "", + "", + mapOf( + ItemInfo.ExtraType.PAGECOUNT to async { images?.size?.toString() } + ) + ) + } + } } } \ No newline at end of file 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 index 61619e0d..4eb803a6 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt @@ -27,14 +27,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import org.kodein.di.* import org.kodein.di.android.x.closestDI -import org.kodein.di.android.x.di -import org.kodein.type.jvmType -import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.pupil.adapters.SourceAdapter -import xyz.quaver.pupil.sources.AnySource -import xyz.quaver.pupil.sources.Source -import xyz.quaver.pupil.sources.SourceEntries -import xyz.quaver.pupil.util.ItemClickSupport +import xyz.quaver.pupil.sources.* class SourceSelectDialog : DialogFragment(), DIAware { @@ -48,9 +42,14 @@ class SourceSelectDialog : DialogFragment(), DIAware { window?.requestFeature(Window.FEATURE_NO_TITLE) window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + val sourcesWithPreferenceID = direct.instance().map { it.first } + val preferences = direct.instance().filter { + it.first in sourcesWithPreferenceID + }.toSet() + setContentView(RecyclerView(context).apply { layoutManager = LinearLayoutManager(context) - adapter = SourceAdapter(direct.instance()).apply { + adapter = SourceAdapter(preferences).apply { onSourceSelectedListener = this@SourceSelectDialog.onSourceSelectedListener onSourceSettingsSelectedListener = this@SourceSelectDialog.onSourceSettingsSelectedListener } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SourceSettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SourceSettingsFragment.kt index 6575ce9d..f921524b 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SourceSettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SourceSettingsFragment.kt @@ -30,7 +30,7 @@ import org.kodein.di.DIAware import org.kodein.di.android.x.closestDI import org.kodein.di.direct import org.kodein.di.instance -import xyz.quaver.pupil.sources.PreferenceIDs +import xyz.quaver.pupil.sources.SourcePreferenceIDs import xyz.quaver.pupil.ui.dialog.DefaultQueryDialogFragment import xyz.quaver.pupil.util.Preferences import xyz.quaver.pupil.util.getAvailableLanguages @@ -45,7 +45,7 @@ class SourceSettingsFragment(private val source: String) : override val di by closestDI() override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(direct.instance().toMap()[source]!!, rootKey) + setPreferencesFromResource(direct.instance().toMap()[source]!!, rootKey) initPreferences() } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt index ec4796dc..ebf4f7aa 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt @@ -105,13 +105,18 @@ class MainViewModel(app: Application) : AndroidViewModel(app), DIAware { fun setModeAndReset(mode: MainMode) { sourceFactory = when (mode) { - MainMode.SEARCH -> defaultSourceFactory + MainMode.SEARCH, MainMode.DOWNLOADS -> defaultSourceFactory MainMode.HISTORY -> { { direct.instance(arg = it) } } - MainMode.DOWNLOADS -> { { direct.instance() } } else -> return } - setSourceAndReset(source.value!!.name) + setSourceAndReset( + when { + mode == MainMode.DOWNLOADS -> "downloads" + source.value is Downloads -> "hitomi.la" + else -> source.value!!.name + } + ) } fun query() { diff --git a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt index 91f41b32..ce4c02fa 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt @@ -20,6 +20,7 @@ package xyz.quaver.pupil.ui.viewmodel import android.app.Application +import android.net.Uri import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -29,8 +30,10 @@ import okhttp3.Headers import okhttp3.Headers.Companion.toHeaders import okhttp3.Request import org.kodein.di.DIAware +import org.kodein.di.android.x.closestDI import org.kodein.di.android.x.di import org.kodein.di.instance +import xyz.quaver.io.FileX import xyz.quaver.pupil.adapters.ReaderItem import xyz.quaver.pupil.sources.AnySource import xyz.quaver.pupil.util.ImageCache @@ -40,7 +43,7 @@ import xyz.quaver.pupil.util.source @Suppress("UNCHECKED_CAST") class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware { - override val di by di() + override val di by closestDI() private val cache: ImageCache by instance() @@ -71,29 +74,38 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware { _images.value = images images.forEachIndexed { index, image -> - val file = cache.load( - Request.Builder() - .url(image) - .headers(source.getHeadersForImage(itemID, image).toHeaders()) - .build() - ) + when (val scheme = image.takeWhile { it != ':' }) { + "http", "https" -> { + val file = cache.load( + Request.Builder() + .url(image) + .headers(source.getHeadersForImage(itemID, image).toHeaders()) + .build() + ) - val channel = cache.channels[image] ?: error("Channel is null") + val channel = cache.channels[image] ?: error("Channel is null") - channel.invokeOnClose { e -> - viewModelScope.launch { - if (e == null) { - _readerItems.value!![index] = ReaderItem(_readerItems.value!![index].progress, file) - _readerItems.notify() + channel.invokeOnClose { e -> + viewModelScope.launch { + if (e == null) { + _readerItems.value!![index] = ReaderItem(_readerItems.value!![index].progress, Uri.fromFile(file)) + _readerItems.notify() + } + } + } + + launch { + for (progress in channel) { + _readerItems.value!![index] = ReaderItem(progress, _readerItems.value!![index].image) + _readerItems.notify() + } } } - } - - launch { - for (progress in channel) { - _readerItems.value!![index] = ReaderItem(progress, _readerItems.value!![index].image) + "content" -> { + _readerItems.value!![index] = ReaderItem(100f, Uri.parse(image)) _readerItems.notify() } + else -> throw IllegalArgumentException("Expected URL scheme 'http(s)' or 'content' but was '$scheme'") } } } diff --git a/app/src/main/res/layout/search_result_item.xml b/app/src/main/res/layout/search_result_item.xml index 0f65bfca..02473e91 100644 --- a/app/src/main/res/layout/search_result_item.xml +++ b/app/src/main/res/layout/search_result_item.xml @@ -104,6 +104,9 @@ android:id="@+id/id_view" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:maxWidth="150dp" + android:ellipsize="end" + android:maxLines="1" android:layout_margin="8dp" app:layout_constraintTop_toBottomOf="@id/divider" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/xml/download_preferences.xml b/app/src/main/res/xml/download_preferences.xml new file mode 100644 index 00000000..6f4b1e38 --- /dev/null +++ b/app/src/main/res/xml/download_preferences.xml @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/history_preferences.xml b/app/src/main/res/xml/history_preferences.xml new file mode 100644 index 00000000..6f4b1e38 --- /dev/null +++ b/app/src/main/res/xml/history_preferences.xml @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file