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