diff --git a/.idea/misc.xml b/.idea/misc.xml
index fb8c126a..7631aec3 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 46f2ce9b..97cb1eb5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,13 +7,13 @@ apply plugin: 'io.fabric'
apply plugin: 'com.google.firebase.firebase-perf'
android {
- compileSdkVersion 28
+ compileSdkVersion 29
defaultConfig {
applicationId "xyz.quaver.pupil"
minSdkVersion 16
- targetSdkVersion 28
- versionCode 16
- versionName "2.9"
+ targetSdkVersion 29
+ versionCode 17
+ versionName "2.10-alpha"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
@@ -42,17 +42,21 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.1.0-beta01'
implementation 'com.google.android.material:material:1.0.0'
- implementation 'com.google.firebase:firebase-core:16.0.9'
- implementation 'com.google.firebase:firebase-perf:17.0.2'
+ implementation 'com.google.firebase:firebase-core:17.0.0'
+ implementation 'com.google.firebase:firebase-perf:18.0.1'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
- implementation 'com.github.deano2390:MaterialShowcaseView:1.3.4'
+ implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "ru.noties.markwon:core:${markwonVersion}"
implementation 'com.github.clans:fab:1.6.4'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation project(path: ':libpupil')
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index efb4fd24..481bb434 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -18,11 +18,4 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
--keep class com.finotes.android.finotescore.* { *; }
-
--keepclassmembers class * {
- @com.finotes.android.finotescore.annotation.Observe *;
-}
-
--keepattributes SourceFile,LineNumberTable
\ No newline at end of file
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/release/output.json b/app/release/output.json
index 0cc69cca..f084575a 100644
--- a/app/release/output.json
+++ b/app/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":16,"versionName":"2.9","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":17,"versionName":"2.9.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt b/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt
index 79db10d2..facb9b50 100644
--- a/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt
@@ -1,16 +1,18 @@
package xyz.quaver.pupil
-import android.graphics.BitmapFactory
+import android.content.Intent
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.ActivityTestRule
import org.junit.Assert.assertEquals
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import xyz.quaver.hiyobi.cookie
import xyz.quaver.hiyobi.getReader
import xyz.quaver.hiyobi.user_agent
-import java.io.File
+import xyz.quaver.pupil.ui.LockActivity
import java.net.URL
import javax.net.ssl.HttpsURLConnection
@@ -21,6 +23,7 @@ import javax.net.ssl.HttpsURLConnection
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
+
@Test
fun useAppContext() {
// Context of the app under test.
@@ -30,12 +33,12 @@ class ExampleInstrumentedTest {
@Test
fun checkCacheDir() {
+ val activityTestRule = ActivityTestRule(LockActivity::class.java)
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- val file = File(appContext.cacheDir, "imageCache/1412251/01.jpg.webp")
- val bitmap = BitmapFactory.decodeFile(file.absolutePath)
+ activityTestRule.launchActivity(Intent())
- Log.d("Pupil", bitmap.byteCount.toString())
+ while(true);
}
@Test
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 294d57a0..c3e6686f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,20 +6,19 @@
-
+ android:theme="@style/AppTheme">
+
-
+ android:name=".ui.ReaderActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:parentActivityName=".ui.MainActivity">
@@ -27,9 +26,9 @@
+ android:pathPrefix="/galleries"
+ android:scheme="https" />
@@ -38,9 +37,9 @@
+ android:pathPrefix="/reader"
+ android:scheme="https" />
@@ -49,9 +48,9 @@
+ android:pathPrefix="/reader"
+ android:scheme="https" />
@@ -60,9 +59,9 @@
+ android:pathPrefix="/g"
+ android:scheme="https" />
@@ -71,9 +70,9 @@
+ android:pathPrefix="/galleries"
+ android:scheme="http" />
@@ -82,9 +81,9 @@
+ android:pathPrefix="/reader"
+ android:scheme="http" />
@@ -93,9 +92,9 @@
+ android:pathPrefix="/reader"
+ android:scheme="http" />
@@ -104,16 +103,16 @@
+ android:pathPrefix="/g"
+ android:scheme="http" />
diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
index 12080356..9cf73343 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
@@ -24,7 +24,7 @@ import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.list
import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.ReaderItem
-import xyz.quaver.pupil.Pupil
+import xyz.quaver.pupil.ui.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.Histories
diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt
index f4f33a09..e75617c4 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt
@@ -6,9 +6,6 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import xyz.quaver.pupil.R
class ReaderAdapter(private val images: List) : RecyclerView.Adapter() {
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt
new file mode 100644
index 00000000..d8eee511
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt
@@ -0,0 +1,85 @@
+package xyz.quaver.pupil.ui
+
+import android.app.Activity
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.widget.Toast
+import com.andrognito.patternlockview.PatternLockView
+import com.google.android.material.snackbar.Snackbar
+import kotlinx.android.synthetic.main.activity_lock.*
+import kotlinx.android.synthetic.main.fragment_pattern_lock.*
+import kotlinx.android.synthetic.main.settings_activity.*
+import xyz.quaver.pupil.R
+import xyz.quaver.pupil.util.Lock
+import xyz.quaver.pupil.util.LockManager
+
+class LockActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_lock)
+
+ val lockManager = LockManager(this)
+
+ val mode = intent.getStringExtra("mode")
+
+ lock_pattern.isEnabled = false
+ lock_pin.isEnabled = false
+ lock_fingerprint.isEnabled = false
+ lock_password.isEnabled = false
+
+ when(mode) {
+ null -> {
+ if (lockManager.empty()) {
+ setResult(RESULT_OK)
+ finish()
+ }
+ }
+ "add_lock" -> {
+ when(intent.getStringExtra("type")!!) {
+ "pattern" -> {
+
+ }
+ }
+ }
+ }
+
+ supportFragmentManager.beginTransaction().add(
+ R.id.lock_content,
+ PatternLockFragment().apply {
+ var lastPass = ""
+ onPatternDrawn = {
+ when(mode) {
+ null -> {
+ val result = lockManager.check(it)
+
+ if (result == true) {
+ setResult(Activity.RESULT_OK)
+ finish()
+ } else
+ lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG)
+ }
+ "add_lock" -> {
+ if (lastPass.isEmpty()) {
+ lastPass = it
+
+ Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show()
+ } else {
+ if (lastPass == it) {
+ LockManager(context!!).add(Lock.generate(Lock.Type.PATTERN, it))
+ finish()
+ } else {
+ lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG)
+ lastPass = ""
+
+ Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show()
+ }
+ }
+ }
+ }
+ }
+ }
+ ).commit()
+ }
+
+}
diff --git a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
similarity index 96%
rename from app/src/main/java/xyz/quaver/pupil/MainActivity.kt
rename to app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
index 1933c54e..8b59da1c 100644
--- a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
@@ -1,12 +1,12 @@
-package xyz.quaver.pupil
+package xyz.quaver.pupil.ui
import android.Manifest
+import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.drawable.Animatable
import android.net.Uri
import android.os.Bundle
-import android.preference.PreferenceManager
import android.text.*
import android.text.style.AlignmentSpan
import android.view.*
@@ -21,6 +21,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.GravityCompat
+import androidx.preference.PreferenceManager
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.arlib.floatingsearchview.FloatingSearchView
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
@@ -40,6 +41,8 @@ import kotlinx.serialization.list
import kotlinx.serialization.stringify
import ru.noties.markwon.Markwon
import xyz.quaver.hitomi.*
+import xyz.quaver.pupil.BuildConfig
+import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.types.TagSuggestion
@@ -51,6 +54,7 @@ import java.net.URL
import java.util.*
import javax.net.ssl.HttpsURLConnection
import kotlin.collections.ArrayList
+import kotlin.math.min
import kotlin.math.roundToInt
class MainActivity : AppCompatActivity() {
@@ -65,9 +69,16 @@ class MainActivity : AppCompatActivity() {
private val galleries = ArrayList>>()
private var query = ""
+ set(value) {
+ field = value
+ findViewById(R.id.search_bar_text)
+ .setText(query, TextView.BufferType.EDITABLE)
+ }
+
private var mode = Mode.SEARCH
- private val SETTINGS = 45162
+ private val REQUEST_SETTINGS = 45162
+ private val REQUEST_LOCK = 561
private var galleryIDs: Deferred>? = null
private var totalItems = 0
@@ -81,6 +92,8 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ startActivityForResult(Intent(this, LockActivity::class.java), REQUEST_LOCK)
+
checkPermissions()
val preference = PreferenceManager.getDefaultSharedPreferences(this)
@@ -110,19 +123,11 @@ class MainActivity : AppCompatActivity() {
initView()
}
- override fun onDestroy() {
- super.onDestroy()
-
- if (cacheDir.exists())
- cacheDir.deleteRecursively()
- }
-
override fun onBackPressed() {
when {
main_drawer_layout.isDrawerOpen(GravityCompat.START) -> main_drawer_layout.closeDrawer(GravityCompat.START)
query.isNotEmpty() -> runOnUiThread {
query = ""
- findViewById(R.id.search_bar_text).setText(query, TextView.BufferType.EDITABLE)
cancelFetch()
clearGalleries()
@@ -142,6 +147,7 @@ class MainActivity : AppCompatActivity() {
WindowManager.LayoutParams.FLAG_SECURE)
else
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
+
super.onResume()
}
@@ -186,7 +192,7 @@ class MainActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode) {
- SETTINGS -> {
+ REQUEST_SETTINGS -> {
runOnUiThread {
cancelFetch()
clearGalleries()
@@ -194,6 +200,10 @@ class MainActivity : AppCompatActivity() {
loadBlocks()
}
}
+ REQUEST_LOCK -> {
+ if (resultCode != Activity.RESULT_OK)
+ finish()
+ }
}
}
@@ -352,8 +362,7 @@ class MainActivity : AppCompatActivity() {
onChipClickedHandler.add {
runOnUiThread {
query = it.toQuery()
- this@MainActivity.findViewById(R.id.search_bar_text)
- .setText(query, TextView.BufferType.EDITABLE)
+ currentPage = 0
cancelFetch()
clearGalleries()
@@ -679,7 +688,7 @@ class MainActivity : AppCompatActivity() {
setOnMenuItemClickListener {
when(it.itemId) {
- R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), SETTINGS)
+ R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS)
R.id.main_menu_jump -> {
val preference = PreferenceManager.getDefaultSharedPreferences(context)
val perPage = preference.getString("per_page", "25")!!.toInt()
@@ -726,7 +735,8 @@ class MainActivity : AppCompatActivity() {
startActivity(intent)
} catch (e: Exception) {
- Snackbar.make(main_layout, R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
+ Snackbar.make(main_layout,
+ R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
}
}
}
@@ -804,7 +814,9 @@ class MainActivity : AppCompatActivity() {
favorites.remove(tag)
}
else {
- setImageDrawable(AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star))
+ setImageDrawable(AnimatedVectorDrawableCompat.create(context,
+ R.drawable.avd_star
+ ))
(drawable as Animatable).start()
favorites.add(tag)
@@ -880,10 +892,8 @@ class MainActivity : AppCompatActivity() {
}
private fun cancelFetch() {
- runBlocking {
- galleryIDs?.cancelAndJoin()
- loadingJob?.cancelAndJoin()
- }
+ galleryIDs?.cancel()
+ loadingJob?.cancel()
}
private fun clearGalleries() {
@@ -992,7 +1002,7 @@ class MainActivity : AppCompatActivity() {
query.isEmpty() and defaultQuery.isEmpty() and (mode == Mode.SEARCH) ->
galleryIDs
else ->
- galleryIDs.slice(currentPage*perPage until Math.min(currentPage*perPage+perPage, galleryIDs.size))
+ galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size))
}.chunked(5).let { chunks ->
for (chunk in chunks)
chunk.map { galleryID ->
@@ -1009,8 +1019,8 @@ class MainActivity : AppCompatActivity() {
getGalleryBlock(galleryID).apply {
this ?: return@apply
- if (!cache.parentFile.exists())
- cache.parentFile.mkdirs()
+ if (cache.parentFile?.exists() == false)
+ cache.parentFile!!.mkdirs()
cache.writeText(json.stringify(serializer, this))
}
@@ -1024,8 +1034,8 @@ class MainActivity : AppCompatActivity() {
if (!exists())
try {
with(URL(galleryBlock.thumbnails[0]).openConnection() as HttpsURLConnection) {
- if (!this@apply.parentFile.exists())
- this@apply.parentFile.mkdirs()
+ if (this@apply.parentFile?.exists() == false)
+ this@apply.parentFile!!.mkdirs()
inputStream.copyTo(FileOutputStream(this@apply))
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/PatternLockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/PatternLockFragment.kt
new file mode 100644
index 00000000..11d8a53b
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/PatternLockFragment.kt
@@ -0,0 +1,47 @@
+package xyz.quaver.pupil.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import com.andrognito.patternlockview.PatternLockView
+import com.andrognito.patternlockview.listener.PatternLockViewListener
+import com.andrognito.patternlockview.utils.PatternLockUtils
+import kotlinx.android.synthetic.main.fragment_pattern_lock.*
+import kotlinx.android.synthetic.main.fragment_pattern_lock.view.*
+import xyz.quaver.pupil.R
+import xyz.quaver.pupil.util.hash
+import xyz.quaver.pupil.util.hashWithSalt
+
+class PatternLockFragment : Fragment(), PatternLockViewListener {
+
+ var onPatternDrawn: ((String) -> Unit)? = null
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_pattern_lock, container, false).apply {
+ lock_pattern_view.addPatternLockListener(this@PatternLockFragment)
+ }
+ }
+
+ override fun onCleared() {
+
+ }
+
+ override fun onComplete(pattern: MutableList?) {
+ val password = PatternLockUtils.patternToMD5(lock_pattern_view, pattern)
+ onPatternDrawn?.invoke(password)
+ }
+
+ override fun onProgress(progressPattern: MutableList?) {
+
+ }
+
+ override fun onStarted() {
+
+ }
+
+}
diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/ui/Pupil.kt
similarity index 94%
rename from app/src/main/java/xyz/quaver/pupil/Pupil.kt
rename to app/src/main/java/xyz/quaver/pupil/ui/Pupil.kt
index add8d659..c1859fe3 100644
--- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/Pupil.kt
@@ -1,14 +1,14 @@
-package xyz.quaver.pupil
+package xyz.quaver.pupil.ui
-import android.app.Application
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
-import android.preference.PreferenceManager
import androidx.core.content.ContextCompat
import androidx.multidex.MultiDexApplication
+import androidx.preference.PreferenceManager
+import xyz.quaver.pupil.R
import xyz.quaver.pupil.util.Histories
import java.io.File
diff --git a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
similarity index 97%
rename from app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
rename to app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
index 49fa1f33..990f7b50 100644
--- a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt
@@ -1,4 +1,4 @@
-package xyz.quaver.pupil
+package xyz.quaver.pupil.ui
import android.content.Intent
import android.graphics.drawable.Animatable
@@ -11,9 +11,9 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
+import com.crashlytics.android.Crashlytics
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_reader.*
import kotlinx.android.synthetic.main.activity_reader.view.*
@@ -28,6 +28,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.getGalleryBlock
+import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.ReaderAdapter
import xyz.quaver.pupil.util.GalleryDownloader
import xyz.quaver.pupil.util.Histories
@@ -72,6 +73,8 @@ class ReaderActivity : AppCompatActivity() {
handleIntent(intent)
+ Crashlytics.setInt("GalleryID", galleryBlock.id)
+
if (!::galleryBlock.isInitialized) {
onBackPressed()
return
@@ -117,7 +120,7 @@ class ReaderActivity : AppCompatActivity() {
} else {
galleryBlock = Json(JsonConfiguration.Stable).parse(
GalleryBlock.serializer(),
- intent.getStringExtra("galleryblock")
+ intent.getStringExtra("galleryblock")!!
)
}
}
@@ -372,10 +375,7 @@ class ReaderActivity : AppCompatActivity() {
reader_recyclerview.layoutManager = LinearLayoutManager(this)
} else {
snapHelper.attachToRecyclerView(reader_recyclerview)
- reader_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false).apply {
- isItemPrefetchEnabled = true
- initialPrefetchItemCount = 4
- }
+ reader_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
}
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0)
diff --git a/app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt
similarity index 58%
rename from app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt
rename to app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt
index e93b0166..1f995222 100644
--- a/app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt
@@ -1,8 +1,8 @@
-package xyz.quaver.pupil
+package xyz.quaver.pupil.ui
+import android.app.Activity
+import android.content.Intent
import android.os.Bundle
-import android.os.Environment
-import android.preference.PreferenceManager
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
@@ -15,12 +15,18 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
+import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.dialog_default_query.view.*
+import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tags
+import xyz.quaver.pupil.util.Lock
+import xyz.quaver.pupil.util.LockManager
import java.io.File
class SettingsActivity : AppCompatActivity() {
+ val REQUEST_LOCK = 38238
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -58,7 +64,25 @@ class SettingsActivity : AppCompatActivity() {
"TB" //really?
)
- private fun getCacheSize(dir: File) : String {
+ override fun onResume() {
+ super.onResume()
+
+ val lockManager = LockManager(context!!)
+
+ findPreference("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) {
+ getString(R.string.settings_lock_none)
+ } else {
+ lockManager.locks?.joinToString(", ") {
+ when(it.type) {
+ Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
+ Lock.Type.PIN -> getString(R.string.settings_lock_pin)
+ Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
+ }
+ }
+ }
+ }
+
+ private fun getDirSize(dir: File) : String {
var size = dir.walk().map { it.length() }.sum()
var suffixIndex = 0
@@ -67,20 +91,53 @@ class SettingsActivity : AppCompatActivity() {
suffixIndex++
}
- return getString(R.string.settings_clear_downloads_summary, size, suffix[suffixIndex])
+ return getString(R.string.settings_clear_summary, size, suffix[suffixIndex])
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
+ with(findPreference("app_version")) {
+ this!!
+
+ val manager = context.packageManager
+ val info = manager.getPackageInfo(context.packageName, 0)
+
+ summary = info.versionName
+ }
+
+ with(findPreference("delete_cache")) {
+ this!!
+
+ val dir = File(context.cacheDir, "imageCache")
+
+ summary = getDirSize(dir)
+
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ AlertDialog.Builder(context).apply {
+ setTitle(R.string.warning)
+ setMessage(R.string.settings_clear_cache_alert_message)
+ setPositiveButton(android.R.string.yes) { _, _ ->
+ if (dir.exists())
+ dir.deleteRecursively()
+
+ summary = getDirSize(dir)
+ }
+ setNegativeButton(android.R.string.no) { _, _ -> }
+ }.show()
+
+ true
+ }
+ }
+
with(findPreference("delete_downloads")) {
- this ?: return@with
+ this!!
- val dir = File(Environment.getExternalStorageDirectory(), "Pupil")
+ val dir = context.getExternalFilesDir("Pupil") ?: return@with
- summary = getCacheSize(dir)
+ summary = getDirSize(dir)
- setOnPreferenceClickListener {
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
AlertDialog.Builder(context).apply {
setTitle(R.string.warning)
setMessage(R.string.settings_clear_downloads_alert_message)
@@ -92,7 +149,7 @@ class SettingsActivity : AppCompatActivity() {
downloads.clear()
- summary = getCacheSize(dir)
+ summary = getDirSize(dir)
}
setNegativeButton(android.R.string.no) { _, _ -> }
}.show()
@@ -101,13 +158,13 @@ class SettingsActivity : AppCompatActivity() {
}
}
with(findPreference("clear_history")) {
- this ?: return@with
+ this!!
val histories = (activity!!.application as Pupil).histories
summary = getString(R.string.settings_clear_history_summary, histories.size)
- setOnPreferenceClickListener {
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
AlertDialog.Builder(context).apply {
setTitle(R.string.warning)
setMessage(R.string.settings_clear_history_alert_message)
@@ -123,7 +180,7 @@ class SettingsActivity : AppCompatActivity() {
}
with(findPreference("default_query")) {
- this ?: return@with
+ this!!
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
@@ -139,7 +196,7 @@ class SettingsActivity : AppCompatActivity() {
val excludeBL = "-male:yaoi"
val excludeGuro = listOf("-female:guro", "-male:guro")
- setOnPreferenceClickListener {
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
val dialogView = LayoutInflater.from(context).inflate(
R.layout.dialog_default_query,
LinearLayout(context),
@@ -154,7 +211,7 @@ class SettingsActivity : AppCompatActivity() {
with(dialogView.default_query_dialog_language_selector) {
adapter =
- ArrayAdapter(
+ ArrayAdapter(
context,
android.R.layout.simple_spinner_dropdown_item,
arrayListOf(
@@ -234,6 +291,82 @@ class SettingsActivity : AppCompatActivity() {
dialog.show()
+ true
+ }
+ }
+ with(findPreference("app_lock")) {
+ this!!
+
+ val lockManager = LockManager(context)
+
+ summary = if (lockManager.locks.isNullOrEmpty()) {
+ getString(R.string.settings_lock_none)
+ } else {
+ lockManager.locks?.joinToString(", ") {
+ when(it.type) {
+ Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
+ Lock.Type.PIN -> getString(R.string.settings_lock_pin)
+ Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
+ }
+ }
+ }
+
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ val intent = Intent(context, LockActivity::class.java)
+ activity?.startActivityForResult(intent, (activity as SettingsActivity).REQUEST_LOCK)
+
+ true
+ }
+ }
+ }
+ }
+
+ class LockFragment : PreferenceFragmentCompat() {
+
+ override fun onResume() {
+ super.onResume()
+
+ val lockManager = LockManager(context!!)
+
+ findPreference("lock_pattern")?.summary =
+ if (lockManager.contains(Lock.Type.PATTERN))
+ getString(R.string.settings_lock_enabled)
+ else
+ ""
+ }
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.lock_preferences, rootKey)
+
+ with(findPreference("lock_pattern")) {
+ this!!
+
+ if (LockManager(context!!).contains(Lock.Type.PATTERN))
+ summary = getString(R.string.settings_lock_enabled)
+
+ onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ val lockManager = LockManager(context!!)
+
+ if (lockManager.contains(Lock.Type.PATTERN)) {
+ AlertDialog.Builder(context).apply {
+ setTitle(R.string.warning)
+ setMessage(R.string.settings_lock_remove_message)
+
+ setPositiveButton(android.R.string.yes) { _, _ ->
+ lockManager.remove(Lock.Type.PATTERN)
+ onResume()
+ }
+ setNegativeButton(android.R.string.no) { _, _ -> }
+ }.show()
+ } else {
+ val intent = Intent(context, LockActivity::class.java).apply {
+ putExtra("mode", "add_lock")
+ putExtra("type", "pattern")
+ }
+
+ startActivity(intent)
+ }
+
true
}
}
@@ -247,4 +380,19 @@ class SettingsActivity : AppCompatActivity() {
return true
}
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ when(requestCode) {
+ REQUEST_LOCK -> {
+ if (resultCode == Activity.RESULT_OK) {
+ supportFragmentManager
+ .beginTransaction()
+ .replace(R.id.settings, LockFragment())
+ .addToBackStack("Lock")
+ .commitAllowingStateLoss()
+ }
+ }
+ else -> super.onActivityResult(requestCode, resultCode, data)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
index f4e08369..fda31db8 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
@@ -4,7 +4,7 @@ import android.app.PendingIntent
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
-import android.os.Environment
+import android.util.Log
import android.util.SparseArray
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
@@ -18,9 +18,9 @@ import kotlinx.serialization.list
import xyz.quaver.hitomi.*
import xyz.quaver.hiyobi.cookie
import xyz.quaver.hiyobi.user_agent
-import xyz.quaver.pupil.Pupil
+import xyz.quaver.pupil.ui.Pupil
import xyz.quaver.pupil.R
-import xyz.quaver.pupil.ReaderActivity
+import xyz.quaver.pupil.ui.ReaderActivity
import java.io.File
import java.io.FileOutputStream
import java.net.URL
@@ -52,7 +52,7 @@ class GalleryDownloader(
cache.deleteRecursively()
}
- if (!reader.isActive && downloadJob?.isActive != true)
+ if (reader?.isActive == false && downloadJob?.isActive != true)
field = false
downloads.add(galleryBlock.id)
@@ -63,7 +63,7 @@ class GalleryDownloader(
onNotifyChangedHandler?.invoke(value)
}
- private val reader: Deferred
+ private val reader: Deferred?
private var downloadJob: Job? = null
private lateinit var notificationBuilder: NotificationCompat.Builder
@@ -126,8 +126,8 @@ class GalleryDownloader(
if (reader.isNotEmpty()) {
//Save cache
- if (!cache.parentFile.exists())
- cache.parentFile.mkdirs()
+ if (cache.parentFile?.exists() == false)
+ cache.parentFile!!.mkdirs()
cache.writeText(json.stringify(serializer, reader))
}
@@ -140,7 +140,7 @@ class GalleryDownloader(
fun start() {
downloadJob = CoroutineScope(Dispatchers.Default).launch {
- val reader = reader.await()
+ val reader = reader!!.await()
if (reader.isEmpty())
onErrorHandler?.invoke(IOException("Couldn't retrieve Reader"))
@@ -183,8 +183,8 @@ class GalleryDownloader(
} else
setRequestProperty("Referer", getReferer(galleryBlock.id))
- if (!cache.parentFile.exists())
- cache.parentFile.mkdirs()
+ if (cache.parentFile?.exists() == false)
+ cache.parentFile!!.mkdirs()
inputStream.copyTo(FileOutputStream(cache))
}
@@ -209,8 +209,6 @@ class GalleryDownloader(
}
}
- onCompleteHandler?.invoke()
-
Timer(false).schedule(1000) {
notificationBuilder
.setContentTitle(galleryBlock.title)
@@ -220,7 +218,7 @@ class GalleryDownloader(
if (download) {
File(cacheDir, "imageCache/${galleryBlock.id}").let {
if (it.exists()) {
- val target = File(Environment.getExternalStorageDirectory(), "Pupil/${galleryBlock.id}")
+ val target = File(getExternalFilesDir("Pupil"), galleryBlock.id.toString())
if (!target.exists())
target.mkdirs()
@@ -231,9 +229,11 @@ class GalleryDownloader(
}
notificationManager.notify(galleryBlock.id, notificationBuilder.build())
- }
- download = false
+ onCompleteHandler?.invoke()
+
+ download = false
+ }
}
remove(galleryBlock.id)
@@ -254,7 +254,7 @@ class GalleryDownloader(
fun invokeOnReaderLoaded() {
CoroutineScope(Dispatchers.Default).launch {
- onReaderLoadedHandler?.invoke(reader.await())
+ onReaderLoadedHandler?.invoke(reader?.await() ?: return@launch)
}
}
diff --git a/app/src/main/java/xyz/quaver/pupil/util/file.kt b/app/src/main/java/xyz/quaver/pupil/util/file.kt
index 7e085650..f351dcd2 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/file.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/file.kt
@@ -2,10 +2,11 @@ package xyz.quaver.pupil.util
import android.content.Context
import android.os.Environment
+import android.provider.MediaStore
import java.io.File
fun getCachedGallery(context: Context, galleryID: Int): File {
- return File(Environment.getExternalStorageDirectory(), "Pupil/$galleryID").let {
+ return File(context.getExternalFilesDir("Pupil"), galleryID.toString()).let {
when {
it.exists() -> it
else -> File(context.cacheDir, "imageCache/$galleryID")
diff --git a/app/src/main/java/xyz/quaver/pupil/util/lock.kt b/app/src/main/java/xyz/quaver/pupil/util/lock.kt
new file mode 100644
index 00000000..13f87003
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/util/lock.kt
@@ -0,0 +1,105 @@
+package xyz.quaver.pupil.util
+
+import android.content.Context
+import android.content.ContextWrapper
+import androidx.core.content.ContextCompat
+import kotlinx.serialization.*
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonConfiguration
+import java.io.File
+import java.security.MessageDigest
+
+fun hash(password: String): String {
+ val bytes = password.toByteArray()
+ val md = MessageDigest.getInstance("SHA-256")
+
+ return md.digest(bytes).fold("") { str, it -> str + "%02x".format(it) }
+}
+
+// Ret1: SHA-256 Hash
+// Ret2: Hash salt
+fun hashWithSalt(password: String): Pair {
+ val salt = (0 until 12).map { source.random() }.joinToString()
+
+ return Pair(hash(password+salt), salt)
+}
+
+val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+@Serializable
+data class Lock(val type: Type, val hash: String, val salt: String) {
+
+ enum class Type {
+ PATTERN,
+ PIN,
+ PASSWORD
+ }
+
+ companion object {
+ fun generate(type: Type, password: String): Lock {
+ val (hash, salt) = hashWithSalt(password)
+ return Lock(type, hash, salt)
+ }
+ }
+
+ fun match(password: String): Boolean {
+ return hash(password+salt) == hash
+ }
+}
+
+class LockManager(base: Context): ContextWrapper(base) {
+
+ var locks: ArrayList? = null
+
+ init {
+ load()
+ }
+
+ @UseExperimental(ImplicitReflectionSerializer::class)
+ private fun load() {
+ val lock = File(ContextCompat.getDataDir(this), "lock.json")
+
+ if (!lock.exists()) {
+ lock.createNewFile()
+ lock.writeText("[]")
+ }
+
+ locks = ArrayList(Json(JsonConfiguration.Stable).parseList(lock.readText()))
+ }
+
+ @UseExperimental(ImplicitReflectionSerializer::class)
+ private fun save() {
+ val lock = File(ContextCompat.getDataDir(this), "lock.json")
+
+ if (!lock.exists())
+ lock.createNewFile()
+
+ lock.writeText(Json(JsonConfiguration.Stable).stringify(locks?.toList() ?: listOf()))
+ }
+
+ fun add(lock: Lock) {
+ remove(lock.type)
+ locks?.add(lock)
+ save()
+ }
+
+ fun remove(type: Lock.Type) {
+ locks?.removeAll { it.type == type }
+ save()
+ }
+
+ fun check(password: String): Boolean? {
+ return locks?.any {
+ it.match(password)
+ }
+ }
+
+ fun empty(): Boolean {
+ return locks.isNullOrEmpty()
+ }
+
+ fun contains(type: Lock.Type): Boolean {
+ return locks?.any { it.type == type } ?: false
+ }
+
+}
\ No newline at end of file
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 2c951cbe..1461f75c 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/update.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt
@@ -1,5 +1,6 @@
package xyz.quaver.pupil.util
+import android.util.Log
import kotlinx.serialization.json.*
import java.net.URL
@@ -19,8 +20,20 @@ fun checkUpdate(url: String, currentVersion: String) : JsonObject? {
if (releases.isEmpty())
return null
- if (currentVersion != releases[0].jsonObject["tag_name"]?.content)
- return releases[0].jsonObject
+ val latestVersion = releases[0].jsonObject["tag_name"]?.content
- return null
+ return when {
+ currentVersion.split('-').size == 1 -> {
+ when {
+ currentVersion != latestVersion -> releases[0].jsonObject
+ else -> null
+ }
+ }
+ else -> {
+ when {
+ (currentVersion.split('-')[0] == latestVersion) -> releases[0].jsonObject
+ else -> null
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/fingerprint.xml b/app/src/main/res/drawable/fingerprint.xml
new file mode 100644
index 00000000..ffa8a34b
--- /dev/null
+++ b/app/src/main/res/drawable/fingerprint.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/lastpass.xml b/app/src/main/res/drawable/lastpass.xml
new file mode 100644
index 00000000..9dbf638b
--- /dev/null
+++ b/app/src/main/res/drawable/lastpass.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/lock_pattern.xml b/app/src/main/res/drawable/lock_pattern.xml
new file mode 100644
index 00000000..f1be51c2
--- /dev/null
+++ b/app/src/main/res/drawable/lock_pattern.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_lock.xml b/app/src/main/res/layout/activity_lock.xml
new file mode 100644
index 00000000..e4632044
--- /dev/null
+++ b/app/src/main/res/layout/activity_lock.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml
index a5b3b266..bde8ddf4 100644
--- a/app/src/main/res/layout/activity_main_content.xml
+++ b/app/src/main/res/layout/activity_main_content.xml
@@ -6,7 +6,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".MainActivity">
+ tools:context=".ui.MainActivity">
+ tools:context=".ui.ReaderActivity">
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 8e7dd7d0..bdab1daf 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -8,7 +8,8 @@
ギャラリー検索
ギャラリー検索
イメージキャッシュクリア
- サイズ: %1$d%2$s
+ キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?
+ サイズ: %1$d%2$s
デフォルトキーワード
一回にロードするギャラリー数
検索設定
@@ -66,4 +67,16 @@
エラーが発生しました
ストレージ
カカオトーク
+ アプリロック
+ アップロックの種類
+ バージョン
+ 生体認識
+ ロック確認のためもう一回入力してください。
+ 有効
+ 指紋
+ パスワード
+ パターン
+ ロックが一致しません。やり直してください。
+ なし
+ ロックを無効にしますか?
\ 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 0b99f608..d7c7956d 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -7,7 +7,8 @@
갤러리 검색
기본 검색어
이미지 캐시 정리하기
- 사용량: %1$d%2$s
+ 캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?
+ 사용량: %1$d%2$s
한 번에 로드할 갤러리 수
검색 설정
설정
@@ -66,4 +67,16 @@
갤러리를 찾지 못했습니다
저장 공간
카카오톡 오픈채팅방
+ 앱 잠금
+ 앱 잠금 종류
+ 앱 버전
+ 생체 인식
+ 잠금 확인을 위해 한번 더 입력해주세요
+ 사용 중
+ 지문
+ 비밀번호
+ 패턴
+ 잠금이 일치하지 않습니다. 다시 시도하세요.
+ 없음
+ 잠금을 해제할까요?
\ 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 2cc8d514..c8ef231d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -80,23 +80,38 @@
Download error
Settings
+ App version
Search Settings
Galleries per page
Default query
Storage
Clear image cache
- Currently using %1$d%2$s
+ Deleting cache can affect image loading speed. Do you want to continue?
+ Currently using %1$d%2$s
Clear downloads
Delete all downloaded galleries.\nDo you want to continue?
Clear history
Do you want to clear histories?
%1$d histories saved
+ App lock
+ App lock type
Miscellaneous
Use hiyobi.me
Load images from hiyobi.me to improve loading speed (if available)
Enable security mode
Enable security mode to make the screen invisible on recent app window
+ None
+ Pattern
+ PIN
+ Password
+ Biomatrics
+ Fingerprint
+ 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
diff --git a/app/src/main/res/xml/lock_preferences.xml b/app/src/main/res/xml/lock_preferences.xml
new file mode 100644
index 00000000..9fed9fba
--- /dev/null
+++ b/app/src/main/res/xml/lock_preferences.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml
index 0ccfbbb2..5a802f27 100644
--- a/app/src/main/res/xml/root_preferences.xml
+++ b/app/src/main/res/xml/root_preferences.xml
@@ -2,6 +2,10 @@
+
+
@@ -24,6 +28,10 @@
+
+
@@ -34,6 +42,15 @@
+
+
+
+
+
+
diff --git a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt
index bc7c0d78..1b864d91 100644
--- a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt
+++ b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt
@@ -1,15 +1,24 @@
package xyz.quaver.hitomi
import org.junit.Test
-import java.io.File
-import java.net.URL
+import java.net.InetAddress
+import java.net.UnknownHostException
+
class UnitTest {
@Test
fun test() {
- val galleries = getGalleryIDsForQuery("series:touhou_project")
- println(galleries.size)
+ }
+
+ private fun getByIp(host: String): InetAddress {
+ try {
+ return InetAddress.getByName(host)
+ } catch (e: UnknownHostException) {
+ // unlikely
+ throw RuntimeException(e)
+ }
+
}
@Test