Separated libpupil to standalone repository

Migrated to Kotlin 1.4
This commit is contained in:
tom5079
2020-08-23 20:26:23 +09:00
parent 735dbab695
commit 216914882c
60 changed files with 233 additions and 486 deletions

View File

@@ -2,6 +2,22 @@
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="120" /> <option name="RIGHT_MARGIN" value="120" />
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">

7
.idea/dictionaries/tom50.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="tom50">
<words>
<w>hitomi</w>
</words>
</dictionary>
</component>

1
.idea/gradle.xml generated
View File

@@ -11,7 +11,6 @@
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/libpupil" />
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />

View File

@@ -58,24 +58,23 @@ android {
} }
dependencies { dependencies {
def markwonVersion = '3.1.0'
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0" implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC"
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation "androidx.biometric:biometric:1.0.1" implementation "androidx.biometric:biometric:1.0.1"
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation "com.daimajia.swipelayout:library:1.2.0@aar" implementation "com.daimajia.swipelayout:library:1.2.0@aar"
implementation 'com.google.android.material:material:1.3.0-alpha02' implementation 'com.google.android.material:material:1.3.0-alpha02'
implementation 'com.google.firebase:firebase-core:17.4.4' implementation 'com.google.firebase:firebase-core:17.5.0'
implementation 'com.google.firebase:firebase-analytics:17.4.4' implementation 'com.google.firebase:firebase-analytics:17.5.0'
implementation 'com.google.firebase:firebase-crashlytics:17.1.1' implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
implementation 'com.google.firebase:firebase-perf:19.0.8' implementation 'com.google.firebase:firebase-perf:19.0.8'
implementation 'com.github.arimorty:floatingsearchview:2.1.1' implementation 'com.github.arimorty:floatingsearchview:2.1.1'
implementation 'com.github.clans:fab:1.6.4' implementation 'com.github.clans:fab:1.6.4'
@@ -92,13 +91,13 @@ dependencies {
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0' implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
//implementation 'com.andrognito.pinlockview:pinlockview:2.1.0' //implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
implementation "ru.noties.markwon:core:${markwonVersion}" implementation "ru.noties.markwon:core:3.1.0"
implementation 'xyz.quaver:libpupil:1.0'
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation project(path: ':libpupil')
} }
androidExtensions { androidExtensions {

View File

@@ -40,9 +40,9 @@
-keepattributes *Annotation*, InnerClasses -keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.SerializationKt -dontnote kotlinx.serialization.SerializationKt
-keep,includedescriptorclasses class xyz.quaver.**$$serializer { *; } # <-- change package name to your app's -keep,includedescriptorclasses class xyz.quaver.**$$serializer { *; } # <-- change package name to your app's
-keepclassmembers class xyz.quaver.** { # <-- change package name to your app's -keepclassmembers class xyz.quaver.pupil** { # <-- change package name to your app's
*** Companion; *** Companion;
} }
-keepclasseswithmembers class xyz.quaver.** { # <-- change package name to your app's -keepclasseswithmembers class xyz.quaver.pupil** { # <-- change package name to your app's
kotlinx.serialization.KSerializer serializer(...); kotlinx.serialization.KSerializer serializer(...);
} }

View File

@@ -29,7 +29,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import xyz.quaver.pupil.util.NOTIFICATION_ID_UPDATE
import xyz.quaver.pupil.util.cancelImport import xyz.quaver.pupil.util.cancelImport
import java.io.File import java.io.File
@@ -92,7 +91,7 @@ class BroadcastReciever : BroadcastReceiver() {
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.build() .build()
notificationManager.notify(NOTIFICATION_ID_UPDATE, notification) notificationManager.notify(R.id.notification_id_update, notification)
} }
ACTION_CANCEL_IMPORT -> { ACTION_CANCEL_IMPORT -> {
cancelImport = true cancelImport = true

View File

@@ -48,8 +48,7 @@ import kotlin.concurrent.schedule
import kotlin.math.roundToInt import kotlin.math.roundToInt
class ReaderAdapter(private val glide: RequestManager, class ReaderAdapter(private val glide: RequestManager,
private val galleryID: Int, private val galleryID: Int) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
private val activity: Activity) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
var reader: Reader? = null var reader: Reader? = null
val timer = Timer() val timer = Timer()

View File

@@ -51,7 +51,9 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main_content.* import kotlinx.android.synthetic.main.activity_main_content.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.serialization.builtins.list import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.doSearch import xyz.quaver.hitomi.doSearch
import xyz.quaver.hitomi.getGalleryIDsFromNozomi import xyz.quaver.hitomi.getGalleryIDsFromNozomi
@@ -59,7 +61,6 @@ import xyz.quaver.hitomi.getSuggestionsForQuery
import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.GalleryBlockAdapter import xyz.quaver.pupil.adapters.GalleryBlockAdapter
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.types.TagSuggestion import xyz.quaver.pupil.types.TagSuggestion
import xyz.quaver.pupil.types.Tags import xyz.quaver.pupil.types.Tags
import xyz.quaver.pupil.ui.dialog.GalleryDialog import xyz.quaver.pupil.ui.dialog.GalleryDialog
@@ -103,9 +104,6 @@ class MainActivity : AppCompatActivity() {
private var mode = Mode.SEARCH private var mode = Mode.SEARCH
private var sortMode = SortMode.NEWEST private var sortMode = SortMode.NEWEST
private val REQUEST_SETTINGS = 45162
private val REQUEST_LOCK = 561
private var galleryIDs: Deferred<List<Int>>? = null private var galleryIDs: Deferred<List<Int>>? = null
private var totalItems = 0 private var totalItems = 0
private var loadingJob: Job? = null private var loadingJob: Job? = null
@@ -132,7 +130,7 @@ class MainActivity : AppCompatActivity() {
} }
if (lockManager.isNotEmpty()) if (lockManager.isNotEmpty())
startActivityForResult(Intent(this, LockActivity::class.java), REQUEST_LOCK) startActivityForResult(Intent(this, LockActivity::class.java), R.id.request_lock.normalizeID())
val preference = PreferenceManager.getDefaultSharedPreferences(this) val preference = PreferenceManager.getDefaultSharedPreferences(this)
@@ -236,7 +234,7 @@ class MainActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
when(requestCode) { when(requestCode) {
REQUEST_SETTINGS -> { R.id.request_settings -> {
runOnUiThread { runOnUiThread {
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
@@ -244,7 +242,7 @@ class MainActivity : AppCompatActivity() {
loadBlocks() loadBlocks()
} }
} }
REQUEST_LOCK -> { R.id.request_lock -> {
if (resultCode != Activity.RESULT_OK) if (resultCode != Activity.RESULT_OK)
finish() finish()
} }
@@ -496,10 +494,10 @@ class MainActivity : AppCompatActivity() {
closeAllItems() closeAllItems()
} }
} }
ItemClickSupport.addTo(this) ItemClickSupport.addTo(this).apply {
.setOnItemClickListener { _, position, v -> onItemClickListener = listener@{ _, position, v ->
if (v !is CardView) if (v !is CardView)
return@setOnItemClickListener return@listener
val intent = Intent(this@MainActivity, ReaderActivity::class.java) val intent = Intent(this@MainActivity, ReaderActivity::class.java)
val gallery = galleries[position] val gallery = galleries[position]
@@ -509,10 +507,11 @@ class MainActivity : AppCompatActivity() {
startActivity(intent) startActivity(intent)
histories.add(gallery.id) histories.add(gallery.id)
}.setOnItemLongClickListener { _, position, v -> }
onItemLongClickListener = listener@{ _, position, v ->
if (v !is CardView) if (v !is CardView)
return@setOnItemLongClickListener true return@listener false
val galleryID = galleries[position].id val galleryID = galleries[position].id
@@ -537,6 +536,7 @@ class MainActivity : AppCompatActivity() {
true true
} }
}
var origin = 0f var origin = 0f
var target = -1 var target = -1
@@ -766,11 +766,10 @@ class MainActivity : AppCompatActivity() {
with(main_searchview as FloatingSearchViewDayNight) { with(main_searchview as FloatingSearchViewDayNight) {
val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json") val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json")
val serializer = Tag.serializer().list
if (!favoritesFile.exists()) { if (!favoritesFile.exists()) {
favoritesFile.createNewFile() favoritesFile.createNewFile()
favoritesFile.writeText(json.stringify(serializer, Tags(listOf()))) favoritesFile.writeText(Json.encodeToString(Tags(listOf())))
} }
setOnLeftMenuClickListener(object: FloatingSearchView.OnLeftMenuClickListener { setOnLeftMenuClickListener(object: FloatingSearchView.OnLeftMenuClickListener {
@@ -785,7 +784,7 @@ class MainActivity : AppCompatActivity() {
setOnMenuItemClickListener { setOnMenuItemClickListener {
when(it.itemId) { when(it.itemId) {
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS) R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), R.id.request_settings.normalizeID())
R.id.main_menu_thin -> { R.id.main_menu_thin -> {
main_recyclerview.apply { main_recyclerview.apply {
(adapter as GalleryBlockAdapter).apply { (adapter as GalleryBlockAdapter).apply {
@@ -832,7 +831,7 @@ class MainActivity : AppCompatActivity() {
clearSuggestions() clearSuggestions()
if (query.isEmpty() or query.endsWith(' ')) { if (query.isEmpty() or query.endsWith(' ')) {
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map { swapSuggestions(Json.decodeFromString<Tags>(favoritesFile.readText()).map {
TagSuggestion(it.tag, -1, "", it.area ?: "tag") TagSuggestion(it.tag, -1, "", it.area ?: "tag")
}) })
@@ -846,7 +845,7 @@ class MainActivity : AppCompatActivity() {
suggestions.filter { suggestions.filter {
val tag = "${it.n}:${it.s.replace(Regex("\\s"), "_")}" val tag = "${it.n}:${it.s.replace(Regex("\\s"), "_")}"
Tags(json.parse(serializer, favoritesFile.readText())).contains(tag) Tags(Json.decodeFromString(favoritesFile.readText())).contains(tag)
}.reversed().forEach { }.reversed().forEach {
suggestions.remove(it) suggestions.remove(it)
suggestions.add(0, it) suggestions.add(0, it)
@@ -884,7 +883,7 @@ class MainActivity : AppCompatActivity() {
with(suggestionView.findViewById<ImageView>(R.id.right_icon)) { with(suggestionView.findViewById<ImageView>(R.id.right_icon)) {
if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag)) if (Tags(Json.decodeFromString(favoritesFile.readText())).contains(tag))
setImageResource(R.drawable.ic_star_filled) setImageResource(R.drawable.ic_star_filled)
else else
setImageResource(R.drawable.ic_star_empty) setImageResource(R.drawable.ic_star_empty)
@@ -895,7 +894,7 @@ class MainActivity : AppCompatActivity() {
isClickable = true isClickable = true
setOnClickListener { setOnClickListener {
val favorites = Tags(json.parse(serializer, favoritesFile.readText())) val favorites = Tags(Json.decodeFromString(favoritesFile.readText()))
if (favorites.contains(tag)) { if (favorites.contains(tag)) {
setImageResource(R.drawable.ic_star_empty) setImageResource(R.drawable.ic_star_empty)
@@ -910,7 +909,7 @@ class MainActivity : AppCompatActivity() {
favorites.add(tag) favorites.add(tag)
} }
favoritesFile.writeText(json.stringify(serializer, favorites)) favoritesFile.writeText(Json.encodeToString(favorites))
} }
} }
@@ -950,7 +949,7 @@ class MainActivity : AppCompatActivity() {
setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener { setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener {
override fun onFocus() { override fun onFocus() {
if (query.isEmpty() or query.endsWith(' ')) if (query.isEmpty() or query.endsWith(' '))
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map { swapSuggestions(Json.decodeFromString<Tags>( favoritesFile.readText()).map {
TagSuggestion(it.tag, -1, "", it.area ?: "tag") TagSuggestion(it.tag, -1, "", it.area ?: "tag")
}) })
} }

View File

@@ -319,7 +319,7 @@ class ReaderActivity : AppCompatActivity() {
private fun initView() { private fun initView() {
with(reader_recyclerview) { with(reader_recyclerview) {
adapter = ReaderAdapter(Glide.with(this@ReaderActivity), galleryID, this@ReaderActivity).apply { adapter = ReaderAdapter(Glide.with(this@ReaderActivity), galleryID).apply {
onItemClickListener = { onItemClickListener = {
if (isScroll) { if (isScroll) {
isScroll = false isScroll = false

View File

@@ -30,8 +30,8 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.settings_activity.* import kotlinx.android.synthetic.main.settings_activity.*
import kotlinx.serialization.builtins.list import kotlinx.serialization.decodeFromString
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.Json
import net.rdrei.android.dirchooser.DirectoryChooserActivity import net.rdrei.android.dirchooser.DirectoryChooserActivity
import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R import xyz.quaver.pupil.R
@@ -80,7 +80,7 @@ class SettingsActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when(requestCode) { when(requestCode) {
REQUEST_LOCK -> { R.id.request_lock -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
supportFragmentManager supportFragmentManager
.beginTransaction() .beginTransaction()
@@ -89,7 +89,7 @@ class SettingsActivity : AppCompatActivity() {
.commitAllowingStateLoss() .commitAllowingStateLoss()
} }
} }
REQUEST_RESTORE -> { R.id.request_restore -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
val uri = data?.data ?: return val uri = data?.data ?: return
@@ -100,7 +100,7 @@ class SettingsActivity : AppCompatActivity() {
inputStream.readBytes().toString(Charset.defaultCharset()) inputStream.readBytes().toString(Charset.defaultCharset())
} }
(application as Pupil).favorites.addAll(json.parse(Int.serializer().list, str).also { (application as Pupil).favorites.addAll(Json.decodeFromString<List<Int>>(str).also {
Snackbar.make( Snackbar.make(
window.decorView, window.decorView,
getString(R.string.settings_restore_successful, it.size), getString(R.string.settings_restore_successful, it.size),
@@ -116,7 +116,7 @@ class SettingsActivity : AppCompatActivity() {
} }
} }
} }
REQUEST_DOWNLOAD_FOLDER -> { R.id.request_download_folder -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
data?.data?.also { uri -> data?.data?.also { uri ->
val takeFlags: Int = val takeFlags: Int =
@@ -140,7 +140,7 @@ class SettingsActivity : AppCompatActivity() {
} }
} }
} }
REQUEST_DOWNLOAD_FOLDER_OLD -> { R.id.request_download_folder_old -> {
if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!! val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!!
@@ -156,7 +156,7 @@ class SettingsActivity : AppCompatActivity() {
.apply() .apply()
} }
} }
REQUEST_IMPORT_OLD_GALLERIES -> { R.id.request_import_old_galleries -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
data?.data?.also { uri -> data?.data?.also { uri ->
val takeFlags: Int = val takeFlags: Int =
@@ -178,7 +178,7 @@ class SettingsActivity : AppCompatActivity() {
} }
} }
} }
REQUEST_IMPORT_OLD_GALLERIES_OLD -> { R.id.request_import_old_galleries_old -> {
if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!! val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!!
@@ -200,13 +200,13 @@ class SettingsActivity : AppCompatActivity() {
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) { when (requestCode) {
REQUEST_WRITE_PERMISSION_AND_SAF -> { R.id.request_write_permission_and_saf -> {
if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) { if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
putExtra("android.content.extra.SHOW_ADVANCED", true) putExtra("android.content.extra.SHOW_ADVANCED", true)
} }
startActivityForResult(intent, REQUEST_DOWNLOAD_FOLDER) startActivityForResult(intent, R.id.request_download_folder.normalizeID())
} }
} }
} }

View File

@@ -96,13 +96,13 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), R.id.request_write_permission_and_saf.normalizeID())
else { else {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
putExtra("android.content.extra.SHOW_ADVANCED", true) putExtra("android.content.extra.SHOW_ADVANCED", true)
} }
activity.startActivityForResult(intent, REQUEST_DOWNLOAD_FOLDER) activity.startActivityForResult(intent, R.id.request_download_folder.normalizeID())
} }
dismiss() dismiss()
@@ -116,7 +116,7 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) {
putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config)
} }
activity.startActivityForResult(intent, REQUEST_DOWNLOAD_FOLDER_OLD) activity.startActivityForResult(intent, R.id.request_download_folder_old.normalizeID())
dismiss() dismiss()
} }
} }

View File

@@ -259,14 +259,14 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
this.adapter = adapter this.adapter = adapter
ItemClickSupport.addTo(this) ItemClickSupport.addTo(this).apply {
.setOnItemClickListener { _, position, _ -> onItemClickListener = { _, position, _ ->
context.startActivity(Intent(context, ReaderActivity::class.java).apply { context.startActivity(Intent(context, ReaderActivity::class.java).apply {
putExtra("galleryID", galleries[position].id) putExtra("galleryID", galleries[position].id)
}) })
(context.applicationContext as Pupil).histories.add(galleries[position].id) (context.applicationContext as Pupil).histories.add(galleries[position].id)
} }
.setOnItemLongClickListener { _, position, _ -> onItemLongClickListener = { _, position, _ ->
GalleryDialog( GalleryDialog(
context, context,
glide, glide,
@@ -279,6 +279,7 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
true true
} }
}
}.let { }.let {
gallery_details_contents.addView(it, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)) gallery_details_contents.addView(it, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))
} }

View File

@@ -29,11 +29,12 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.dialog_proxy.view.* import kotlinx.android.synthetic.main.dialog_proxy.view.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import xyz.quaver.proxy import xyz.quaver.proxy
import xyz.quaver.pupil.R import xyz.quaver.pupil.R
import xyz.quaver.pupil.util.ProxyInfo import xyz.quaver.pupil.util.ProxyInfo
import xyz.quaver.pupil.util.getProxyInfo import xyz.quaver.pupil.util.getProxyInfo
import xyz.quaver.pupil.util.json
import java.net.Proxy import java.net.Proxy
class ProxyDialog(context: Context) : Dialog(context) { class ProxyDialog(context: Context) : Dialog(context) {
@@ -118,7 +119,7 @@ class ProxyDialog(context: Context) : Dialog(context) {
ProxyInfo(type, addr, port, username, password).let { ProxyInfo(type, addr, port, username, password).let {
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy", PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy",
json.stringify(ProxyInfo.serializer(), it) Json.encodeToString(it)
).apply() ).apply()
proxy = it.proxy() proxy = it.proxy()

View File

@@ -168,7 +168,7 @@ class SettingsFragment :
} }
"app_lock" -> { "app_lock" -> {
val intent = Intent(requireContext(), LockActivity::class.java) val intent = Intent(requireContext(), LockActivity::class.java)
activity?.startActivityForResult(intent, REQUEST_LOCK) activity?.startActivityForResult(intent, R.id.request_lock.normalizeID())
} }
"mirrors" -> { "mirrors" -> {
MirrorDialog(requireContext()) MirrorDialog(requireContext())
@@ -196,19 +196,19 @@ class SettingsFragment :
type = "*/*" type = "*/*"
} }
activity?.startActivityForResult(intent, REQUEST_RESTORE) activity?.startActivityForResult(intent, R.id.request_restore.normalizeID())
} }
"old_import_galleries" -> { "old_import_galleries" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), R.id.request_write_permission_and_saf.normalizeID())
else { else {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
putExtra("android.content.extra.SHOW_ADVANCED", true) putExtra("android.content.extra.SHOW_ADVANCED", true)
} }
activity?.startActivityForResult(intent, REQUEST_IMPORT_OLD_GALLERIES) activity?.startActivityForResult(intent, R.id.request_import_old_galleries.normalizeID())
} }
} else { // Can't use SAF on old Androids! } else { // Can't use SAF on old Androids!
val config = DirectoryChooserConfig.builder() val config = DirectoryChooserConfig.builder()
@@ -220,7 +220,7 @@ class SettingsFragment :
putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config)
} }
activity?.startActivityForResult(intent, REQUEST_IMPORT_OLD_GALLERIES_OLD) activity?.startActivityForResult(intent, R.id.request_import_old_galleries_old.normalizeID())
} }
} }
"user_id" -> { "user_id" -> {

View File

@@ -1,39 +0,0 @@
/*
* Pupil, Hitomi.la viewer for Android
* Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
*/
package xyz.quaver.pupil.util
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import okhttp3.Dispatcher
import okhttp3.OkHttpClient
import xyz.quaver.proxy
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
const val REQUEST_LOCK = 38238
const val REQUEST_RESTORE = 16546
const val REQUEST_IMPORT_OLD_GALLERIES = 6458
const val REQUEST_IMPORT_OLD_GALLERIES_OLD = 5946
const val REQUEST_DOWNLOAD_FOLDER = 3874
const val REQUEST_DOWNLOAD_FOLDER_OLD = 3425
const val REQUEST_WRITE_PERMISSION_AND_SAF = 13900
const val NOTIFICATION_ID_UPDATE = 2345
val json = Json(JsonConfiguration.Stable)

View File

@@ -1,107 +0,0 @@
package xyz.quaver.pupil.util;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import xyz.quaver.pupil.R;
/*
Source: http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/
USAGE:
ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// do it
}
});
*/
public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
return false;
}
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(@NonNull View view) {
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(@NonNull View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}

View File

@@ -0,0 +1,69 @@
/*
* Pupil, Hitomi.la viewer for Android
* Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
*/
package xyz.quaver.pupil.util
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import xyz.quaver.pupil.R
class ItemClickSupport(private val recyclerView: RecyclerView) {
var onItemClickListener: ((RecyclerView, Int, View) -> Unit)? = null
var onItemLongClickListener: ((RecyclerView, Int, View) -> Boolean)? = null
init {
recyclerView.apply {
setTag(R.id.item_click_support, this)
addOnChildAttachStateChangeListener(object: RecyclerView.OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {
onItemClickListener?.let { listener ->
view.setOnClickListener {
recyclerView.getChildViewHolder(view).let { holder ->
listener.invoke(recyclerView, holder.adapterPosition, view)
}
}
}
onItemLongClickListener?.let { listener ->
view.setOnLongClickListener {
recyclerView.getChildViewHolder(view).let { holder ->
listener.invoke(recyclerView, holder.adapterPosition, view)
}
}
}
}
override fun onChildViewDetachedFromWindow(view: View) {
// Do Nothing
}
})
}
}
fun detach() {
recyclerView.apply {
clearOnChildAttachStateChangeListeners()
setTag(R.id.item_click_support, null)
}
}
companion object {
fun addTo(view: RecyclerView) = view.let { removeFrom(it); ItemClickSupport(it) }
fun removeFrom(view: RecyclerView) = (view.tag as? ItemClickSupport)?.detach()
}
}

View File

@@ -25,6 +25,10 @@ import android.util.SparseArray
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.Dispatcher
import xyz.quaver.Code import xyz.quaver.Code
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.Reader import xyz.quaver.hitomi.Reader
@@ -32,15 +36,11 @@ import xyz.quaver.proxy
import xyz.quaver.pupil.util.getCachedGallery import xyz.quaver.pupil.util.getCachedGallery
import xyz.quaver.pupil.util.getDownloadDirectory import xyz.quaver.pupil.util.getDownloadDirectory
import xyz.quaver.pupil.util.isParentOf import xyz.quaver.pupil.util.isParentOf
import xyz.quaver.pupil.util.json
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.InputStream import java.io.InputStream
import java.net.URL import java.net.URL
import java.util.*
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
class Cache(context: Context) : ContextWrapper(context) { class Cache(context: Context) : ContextWrapper(context) {
@@ -49,20 +49,6 @@ class Cache(context: Context) : ContextWrapper(context) {
private val readers = SparseArray<Reader?>() private val readers = SparseArray<Reader?>()
} }
private val locks = SparseArray<Lock>()
private fun lock(galleryID: Int) {
synchronized(locks) {
if (locks.indexOfKey(galleryID) < 0)
locks.put(galleryID, ReentrantLock())
}
locks[galleryID].lock()
}
private fun unlock(galleryID: Int) {
locks[galleryID]?.unlock()
}
private val preference = PreferenceManager.getDefaultSharedPreferences(this) private val preference = PreferenceManager.getDefaultSharedPreferences(this)
// Search in this order // Search in this order
@@ -79,7 +65,7 @@ class Cache(context: Context) : ContextWrapper(context) {
return null return null
return try { return try {
json.parse(Metadata.serializer(), file.readText()) Json.decodeFromString(file.readText())
} catch (e: Exception) { } catch (e: Exception) {
//File corrupted //File corrupted
file.delete() file.delete()
@@ -96,7 +82,7 @@ class Cache(context: Context) : ContextWrapper(context) {
it.createNewFile() it.createNewFile()
} }
file.writeText(json.stringify(Metadata.serializer(), metadata)) file.writeText(Json.encodeToString(metadata))
} }
suspend fun getThumbnail(galleryID: Int): String? { suspend fun getThumbnail(galleryID: Int): String? {
@@ -134,7 +120,7 @@ class Cache(context: Context) : ContextWrapper(context) {
) )
val galleryBlock = if (metadata?.galleryBlock == null) { val galleryBlock = if (metadata?.galleryBlock == null) {
CoroutineScope(Dispatchers.IO).async { withContext(Dispatchers.IO) {
var galleryBlock: GalleryBlock? = null var galleryBlock: GalleryBlock? = null
for (source in sources) { for (source in sources) {
@@ -149,7 +135,7 @@ class Cache(context: Context) : ContextWrapper(context) {
} }
galleryBlock galleryBlock
}.await() ?: return null } ?: return null
} }
else else
metadata.galleryBlock metadata.galleryBlock
@@ -175,11 +161,9 @@ class Cache(context: Context) : ContextWrapper(context) {
Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) } Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) }
).let { ).let {
if (mirrors.isNotEmpty()) if (mirrors.isNotEmpty())
it.toSortedMap( it.toSortedMap{ o1, o2 ->
Comparator { o1, o2 -> mirrors.indexOf(o1.name) - mirrors.indexOf(o2.name)
mirrors.indexOf(o1.name) - mirrors.indexOf(o2.name) }
}
)
else else
it it
} }

View File

@@ -151,7 +151,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
}).build() }).build()
} }
val client = val client : OkHttpClient =
OkHttpClient.Builder() OkHttpClient.Builder()
.connectTimeout(0, TimeUnit.SECONDS) .connectTimeout(0, TimeUnit.SECONDS)
.addInterceptor(interceptor) .addInterceptor(interceptor)

View File

@@ -18,15 +18,13 @@
package xyz.quaver.pupil.util package xyz.quaver.pupil.util
import kotlinx.serialization.KSerializer import kotlinx.serialization.decodeFromString
import kotlinx.serialization.builtins.list import kotlinx.serialization.encodeToString
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.Json
import java.io.File import java.io.File
class Histories(private val file: File) : ArrayList<Int>() { class Histories(private val file: File) : ArrayList<Int>() {
val serializer: KSerializer<List<Int>> = Int.serializer().list
init { init {
if (!file.exists()) if (!file.exists())
file.parentFile?.mkdirs() file.parentFile?.mkdirs()
@@ -42,16 +40,13 @@ class Histories(private val file: File) : ArrayList<Int>() {
return apply { return apply {
super.clear() super.clear()
super.addAll( super.addAll(
json.parse( Json.decodeFromString(file.bufferedReader().use { it.readText() })
serializer,
file.bufferedReader().use { it.readText() }
)
) )
} }
} }
fun save() { fun save() {
file.writeText(json.stringify(serializer, this)) file.writeText(Json.encodeToString(toList()))
} }
override fun add(element: Int): Boolean { override fun add(element: Int): Boolean {

View File

@@ -22,7 +22,9 @@ import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.list import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File import java.io.File
import java.security.MessageDigest import java.security.MessageDigest
@@ -41,7 +43,7 @@ fun hashWithSalt(password: String): Pair<String, String> {
return Pair(hash(password+salt), salt) return Pair(hash(password+salt), salt)
} }
val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" const val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
@Serializable @Serializable
data class Lock(val type: Type, val hash: String, val salt: String) { data class Lock(val type: Type, val hash: String, val salt: String) {
@@ -80,7 +82,7 @@ class LockManager(base: Context): ContextWrapper(base) {
lock.writeText("[]") lock.writeText("[]")
} }
locks = ArrayList(json.parse(Lock.serializer().list, lock.readText())) locks = Json.decodeFromString(lock.readText())
} }
private fun save() { private fun save() {
@@ -89,7 +91,7 @@ class LockManager(base: Context): ContextWrapper(base) {
if (!lock.exists()) if (!lock.exists())
lock.createNewFile() lock.createNewFile()
lock.writeText(json.stringify(Lock.serializer().list, locks?.toList() ?: listOf())) lock.writeText(Json.encodeToString(locks?.toList() ?: listOf()))
} }
fun add(lock: Lock) { fun add(lock: Lock) {

View File

@@ -52,3 +52,11 @@ fun byteToString(byte: Long, precision : Int = 1) : String {
return "%.${precision}f ${suffix[suffixIndex]}".format(size) return "%.${precision}f ${suffix[suffixIndex]}".format(size)
} }
/*
* Convert android generated ID to requestCode
* to prevent java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
*
* https://stackoverflow.com/questions/38072322/generate-16-bit-unique-ids-in-android-for-startactivityforresult
*/
fun Int.normalizeID() = this.and(0xFFFF)

View File

@@ -21,6 +21,8 @@ package xyz.quaver.pupil.util
import android.content.Context import android.content.Context
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Authenticator import okhttp3.Authenticator
import okhttp3.Credentials import okhttp3.Credentials
import java.net.InetSocketAddress import java.net.InetSocketAddress
@@ -59,5 +61,5 @@ fun getProxyInfo(context: Context) =
if (it == null) if (it == null)
ProxyInfo(Proxy.Type.DIRECT) ProxyInfo(Proxy.Type.DIRECT)
else else
json.parse(ProxyInfo.serializer(), it) Json.decodeFromString(it)
} }

View File

@@ -30,10 +30,8 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.*
import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.content
import okhttp3.* import okhttp3.*
import ru.noties.markwon.Markwon import ru.noties.markwon.Markwon
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
@@ -55,7 +53,7 @@ import java.util.concurrent.TimeUnit
fun getReleases(url: String) : JsonArray { fun getReleases(url: String) : JsonArray {
return try { return try {
URL(url).readText().let { URL(url).readText().let {
json.parse(JsonArray.serializer(), it) Json.decodeFromString(it)
} }
} catch (e: Exception) { } catch (e: Exception) {
JsonArray(emptyList()) JsonArray(emptyList())
@@ -72,9 +70,9 @@ fun checkUpdate(context: Context, url: String) : JsonObject? {
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("beta", false)) if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("beta", false))
true true
else else
it.jsonObject["prerelease"]?.boolean == false it.jsonObject["prerelease"]?.jsonPrimitive?.booleanOrNull == false
}?.let { }?.let {
if (it.jsonObject["tag_name"]?.content == BuildConfig.VERSION_NAME) if (it.jsonObject["tag_name"]?.jsonPrimitive?.contentOrNull == BuildConfig.VERSION_NAME)
null null
else else
it.jsonObject it.jsonObject
@@ -83,13 +81,12 @@ fun checkUpdate(context: Context, url: String) : JsonObject? {
fun getApkUrl(releases: JsonObject) : String? { fun getApkUrl(releases: JsonObject) : String? {
return releases["assets"]?.jsonArray?.firstOrNull { return releases["assets"]?.jsonArray?.firstOrNull {
Regex("Pupil-v.+\\.apk").matches(it.jsonObject["name"]?.content ?: "") Regex("Pupil-v.+\\.apk").matches(it.jsonObject["name"]?.jsonPrimitive?.contentOrNull ?: "")
}.let { }.let {
it?.jsonObject?.get("browser_download_url")?.content it?.jsonObject?.get("browser_download_url")?.jsonPrimitive?.contentOrNull
} }
} }
const val UPDATE_NOTIFICATION_ID = 384823
fun checkUpdate(context: Context, force: Boolean = false) { fun checkUpdate(context: Context, force: Boolean = false) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) val preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -99,7 +96,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
return return
fun extractReleaseNote(update: JsonObject, locale: Locale) : String { fun extractReleaseNote(update: JsonObject, locale: Locale) : String {
val markdown = update["body"]!!.content val markdown = update["body"]!!.jsonPrimitive.content
val target = when(locale.language) { val target = when(locale.language) {
"ko" -> "한국어" "ko" -> "한국어"
@@ -137,7 +134,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
} }
} }
return context.getString(R.string.update_release_note, update["tag_name"]?.content, result.toString()) return context.getString(R.string.update_release_note, update["tag_name"]?.jsonPrimitive?.contentOrNull, result.toString())
} }
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {
@@ -253,14 +250,14 @@ fun importOldGalleries(context: Context, folder: File) = CoroutineScope(Dispatch
val reader = async { val reader = async {
kotlin.runCatching { kotlin.runCatching {
json.parse(Reader.serializer(), File(gallery, "reader.json").readText()) Json.decodeFromString<Reader>(File(gallery, "reader.json").readText())
}.getOrElse { }.getOrElse {
getReader(galleryID) getReader(galleryID)
} }
} }
val galleryBlock = async { val galleryBlock = async {
kotlin.runCatching { kotlin.runCatching {
json.parse(GalleryBlock.serializer(), File(gallery, "galleryBlock.json").readText()) Json.decodeFromString<GalleryBlock>(File(gallery, "galleryBlock.json").readText())
}.getOrElse { }.getOrElse {
getGalleryBlock(galleryID) getGalleryBlock(galleryID)
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 687 B

View File

@@ -1,8 +0,0 @@
<!-- drawable/export.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#fff" android:pathData="M23,12L19,8V11H10V13H19V16M1,18V6C1,4.89 1.9,4 3,4H15A2,2 0 0,1 17,6V9H15V6H3V18H15V15H17V18A2,2 0 0,1 15,20H3A2,2 0 0,1 1,18Z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>
</vector>

View File

@@ -1,8 +0,0 @@
<!-- drawable/sort_variant.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#fff" android:pathData="M3,13H15V11H3M3,6V8H21V6M3,18H9V16H3V18Z" />
</vector>

View File

@@ -17,9 +17,7 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>. ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<RelativeLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -17,9 +17,7 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>. ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<RelativeLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -108,7 +108,6 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/default_query_dialog_loli_layout"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"

View File

@@ -18,6 +18,7 @@
--> -->
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/gallery_layout" android:id="@+id/gallery_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -47,7 +48,8 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/gallery_title"/> app:layout_constraintRight_toLeftOf="@id/gallery_title"
tools:ignore="ContentDescription" />
<TextView <TextView
android:id="@+id/gallery_title" android:id="@+id/gallery_title"
@@ -72,7 +74,6 @@
android:layout_marginStart="8dp"/> android:layout_marginStart="8dp"/>
<View <View
android:id="@+id/gallery_padding"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/gallery_artist" app:layout_constraintTop_toBottomOf="@id/gallery_artist"

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3"/>

View File

@@ -20,6 +20,7 @@
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="8dp" android:layout_margin="8dp"
@@ -34,8 +35,7 @@
app:show_mode="pull_out"> app:show_mode="pull_out">
<LinearLayout <LinearLayout
android:id="@+id/galleryblock_secondary" android:layout_width="wrap_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
@@ -50,7 +50,8 @@
android:text="@string/main_download" android:text="@string/main_download"
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:focusable="true" android:focusable="true"
android:clickable="true"/> android:clickable="true"
tools:ignore="UnusedAttribute" />
<TextView <TextView
android:id="@+id/galleryblock_delete" android:id="@+id/galleryblock_delete"
@@ -64,7 +65,8 @@
android:text="@string/main_delete" android:text="@string/main_delete"
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:focusable="true" android:focusable="true"
android:clickable="true"/> android:clickable="true"
tools:ignore="UnusedAttribute" />
</LinearLayout> </LinearLayout>
@@ -75,7 +77,8 @@
android:orientation="vertical" android:orientation="vertical"
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:focusable="true" android:focusable="true"
android:clickable="true"> android:clickable="true"
tools:ignore="UnusedAttribute">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -18,6 +18,7 @@
--> -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -44,6 +45,7 @@
app:tint="?attr/colorControlNormal" app:tint="?attr/colorControlNormal"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/> app:layout_constraintBottom_toBottomOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"
android:layout_width="match_parent" android:layout_height="wrap_content">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/gallery_favorite"
android:icon="@drawable/ic_star_empty"
android:title=""
app:showAsAction="ifRoom"/>
<item
android:id="@+id/gallery_download"
android:icon="@drawable/ic_download"
android:title=""
app:showAsAction="always"/>
</menu>

View File

@@ -23,9 +23,7 @@
<item android:id="@+id/main_menu_thin" <item android:id="@+id/main_menu_thin"
android:title="@string/main_menu_thin"/> android:title="@string/main_menu_thin"/>
<item <item android:title="@string/main_menu_sort">
android:id="@+id/main_menu_sort"
android:title="@string/main_menu_sort">
<menu> <menu>
<group android:checkableBehavior="single"> <group android:checkableBehavior="single">
<item android:id="@+id/main_menu_sort_newest" <item android:id="@+id/main_menu_sort_newest"

View File

@@ -4,9 +4,7 @@
<string name="galleryblock_series">シリーズ: %1$s</string> <string name="galleryblock_series">シリーズ: %1$s</string>
<string name="galleryblock_type">タイプ: %1$s</string> <string name="galleryblock_type">タイプ: %1$s</string>
<string name="main_no_result">結果なし</string> <string name="main_no_result">結果なし</string>
<string name="main_search">検索</string>
<string name="search_hint">ギャラリー検索</string> <string name="search_hint">ギャラリー検索</string>
<string name="search_hint_with_page">ギャラリー検索</string>
<string name="settings_clear_cache">キャッシュクリア</string> <string name="settings_clear_cache">キャッシュクリア</string>
<string name="settings_clear_cache_alert_message">キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?</string> <string name="settings_clear_cache_alert_message">キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?</string>
<string name="settings_storage_usage">%s使用中</string> <string name="settings_storage_usage">%s使用中</string>
@@ -25,7 +23,6 @@
<string name="settings_clear_history_summary">履歴数: %1$d</string> <string name="settings_clear_history_summary">履歴数: %1$d</string>
<string name="main_drawer_history">履歴</string> <string name="main_drawer_history">履歴</string>
<string name="main_drawer_home">トップ</string> <string name="main_drawer_home">トップ</string>
<string name="update_download_started">ダウンロード中</string>
<string name="update_release_note"># リリースノート(v%1$s)\n%2$s</string> <string name="update_release_note"># リリースノート(v%1$s)\n%2$s</string>
<string name="settings_security_mode_title">セキュリティーモード</string> <string name="settings_security_mode_title">セキュリティーモード</string>
<string name="settings_security_mode_summary">アプリ履歴でアプリの画面を表示しない</string> <string name="settings_security_mode_summary">アプリ履歴でアプリの画面を表示しない</string>
@@ -46,9 +43,7 @@
<string name="reader_fab_download">バックグラウンドダウンロード</string> <string name="reader_fab_download">バックグラウンドダウンロード</string>
<string name="reader_notification_text">ダウンロード中…</string> <string name="reader_notification_text">ダウンロード中…</string>
<string name="reader_notification_complete">ダウンロード完了</string> <string name="reader_notification_complete">ダウンロード完了</string>
<string name="reader_notification_error">ダウンロードエラー</string>
<string name="reader_fab_download_cancel">バックグラウンドダウンロード中止</string> <string name="reader_fab_download_cancel">バックグラウンドダウンロード中止</string>
<string name="main_dialog_delete">このギャラリーを削除</string>
<string name="main_drawer_downloads">ダウンロード</string> <string name="main_drawer_downloads">ダウンロード</string>
<string name="main_jump_title">ページ移動</string> <string name="main_jump_title">ページ移動</string>
<string name="main_jump_message">現ページ番号: %1$d\nページ数: %2$d</string> <string name="main_jump_message">現ページ番号: %1$d\nページ数: %2$d</string>
@@ -56,10 +51,6 @@
<string name="main_move">%1$dページへ移動</string> <string name="main_move">%1$dページへ移動</string>
<string name="https_block_alert_title">(Korean only)</string> <string name="https_block_alert_title">(Korean only)</string>
<string name="https_block_alert">(Korean only)</string> <string name="https_block_alert">(Korean only)</string>
<string name="main_dialog_export">ギャラリーエクスポート</string>
<string name="main_export_complete">エクスポート完了</string>
<string name="main_export_open_folder">フォルダを開く</string>
<string name="main_export_error">エクスポートエラーが発生しました</string>
<string name="settings_clear_downloads">ダウンロード削除</string> <string name="settings_clear_downloads">ダウンロード削除</string>
<string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか</string> <string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか</string>
<string name="settings_mirror_summary">ミラーサーバからイメージをロード</string> <string name="settings_mirror_summary">ミラーサーバからイメージをロード</string>
@@ -84,11 +75,8 @@
<string name="main_menu_sort">ソート</string> <string name="main_menu_sort">ソート</string>
<string name="main_menu_sort_newest">投稿日時順</string> <string name="main_menu_sort_newest">投稿日時順</string>
<string name="main_menu_sort_popular">人気順</string> <string name="main_menu_sort_popular">人気順</string>
<string name="update_failed">アップデートに失敗しました</string>
<string name="update_failed_message">アップデート中エラーが発生しました</string>
<string name="ignore_update">無視</string> <string name="ignore_update">無視</string>
<string name="lock_corrupted">ロックファイルが破損されています。Pupilを再再インストールしてください。</string> <string name="lock_corrupted">ロックファイルが破損されています。Pupilを再再インストールしてください。</string>
<string name="update_no_permission">権限がないため自動アップデートを行えません。ホームページで直接ダウンロードしてください。</string>
<string name="settings_dark_mode_title">ダークモード</string> <string name="settings_dark_mode_title">ダークモード</string>
<string name="settings_dark_mode_summary">夜にシコりたい方々へ</string> <string name="settings_dark_mode_summary">夜にシコりたい方々へ</string>
<string name="gallery_details">ギャラリー情報</string> <string name="gallery_details">ギャラリー情報</string>
@@ -101,13 +89,11 @@
<string name="gallery_thumbnails">サムネイル</string> <string name="gallery_thumbnails">サムネイル</string>
<string name="gallery_related">おすすめ</string> <string name="gallery_related">おすすめ</string>
<string name="settings_nomedia_title">イメージを隠す</string> <string name="settings_nomedia_title">イメージを隠す</string>
<string name="reader_help">ヘルプ</string>
<string name="main_delete">削除</string> <string name="main_delete">削除</string>
<string name="main_download">ダウンロード</string> <string name="main_download">ダウンロード</string>
<string name="settings_backup_title">お気に入りバックアップ</string> <string name="settings_backup_title">お気に入りバックアップ</string>
<string name="settings_restore_title">お気に入り復元</string> <string name="settings_restore_title">お気に入り復元</string>
<string name="settings_backup_snackbar">バックアップファイルを作成しました</string> <string name="settings_backup_snackbar">バックアップファイルを作成しました</string>
<string name="settings_backup_checkout">確認</string>
<string name="settings_restore_failed">復元に失敗しました</string> <string name="settings_restore_failed">復元に失敗しました</string>
<string name="settings_restore_successful">%1$d項目を復元しました</string> <string name="settings_restore_successful">%1$d項目を復元しました</string>
<string name="settings_dl_location">ダウンロード場所</string> <string name="settings_dl_location">ダウンロード場所</string>
@@ -134,8 +120,6 @@
<string name="main_fab_cancel">すべてのダウンロードキャンセル</string> <string name="main_fab_cancel">すべてのダウンロードキャンセル</string>
<string name="channel_update">アップデート</string> <string name="channel_update">アップデート</string>
<string name="channel_update_description">アップデートの進行状態を表示</string> <string name="channel_update_description">アップデートの進行状態を表示</string>
<string name="channel_import">インポート</string>
<string name="channel_import_description">インポート状態を表示</string>
<string name="settings_import_old_galleries">旧ギャラリーインポート</string> <string name="settings_import_old_galleries">旧ギャラリーインポート</string>
<string name="import_old_galleries_folder_not_readable">フォルダを読めません</string> <string name="import_old_galleries_folder_not_readable">フォルダを読めません</string>
<string name="import_old_galleries_notification">旧ギャラリーインポート中…</string> <string name="import_old_galleries_notification">旧ギャラリーインポート中…</string>
@@ -149,7 +133,6 @@
<string name="settings_download_when_cache_disable_warning">キャッシュを使用しないため、ダウンロードできません</string> <string name="settings_download_when_cache_disable_warning">キャッシュを使用しないため、ダウンロードできません</string>
<string name="settings_user_id">ユーザーID</string> <string name="settings_user_id">ユーザーID</string>
<string name="settings_user_id_toast">ユーザーIDをクリップボードにコピーしました</string> <string name="settings_user_id_toast">ユーザーIDをクリップボードにコピーしました</string>
<string name="reader_error_retry">ダウンロードエラーが発生しました。リトライしますか?</string>
<string name="reader_fab_retry">リトライ</string> <string name="reader_fab_retry">リトライ</string>
<string name="reader_fab_auto">自動スクロール</string> <string name="reader_fab_auto">自動スクロール</string>
</resources> </resources>

View File

@@ -4,7 +4,6 @@
<string name="galleryblock_series">시리즈: %1$s</string> <string name="galleryblock_series">시리즈: %1$s</string>
<string name="galleryblock_type">종류: %1$s</string> <string name="galleryblock_type">종류: %1$s</string>
<string name="search_hint">갤러리 검색</string> <string name="search_hint">갤러리 검색</string>
<string name="search_hint_with_page">갤러리 검색</string>
<string name="settings_default_query">기본 검색어</string> <string name="settings_default_query">기본 검색어</string>
<string name="settings_clear_cache">캐시 정리하기</string> <string name="settings_clear_cache">캐시 정리하기</string>
<string name="settings_clear_cache_alert_message">캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?</string> <string name="settings_clear_cache_alert_message">캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?</string>
@@ -17,14 +16,12 @@
<string name="update_title">업데이트가 있습니다!</string> <string name="update_title">업데이트가 있습니다!</string>
<string name="warning">경고</string> <string name="warning">경고</string>
<string name="main_no_result">결과 없음</string> <string name="main_no_result">결과 없음</string>
<string name="main_search">검색</string>
<string name="settings_miscellaneous_title">기타</string> <string name="settings_miscellaneous_title">기타</string>
<string name="settings_clear_history">기록 삭제</string> <string name="settings_clear_history">기록 삭제</string>
<string name="settings_clear_history_alert_message">기록을 삭제하시겠습니까?</string> <string name="settings_clear_history_alert_message">기록을 삭제하시겠습니까?</string>
<string name="settings_clear_history_summary">기록 %1$d개 저장됨</string> <string name="settings_clear_history_summary">기록 %1$d개 저장됨</string>
<string name="main_drawer_history">기록</string> <string name="main_drawer_history">기록</string>
<string name="main_drawer_home"></string> <string name="main_drawer_home"></string>
<string name="update_download_started">다운로드 중</string>
<string name="update_release_note"># 릴리즈 노트(v%1$s)\n%2$s</string> <string name="update_release_note"># 릴리즈 노트(v%1$s)\n%2$s</string>
<string name="settings_security_mode_summary">최근 앱 목록 창에서 앱 화면을 보이지 않게 합니다</string> <string name="settings_security_mode_summary">최근 앱 목록 창에서 앱 화면을 보이지 않게 합니다</string>
<string name="settings_security_mode_title">보안 모드 활성화</string> <string name="settings_security_mode_title">보안 모드 활성화</string>
@@ -45,9 +42,7 @@
<string name="reader_fab_download">백그라운드 다운로드</string> <string name="reader_fab_download">백그라운드 다운로드</string>
<string name="reader_notification_text">다운로드 중…</string> <string name="reader_notification_text">다운로드 중…</string>
<string name="reader_notification_complete">다운로드 완료</string> <string name="reader_notification_complete">다운로드 완료</string>
<string name="reader_notification_error">다운로드 오류</string>
<string name="reader_fab_download_cancel">백그라운드 다운로드 취소</string> <string name="reader_fab_download_cancel">백그라운드 다운로드 취소</string>
<string name="main_dialog_delete">갤러리 삭제</string>
<string name="main_drawer_downloads">다운로드</string> <string name="main_drawer_downloads">다운로드</string>
<string name="main_jump_title">페이지 이동</string> <string name="main_jump_title">페이지 이동</string>
<string name="main_jump_message">현재 페이지: %1$d\n페이지 수: %2$d</string> <string name="main_jump_message">현재 페이지: %1$d\n페이지 수: %2$d</string>
@@ -55,10 +50,6 @@
<string name="main_move">%1$d 페이지로 이동</string> <string name="main_move">%1$d 페이지로 이동</string>
<string name="https_block_alert_title">접속 불가 현상 안내</string> <string name="https_block_alert_title">접속 불가 현상 안내</string>
<string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다 이 경우 플레이스토어에서 Intra앱을 이용하시면 정상이용이 가능합니다.</string> <string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다 이 경우 플레이스토어에서 Intra앱을 이용하시면 정상이용이 가능합니다.</string>
<string name="main_dialog_export">갤러리 내보내기</string>
<string name="main_export_complete">내보내기 완료</string>
<string name="main_export_open_folder">폴더 열기</string>
<string name="main_export_error">내보내기 오류가 발생했습니다</string>
<string name="settings_clear_downloads">다운로드 삭제</string> <string name="settings_clear_downloads">다운로드 삭제</string>
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string> <string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
<string name="main_drawer_favorite">즐겨찾기</string> <string name="main_drawer_favorite">즐겨찾기</string>
@@ -82,11 +73,8 @@
<string name="main_menu_sort">정렬</string> <string name="main_menu_sort">정렬</string>
<string name="main_menu_sort_popular">인기순</string> <string name="main_menu_sort_popular">인기순</string>
<string name="main_menu_sort_newest">시간순</string> <string name="main_menu_sort_newest">시간순</string>
<string name="update_failed">"업데이트 에러</string>
<string name="update_failed_message">업데이트 중 에러가 발생했습니다</string>
<string name="ignore_update">무시</string> <string name="ignore_update">무시</string>
<string name="lock_corrupted">잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.</string> <string name="lock_corrupted">잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.</string>
<string name="update_no_permission">권한이 부여되어 있지 않아 자동 업데이트를 진행할 수 없습니다. 홈페이지에서 직접 다운로드 받으시기 바랍니다.</string>
<string name="settings_dark_mode_title">다크 모드</string> <string name="settings_dark_mode_title">다크 모드</string>
<string name="settings_dark_mode_summary">딥 다크한 모오드</string> <string name="settings_dark_mode_summary">딥 다크한 모오드</string>
<string name="gallery_details">갤러리 정보</string> <string name="gallery_details">갤러리 정보</string>
@@ -99,13 +87,11 @@
<string name="gallery_related">관련 갤러리</string> <string name="gallery_related">관련 갤러리</string>
<string name="gallery_thumbnails">미리보기</string> <string name="gallery_thumbnails">미리보기</string>
<string name="settings_nomedia_title">이미지 숨기기</string> <string name="settings_nomedia_title">이미지 숨기기</string>
<string name="reader_help">도움말</string>
<string name="main_delete">삭제</string> <string name="main_delete">삭제</string>
<string name="main_download">다운로드</string> <string name="main_download">다운로드</string>
<string name="settings_backup_title">즐겨찾기 백업</string> <string name="settings_backup_title">즐겨찾기 백업</string>
<string name="settings_restore_title">즐겨찾기 복원</string> <string name="settings_restore_title">즐겨찾기 복원</string>
<string name="settings_backup_snackbar">백업 파일을 생성하였습니다</string> <string name="settings_backup_snackbar">백업 파일을 생성하였습니다</string>
<string name="settings_backup_checkout">확인</string>
<string name="settings_restore_failed">복원에 실패했습니다</string> <string name="settings_restore_failed">복원에 실패했습니다</string>
<string name="settings_restore_successful">%1$d개 항목을 복원했습니다</string> <string name="settings_restore_successful">%1$d개 항목을 복원했습니다</string>
<string name="settings_dl_location">다운로드 위치</string> <string name="settings_dl_location">다운로드 위치</string>
@@ -134,8 +120,6 @@
<string name="main_fab_cancel">다운로드 모두 취소</string> <string name="main_fab_cancel">다운로드 모두 취소</string>
<string name="channel_update">업데이트</string> <string name="channel_update">업데이트</string>
<string name="channel_update_description">업데이트 진행상황 표시</string> <string name="channel_update_description">업데이트 진행상황 표시</string>
<string name="channel_import">가져오기</string>
<string name="channel_import_description">가져오기 상태 표시</string>
<string name="settings_import_old_galleries">이전 버전 갤러리 가져오기</string> <string name="settings_import_old_galleries">이전 버전 갤러리 가져오기</string>
<string name="import_old_galleries_folder_not_readable">폴더를 읽을 수 없습니다</string> <string name="import_old_galleries_folder_not_readable">폴더를 읽을 수 없습니다</string>
<string name="import_old_galleries_notification">이전 버전 갤러리 가져오는 중…</string> <string name="import_old_galleries_notification">이전 버전 갤러리 가져오는 중…</string>
@@ -149,7 +133,6 @@
<string name="settings_download_when_cache_disable_warning">캐시를 활성화 해야 다운로드를 진행할 수 있습니다</string> <string name="settings_download_when_cache_disable_warning">캐시를 활성화 해야 다운로드를 진행할 수 있습니다</string>
<string name="settings_user_id">유저 ID</string> <string name="settings_user_id">유저 ID</string>
<string name="settings_user_id_toast">유저 ID를 클립보드에 복사했습니다</string> <string name="settings_user_id_toast">유저 ID를 클립보드에 복사했습니다</string>
<string name="reader_error_retry">다운로드 에러가 발생했습니. 재시도 하시겠습니까?</string>
<string name="reader_fab_retry">재시도</string> <string name="reader_fab_retry">재시도</string>
<string name="reader_fab_auto">자동 스크롤</string> <string name="reader_fab_auto">자동 스크롤</string>
</resources> </resources>

View File

@@ -6,16 +6,6 @@
<item>25</item> <item>25</item>
<item>50</item> <item>50</item>
</string-array> </string-array>
<!-- Reply Preference -->
<string-array name="reply_entries">
<item>Reply</item>
<item>Reply to all</item>
</string-array>
<string-array name="reply_values">
<item>reply</item>
<item>reply_all</item>
</string-array>
<string-array name="languages"> <string-array name="languages">
<item>indonesian|Bahasa Indonesia</item> <item>indonesian|Bahasa Indonesia</item>

View File

@@ -3,7 +3,6 @@
<color name="colorPrimary">#4fc3f7</color> <color name="colorPrimary">#4fc3f7</color>
<color name="colorPrimaryDark">#0093c4</color> <color name="colorPrimaryDark">#0093c4</color>
<color name="colorAccent">#D81B60</color> <color name="colorAccent">#D81B60</color>
<color name="appbar">#FFFFFF</color>
<color name="material_pink_600">#d81b60</color> <color name="material_pink_600">#d81b60</color>
<color name="material_blue_700">#1976d2</color> <color name="material_blue_700">#1976d2</color>

View File

@@ -1,16 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<dimen name="appbar_padding">64dp</dimen>
<dimen name="progress_view_start">32dp</dimen>
<dimen name="progress_view_offset">96dp</dimen>
<dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="thumbnail_margin">8dp</dimen>
<dimen name="galleryblock_thumbnail_thin">100dp</dimen> <dimen name="galleryblock_thumbnail_thin">100dp</dimen>
<dimen name="galleryblock_thumbnail_normal">150dp</dimen>
</resources> </resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<item name="item_click_support" type="id" /> <item name="item_click_support" type="id" />
<item name="request_settings" type="id" />
<item name="request_lock" type="id" />
<item name="request_restore" type="id" />
<item name="request_import_old_galleries" type="id" />
<item name="request_import_old_galleries_old" type="id" />
<item name="request_download_folder" type="id" />
<item name="request_download_folder_old" type="id" />
<item name="request_write_permission_and_saf" type="id" />
<item name="notification_id_update" type="id" />
</resources> </resources>

View File

@@ -2,15 +2,12 @@
<string name="app_name" translatable="false" tools:override="true">Pupil</string> <string name="app_name" translatable="false" tools:override="true">Pupil</string>
<string name="release_url" translatable="false">https://api.github.com/repos/tom5079/Pupil/releases</string> <string name="release_url" translatable="false">https://api.github.com/repos/tom5079/Pupil/releases</string>
<string name="release_name" translatable="false">Pupil-v(\\d+\\.)+\\d+\\.apk</string>
<string name="home_page" translatable="false">http://bit.ly/2EZDClw</string> <string name="home_page" translatable="false">http://bit.ly/2EZDClw</string>
<string name="update" translatable="false">http://bit.ly/2ZlOjXJ</string>
<string name="help" translatable="false">http://bit.ly/2Z7lNZE</string> <string name="help" translatable="false">http://bit.ly/2Z7lNZE</string>
<string name="github" translatable="false">https://github.com/tom5079/Pupil/</string> <string name="github" translatable="false">https://github.com/tom5079/Pupil/</string>
<string name="email" translatable="false">mailto:pupil.hentai@gmail.com</string> <string name="email" translatable="false">mailto:pupil.hentai@gmail.com</string>
<string name="discord" translatable="false">https://discord.gg/Stj4b5v</string> <string name="discord" translatable="false">https://discord.gg/Stj4b5v</string>
<string name="error_help" translatable="false">http://bit.ly/2KYYhto</string>
<string name="main_settings" translatable="false">Settings</string> <string name="main_settings" translatable="false">Settings</string>
<string name="galleryblock_thumbnail_description" translatable="false">Thumbnail</string> <string name="galleryblock_thumbnail_description" translatable="false">Thumbnail</string>
@@ -18,8 +15,6 @@
<string name="reader_imageview_description" translatable="false">Content ImageView</string> <string name="reader_imageview_description" translatable="false">Content ImageView</string>
<string name="page_indicator_placeholder" translatable="false">-/-</string> <string name="page_indicator_placeholder" translatable="false">-/-</string>
<string name="plus_to_close" translatable="false">Fab</string>
<!-- Translate needed down here --> <!-- Translate needed down here -->
<string name="warning">Warning</string> <string name="warning">Warning</string>
@@ -27,9 +22,6 @@
<string name="https_block_alert_title">(Korean only)</string> <string name="https_block_alert_title">(Korean only)</string>
<string name="https_block_alert">(Korean only)</string> <string name="https_block_alert">(Korean only)</string>
<string name="update_failed">Update failed</string>
<string name="update_failed_message">Please install manually by visiting github release page :{ (or try again!)</string>
<string name="update_no_permission">Cannot auto update because permission is denied. Please download manually from the webpage.</string>
<string name="ignore_update">Ignore</string> <string name="ignore_update">Ignore</string>
<string name="channel_download">Download</string> <string name="channel_download">Download</string>
@@ -38,14 +30,10 @@
<string name="channel_update">Update</string> <string name="channel_update">Update</string>
<string name="channel_update_description">Shows update progress</string> <string name="channel_update_description">Shows update progress</string>
<string name="channel_import">Import</string>
<string name="channel_import_description">Shows progress of import</string>
<string name="unable_to_connect">Unable to connect to hitomi.la</string> <string name="unable_to_connect">Unable to connect to hitomi.la</string>
<string name="lock_corrupted">Lock file corrupted! Please re-install Pupil</string> <string name="lock_corrupted">Lock file corrupted! Please re-install Pupil</string>
<string name="main_search">Search</string>
<string name="main_no_result">No result</string> <string name="main_no_result">No result</string>
<string name="main_drawer_home">Home</string> <string name="main_drawer_home">Home</string>
@@ -74,25 +62,16 @@
<string name="main_move">Move to page %1$d</string> <string name="main_move">Move to page %1$d</string>
<string name="main_dialog_delete">Delete this gallery</string>
<string name="main_dialog_export">Export this gallery</string>
<string name="main_export_complete">Export completed</string>
<string name="main_export_open_folder">Open Folder</string>
<string name="main_export_error">Error occurred during export</string>
<string name="main_download">DOWNLOAD</string> <string name="main_download">DOWNLOAD</string>
<string name="main_delete">DELETE</string> <string name="main_delete">DELETE</string>
<string name="update_title">Update available</string> <string name="update_title">Update available</string>
<string name="update_download_started">Download started</string>
<string name="update_download_completed">Download Completed</string> <string name="update_download_completed">Download Completed</string>
<string name="update_download_completed_description">Click here to update</string> <string name="update_download_completed_description">Click here to update</string>
<string name="update_notification_description">Downloading update&#8230;</string> <string name="update_notification_description">Downloading update&#8230;</string>
<string name="update_release_note"># Release Note(v%1$s)\n%2$s</string> <string name="update_release_note"># Release Note(v%1$s)\n%2$s</string>
<string name="search_hint">Search galleries</string> <string name="search_hint">Search galleries</string>
<string name="search_hint_with_page">Search galleries</string>
<string name="gallery_details">Details</string> <string name="gallery_details">Details</string>
<string name="gallery_thumbnails">Thumbnails</string> <string name="gallery_thumbnails">Thumbnails</string>
@@ -120,11 +99,6 @@
<string name="reader_fab_download_cancel">Cancel background download</string> <string name="reader_fab_download_cancel">Cancel background download</string>
<string name="reader_notification_text">Downloading&#8230;</string> <string name="reader_notification_text">Downloading&#8230;</string>
<string name="reader_notification_complete">Download complete</string> <string name="reader_notification_complete">Download complete</string>
<string name="reader_notification_error">Download error</string>
<string name="reader_error_retry">Download Error. Retry?</string>
<string name="reader_help">Help</string>
<!-- SETTINGS --> <!-- SETTINGS -->
@@ -180,7 +154,6 @@
<string name="settings_nomedia_title">Hide image from gallery</string> <string name="settings_nomedia_title">Hide image from gallery</string>
<string name="settings_backup_title">Backup favorites</string> <string name="settings_backup_title">Backup favorites</string>
<string name="settings_backup_snackbar">Backup file created</string> <string name="settings_backup_snackbar">Backup file created</string>
<string name="settings_backup_checkout">Check out</string>
<string name="settings_restore_title">Restore favorites</string> <string name="settings_restore_title">Restore favorites</string>
<string name="settings_restore_failed">Restore failed</string> <string name="settings_restore_failed">Restore failed</string>
<string name="settings_restore_successful">%1$d entries restored</string> <string name="settings_restore_successful">%1$d entries restored</string>

View File

@@ -1,7 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.72'
repositories { repositories {
google() google()
jcenter() jcenter()

View File

@@ -18,3 +18,5 @@ org.gradle.configureondemand=true
kotlin.code.style=official kotlin.code.style=official
android.enableJetifier=true android.enableJetifier=true
android.useAndroidX=true android.useAndroidX=true
kotlin_version=1.4.0

View File

@@ -1 +1 @@
include ':app', ':libpupil' include ':app'