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"?>
<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" />
</component>
</project>

View File

@@ -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
targetSdkVersion 29
versionCode 17
versionName "2.9.1"
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')

View File

@@ -19,10 +19,3 @@
# 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

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
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>(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

View File

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

View File

@@ -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

View File

@@ -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<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.content.Intent
@@ -6,7 +6,6 @@ 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 +20,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 +40,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 +53,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,6 +68,12 @@ class MainActivity : AppCompatActivity() {
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
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 val SETTINGS = 45162
@@ -110,19 +119,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<SearchInputView>(R.id.search_bar_text).setText(query, TextView.BufferType.EDITABLE)
cancelFetch()
clearGalleries()
@@ -352,8 +353,7 @@ class MainActivity : AppCompatActivity() {
onChipClickedHandler.add {
runOnUiThread {
query = it.toQuery()
this@MainActivity.findViewById<SearchInputView>(R.id.search_bar_text)
.setText(query, TextView.BufferType.EDITABLE)
currentPage = 0
cancelFetch()
clearGalleries()
@@ -726,7 +726,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 +805,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 +883,8 @@ class MainActivity : AppCompatActivity() {
}
private fun cancelFetch() {
runBlocking {
galleryIDs?.cancelAndJoin()
loadingJob?.cancelAndJoin()
}
galleryIDs?.cancel()
loadingJob?.cancel()
}
private fun clearGalleries() {
@@ -992,7 +993,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 +1010,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 +1025,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))
}

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.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

View File

@@ -1,4 +1,4 @@
package xyz.quaver.pupil
package xyz.quaver.pupil.ui
import android.content.Intent
import android.graphics.drawable.Animatable
@@ -13,6 +13,7 @@ import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
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.*
@@ -27,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
@@ -71,6 +73,8 @@ class ReaderActivity : AppCompatActivity() {
handleIntent(intent)
Crashlytics.setInt("GalleryID", galleryBlock.id)
if (!::galleryBlock.isInitialized) {
onBackPressed()
return
@@ -116,7 +120,7 @@ class ReaderActivity : AppCompatActivity() {
} else {
galleryBlock = Json(JsonConfiguration.Stable).parse(
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.Environment
import android.preference.PreferenceManager
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
@@ -15,7 +13,10 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import io.fabric.sdk.android.BuildConfig
import kotlinx.android.synthetic.main.dialog_default_query.view.*
import xyz.quaver.pupil.R
import xyz.quaver.pupil.types.Tags
import java.io.File
@@ -58,7 +59,7 @@ class SettingsActivity : AppCompatActivity() {
"TB" //really?
)
private fun getCacheSize(dir: File) : String {
private fun getDirSize(dir: File) : String {
var size = dir.walk().map { it.length() }.sum()
var suffixIndex = 0
@@ -67,20 +68,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<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")) {
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 {
setTitle(R.string.warning)
setMessage(R.string.settings_clear_downloads_alert_message)
@@ -92,7 +126,7 @@ class SettingsActivity : AppCompatActivity() {
downloads.clear()
summary = getCacheSize(dir)
summary = getDirSize(dir)
}
setNegativeButton(android.R.string.no) { _, _ -> }
}.show()
@@ -107,7 +141,7 @@ class SettingsActivity : AppCompatActivity() {
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)
@@ -139,7 +173,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 +188,7 @@ class SettingsActivity : AppCompatActivity() {
with(dialogView.default_query_dialog_language_selector) {
adapter =
ArrayAdapter<String>(
ArrayAdapter(
context,
android.R.layout.simple_spinner_dropdown_item,
arrayListOf(
@@ -237,6 +271,9 @@ class SettingsActivity : AppCompatActivity() {
true
}
}
with(findPreference<Preference>("app_lock")) {
}
}
}

View File

@@ -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<Reader>
private val reader: Deferred<Reader>?
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)
}
}

View File

@@ -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")

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
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
}
}
}
}

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

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dark_gray"
tools:context=".ReaderActivity">
tools:context=".ui.ReaderActivity">
<LinearLayout
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_with_page">ギャラリー検索</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_galleries_per_page">一回にロードするギャラリー数</string>
<string name="settings_search_title">検索設定</string>
@@ -66,4 +67,7 @@
<string name="main_open_gallery_by_id_error">エラーが発生しました</string>
<string name="settings_storage">ストレージ</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>

View File

@@ -7,7 +7,8 @@
<string name="search_hint_with_page">갤러리 검색</string>
<string name="settings_default_query">기본 검색어</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_search_title">검색 설정</string>
<string name="settings_title">설정</string>
@@ -66,4 +67,7 @@
<string name="main_open_gallery_by_id_error">갤러리를 찾지 못했습니다</string>
<string name="settings_storage">저장 공간</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>

View File

@@ -80,17 +80,21 @@
<string name="reader_notification_error">Download error</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_galleries_per_page">Galleries per page</string>
<string name="settings_default_query">Default query</string>
<string name="settings_storage">Storage</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_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_alert_message">Do you want to clear histories?</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_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>

View File

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

View File

@@ -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