Migrate to Android 29

Re-Added Cache clear to prevent deleting downloading images
This commit is contained in:
tom5079
2019-06-23 00:23:17 +09:00
parent f303e49e97
commit 6d1505241e
30 changed files with 420 additions and 119 deletions

2
.idea/misc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8 (2)" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/classes" /> <output url="file://$PROJECT_DIR$/classes" />
</component> </component>
</project> </project>

View File

@@ -7,13 +7,13 @@ apply plugin: 'io.fabric'
apply plugin: 'com.google.firebase.firebase-perf' apply plugin: 'com.google.firebase.firebase-perf'
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
applicationId "xyz.quaver.pupil" applicationId "xyz.quaver.pupil"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 29
versionCode 17 versionCode 17
versionName "2.9.1" versionName "2.10-alpha"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
} }
@@ -42,17 +42,21 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.1.0-beta01' implementation 'androidx.preference:preference:1.1.0-beta01'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.firebase:firebase-core:16.0.9' implementation 'com.google.firebase:firebase-core:17.0.0'
implementation 'com.google.firebase:firebase-perf:17.0.2' implementation 'com.google.firebase:firebase-perf:18.0.1'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation 'com.github.arimorty:floatingsearchview:2.1.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.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "ru.noties.markwon:core:${markwonVersion}" implementation "ru.noties.markwon:core:${markwonVersion}"
implementation 'com.github.clans:fab:1.6.4' 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' testImplementation 'junit:junit:4.12'
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: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') implementation project(path: ':libpupil')

View File

@@ -18,11 +18,4 @@
# If you keep the line number information, uncomment this to # If you keep the line number information, uncomment this to
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
-keep class com.finotes.android.finotescore.* { *; }
-keepclassmembers class * {
@com.finotes.android.finotescore.annotation.Observe *;
}
-keepattributes SourceFile,LineNumberTable

View File

@@ -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":{}}] [{"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":{}}]

View File

@@ -1,16 +1,18 @@
package xyz.quaver.pupil package xyz.quaver.pupil
import android.graphics.BitmapFactory import android.content.Intent
import android.util.Log import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import xyz.quaver.hiyobi.cookie import xyz.quaver.hiyobi.cookie
import xyz.quaver.hiyobi.getReader import xyz.quaver.hiyobi.getReader
import xyz.quaver.hiyobi.user_agent import xyz.quaver.hiyobi.user_agent
import java.io.File import xyz.quaver.pupil.ui.LockActivity
import java.net.URL import java.net.URL
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
@@ -21,6 +23,7 @@ import javax.net.ssl.HttpsURLConnection
*/ */
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest { class ExampleInstrumentedTest {
@Test @Test
fun useAppContext() { fun useAppContext() {
// Context of the app under test. // Context of the app under test.
@@ -30,12 +33,12 @@ class ExampleInstrumentedTest {
@Test @Test
fun checkCacheDir() { fun checkCacheDir() {
val activityTestRule = ActivityTestRule<LockActivity>(LockActivity::class.java)
val appContext = InstrumentationRegistry.getInstrumentation().targetContext 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 @Test

View File

@@ -6,20 +6,19 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:name=".ui.Pupil"
android:allowBackup="true" android:allowBackup="true"
android:fullBackupContent="true" android:fullBackupContent="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme">
android:name=".Pupil"> <activity android:name=".ui.LockActivity"/>
<activity <activity
android:name=".ReaderActivity" android:name=".ui.ReaderActivity"
android:parentActivityName=".MainActivity" android:configChanges="keyboardHidden|orientation|screenSize"
android:configChanges="keyboardHidden|orientation|screenSize"> android:parentActivityName=".ui.MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -27,9 +26,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="hitomi.la" android:host="hitomi.la"
android:pathPrefix="/galleries" /> android:pathPrefix="/galleries"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -38,9 +37,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="히요비.asia" android:host="히요비.asia"
android:pathPrefix="/reader" /> android:pathPrefix="/reader"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -49,9 +48,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="xn--9w3b15m8vo.asia" android:host="xn--9w3b15m8vo.asia"
android:pathPrefix="/reader" /> android:pathPrefix="/reader"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -60,9 +59,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="e-hentai.org" android:host="e-hentai.org"
android:pathPrefix="/g" /> android:pathPrefix="/g"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -71,9 +70,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="http"
android:host="hitomi.la" android:host="hitomi.la"
android:pathPrefix="/galleries" /> android:pathPrefix="/galleries"
android:scheme="http" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -82,9 +81,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="http"
android:host="히요비.asia" android:host="히요비.asia"
android:pathPrefix="/reader" /> android:pathPrefix="/reader"
android:scheme="http" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -93,9 +92,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="http"
android:host="xn--9w3b15m8vo.asia" android:host="xn--9w3b15m8vo.asia"
android:pathPrefix="/reader" /> android:pathPrefix="/reader"
android:scheme="http" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@@ -104,16 +103,16 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="http"
android:host="e-hentai.org" android:host="e-hentai.org"
android:pathPrefix="/g" /> android:pathPrefix="/g"
android:scheme="http" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".SettingsActivity" android:name=".ui.SettingsActivity"
android:label="@string/settings_title" /> android:label="@string/settings_title" />
<activity <activity
android:name=".MainActivity" android:name=".ui.MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/NoActionBarAppTheme"> android:theme="@style/NoActionBarAppTheme">
<intent-filter> <intent-filter>

View File

@@ -24,7 +24,7 @@ import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.list import kotlinx.serialization.list
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.ReaderItem 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.R
import xyz.quaver.pupil.types.Tag import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.Histories import xyz.quaver.pupil.util.Histories

View File

@@ -6,9 +6,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import xyz.quaver.pupil.R import xyz.quaver.pupil.R
class ReaderAdapter(private val images: List<String>) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() { class ReaderAdapter(private val images: List<String>) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {

View File

@@ -0,0 +1,29 @@
package xyz.quaver.pupil.ui
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_lock.*
import xyz.quaver.pupil.R
class LockActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lock)
supportFragmentManager.beginTransaction().add(
R.id.lock_content,
PatternLockFragment().apply {
onPatternDrawn = {
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
}
}
).commit()
lock_pattern.isEnabled = false
lock_fingerprint.isEnabled = false
lock_password.isEnabled = false
}
}

View File

@@ -1,4 +1,4 @@
package xyz.quaver.pupil package xyz.quaver.pupil.ui
import android.Manifest import android.Manifest
import android.content.Intent import android.content.Intent
@@ -6,7 +6,6 @@ import android.content.pm.PackageManager
import android.graphics.drawable.Animatable import android.graphics.drawable.Animatable
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.text.* import android.text.*
import android.text.style.AlignmentSpan import android.text.style.AlignmentSpan
import android.view.* import android.view.*
@@ -21,6 +20,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.preference.PreferenceManager
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.arlib.floatingsearchview.FloatingSearchView import com.arlib.floatingsearchview.FloatingSearchView
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
@@ -40,6 +40,8 @@ import kotlinx.serialization.list
import kotlinx.serialization.stringify import kotlinx.serialization.stringify
import ru.noties.markwon.Markwon import ru.noties.markwon.Markwon
import xyz.quaver.hitomi.* import xyz.quaver.hitomi.*
import xyz.quaver.pupil.BuildConfig
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.Tag
import xyz.quaver.pupil.types.TagSuggestion import xyz.quaver.pupil.types.TagSuggestion
@@ -51,6 +53,7 @@ import java.net.URL
import java.util.* import java.util.*
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@@ -65,6 +68,12 @@ class MainActivity : AppCompatActivity() {
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>() private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
private var query = "" private var query = ""
set(value) {
field = value
findViewById<SearchInputView>(R.id.search_bar_text)
.setText(query, TextView.BufferType.EDITABLE)
}
private var mode = Mode.SEARCH private var mode = Mode.SEARCH
private val SETTINGS = 45162 private val SETTINGS = 45162
@@ -110,19 +119,11 @@ class MainActivity : AppCompatActivity() {
initView() initView()
} }
override fun onDestroy() {
super.onDestroy()
if (cacheDir.exists())
cacheDir.deleteRecursively()
}
override fun onBackPressed() { override fun onBackPressed() {
when { when {
main_drawer_layout.isDrawerOpen(GravityCompat.START) -> main_drawer_layout.closeDrawer(GravityCompat.START) main_drawer_layout.isDrawerOpen(GravityCompat.START) -> main_drawer_layout.closeDrawer(GravityCompat.START)
query.isNotEmpty() -> runOnUiThread { query.isNotEmpty() -> runOnUiThread {
query = "" query = ""
findViewById<SearchInputView>(R.id.search_bar_text).setText(query, TextView.BufferType.EDITABLE)
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
@@ -352,8 +353,7 @@ class MainActivity : AppCompatActivity() {
onChipClickedHandler.add { onChipClickedHandler.add {
runOnUiThread { runOnUiThread {
query = it.toQuery() query = it.toQuery()
this@MainActivity.findViewById<SearchInputView>(R.id.search_bar_text) currentPage = 0
.setText(query, TextView.BufferType.EDITABLE)
cancelFetch() cancelFetch()
clearGalleries() clearGalleries()
@@ -726,7 +726,8 @@ class MainActivity : AppCompatActivity() {
startActivity(intent) startActivity(intent)
} catch (e: Exception) { } 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 +805,9 @@ class MainActivity : AppCompatActivity() {
favorites.remove(tag) favorites.remove(tag)
} }
else { else {
setImageDrawable(AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star)) setImageDrawable(AnimatedVectorDrawableCompat.create(context,
R.drawable.avd_star
))
(drawable as Animatable).start() (drawable as Animatable).start()
favorites.add(tag) favorites.add(tag)
@@ -880,10 +883,8 @@ class MainActivity : AppCompatActivity() {
} }
private fun cancelFetch() { private fun cancelFetch() {
runBlocking { galleryIDs?.cancel()
galleryIDs?.cancelAndJoin() loadingJob?.cancel()
loadingJob?.cancelAndJoin()
}
} }
private fun clearGalleries() { private fun clearGalleries() {
@@ -992,7 +993,7 @@ class MainActivity : AppCompatActivity() {
query.isEmpty() and defaultQuery.isEmpty() and (mode == Mode.SEARCH) -> query.isEmpty() and defaultQuery.isEmpty() and (mode == Mode.SEARCH) ->
galleryIDs galleryIDs
else -> 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 -> }.chunked(5).let { chunks ->
for (chunk in chunks) for (chunk in chunks)
chunk.map { galleryID -> chunk.map { galleryID ->
@@ -1009,8 +1010,8 @@ class MainActivity : AppCompatActivity() {
getGalleryBlock(galleryID).apply { getGalleryBlock(galleryID).apply {
this ?: return@apply this ?: return@apply
if (!cache.parentFile.exists()) if (cache.parentFile?.exists() == false)
cache.parentFile.mkdirs() cache.parentFile!!.mkdirs()
cache.writeText(json.stringify(serializer, this)) cache.writeText(json.stringify(serializer, this))
} }
@@ -1024,8 +1025,8 @@ class MainActivity : AppCompatActivity() {
if (!exists()) if (!exists())
try { try {
with(URL(galleryBlock.thumbnails[0]).openConnection() as HttpsURLConnection) { with(URL(galleryBlock.thumbnails[0]).openConnection() as HttpsURLConnection) {
if (!this@apply.parentFile.exists()) if (this@apply.parentFile?.exists() == false)
this@apply.parentFile.mkdirs() this@apply.parentFile!!.mkdirs()
inputStream.copyTo(FileOutputStream(this@apply)) inputStream.copyTo(FileOutputStream(this@apply))
} }

View File

@@ -0,0 +1,46 @@
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
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<PatternLockView.Dot>?) {
val password = PatternLockUtils.patternToMD5(lock_pattern_view, pattern)
onPatternDrawn?.invoke(hash(password))
}
override fun onProgress(progressPattern: MutableList<PatternLockView.Dot>?) {
}
override fun onStarted() {
}
}

View File

@@ -1,14 +1,14 @@
package xyz.quaver.pupil package xyz.quaver.pupil.ui
import android.app.Application
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.preference.PreferenceManager
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.multidex.MultiDexApplication import androidx.multidex.MultiDexApplication
import androidx.preference.PreferenceManager
import xyz.quaver.pupil.R
import xyz.quaver.pupil.util.Histories import xyz.quaver.pupil.util.Histories
import java.io.File import java.io.File

View File

@@ -1,4 +1,4 @@
package xyz.quaver.pupil package xyz.quaver.pupil.ui
import android.content.Intent import android.content.Intent
import android.graphics.drawable.Animatable import android.graphics.drawable.Animatable
@@ -13,6 +13,7 @@ import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.vectordrawable.graphics.drawable.Animatable2Compat import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.crashlytics.android.Crashlytics
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.android.synthetic.main.activity_reader.*
import kotlinx.android.synthetic.main.activity_reader.view.* import kotlinx.android.synthetic.main.activity_reader.view.*
@@ -27,6 +28,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.json.JsonConfiguration
import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.getGalleryBlock import xyz.quaver.hitomi.getGalleryBlock
import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.ReaderAdapter import xyz.quaver.pupil.adapters.ReaderAdapter
import xyz.quaver.pupil.util.GalleryDownloader import xyz.quaver.pupil.util.GalleryDownloader
import xyz.quaver.pupil.util.Histories import xyz.quaver.pupil.util.Histories
@@ -71,6 +73,8 @@ class ReaderActivity : AppCompatActivity() {
handleIntent(intent) handleIntent(intent)
Crashlytics.setInt("GalleryID", galleryBlock.id)
if (!::galleryBlock.isInitialized) { if (!::galleryBlock.isInitialized) {
onBackPressed() onBackPressed()
return return
@@ -116,7 +120,7 @@ class ReaderActivity : AppCompatActivity() {
} else { } else {
galleryBlock = Json(JsonConfiguration.Stable).parse( galleryBlock = Json(JsonConfiguration.Stable).parse(
GalleryBlock.serializer(), GalleryBlock.serializer(),
intent.getStringExtra("galleryblock") intent.getStringExtra("galleryblock")!!
) )
} }
} }

View File

@@ -1,8 +1,6 @@
package xyz.quaver.pupil package xyz.quaver.pupil.ui
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.preference.PreferenceManager
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -15,7 +13,10 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import io.fabric.sdk.android.BuildConfig
import kotlinx.android.synthetic.main.dialog_default_query.view.* import kotlinx.android.synthetic.main.dialog_default_query.view.*
import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tags import xyz.quaver.pupil.types.Tags
import java.io.File import java.io.File
@@ -58,7 +59,7 @@ class SettingsActivity : AppCompatActivity() {
"TB" //really? "TB" //really?
) )
private fun getCacheSize(dir: File) : String { private fun getDirSize(dir: File) : String {
var size = dir.walk().map { it.length() }.sum() var size = dir.walk().map { it.length() }.sum()
var suffixIndex = 0 var suffixIndex = 0
@@ -67,20 +68,53 @@ class SettingsActivity : AppCompatActivity() {
suffixIndex++ 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?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey) setPreferencesFromResource(R.xml.root_preferences, rootKey)
with(findPreference<Preference>("app_version")) {
this ?: return@with
val manager = context.packageManager
val info = manager.getPackageInfo(context.packageName, 0)
summary = info.versionName
}
with(findPreference<Preference>("delete_cache")) {
this ?: return@with
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<Preference>("delete_downloads")) { with(findPreference<Preference>("delete_downloads")) {
this ?: return@with this ?: return@with
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 { AlertDialog.Builder(context).apply {
setTitle(R.string.warning) setTitle(R.string.warning)
setMessage(R.string.settings_clear_downloads_alert_message) setMessage(R.string.settings_clear_downloads_alert_message)
@@ -92,7 +126,7 @@ class SettingsActivity : AppCompatActivity() {
downloads.clear() downloads.clear()
summary = getCacheSize(dir) summary = getDirSize(dir)
} }
setNegativeButton(android.R.string.no) { _, _ -> } setNegativeButton(android.R.string.no) { _, _ -> }
}.show() }.show()
@@ -107,7 +141,7 @@ class SettingsActivity : AppCompatActivity() {
summary = getString(R.string.settings_clear_history_summary, histories.size) summary = getString(R.string.settings_clear_history_summary, histories.size)
setOnPreferenceClickListener { onPreferenceClickListener = Preference.OnPreferenceClickListener {
AlertDialog.Builder(context).apply { AlertDialog.Builder(context).apply {
setTitle(R.string.warning) setTitle(R.string.warning)
setMessage(R.string.settings_clear_history_alert_message) setMessage(R.string.settings_clear_history_alert_message)
@@ -139,7 +173,7 @@ class SettingsActivity : AppCompatActivity() {
val excludeBL = "-male:yaoi" val excludeBL = "-male:yaoi"
val excludeGuro = listOf("-female:guro", "-male:guro") val excludeGuro = listOf("-female:guro", "-male:guro")
setOnPreferenceClickListener { onPreferenceClickListener = Preference.OnPreferenceClickListener {
val dialogView = LayoutInflater.from(context).inflate( val dialogView = LayoutInflater.from(context).inflate(
R.layout.dialog_default_query, R.layout.dialog_default_query,
LinearLayout(context), LinearLayout(context),
@@ -154,7 +188,7 @@ class SettingsActivity : AppCompatActivity() {
with(dialogView.default_query_dialog_language_selector) { with(dialogView.default_query_dialog_language_selector) {
adapter = adapter =
ArrayAdapter<String>( ArrayAdapter(
context, context,
android.R.layout.simple_spinner_dropdown_item, android.R.layout.simple_spinner_dropdown_item,
arrayListOf( arrayListOf(
@@ -237,6 +271,9 @@ class SettingsActivity : AppCompatActivity() {
true true
} }
} }
with(findPreference<Preference>("app_lock")) {
}
} }
} }

View File

@@ -4,7 +4,7 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import android.os.Environment import android.util.Log
import android.util.SparseArray import android.util.SparseArray
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
@@ -18,9 +18,9 @@ import kotlinx.serialization.list
import xyz.quaver.hitomi.* import xyz.quaver.hitomi.*
import xyz.quaver.hiyobi.cookie import xyz.quaver.hiyobi.cookie
import xyz.quaver.hiyobi.user_agent 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.R
import xyz.quaver.pupil.ReaderActivity import xyz.quaver.pupil.ui.ReaderActivity
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.net.URL import java.net.URL
@@ -52,7 +52,7 @@ class GalleryDownloader(
cache.deleteRecursively() cache.deleteRecursively()
} }
if (!reader.isActive && downloadJob?.isActive != true) if (reader?.isActive == false && downloadJob?.isActive != true)
field = false field = false
downloads.add(galleryBlock.id) downloads.add(galleryBlock.id)
@@ -63,7 +63,7 @@ class GalleryDownloader(
onNotifyChangedHandler?.invoke(value) onNotifyChangedHandler?.invoke(value)
} }
private val reader: Deferred<Reader> private val reader: Deferred<Reader>?
private var downloadJob: Job? = null private var downloadJob: Job? = null
private lateinit var notificationBuilder: NotificationCompat.Builder private lateinit var notificationBuilder: NotificationCompat.Builder
@@ -126,8 +126,8 @@ class GalleryDownloader(
if (reader.isNotEmpty()) { if (reader.isNotEmpty()) {
//Save cache //Save cache
if (!cache.parentFile.exists()) if (cache.parentFile?.exists() == false)
cache.parentFile.mkdirs() cache.parentFile!!.mkdirs()
cache.writeText(json.stringify(serializer, reader)) cache.writeText(json.stringify(serializer, reader))
} }
@@ -140,7 +140,7 @@ class GalleryDownloader(
fun start() { fun start() {
downloadJob = CoroutineScope(Dispatchers.Default).launch { downloadJob = CoroutineScope(Dispatchers.Default).launch {
val reader = reader.await() val reader = reader!!.await()
if (reader.isEmpty()) if (reader.isEmpty())
onErrorHandler?.invoke(IOException("Couldn't retrieve Reader")) onErrorHandler?.invoke(IOException("Couldn't retrieve Reader"))
@@ -183,8 +183,8 @@ class GalleryDownloader(
} else } else
setRequestProperty("Referer", getReferer(galleryBlock.id)) setRequestProperty("Referer", getReferer(galleryBlock.id))
if (!cache.parentFile.exists()) if (cache.parentFile?.exists() == false)
cache.parentFile.mkdirs() cache.parentFile!!.mkdirs()
inputStream.copyTo(FileOutputStream(cache)) inputStream.copyTo(FileOutputStream(cache))
} }
@@ -209,8 +209,6 @@ class GalleryDownloader(
} }
} }
onCompleteHandler?.invoke()
Timer(false).schedule(1000) { Timer(false).schedule(1000) {
notificationBuilder notificationBuilder
.setContentTitle(galleryBlock.title) .setContentTitle(galleryBlock.title)
@@ -220,7 +218,7 @@ class GalleryDownloader(
if (download) { if (download) {
File(cacheDir, "imageCache/${galleryBlock.id}").let { File(cacheDir, "imageCache/${galleryBlock.id}").let {
if (it.exists()) { if (it.exists()) {
val target = File(Environment.getExternalStorageDirectory(), "Pupil/${galleryBlock.id}") val target = File(getExternalFilesDir("Pupil"), galleryBlock.id.toString())
if (!target.exists()) if (!target.exists())
target.mkdirs() target.mkdirs()
@@ -231,9 +229,11 @@ class GalleryDownloader(
} }
notificationManager.notify(galleryBlock.id, notificationBuilder.build()) notificationManager.notify(galleryBlock.id, notificationBuilder.build())
}
download = false onCompleteHandler?.invoke()
download = false
}
} }
remove(galleryBlock.id) remove(galleryBlock.id)
@@ -254,7 +254,7 @@ class GalleryDownloader(
fun invokeOnReaderLoaded() { fun invokeOnReaderLoaded() {
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {
onReaderLoadedHandler?.invoke(reader.await()) onReaderLoadedHandler?.invoke(reader?.await() ?: return@launch)
} }
} }

View File

@@ -2,10 +2,11 @@ package xyz.quaver.pupil.util
import android.content.Context import android.content.Context
import android.os.Environment import android.os.Environment
import android.provider.MediaStore
import java.io.File import java.io.File
fun getCachedGallery(context: Context, galleryID: Int): File { fun getCachedGallery(context: Context, galleryID: Int): File {
return File(Environment.getExternalStorageDirectory(), "Pupil/$galleryID").let { return File(context.getExternalFilesDir("Pupil"), galleryID.toString()).let {
when { when {
it.exists() -> it it.exists() -> it
else -> File(context.cacheDir, "imageCache/$galleryID") else -> File(context.cacheDir, "imageCache/$galleryID")

View File

@@ -0,0 +1,39 @@
package xyz.quaver.pupil.util
import android.content.Context
import android.content.ContextWrapper
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<String, String> {
val salt = (0 until 12).map { source.random() }.joinToString()
return Pair(hash(password+salt), salt)
}
val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
data class Lock(private val type: Type, private val hash: String, private val salt: String) {
enum class Type {
PATTERN
}
fun match(password: String): Boolean {
return hash(password+salt) == hash
}
}
class LockManager(base: Context): ContextWrapper(base) {
}

View File

@@ -1,5 +1,6 @@
package xyz.quaver.pupil.util package xyz.quaver.pupil.util
import android.util.Log
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import java.net.URL import java.net.URL
@@ -19,8 +20,20 @@ fun checkUpdate(url: String, currentVersion: String) : JsonObject? {
if (releases.isEmpty()) if (releases.isEmpty())
return null return null
if (currentVersion != releases[0].jsonObject["tag_name"]?.content) val latestVersion = releases[0].jsonObject["tag_name"]?.content
return releases[0].jsonObject
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
}
}
}
} }

View File

@@ -0,0 +1,8 @@
<!-- drawable/fingerprint.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="#000" android:pathData="M17.81,4.47C17.73,4.47 17.65,4.45 17.58,4.41C15.66,3.42 14,3 12,3C10.03,3 8.15,3.47 6.44,4.41C6.2,4.54 5.9,4.45 5.76,4.21C5.63,3.97 5.72,3.66 5.96,3.53C7.82,2.5 9.86,2 12,2C14.14,2 16,2.47 18.04,3.5C18.29,3.65 18.38,3.95 18.25,4.19C18.16,4.37 18,4.47 17.81,4.47M3.5,9.72C3.4,9.72 3.3,9.69 3.21,9.63C3,9.47 2.93,9.16 3.09,8.93C4.08,7.53 5.34,6.43 6.84,5.66C10,4.04 14,4.03 17.15,5.65C18.65,6.42 19.91,7.5 20.9,8.9C21.06,9.12 21,9.44 20.78,9.6C20.55,9.76 20.24,9.71 20.08,9.5C19.18,8.22 18.04,7.23 16.69,6.54C13.82,5.07 10.15,5.07 7.29,6.55C5.93,7.25 4.79,8.25 3.89,9.5C3.81,9.65 3.66,9.72 3.5,9.72M9.75,21.79C9.62,21.79 9.5,21.74 9.4,21.64C8.53,20.77 8.06,20.21 7.39,19C6.7,17.77 6.34,16.27 6.34,14.66C6.34,11.69 8.88,9.27 12,9.27C15.12,9.27 17.66,11.69 17.66,14.66A0.5,0.5 0 0,1 17.16,15.16A0.5,0.5 0 0,1 16.66,14.66C16.66,12.24 14.57,10.27 12,10.27C9.43,10.27 7.34,12.24 7.34,14.66C7.34,16.1 7.66,17.43 8.27,18.5C8.91,19.66 9.35,20.15 10.12,20.93C10.31,21.13 10.31,21.44 10.12,21.64C10,21.74 9.88,21.79 9.75,21.79M16.92,19.94C15.73,19.94 14.68,19.64 13.82,19.05C12.33,18.04 11.44,16.4 11.44,14.66A0.5,0.5 0 0,1 11.94,14.16A0.5,0.5 0 0,1 12.44,14.66C12.44,16.07 13.16,17.4 14.38,18.22C15.09,18.7 15.92,18.93 16.92,18.93C17.16,18.93 17.56,18.9 17.96,18.83C18.23,18.78 18.5,18.96 18.54,19.24C18.59,19.5 18.41,19.77 18.13,19.82C17.56,19.93 17.06,19.94 16.92,19.94M14.91,22C14.87,22 14.82,22 14.78,22C13.19,21.54 12.15,20.95 11.06,19.88C9.66,18.5 8.89,16.64 8.89,14.66C8.89,13.04 10.27,11.72 11.97,11.72C13.67,11.72 15.05,13.04 15.05,14.66C15.05,15.73 16,16.6 17.13,16.6C18.28,16.6 19.21,15.73 19.21,14.66C19.21,10.89 15.96,7.83 11.96,7.83C9.12,7.83 6.5,9.41 5.35,11.86C4.96,12.67 4.76,13.62 4.76,14.66C4.76,15.44 4.83,16.67 5.43,18.27C5.53,18.53 5.4,18.82 5.14,18.91C4.88,19 4.59,18.87 4.5,18.62C4,17.31 3.77,16 3.77,14.66C3.77,13.46 4,12.37 4.45,11.42C5.78,8.63 8.73,6.82 11.96,6.82C16.5,6.82 20.21,10.33 20.21,14.65C20.21,16.27 18.83,17.59 17.13,17.59C15.43,17.59 14.05,16.27 14.05,14.65C14.05,13.58 13.12,12.71 11.97,12.71C10.82,12.71 9.89,13.58 9.89,14.65C9.89,16.36 10.55,17.96 11.76,19.16C12.71,20.1 13.62,20.62 15.03,21C15.3,21.08 15.45,21.36 15.38,21.62C15.33,21.85 15.12,22 14.91,22Z" />
</vector>

View File

@@ -0,0 +1,8 @@
<!-- drawable/lastpass.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="#000" android:pathData="M14,12A2,2 0 0,1 16,10A2,2 0 0,1 18,12A2,2 0 0,1 16,14A2,2 0 0,1 14,12M8,12A2,2 0 0,1 10,10A2,2 0 0,1 12,12A2,2 0 0,1 10,14A2,2 0 0,1 8,12M2,12A2,2 0 0,1 4,10A2,2 0 0,1 6,12A2,2 0 0,1 4,14A2,2 0 0,1 2,12M22,5H20V19H22V5Z" />
</vector>

View File

@@ -0,0 +1,8 @@
<!-- drawable/lock_pattern.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="#000" android:pathData="M7,3A4,4 0 0,1 11,7C11,8.86 9.73,10.43 8,10.87V13.13C8.37,13.22 8.72,13.37 9.04,13.56L13.56,9.04C13.2,8.44 13,7.75 13,7A4,4 0 0,1 17,3A4,4 0 0,1 21,7A4,4 0 0,1 17,11C16.26,11 15.57,10.8 15,10.45L10.45,15C10.8,15.57 11,16.26 11,17A4,4 0 0,1 7,21A4,4 0 0,1 3,17C3,15.14 4.27,13.57 6,13.13V10.87C4.27,10.43 3,8.86 3,7A4,4 0 0,1 7,3M17,13A4,4 0 0,1 21,17A4,4 0 0,1 17,21A4,4 0 0,1 13,17A4,4 0 0,1 17,13M17,15A2,2 0 0,0 15,17A2,2 0 0,0 17,19A2,2 0 0,0 19,17A2,2 0 0,0 17,15Z" />
</vector>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.LockActivity">
<FrameLayout
android:id="@+id/lock_content"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/lock_button_layout"/>
<LinearLayout
android:id="@+id/lock_button_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="32dp"
app:layout_constraintTop_toBottomOf="@id/lock_content"
app:layout_constraintBottom_toBottomOf="parent"
android:gravity="center">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/lock_pattern"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/lock_pattern"
app:backgroundTint="@color/colorPrimary"
app:fabSize="mini"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/lock_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/fingerprint"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:backgroundTint="@color/dark_gray"
app:fabSize="mini"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/lock_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/lastpass"
app:backgroundTint="@color/dark_gray"
app:fabSize="mini"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -6,7 +6,7 @@
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"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> tools:context=".ui.MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/dark_gray" android:background="@color/dark_gray"
tools:context=".ReaderActivity"> tools:context=".ui.ReaderActivity">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ui.PatternLockFragment">
<com.andrognito.patternlockview.PatternLockView
android:id="@+id/lock_pattern_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
app:aspectRatioEnabled="true"
app:normalStateColor="@color/colorPrimary"
app:correctStateColor="@color/colorPrimaryDark"
app:wrongStateColor="@color/colorAccent"/>
</FrameLayout>

View File

@@ -8,7 +8,8 @@
<string name="search_hint">ギャラリー検索</string> <string name="search_hint">ギャラリー検索</string>
<string name="search_hint_with_page">ギャラリー検索</string> <string name="search_hint_with_page">ギャラリー検索</string>
<string name="settings_clear_image_cache">イメージキャッシュクリア</string> <string name="settings_clear_image_cache">イメージキャッシュクリア</string>
<string name="settings_clear_downloads_summary">サイズ: %1$d%2$s</string> <string name="settings_clear_cache_alert_message">キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?</string>
<string name="settings_clear_summary">サイズ: %1$d%2$s</string>
<string name="settings_default_query">デフォルトキーワード</string> <string name="settings_default_query">デフォルトキーワード</string>
<string name="settings_galleries_per_page">一回にロードするギャラリー数</string> <string name="settings_galleries_per_page">一回にロードするギャラリー数</string>
<string name="settings_search_title">検索設定</string> <string name="settings_search_title">検索設定</string>
@@ -66,4 +67,7 @@
<string name="main_open_gallery_by_id_error">エラーが発生しました</string> <string name="main_open_gallery_by_id_error">エラーが発生しました</string>
<string name="settings_storage">ストレージ</string> <string name="settings_storage">ストレージ</string>
<string name="main_drawer_grouop_contact_kakaotalk">カカオトーク</string> <string name="main_drawer_grouop_contact_kakaotalk">カカオトーク</string>
<string name="settings_app_lock">アプリロック</string>
<string name="settings_app_lock_type">アップロックの種類</string>
<string name="settings_app_version_title">バージョン</string>
</resources> </resources>

View File

@@ -7,7 +7,8 @@
<string name="search_hint_with_page">갤러리 검색</string> <string name="search_hint_with_page">갤러리 검색</string>
<string name="settings_default_query">기본 검색어</string> <string name="settings_default_query">기본 검색어</string>
<string name="settings_clear_image_cache">이미지 캐시 정리하기</string> <string name="settings_clear_image_cache">이미지 캐시 정리하기</string>
<string name="settings_clear_downloads_summary">사용량: %1$d%2$s</string> <string name="settings_clear_cache_alert_message">캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?</string>
<string name="settings_clear_summary">사용량: %1$d%2$s</string>
<string name="settings_galleries_per_page">한 번에 로드할 갤러리 수</string> <string name="settings_galleries_per_page">한 번에 로드할 갤러리 수</string>
<string name="settings_search_title">검색 설정</string> <string name="settings_search_title">검색 설정</string>
<string name="settings_title">설정</string> <string name="settings_title">설정</string>
@@ -66,4 +67,7 @@
<string name="main_open_gallery_by_id_error">갤러리를 찾지 못했습니다</string> <string name="main_open_gallery_by_id_error">갤러리를 찾지 못했습니다</string>
<string name="settings_storage">저장 공간</string> <string name="settings_storage">저장 공간</string>
<string name="main_drawer_grouop_contact_kakaotalk">카카오톡 오픈채팅방</string> <string name="main_drawer_grouop_contact_kakaotalk">카카오톡 오픈채팅방</string>
<string name="settings_app_lock">앱 잠금</string>
<string name="settings_app_lock_type">앱 잠금 종류</string>
<string name="settings_app_version_title">앱 버전</string>
</resources> </resources>

View File

@@ -80,17 +80,21 @@
<string name="reader_notification_error">Download error</string> <string name="reader_notification_error">Download error</string>
<string name="settings_title">Settings</string> <string name="settings_title">Settings</string>
<string name="settings_app_version_title">App version</string>
<string name="settings_search_title">Search Settings</string> <string name="settings_search_title">Search Settings</string>
<string name="settings_galleries_per_page">Galleries per page</string> <string name="settings_galleries_per_page">Galleries per page</string>
<string name="settings_default_query">Default query</string> <string name="settings_default_query">Default query</string>
<string name="settings_storage">Storage</string> <string name="settings_storage">Storage</string>
<string name="settings_clear_image_cache">Clear image cache</string> <string name="settings_clear_image_cache">Clear image cache</string>
<string name="settings_clear_downloads_summary">Currently using %1$d%2$s</string> <string name="settings_clear_cache_alert_message">Deleting cache can affect image loading speed. Do you want to continue?</string>
<string name="settings_clear_summary">Currently using %1$d%2$s</string>
<string name="settings_clear_downloads">Clear downloads</string> <string name="settings_clear_downloads">Clear downloads</string>
<string name="settings_clear_downloads_alert_message">Delete all downloaded galleries.\nDo you want to continue?</string> <string name="settings_clear_downloads_alert_message">Delete all downloaded galleries.\nDo you want to continue?</string>
<string name="settings_clear_history">Clear history</string> <string name="settings_clear_history">Clear history</string>
<string name="settings_clear_history_alert_message">Do you want to clear histories?</string> <string name="settings_clear_history_alert_message">Do you want to clear histories?</string>
<string name="settings_clear_history_summary">%1$d histories saved</string> <string name="settings_clear_history_summary">%1$d histories saved</string>
<string name="settings_app_lock">App lock</string>
<string name="settings_app_lock_type">App lock type</string>
<string name="settings_miscellaneous_title">Miscellaneous</string> <string name="settings_miscellaneous_title">Miscellaneous</string>
<string name="settings_use_hiyobi_title">Use hiyobi.me</string> <string name="settings_use_hiyobi_title">Use hiyobi.me</string>
<string name="settings_use_hiyobi_summary">Load images from hiyobi.me to improve loading speed (if available)</string> <string name="settings_use_hiyobi_summary">Load images from hiyobi.me to improve loading speed (if available)</string>

View File

@@ -2,6 +2,10 @@
<androidx.preference.PreferenceScreen <androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:title="@string/settings_app_version_title"
app:key="app_version"/>
<PreferenceCategory <PreferenceCategory
app:title="@string/settings_search_title"> app:title="@string/settings_search_title">
@@ -24,6 +28,10 @@
<PreferenceCategory <PreferenceCategory
app:title="@string/settings_storage"> app:title="@string/settings_storage">
<Preference
app:title="Clear cache"
app:key="delete_cache"/>
<Preference <Preference
app:title="@string/settings_clear_downloads" app:title="@string/settings_clear_downloads"
app:key="delete_downloads"/> app:key="delete_downloads"/>
@@ -34,6 +42,15 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory
app:title="@string/settings_app_lock">
<Preference
app:title="@string/settings_app_lock_type"
app:key="app_lock"/>
</PreferenceCategory>
<PreferenceCategory <PreferenceCategory
app:title="@string/settings_miscellaneous_title"> app:title="@string/settings_miscellaneous_title">

View File

@@ -1,15 +1,24 @@
package xyz.quaver.hitomi package xyz.quaver.hitomi
import org.junit.Test import org.junit.Test
import java.io.File import java.net.InetAddress
import java.net.URL import java.net.UnknownHostException
class UnitTest { class UnitTest {
@Test @Test
fun 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 @Test