diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index c6c1e863..1342638b 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -12,6 +12,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index da4d115b..806b8603 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -131,7 +131,7 @@ dependencies {
implementation("xyz.quaver:libpupil:2.1.11")
implementation("xyz.quaver:documentfilex:0.7.1")
- implementation("xyz.quaver:subsampledimage:0.0.1-alpha10-SNAPSHOT")
+ implementation("xyz.quaver:subsampledimage:0.0.1-alpha11-SNAPSHOT")
implementation("org.kodein.log:kodein-log:0.11.1")
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.7")
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 139f7091..2344c10a 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt
@@ -43,7 +43,6 @@ data class SearchResultEvent(val type: Type, val itemID: String, val payload: Pa
abstract class Source {
abstract val name: String
abstract val iconResID: Int
- abstract val preferenceID: Int
abstract val availableSortMode: List
abstract suspend fun search(query: String, range: IntRange, sortMode: Int): Pair, Int>
diff --git a/app/src/main/java/xyz/quaver/pupil/sources/History.kt b/app/src/main/java/xyz/quaver/pupil/sources/History.kt
index c3c52b08..ab0590c3 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/History.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/History.kt
@@ -36,8 +36,6 @@ class History(override val di: DI) : Source(), DIAware {
get() = "history"
override val iconResID: Int
get() = 0 //TODO
- override val preferenceID: Int
- get() = 0 //TODO
override val availableSortMode: List = emptyList()
private val history = direct.database().historyDao()
diff --git a/app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt b/app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt
index 3f8a7441..e56856ea 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt
@@ -122,7 +122,6 @@ class Hitomi(app: Application) : Source(), DIAware {
override val name: String = "hitomi.la"
override val iconResID: Int = R.drawable.hitomi
- override val preferenceID: Int = R.xml.hitomi_preferences
override val availableSortMode: List = app.resources.getStringArray(R.array.hitomi_sort_mode).toList()
var cachedQuery: String? = null
diff --git a/app/src/main/java/xyz/quaver/pupil/sources/Hiyobi_io.kt b/app/src/main/java/xyz/quaver/pupil/sources/Hiyobi_io.kt
index 0c9e616f..0d9fb3ef 100644
--- a/app/src/main/java/xyz/quaver/pupil/sources/Hiyobi_io.kt
+++ b/app/src/main/java/xyz/quaver/pupil/sources/Hiyobi_io.kt
@@ -153,7 +153,6 @@ class Hiyobi_io(app: Application): Source(), DIAware {
override val name = "hiyobi.io"
override val iconResID = R.drawable.hitomi
- override val preferenceID = 0
override val availableSortMode = emptyList()
private val client: HttpClient by instance()
diff --git a/app/src/main/java/xyz/quaver/pupil/types/Tags.kt b/app/src/main/java/xyz/quaver/pupil/types/Tags.kt
deleted file mode 100644
index 29340644..00000000
--- a/app/src/main/java/xyz/quaver/pupil/types/Tags.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Pupil, Hitomi.la viewer for Android
- * Copyright (C) 2019 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.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 {
- if (tag.firstOrNull() == '-') {
- tag.substring(1).split(Regex(":"), 2).let {
- return when(it.size) {
- 2 -> Tag(it[0], it[1], true)
- else -> Tag(null, tag, true)
- }
- }
- }
- tag.split(Regex(":"), 2).let {
- return when(it.size) {
- 2 -> Tag(it[0], it[1])
- else -> Tag(null, tag)
- }
- }
- }
- }
-
- override fun toString(): String {
- return (if (isNegative) "-" else "") + when(area) {
- null -> tag
- else -> "$area:$tag"
- }
- }
-
- fun toQuery(): String {
- return toString().replace(' ', '_')
- }
-
- override fun equals(other: Any?): Boolean {
- if (other !is Tag)
- return false
-
- if (other.area == area && other.tag == tag)
- return true
-
- return false
- }
-
- override fun hashCode() = toString().hashCode()
-}
-
-class Tags(val tags: MutableSet = mutableSetOf()) : MutableSet by tags {
-
- companion object {
- fun parse(tags: String) : Tags {
- return Tags(
- tags.split(' ').mapNotNull {
- if (it.isNotEmpty())
- Tag.parse(it)
- else
- null
- }.toMutableSet()
- )
- }
- }
-
- fun contains(element: String): Boolean {
- tags.forEach {
- if (it.toString() == element)
- return true
- }
-
- return false
- }
-
- fun add(element: String): Boolean {
- return tags.add(Tag.parse(element))
- }
-
- fun remove(element: String) {
- tags.filter { it.toString() == element }.forEach {
- tags.remove(it)
- }
- }
-
- fun removeByArea(area: String, isNegative: Boolean? = null) {
- tags.filter { it.area == area && (if(isNegative == null) true else (it.isNegative == isNegative)) }.forEach {
- tags.remove(it)
- }
- }
-
- override fun toString(): String {
- return tags.joinToString(" ") { it.toString() }
- }
-}
\ 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 06d42f43..0aa6ce82 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
@@ -58,7 +58,6 @@ import org.kodein.log.newLogger
import xyz.quaver.pupil.*
import xyz.quaver.pupil.R
import xyz.quaver.pupil.sources.SearchResultEvent
-import xyz.quaver.pupil.types.*
import xyz.quaver.pupil.ui.composable.FloatingActionButtonState
import xyz.quaver.pupil.ui.composable.FloatingSearchBar
import xyz.quaver.pupil.ui.composable.MultipleFloatingActionButton
@@ -66,6 +65,7 @@ import xyz.quaver.pupil.ui.composable.SubFabItem
import xyz.quaver.pupil.ui.dialog.SourceSelectDialog
import xyz.quaver.pupil.ui.theme.PupilTheme
import xyz.quaver.pupil.ui.composable.ProgressCard
+import xyz.quaver.pupil.ui.dialog.OpenWithItemIDDialog
import xyz.quaver.pupil.ui.viewmodel.MainViewModel
import xyz.quaver.pupil.util.*
import kotlin.math.*
@@ -108,21 +108,51 @@ class MainActivity : ComponentActivity(), DIAware {
}
}
- var openSourceSelectDialog by remember { mutableStateOf(false) }
+ val onSearchResultEvent: (SearchResultEvent) -> Unit = { event ->
+ when (event.type) {
+ SearchResultEvent.Type.OPEN_READER -> {
+ startActivity(
+ Intent(
+ this@MainActivity,
+ ReaderActivity::class.java
+ ).apply {
+ putExtra("source", model.source.name)
+ putExtra("id", event.itemID)
+ putExtra("payload", event.payload)
+ })
+ }
+ else -> TODO("")
+ }
+ }
+
+ var sourceSelectDialog by remember { mutableStateOf(false) }
+ var openWithItemIDDialog by remember { mutableStateOf(false) }
LaunchedEffect(navigationIconProgress) {
navigationIcon.progress = navigationIconProgress
}
- if (openSourceSelectDialog)
+ if (sourceSelectDialog)
SourceSelectDialog(
currentSource = model.source.name,
- onDismissRequest = { openSourceSelectDialog = false }
+ onDismissRequest = { sourceSelectDialog = false }
) { source ->
- openSourceSelectDialog = false
+ sourceSelectDialog = false
model.setSourceAndReset(source.name)
}
+ if (openWithItemIDDialog)
+ OpenWithItemIDDialog {
+ openWithItemIDDialog = false
+
+ it?.let {
+ onSearchResultEvent(SearchResultEvent(
+ SearchResultEvent.Type.OPEN_READER,
+ it
+ ))
+ }
+ }
+
Scaffold(
floatingActionButton = {
MultipleFloatingActionButton(
@@ -142,7 +172,9 @@ class MainActivity : ComponentActivity(), DIAware {
SubFabItem(
painterResource(R.drawable.numeric),
stringResource(R.string.main_open_gallery_by_id)
- ),
+ ) {
+ openWithItemIDDialog = true
+ }
),
visible = isFabVisible,
targetState = isFabExpanded,
@@ -178,22 +210,7 @@ class MainActivity : ComponentActivity(), DIAware {
ProgressCard(
progress = 0.5f
) {
- model.source.SearchResult(itemInfo = itemInfo) { event ->
- when (event.type) {
- SearchResultEvent.Type.OPEN_READER -> {
- startActivity(
- Intent(
- this@MainActivity,
- ReaderActivity::class.java
- ).apply {
- putExtra("source", model.source.name)
- putExtra("id", event.itemID)
- putExtra("payload", event.payload)
- })
- }
- else -> TODO("")
- }
- }
+ model.source.SearchResult(itemInfo = itemInfo, onEvent = onSearchResultEvent)
}
}
}
@@ -224,7 +241,7 @@ class MainActivity : ComponentActivity(), DIAware {
painterResource(model.source.iconResID),
contentDescription = null,
modifier = Modifier.size(24.dp).clickable {
- openSourceSelectDialog = true
+ sourceSelectDialog = true
}
)
Icon(
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 b49f8c41..5ada3b63 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
@@ -19,12 +19,16 @@
package xyz.quaver.pupil.ui
import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
@@ -33,21 +37,18 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BrokenImage
import androidx.compose.material.icons.filled.Fullscreen
import androidx.compose.runtime.*
-import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import coil.annotation.ExperimentalCoilApi
-import com.google.accompanist.appcompattheme.AppCompatTheme
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
@@ -71,7 +72,7 @@ class ReaderActivity : ComponentActivity(), DIAware {
private val logger = newLogger(LoggerFactory.default)
- @OptIn(ExperimentalCoilApi::class)
+ @OptIn(ExperimentalCoilApi::class, ExperimentalFoundationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -80,24 +81,20 @@ class ReaderActivity : ComponentActivity(), DIAware {
setContent {
var isFABExpanded by remember { mutableStateOf(FloatingActionButtonState.COLLAPSED) }
- val isFullscreen by model.isFullscreen.observeAsState(false)
val imageSources = remember { mutableStateListOf() }
- val imageHeights = remember { mutableStateListOf() }
val states = remember { mutableStateListOf() }
+ val scaffoldState = rememberScaffoldState()
+ val snackbarCoroutineScope = rememberCoroutineScope()
+
LaunchedEffect(model.imageList.count { it != null }) {
if (imageSources.isEmpty() && model.imageList.isNotEmpty())
imageSources.addAll(List(model.imageList.size) { null })
if (states.isEmpty() && model.imageList.isNotEmpty())
- states.addAll(List(model.imageList.size) { SubSampledImageState(ScaleTypes.FIT_WIDTH, Bounds.FORCE_OVERLAP_OR_CENTER) })
-
- if (imageHeights.isEmpty() && model.imageList.isNotEmpty())
- imageHeights.addAll(List(model.imageList.size) { null })
-
- logger.info {
- "${model.imageList.count { it == null }} nulls"
- }
+ states.addAll(List(model.imageList.size) { SubSampledImageState(ScaleTypes.FIT_WIDTH, Bounds.FORCE_OVERLAP_OR_CENTER).apply {
+ isGestureEnabled = true
+ } })
model.imageList.forEachIndexed { i, image ->
if (imageSources[i] == null && image != null)
@@ -108,24 +105,27 @@ class ReaderActivity : ComponentActivity(), DIAware {
model.error(i)
}.getOrNull()
}
-
- logger.info {
- "${imageSources.count { it == null }} nulls"
- }
}
WindowInsetsControllerCompat(window, window.decorView).run {
- if (isFullscreen) {
+ if (model.isFullscreen) {
hide(WindowInsetsCompat.Type.systemBars())
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
} else
show(WindowInsetsCompat.Type.systemBars())
}
+ if (model.error)
+ stringResource(R.string.reader_failed_to_find_gallery).let {
+ snackbarCoroutineScope.launch {
+ scaffoldState.snackbarHostState.showSnackbar(it, duration = SnackbarDuration.Indefinite)
+ }
+ }
+
PupilTheme {
Scaffold(
topBar = {
- if (!isFullscreen)
+ if (!model.isFullscreen)
TopAppBar(
title = {
Text(
@@ -145,14 +145,14 @@ class ReaderActivity : ComponentActivity(), DIAware {
)
},
floatingActionButton = {
- if (!isFullscreen)
+ if (!model.isFullscreen)
MultipleFloatingActionButton(
items = listOf(
SubFabItem(
icon = Icons.Default.Fullscreen,
label = stringResource(id = R.string.reader_fab_fullscreen)
) {
- model.isFullscreen.postValue(true)
+ model.isFullscreen = true
}
),
targetState = isFABExpanded,
@@ -160,61 +160,76 @@ class ReaderActivity : ComponentActivity(), DIAware {
isFABExpanded = it
}
)
- }
+ },
+ scaffoldState = scaffoldState,
+ snackbarHost = { scaffoldState.snackbarHostState }
) {
- LazyColumn(
- Modifier.fillMaxSize(),
- verticalArrangement = Arrangement.spacedBy(4.dp)
- ) {
- itemsIndexed(imageSources) { i, imageSource ->
- LaunchedEffect(states[i].canvasSize, states[i].imageSize) {
- if (imageHeights.isNotEmpty() && imageHeights[i] == null)
- states[i].canvasSize?.let { canvasSize ->
- states[i].imageSize?.let { imageSize ->
- imageHeights[i] = imageSize.height * canvasSize.width / imageSize.width
- } }
- }
+ Box {
+ LazyColumn(
+ Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ itemsIndexed(imageSources) { i, imageSource ->
+ Box(
+ Modifier
+ .wrapContentHeight(states[i], 500.dp)
+ .fillMaxWidth()
+ .border(1.dp, Color.Gray),
+ contentAlignment = Alignment.Center
+ ) {
+ if (imageSource == null)
+ model.progressList.getOrNull(i)?.let { progress ->
+ if (progress < 0f)
+ Icon(Icons.Filled.BrokenImage, null)
+ else
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ LinearProgressIndicator(progress)
+ Text((i + 1).toString())
+ }
+ }
+ else {
+ val haptic = LocalHapticFeedback.current
- Box(
- Modifier
- .height(
- imageHeights
- .getOrNull(i)
- ?.let { with(LocalDensity.current) { it.toDp() } }
- ?: 500.dp)
- .fillMaxWidth()
- .border(1.dp, Color.Gray),
- contentAlignment = Alignment.Center
- ) {
- if (imageSource == null)
- model.progressList.getOrNull(i)?.let { progress ->
- if (progress < 0f)
- Icon(Icons.Filled.BrokenImage, null)
- else
- Column(
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- LinearProgressIndicator(progress)
- Text((i + 1).toString())
- }
+ SubSampledImage(
+ modifier = Modifier
+ .fillMaxSize()
+ .run {
+ if (model.isFullscreen)
+ doubleClickCycleZoom(states[i], 2f)
+ else
+ combinedClickable(
+ onLongClick = {
+ haptic.performHapticFeedback(HapticFeedbackType.LongPress)
+ }
+ ) {
+ model.isFullscreen = true
+ }
+ },
+ imageSource = imageSource,
+ state = states[i]
+ )
}
- else {
- SubSampledImage(
- modifier = Modifier.fillMaxSize(),
- imageSource = imageSource,
- state = states[i]
- )
}
}
}
- }
- if (model.totalProgress != model.imageCount)
- LinearProgressIndicator(
- modifier = Modifier.fillMaxWidth(),
- progress = model.progressList.map { abs(it) }.sum() / model.progressList.size,
- color = colorResource(id = R.color.colorAccent)
+ if (model.totalProgress != model.imageCount)
+ LinearProgressIndicator(
+ modifier = Modifier
+ .fillMaxWidth()
+ .align(Alignment.TopCenter),
+ progress = model.progressList.map { abs(it) }
+ .sum() / model.progressList.size,
+ color = MaterialTheme.colors.secondary
+ )
+
+ SnackbarHost(
+ scaffoldState.snackbarHostState,
+ modifier = Modifier.align(Alignment.BottomCenter)
)
+ }
}
}
}
@@ -227,7 +242,7 @@ class ReaderActivity : ComponentActivity(), DIAware {
override fun onBackPressed() {
when {
- model.isFullscreen.value == true -> model.isFullscreen.postValue(false)
+ model.isFullscreen -> model.isFullscreen = false
else -> super.onBackPressed()
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/OpenWithItemIDDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/OpenWithItemIDDialog.kt
new file mode 100644
index 00000000..351810a1
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/OpenWithItemIDDialog.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.ui.dialog
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import xyz.quaver.pupil.R
+
+@Composable
+fun OpenWithItemIDDialog(onDismissRequest: (String?) -> Unit = { }) {
+ var itemID by remember { mutableStateOf("") }
+
+ Dialog(onDismissRequest = { onDismissRequest(null) }) {
+ Card(
+ elevation = 8.dp,
+ shape = RoundedCornerShape(12.dp)
+ ) {
+ Column(
+ modifier = Modifier.padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ Text(
+ stringResource(R.string.main_open_gallery_by_id),
+ style = MaterialTheme.typography.h6
+ )
+ TextField(
+ modifier = Modifier.fillMaxWidth(),
+ value = itemID,
+ onValueChange = {
+ itemID = it
+ },
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Go),
+ keyboardActions = KeyboardActions(
+ onGo = { onDismissRequest(itemID) }
+ )
+ )
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ onClick = { onDismissRequest(itemID) }
+ ) {
+ Text(stringResource(android.R.string.ok))
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt b/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
index 05fe729d..3d6ef1cb 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
@@ -26,6 +26,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
private val DarkColorPalette = darkColors(
+ primary = LightBlue300,
+ primaryVariant = LightBlue700,
secondary = Pink600,
onSecondary = Color.White
)
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 a3880e37..a4dc45f8 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
@@ -53,13 +53,16 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware {
private val logger = newLogger(LoggerFactory.default)
- val isFullscreen = MutableLiveData(false)
+ var isFullscreen by mutableStateOf(false)
private val database: AppDatabase by instance()
private val historyDao = database.historyDao()
private val bookmarkDao = database.bookmarkDao()
+ var error by mutableStateOf(false)
+ private set
+
var source by mutableStateOf(null)
private set
var itemID by mutableStateOf(null)
@@ -121,14 +124,20 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware {
viewModelScope.launch {
if (title == null)
title = withContext(Dispatchers.IO) {
- source.info(itemID)
- }.title
+ kotlin.runCatching {
+ source.info(itemID)
+ }.getOrNull()
+ }?.title
}
viewModelScope.launch {
withContext(Dispatchers.IO) {
- source.images(itemID)
- }.let { images ->
+ kotlin.runCatching {
+ source.images(itemID)
+ }.onFailure {
+ error = true
+ }.getOrNull()
+ }?.let { images ->
this@ReaderViewModel.images = images
imageCount = images.size
diff --git a/app/src/main/java/xyz/quaver/pupil/util/misc.kt b/app/src/main/java/xyz/quaver/pupil/util/misc.kt
index 0cb01414..2911f76b 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/misc.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/misc.kt
@@ -149,7 +149,7 @@ fun View.show() {
visibility = View.VISIBLE
}
-class FileXImageSource(file: FileX): ImageSource {
+class FileXImageSource(val file: FileX): ImageSource {
private val decoder = newBitmapRegionDecoder(file.inputStream()!!)
override val imageSize by lazy { Size(decoder.width.toFloat(), decoder.height.toFloat()) }
diff --git a/app/src/main/java/xyz/quaver/pupil/util/update.kt b/app/src/main/java/xyz/quaver/pupil/util/update.kt
index 132f52b5..1819821d 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/update.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt
@@ -150,7 +150,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
Preferences["update_download_id"] = it
}
}
- setNegativeButton(if (force) android.R.string.cancel else R.string.ignore_update) { _, _ ->
+ setNegativeButton(if (force) android.R.string.cancel else R.string.ignore) { _, _ ->
if (!force)
preferences.edit()
.putLong("ignore_update_until", System.currentTimeMillis() + 604800000)
diff --git a/app/src/main/res/drawable/swap_horizontal.xml b/app/src/main/res/drawable/swap_horizontal.xml
deleted file mode 100644
index 90d142ac..00000000
--- a/app/src/main/res/drawable/swap_horizontal.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 31decf54..9ecb1ba4 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -3,25 +3,158 @@
言語: %1$s
シリーズ: %1$s
タイプ: %1$s
- ギャラリー検索
+ 結果なし
+ 検索…
+ キャッシュクリア
+ キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?
+ %s使用中
+ ストレージ使用量読み込み中…
デフォルトキーワード
+ 一回にロードするギャラリー数
+ 検索設定
+ 設定
アップデートダウンロード中
新しいアップデートがあります
+ 注意
+ その他
+ ミラーサーバー
+ 履歴を削除
+ 履歴を削除しますか?
+ 履歴数: %1$d
+ 履歴
+ トップ
# リリースノート(v%1$s)\n%2$s
+ セキュリティーモード
+ アプリ履歴でアプリの画面を表示しない
+ 移動
+ 非選択
+ BLフィルター
+ グロフィルター
+ "言語: "
+ デフォルトキーワード設定
+ お問い合わせ先
+ ホームページ
+ ヘルプ
+ Github
+ メールを送る
フルスクリーン
ダウンロード
ダウンロードの進行を通知
+ バックグラウンドダウンロード
+ ダウンロード中…
+ ダウンロード完了
+ バックグラウンドダウンロード中止
+ ダウンロード
ページ移動
+ 現ページ番号: %1$d\nページ数: %2$d
+ hitomi.laに接続できません
+ %1$dページへ移動
+ ダウンロード削除
+ ダウンロードしたギャラリーを全て削除します。\n実行しますか?
+ ミラーサーバからイメージをロード
+ ブックマーク
ギャラリー番号で見る
+ エラーが発生しました
+ ストレージ
+ ディスコード
+ アプリロック
+ アップロックの種類
+ バージョン(アップデート確認)
+ 生体認識
+ ロック確認のためもう一回入力してください。
+ 有効
+ 指紋
+ パスワード
+ パターン
+ ロックが一致しません。やり直してください。
+ なし
+ ロックを無効にしますか?
ロード中
- 無視
+ ソート
+ 投稿日時順
+ 人気順
+ 無視
+ ロックファイルが破損されています。Pupilを再再インストールしてください。
+ ダークモード
+ 夜にシコりたい方々へ
+ ギャラリー情報
+ アーティスト
+ キャラクター
+ グループ
+ 言語
+ シリーズ
+ タグ
+ サムネイル
+ おすすめ
+ イメージを隠す
+ 削除
+ ダウンロード
+ ブックマークバックアップ
+ ブックマーク復元
+ バックアップファイルを作成しました
+ 復元に失敗しました
+ %1$d項目を復元しました
+ ダウンロード場所
+ 内部ストレージ
+ 外部SDカード
+ %s 使用可能
ダウンロードが完了しました
ここをクリックしてアップデートを行えます
+ ベータチャンネルでアップデートを受信
+ v%s
+ 低解像度イメージ
+ ロード速度とデータ使用料を改善するため低解像度イメージをロード
+ 手動で設定
+ このフォルダにアクセスできません。他のフォルダを選択してください。
+ プロクシ
+ ID
+ プロクシタイプ
+ ポート
+ パスワード
+ エラー
+ サーバーアドレス
+ サーバー
+ 簡単モード
すべてのダウンロードキャンセル
アップデート
アップデートの進行状態を表示
+ 旧ギャラリーインポート
+ フォルダを読めません
+ 旧ギャラリーインポート中…
+ インポート完了
ランダムギャラリーを開く
+ 予備のロックが設定されていないと指紋ロックは使用できません
+ Pupil指紋ロック™
+ こうかはばつぐんだ!
+ 登場人物を全て18歳以上にする
+ ユーザーID
+ クリップボードにコピーしました
+ リトライ
+ まばたき検知スクロール
+ 全てのギャラリーを対象に検索
+ 綴じ方向を左にする
+ ブックマーク管理
+ エラーが発生しました
+ バックアップ共有
ダウンローダ
ダウンローダの状態を表示
+ ダウンローダー起動中
+ フォルダ名パターン
+ フォルダ名に使用できない文字が含まれています
+ %sに含まれている文字列を対応する変数に置換します\n\n%s
+ ストレージ管理
+ オープンソースライセンス
+ お気に入りのタグを見る
+ 履歴を見る
+ まばたき検知を中止
+ カメラ権限が拒否されているため、まばたき検知使用できません
+ この機器には前面カメラが装着されていません
+ エラー
+ キャッシュサイズ制限
+ 制限なし
タグ言語
+ Githubにて翻訳に参加できます
+ 並列ダウンロード
+ アンドロイド11以上では外部からのアプリ内部空間接近が不可能です。ダウンロードフォルダを変更しますか?
+ ネットワーク
\ 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 fe7fbd68..6bedb6a2 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -3,25 +3,158 @@
언어: %1$s
시리즈: %1$s
종류: %1$s
- 갤러리 검색
+ 검색…
기본 검색어
+ 캐시 정리하기
+ 캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?
+ %s 사용중
+ 저장공간 사용량 계산 중…
+ 한 번에 로드할 갤러리 수
+ 검색 설정
+ 설정
업데이트 다운로드중…
업데이트가 있습니다!
+ 경고
+ 결과 없음\n해결법
+ 기타
+ 기록 삭제
+ 기록을 삭제하시겠습니까?
+ 기록 %1$d개 저장됨
+ 기록
+ 홈
# 릴리즈 노트(v%1$s)\n%2$s
+ 최근 앱 목록 창에서 앱 화면을 보이지 않게 합니다
+ 보안 모드 활성화
+ 이동
+ 미선택
+ BL물 필터
+ 고어물 필터
+ "언어: "
+ 기본 검색어 설정
+ 메일 보내기!
+ Github
+ 도움말
+ 홈페이지
+ 문의
전체 화면
다운로드
다운로드 상태 알림
+ 백그라운드 다운로드
+ 다운로드 중…
+ 다운로드 완료
+ 백그라운드 다운로드 취소
+ 다운로드
페이지 이동
+ 현재 페이지: %1$d\n페이지 수: %2$d
+ hitomi.la에 연결할 수 없습니다
+ %1$d 페이지로 이동
+ 다운로드 삭제
+ 다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?
+ 즐겨찾기
갤러리 번호로 열기
+ 갤러리를 찾지 못했습니다
+ 저장 공간
+ 디스코드
+ 앱 잠금
+ 앱 잠금 종류
+ 앱 버전(업데이트 확인)
+ 생체 인식
+ 잠금 확인을 위해 한번 더 입력해주세요
+ 사용 중
+ 지문
+ 비밀번호
+ 패턴
+ 잠금이 일치하지 않습니다. 다시 시도하세요.
+ 없음
+ 잠금을 해제할까요?
로딩중
- 무시
+ 정렬
+ 인기순
+ 시간순
+ 무시
+ 잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.
+ 다크 모드
+ 딥 다크한 모오드
+ 갤러리 정보
+ 작가
+ 캐릭터
+ 그룹
+ 언어
+ 시리즈
+ 태그
+ 관련 갤러리
+ 미리보기
+ 이미지 숨기기
+ 삭제
+ 다운로드
+ 즐겨찾기 백업
+ 즐겨찾기 복원
+ 백업 파일을 생성하였습니다
+ 복원에 실패했습니다
+ %1$d개 항목을 복원했습니다
+ 다운로드 위치
+ 내부 저장공간
+ 외부 SD카드
+ %s 사용 가능
다운로드가 완료되었습니다
여기를 클릭해서 업데이트를 진행할 수 있습니다
+ 베타 채널에서 업데이트
+ v%s
+ 저해상도 이미지
+ 로드 속도와 데이터 사용량을 줄이기 위해 저해상도 이미지를 로드
+ 미러 서버에서 이미지 로드
+ 미러 설정
+ 직접 설정
+ 이 폴더에 접근할 수 없습니다. 다른 폴더를 선택해주세요.
+ 프록시
+ ID
+ 프록시 타입
+ 포트
+ 비밀번호
+ 잘못된 값
+ 서버 주소
+ 서버
+ 간단히 보기
다운로드 모두 취소
업데이트
업데이트 진행상황 표시
+ 이전 버전 갤러리 가져오기
+ 폴더를 읽을 수 없습니다
+ 이전 버전 갤러리 가져오는 중…
+ 가져오기 완료
무작위 갤러리 열기
+ 지문 잠금은 다른 잠금 방식이 활성화 되어 있을 때만 사용 가능합니다
+ Pupil 지문 인식™
+ 힘세고 강한 지문 인식
+ 판사님 저는 페도가 아닙니다
+ 유저 ID
+ 클립보드에 복사됨
+ 재시도
+ 눈 깜빡임 감지 스크롤
+ 모든 갤러리 검색
+ 좌측으로 페이지 넘기기
+ 즐겨찾기 관리
+ 업로드 실패
+ 백업 공유
다운로더
다운로더 작동 여부 표시
+ 다운로더 작동중…
+ 폴더명 패턴
+ 폴더 패턴에 사용할 수 없는 문자가 포함되어 있습니다
+ 지원되는 변수는 %s 입니다\n\n%s
+ 저장소 관리
+ 오픈 소스 라이선스
+ 검색 기록 보기
+ 즐겨찾기 태그 보기
+ 눈 깜빡임 감지 중지
+ 카메라 권한이 거부되었기 때문에 눈 깜빡임 감지가 불가능합니다
+ 이 장치에는 전면 카메라가 없습니다
+ 오류
+ 캐시 크기 제한
+ 무제한
태그 언어
+ Github에서 번역에 참여하세요
+ 병렬 다운로드
+ 안드로이드 11 이상에서는 외부에서 현재 다운로드 폴더에 접근할 수 없습니다. 변경하시겠습니까?
+ 네트워크
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 22cfeabf..a78d659e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,13 +1,38 @@
- Pupil-BETA
+ Pupil
https://api.github.com/repos/tom5079/Pupil/releases
+ http://bit.ly/2EZDClw
+ http://bit.ly/2Z7lNZE
+ https://github.com/tom5079/Pupil/
+ mailto:pupil.hentai@gmail.com
+ https://discord.gg/Stj4b5v
+
+ 해결법
+ https://bit.ly/34dUBwy
+
+ http://ix.io/
+
+ Settings
+ Thumbnail
+
+ Content ImageView
+ -/-
+
+ %s (%s)
- Ignore
+ Warning
+ Error
+
+ Ignore
+
+ Unlimited
+
+ Copied to clipboard
Download
Shows download status
@@ -18,56 +43,210 @@
Update
Shows update progress
+ Unable to connect to hitomi.la
+
+ Lock file corrupted! Please re-install Pupil
+
+ No result
+
+ From Android 11 and above, current Download folder cannot be accessed by outside apps. Would you like to change the download folder?
+
+ Home
+ History
+ Downloads
+ Favorites
+ Contact
+ Help
+ Visit homepage
+ Visit github
+ Email me!
+ Discord
+
+ Thin Mode
+
+ Sort
+ Newest
+ Popular
+
Jump to page
+ Current page: %1$d\nMaximum page: %2$d
Open Gallery by ID
+ Failed to open gallery
Open a random gallery
Cancel all downloads
+ Move to page %1$d
+
+ DOWNLOAD
+ DELETE
+
Update available
Download Completed
Click here to update
Downloading update…
# Release Note(v%1$s)\n%2$s
- Search galleries
+ Search…
+ Search all galleries
+ Show histories
+ Show favorite tags
+
+ Details
+ Thumbnails
+ Related Galleries
+ Artists
+ Groups
+ Language
+ Series
+ Characters
+ Tags
Series: %1$s
Type: %1$s
Language: %1$s
+ %dP
Loading
- Fullscreen
+ Go to page
+ Fullscreen>
+ Retry
+ Scroll with eye blink
+ Stop scroll with eye blink
+ Background download
+ Cancel background download
+ Downloading…
+ Download complete
- ]]>
+ Eye blink detection cannot be used without a permission
+ There is no front facing camera in this device
+
+
+ Downloader running…
+ Settings
+
+ App version(Click to check update)
+ v%s
+ Update from beta channel
+
+ Search Settings
+ Galleries per page
Default query
+ Storage
+
+ Manage Storage
+ Currently using %s
+ Calculating storage usage…
+ Clear cache
+ Deleting cache can affect image loading speed. Do you want to continue?
+ Clear downloads
+ Delete all downloaded galleries.\nDo you want to continue?
+ Clear history
+ Do you want to clear histories?
+ %1$d histories saved
+
+ Folder naming pattern
+ Folder naming pattern is containing invalid characters
+ %s will be replaced to its corresponding value\n\n%s
+ Download folder
+ Removable Storage
+ Internal Storage
+ %s available
+ Custom Location
+ This folder is not writable. Please select another folder.
+ Cache Limit
+ Hide image from gallery
+ Low quality images
+ Load low quality images to improve load speed and data usage
+
+ App lock
+ App lock type
+
+
+ Networking
+ Load images from mirrors
+ Proxy
+ Concurrent Download
+
+ Miscellaneous
Tag Language
+ Participate in translation on Github
+ Turn pages Right-to-Left
+ Enable security mode
+ Enable security mode to make the screen invisible on recent app window
+ Dark mode
+ Protect yourself against light attacks!
+ Import old galleries
+ User ID
+ Open Source Notice
+ Manage favorites
+ Backup favorites
+ Upload Failed
+ Share Backup
+ Backup file created
+ Restore favorites
+ Restore failed
+ %1$d entries restored
+
+ None
+ Pattern
+ PIN
+ Password
+ Biometrics
+ Fingerprint
+ Fingerprint can be only enabled if one of the other locks are enabled
+ Pupil Fingerprint Lock™
+ Enabled
+ Input same lock once more to confirm Lock
+ Do you want to remove lock?
+ Lock is different from last one. Please try again.
+
+ Set default query
+ Language:
+ Filter BL
+ Filter Guro
+ I\'m not a pedophile
+ Any
+ Mirrors
+
+ type
+ address
+ port
+ username
+ password
+ Wrong value
+ server
+ This folder is not readable
+ Importing old galleries…
+ %1$d/%2$d
+ Importing completed
+ Ah Shit, Here we go again
-
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/hitomi_preferences.xml b/app/src/main/res/xml/hitomi_preferences.xml
deleted file mode 100644
index eaa11b65..00000000
--- a/app/src/main/res/xml/hitomi_preferences.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file