diff --git a/app/build.gradle b/app/build.gradle index bd3755c2..415b38c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'kotlinx-serialization' if (file("google-services.json").exists() && file("src/debug/google-services.json").exists()) { logger.lifecycle("Firebase Enabled") apply plugin: 'com.google.gms.google-services' - apply plugin: 'io.fabric' + apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.firebase-perf' } else { logger.lifecycle("Firebase Disabled") @@ -19,8 +19,8 @@ android { applicationId "xyz.quaver.pupil" minSdkVersion 16 targetSdkVersion 29 - versionCode 52 - versionName "4.17" + versionCode 53 + versionName "4.18" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true @@ -50,12 +50,12 @@ android { } dependencies { - def markwonVersion = "3.0.1" + def markwonVersion = '3.1.0' - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' @@ -66,8 +66,9 @@ dependencies { implementation "com.daimajia.swipelayout:library:1.2.0@aar" implementation 'com.google.android.material:material:1.3.0-alpha01' implementation 'com.google.firebase:firebase-core:17.4.3' + implementation 'com.google.firebase:firebase-analytics:17.4.3' + implementation 'com.google.firebase:firebase-crashlytics:17.1.0' implementation 'com.google.firebase:firebase-perf:19.0.7' - implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.github.arimorty:floatingsearchview:2.1.1' implementation 'com.github.clans:fab:1.6.4' implementation 'com.github.bumptech.glide:glide:4.11.0' @@ -79,6 +80,7 @@ dependencies { implementation 'net.rdrei.android.dirchooser:library:3.2@aar' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.andrognito.patternlockview:patternlockview:1.0.0' + //implementation 'com.andrognito.pinlockview:pinlockview:2.1.0' implementation "ru.noties.markwon:core:${markwonVersion}" testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test.ext:junit:1.1.1' diff --git a/app/libs/pinlockview-release.aar b/app/libs/pinlockview-release.aar new file mode 100644 index 00000000..646f97a4 Binary files /dev/null and b/app/libs/pinlockview-release.aar differ diff --git a/app/release/output.json b/app/release/output.json index 41aaa36f..246862e8 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1,20 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":52,"versionName":"4.17","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}] \ No newline at end of file +{ + "version": 1, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "xyz.quaver.pupil", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "properties": [], + "versionCode": 53, + "versionName": "53", + "enabled": true, + "outputFile": "app-release.apk" + } + ] +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b61f152c..dab7dfb3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,6 +53,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - @@ -97,21 +196,10 @@ - - - - - - - - + android:scheme="https" /> . + */ + +package com.arlib.floatingsearchview + +import android.content.Context +import android.os.Parcelable +import android.util.AttributeSet + +class FloatingSearchViewDayNight @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null) + : FloatingSearchView(context, attrs) { + + // hack to remove color attributes which should not be reused + override fun onSaveInstanceState(): Parcelable? { + super.onSaveInstanceState() + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index 54b1b78c..1a723eec 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -31,10 +31,12 @@ import com.google.android.gms.common.GooglePlayServicesNotAvailableException import com.google.android.gms.common.GooglePlayServicesRepairableException import com.google.android.gms.security.ProviderInstaller import com.google.firebase.analytics.FirebaseAnalytics +import com.google.firebase.crashlytics.FirebaseCrashlytics import xyz.quaver.proxy import xyz.quaver.pupil.util.Histories import xyz.quaver.pupil.util.getProxy import java.io.File +import java.util.* class Pupil : MultiDexApplication() { @@ -48,6 +50,16 @@ class Pupil : MultiDexApplication() { override fun onCreate() { val preference = PreferenceManager.getDefaultSharedPreferences(this) + val userID = + if (preference.getString("user_id", "").isNullOrEmpty()) { + UUID.randomUUID().toString().also { + preference.edit().putString("user_id", it).apply() + } + } else + preference.getString("user_id", "") ?: "" + + FirebaseCrashlytics.getInstance().setUserId(userID) + proxy = getProxy(this) try { 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 618bbe72..c2886904 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt @@ -28,6 +28,7 @@ import android.view.ViewGroup import android.widget.LinearLayout import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.CircularProgressDrawable import androidx.vectordrawable.graphics.drawable.Animatable2Compat @@ -42,7 +43,9 @@ import kotlinx.android.synthetic.main.item_galleryblock.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import xyz.quaver.hitomi.GalleryBlock +import xyz.quaver.hitomi.getReader import xyz.quaver.pupil.BuildConfig import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.R @@ -75,7 +78,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri val reader = Cache(context).getReaderOrNull(galleryID) CoroutineScope(Dispatchers.Main).launch { - if (reader == null) { + if (reader == null || PreferenceManager.getDefaultSharedPreferences(context).getBoolean("cache_disable", false)) { view.galleryblock_progressbar.visibility = View.GONE view.galleryblock_progress_complete.visibility = View.GONE return@launch @@ -218,12 +221,12 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri "male" -> { setChipBackgroundColorResource(R.color.material_blue_700) setTextColor(ContextCompat.getColor(context, android.R.color.white)) - ContextCompat.getDrawable(context, R.drawable.ic_gender_male_white) + ContextCompat.getDrawable(context, R.drawable.gender_male) } "female" -> { setChipBackgroundColorResource(R.color.material_pink_600) setTextColor(ContextCompat.getColor(context, android.R.color.white)) - ContextCompat.getDrawable(context, R.drawable.ic_gender_female_white) + ContextCompat.getDrawable(context, R.drawable.gender_female) } else -> null } @@ -237,6 +240,15 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri } galleryblock_id.text = galleryBlock.id.toString() + galleryblock_pagecount.text = "-" + CoroutineScope(Dispatchers.IO).launch { + val pageCount = kotlin.runCatching { + getReader(galleryBlock.id).galleryInfo.files.size + }.getOrNull() ?: return@launch + withContext(Dispatchers.Main) { + galleryblock_pagecount.text = context.getString(R.string.galleryblock_pagecount, pageCount) + } + } if (!::favorites.isInitialized) favorites = (context.applicationContext as Pupil).favorites diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/MirrorAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/MirrorAdapter.kt index 273922e9..91362fb6 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/MirrorAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/MirrorAdapter.kt @@ -18,6 +18,7 @@ package xyz.quaver.pupil.adapters +import android.annotation.SuppressLint import android.content.Context import android.view.LayoutInflater import android.view.MotionEvent @@ -60,6 +61,7 @@ class MirrorAdapter(context: Context) : RecyclerView.Adapter Unit)? = null var onItemMoved : ((List) -> (Unit))? = null + @SuppressLint("ClickableViewAccessibility") override fun onBindViewHolder(holder: ViewHolder, position: Int) { with(holder.view) { mirror_name.text = mirrors[list.elementAt(position)] 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 04c3aa44..d008e837 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt @@ -25,15 +25,15 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.RequestManager import com.bumptech.glide.load.engine.DiskCacheStrategy -import com.crashlytics.android.Crashlytics -import io.fabric.sdk.android.Fabric +import com.google.android.material.snackbar.Snackbar +import com.google.firebase.crashlytics.FirebaseCrashlytics +import kotlinx.android.synthetic.main.activity_reader.view.* import kotlinx.android.synthetic.main.item_reader.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import xyz.quaver.hitomi.Reader import xyz.quaver.pupil.R -import xyz.quaver.pupil.util.download.Cache import xyz.quaver.pupil.util.download.DownloadWorker import java.util.* import kotlin.concurrent.schedule @@ -51,6 +51,8 @@ class ReaderAdapter(private val glide: RequestManager, class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) + var downloadWorker: DownloadWorker? = null + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return LayoutInflater.from(parent.context).inflate( R.layout.item_reader, parent, false @@ -62,6 +64,9 @@ class ReaderAdapter(private val glide: RequestManager, override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.view as ConstraintLayout + if (downloadWorker == null) + downloadWorker = DownloadWorker.getInstance(holder.view.context) + if (isFullScreen) { holder.view.layoutParams.height = RecyclerView.LayoutParams.MATCH_PARENT holder.view.container.layoutParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT @@ -83,15 +88,15 @@ class ReaderAdapter(private val glide: RequestManager, holder.view.reader_index.text = (position+1).toString() - val images = Cache(holder.view.context).getImage(galleryID, position) - val progress = DownloadWorker.getInstance(holder.view.context).progress[galleryID]?.get(position) + val image = downloadWorker!!.results[galleryID]?.get(position) + val progress = downloadWorker!!.progress[galleryID]?.get(position) - if (progress?.isInfinite() == true && images != null) { + if (progress?.isInfinite() == true && image != null) { holder.view.reader_item_progressbar.visibility = View.INVISIBLE holder.view.image.post { glide - .load(images) + .load(image) .diskCacheStrategy(DiskCacheStrategy.NONE) .skipMemoryCache(true) .fitCenter() @@ -105,13 +110,22 @@ class ReaderAdapter(private val glide: RequestManager, glide.clear(holder.view.image) if (progress?.isNaN() == true) { - if (Fabric.isInitialized()) - Crashlytics.logException(DownloadWorker.getInstance(holder.view.context).exception[galleryID]?.get(position)) + FirebaseCrashlytics.getInstance().recordException( + DownloadWorker.getInstance(holder.view.context).exception[galleryID]?.get(position)!! + ) glide .load(R.drawable.image_broken_variant) .into(holder.view.image) + Snackbar.make(holder.view.reader_layout, R.string.reader_error_retry, Snackbar.LENGTH_SHORT).apply { + setAction(android.R.string.no) { } + setAction(android.R.string.yes) { + downloadWorker!!.cancel(galleryID) + downloadWorker!!.queue.add(galleryID) + } + }.show() + return } else { holder.view.reader_item_progressbar.progress = diff --git a/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt index f8d77d95..144ec79d 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt @@ -21,23 +21,157 @@ package xyz.quaver.pupil.ui import android.app.Activity import android.app.AlertDialog import android.os.Bundle +import android.view.animation.Animation +import android.view.animation.AnimationUtils import androidx.appcompat.app.AppCompatActivity +import androidx.biometric.BiometricManager +import androidx.biometric.BiometricPrompt +import androidx.core.content.ContextCompat +import androidx.preference.PreferenceManager 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.fragment_pin_lock.* import xyz.quaver.pupil.R +import xyz.quaver.pupil.ui.fragment.PINLockFragment import xyz.quaver.pupil.ui.fragment.PatternLockFragment import xyz.quaver.pupil.util.Lock import xyz.quaver.pupil.util.LockManager class LockActivity : AppCompatActivity() { + private lateinit var lockManager: LockManager + private var mode: String? = null + + private val patternLockFragment = 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() + } + } + } + } + } + } + + private val pinLockFragment = PINLockFragment().apply { + var lastPass = "" + onPINEntered = { + when(mode) { + null -> { + val result = lockManager.check(it) + + if (result == true) { + setResult(Activity.RESULT_OK) + finish() + } else { + indicator_dots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply { + setAnimationListener(object: Animation.AnimationListener { + override fun onAnimationEnd(animation: Animation?) { + pin_lock_view.resetPinLockView() + pin_lock_view.isEnabled = true + } + + override fun onAnimationStart(animation: Animation?) { + pin_lock_view.isEnabled = false + } + + override fun onAnimationRepeat(animation: Animation?) { + // Do Nothing + } + }) + }) + } + } + "add_lock" -> { + if (lastPass.isEmpty()) { + lastPass = it + + pin_lock_view.resetPinLockView() + Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show() + } else { + if (lastPass == it) { + LockManager(context!!).add(Lock.generate(Lock.Type.PIN, it)) + finish() + } else { + indicator_dots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply { + setAnimationListener(object: Animation.AnimationListener { + override fun onAnimationEnd(animation: Animation?) { + pin_lock_view.resetPinLockView() + pin_lock_view.isEnabled = true + } + + override fun onAnimationStart(animation: Animation?) { + pin_lock_view.isEnabled = false + } + + override fun onAnimationRepeat(animation: Animation?) { + // Do Nothing + } + }) + }) + lastPass = "" + + Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show() + } + } + } + } + } + } + + private fun showBiometricPrompt() { + val promptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle(getText(R.string.settings_lock_fingerprint_prompt)) + .setSubtitle(getText(R.string.settings_lock_fingerprint_prompt_subtitle)) + .setNegativeButtonText(getText(android.R.string.cancel)) + .setConfirmationRequired(false) + .build() + + val biometricPrompt = BiometricPrompt(this, ContextCompat.getMainExecutor(this), + object : BiometricPrompt.AuthenticationCallback() { + override fun onAuthenticationSucceeded( + result: BiometricPrompt.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + setResult(RESULT_OK) + finish() + return + } + }) + + // Displays the "log in" prompt. + biometricPrompt.authenticate(promptInfo) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_lock) - val lockManager = try { + lockManager = try { LockManager(this) } catch (e: Exception) { AlertDialog.Builder(this).apply { @@ -50,12 +184,7 @@ class LockActivity : AppCompatActivity() { return } - val mode = intent.getStringExtra("mode") - - lock_pattern.isEnabled = false - lock_pin.isEnabled = false - lock_fingerprint.isEnabled = false - lock_password.isEnabled = false + mode = intent.getStringExtra("mode") when(mode) { null -> { @@ -64,52 +193,75 @@ class LockActivity : AppCompatActivity() { finish() return } + + if ( + PreferenceManager.getDefaultSharedPreferences(this).getBoolean("lock_fingerprint", false) + && BiometricManager.from(this).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS + ) { + lock_fingerprint.apply { + isEnabled = true + setOnClickListener { + showBiometricPrompt() + } + } + showBiometricPrompt() + } + + lock_pattern.apply { + isEnabled = lockManager.contains(Lock.Type.PATTERN) + setOnClickListener { + supportFragmentManager.beginTransaction().replace( + R.id.lock_content, patternLockFragment + ).commit() + } + } + lock_pin.apply { + isEnabled = lockManager.contains(Lock.Type.PIN) + setOnClickListener { + supportFragmentManager.beginTransaction().replace( + R.id.lock_content, pinLockFragment + ).commit() + } + } + lock_password.isEnabled = false + + when (lockManager.locks!!.first().type) { + Lock.Type.PIN -> { + + supportFragmentManager.beginTransaction().add( + R.id.lock_content, pinLockFragment + ).commit() + } + Lock.Type.PATTERN -> { + supportFragmentManager.beginTransaction().add( + R.id.lock_content, patternLockFragment + ).commit() + } + else -> return + } } "add_lock" -> { + lock_pattern.isEnabled = false + lock_pin.isEnabled = false + lock_fingerprint.isEnabled = false + lock_password.isEnabled = false + when(intent.getStringExtra("type")!!) { "pattern" -> { - + lock_pattern.isEnabled = true + supportFragmentManager.beginTransaction().add( + R.id.lock_content, patternLockFragment + ).commit() + } + "pin" -> { + lock_pin.isEnabled = true + supportFragmentManager.beginTransaction().add( + R.id.lock_content, pinLockFragment + ).commit() } } } } - - 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/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt index 714d4fb2..65f37e9e 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -18,6 +18,7 @@ package xyz.quaver.pupil.ui +import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.graphics.drawable.Animatable @@ -30,10 +31,7 @@ import android.view.MotionEvent import android.view.View import android.view.WindowManager import android.view.inputmethod.EditorInfo -import android.widget.EditText -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView +import android.widget.* import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.cardview.widget.CardView @@ -43,12 +41,12 @@ import androidx.core.view.GravityCompat import androidx.preference.PreferenceManager import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import com.arlib.floatingsearchview.FloatingSearchView +import com.arlib.floatingsearchview.FloatingSearchViewDayNight import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion import com.arlib.floatingsearchview.util.view.SearchInputView import com.bumptech.glide.Glide -import com.crashlytics.android.Crashlytics import com.google.android.material.appbar.AppBarLayout -import io.fabric.sdk.android.Fabric +import com.google.firebase.crashlytics.FirebaseCrashlytics import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main_content.* import kotlinx.coroutines.* @@ -146,6 +144,30 @@ class MainActivity : AppCompatActivity() { preference.edit().putBoolean("https_block_alert", true).apply() } + + if (!preference.getBoolean("apcjsa_option", false)) { + android.app.AlertDialog.Builder(this).apply { + setTitle(R.string.apcjsa_option_title) + setMessage(R.string.apcjsa_option_message) + setPositiveButton(android.R.string.yes) { _, _ -> + val tags = Tags.parse( + preference.getString("default_query", "") ?: "" + ) + + tags.add("-female:loli") + tags.add("-male:shota") + + preference.edit() + .putString("default_query", tags.toString()) + .putBoolean("cache_disable", true) + .putBoolean("apcjsa_option", true) + .apply() + } + setNegativeButton(android.R.string.no) { _, _ -> } + }.show() + + preference.edit().putBoolean("apcjsa_option", true).apply() + } } with(application as Pupil) { @@ -421,6 +443,7 @@ class MainActivity : AppCompatActivity() { loadBlocks() } + @SuppressLint("ClickableViewAccessibility") private fun setupRecyclerView() { with(main_recyclerview) { adapter = GalleryBlockAdapter(Glide.with(this@MainActivity), galleries).apply { @@ -438,13 +461,16 @@ class MainActivity : AppCompatActivity() { onDownloadClickedHandler = { position -> val galleryID = galleries[position].id val worker = DownloadWorker.getInstance(context) - - if (Cache(context).isDownloading(galleryID)) //download in progress - worker.cancel(galleryID) + if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("cache_disable", false)) + Toast.makeText(context, R.string.settings_download_when_cache_disable_warning, Toast.LENGTH_SHORT).show() else { - Cache(context).setDownloading(galleryID, true) + if (Cache(context).isDownloading(galleryID)) //download in progress + worker.cancel(galleryID) + else { + Cache(context).setDownloading(galleryID, true) - worker.queue.add(galleryID) + worker.queue.add(galleryID) + } } closeAllItems() @@ -742,7 +768,7 @@ class MainActivity : AppCompatActivity() { }) searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI - with(main_searchview as FloatingSearchView) { + with(main_searchview as FloatingSearchViewDayNight) { val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json") val serializer = Tag.serializer().list @@ -845,14 +871,14 @@ class MainActivity : AppCompatActivity() { ResourcesCompat.getDrawable( resources, when(item.n) { - "female" -> R.drawable.ic_gender_female - "male" -> R.drawable.ic_gender_male - "language" -> R.drawable.ic_translate - "group" -> R.drawable.ic_account_group - "character" -> R.drawable.ic_account_star - "series" -> R.drawable.ic_book_open - "artist" -> R.drawable.ic_brush - else -> R.drawable.ic_tag + "female" -> R.drawable.gender_female + "male" -> R.drawable.gender_male + "language" -> R.drawable.translate + "group" -> R.drawable.account_group + "character" -> R.drawable.account_star + "series" -> R.drawable.book_open + "artist" -> R.drawable.brush + else -> R.drawable.tag }, null) ) @@ -1058,8 +1084,8 @@ class MainActivity : AppCompatActivity() { } } catch (e: Exception) { - if (Fabric.isInitialized() && e.message != "No result") - Crashlytics.logException(e) + if (e.message != "No result") + FirebaseCrashlytics.getInstance().recordException(e) withContext(Dispatchers.Main) { main_noresult.visibility = View.VISIBLE diff --git a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt index 64cb2b5d..7681698f 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt @@ -23,6 +23,7 @@ import android.graphics.drawable.Animatable import android.graphics.drawable.Drawable import android.os.Bundle import android.view.* +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat @@ -33,9 +34,8 @@ import androidx.recyclerview.widget.RecyclerView import androidx.vectordrawable.graphics.drawable.Animatable2Compat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import com.bumptech.glide.Glide -import com.crashlytics.android.Crashlytics import com.google.android.material.snackbar.Snackbar -import io.fabric.sdk.android.Fabric +import com.google.firebase.crashlytics.FirebaseCrashlytics import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.android.synthetic.main.activity_reader.view.* import kotlinx.android.synthetic.main.dialog_numberpicker.view.* @@ -91,8 +91,7 @@ class ReaderActivity : AppCompatActivity() { handleIntent(intent) - if (Fabric.isInitialized()) - Crashlytics.setInt("GalleryID", galleryID) + FirebaseCrashlytics.getInstance().setCustomKey("GalleryID", galleryID) if (galleryID == 0) { onBackPressed() @@ -113,14 +112,12 @@ class ReaderActivity : AppCompatActivity() { val uri = intent.data val lastPathSegment = uri?.lastPathSegment if (uri != null && lastPathSegment != null) { - val nonNumber = Regex("[^-?0-9]+") - galleryID = when (uri.host) { - "hitomi.la" -> lastPathSegment.replace(nonNumber, "").toInt() - "히요비.asia" -> lastPathSegment.toInt() - "xn--9w3b15m8vo.asia" -> lastPathSegment.toInt() + "hitomi.la" -> + Regex("([0-9]+).html").find(lastPathSegment)?.groupValues?.get(1)?.toIntOrNull() ?: 0 + "hiyobi.me" -> lastPathSegment.toInt() "e-hentai.org" -> uri.pathSegments[1].toInt() - else -> return + else -> 0 } } } else { @@ -325,13 +322,27 @@ class ReaderActivity : AppCompatActivity() { animateDownloadFAB(Cache(context).isDownloading(galleryID)) //If download in progress, animate button setOnClickListener { - if (Cache(context).isDownloading(galleryID)) { - Cache(context).setDownloading(galleryID, false) + if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("cache_disable", false)) + Toast.makeText(context, R.string.settings_download_when_cache_disable_warning, Toast.LENGTH_SHORT).show() + else { + if (Cache(context).isDownloading(galleryID)) { + Cache(context).setDownloading(galleryID, false) - animateDownloadFAB(false) - } else { - Cache(context).setDownloading(galleryID, true) - animateDownloadFAB(true) + animateDownloadFAB(false) + } else { + Cache(context).setDownloading(galleryID, true) + animateDownloadFAB(true) + } + } + } + } + + with(reader_fab_retry) { + setImageResource(R.drawable.refresh) + setOnClickListener { + DownloadWorker.getInstance(context).let { + it.cancel(galleryID) + it.queue.add(galleryID) } } } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt index 20621e38..7bc79d66 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt @@ -35,7 +35,7 @@ import kotlinx.serialization.builtins.serializer import net.rdrei.android.dirchooser.DirectoryChooserActivity import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.R -import xyz.quaver.pupil.ui.fragment.LockFragment +import xyz.quaver.pupil.ui.fragment.LockSettingsFragment import xyz.quaver.pupil.ui.fragment.SettingsFragment import xyz.quaver.pupil.util.* import java.io.File @@ -84,7 +84,7 @@ class SettingsActivity : AppCompatActivity() { if (resultCode == Activity.RESULT_OK) { supportFragmentManager .beginTransaction() - .replace(R.id.settings, LockFragment()) + .replace(R.id.settings, LockSettingsFragment()) .addToBackStack("Lock") .commitAllowingStateLoss() } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt index 3d39c6e4..94029cd5 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt @@ -45,6 +45,7 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { private val excludeBL = "-male:yaoi" private val excludeGuro = listOf("-female:guro", "-male:guro") + private val excludeLoli = listOf("-female:loli", "-male:shota") var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null @@ -68,6 +69,11 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { newTags.add(tag) } + if (default_query_dialog_loli_checkbox.isChecked) + excludeLoli.forEach { tag -> + newTags.add(tag) + } + onPositiveButtonClickListener?.invoke(newTags) } @@ -120,6 +126,14 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } } + with(view.default_query_dialog_loli_checkbox) { + isChecked = excludeLoli.all { tags.contains(it) } + if (excludeLoli.all { tags.contains(it) }) + excludeLoli.forEach { + tags.remove(it) + } + } + with(view.default_query_dialog_edittext) { setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE) addTextChangedListener(object : TextWatcher { diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt index 06c87882..548c3aec 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt @@ -18,7 +18,6 @@ package xyz.quaver.pupil.ui.dialog -import android.app.Activity import android.app.Dialog import android.content.Context import android.content.Intent @@ -170,12 +169,12 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private "male" -> { setChipBackgroundColorResource(R.color.material_blue_700) setTextColor(ContextCompat.getColor(context, android.R.color.white)) - ContextCompat.getDrawable(context, R.drawable.ic_gender_male_white) + ContextCompat.getDrawable(context, R.drawable.gender_male) } "female" -> { setChipBackgroundColorResource(R.color.material_pink_600) setTextColor(ContextCompat.getColor(context, android.R.color.white)) - ContextCompat.getDrawable(context, R.drawable.ic_gender_female_white) + ContextCompat.getDrawable(context, R.drawable.gender_female) } else -> null } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockFragment.kt deleted file mode 100644 index b95900c1..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockFragment.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.fragment - -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.app.AlertDialog -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import xyz.quaver.pupil.R -import xyz.quaver.pupil.ui.LockActivity -import xyz.quaver.pupil.util.Lock -import xyz.quaver.pupil.util.LockManager - -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 - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt new file mode 100644 index 00000000..c4a76ee0 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt @@ -0,0 +1,147 @@ +/* + * Pupil, Hitomi.la viewer for Android + * Copyright (C) 2020 tom5079 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package xyz.quaver.pupil.ui.fragment + +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager +import androidx.preference.SwitchPreferenceCompat +import xyz.quaver.pupil.R +import xyz.quaver.pupil.ui.LockActivity +import xyz.quaver.pupil.util.Lock +import xyz.quaver.pupil.util.LockManager + +class LockSettingsFragment : + PreferenceFragmentCompat() { + + override fun onResume() { + super.onResume() + + val lockManager = LockManager(requireContext()) + + findPreference("lock_pattern")?.summary = + if (lockManager.contains(Lock.Type.PATTERN)) + getString(R.string.settings_lock_enabled) + else + "" + + findPreference("lock_pin")?.summary = + if (lockManager.contains(Lock.Type.PIN)) + getString(R.string.settings_lock_enabled) + else + "" + + if (lockManager.isEmpty()) { + (findPreference("lock_fingerprint") as SwitchPreferenceCompat).isChecked = false + + PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("lock_fingerprint", false).apply() + } + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.lock_preferences, rootKey) + + with(findPreference("lock_pattern")) { + this!! + + if (LockManager(requireContext()).contains(Lock.Type.PATTERN)) + summary = getString(R.string.settings_lock_enabled) + + onPreferenceClickListener = Preference.OnPreferenceClickListener { + val lockManager = LockManager(requireContext()) + + if (lockManager.contains(Lock.Type.PATTERN)) { + AlertDialog.Builder(requireContext()).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(requireContext(), LockActivity::class.java).apply { + putExtra("mode", "add_lock") + putExtra("type", "pattern") + } + + startActivity(intent) + } + + true + } + } + + with(findPreference("lock_pin")) { + this!! + + if (LockManager(requireContext()).contains(Lock.Type.PIN)) + summary = getString(R.string.settings_lock_enabled) + + onPreferenceClickListener = Preference.OnPreferenceClickListener { + val lockManager = LockManager(requireContext()) + + if (lockManager.contains(Lock.Type.PIN)) { + AlertDialog.Builder(requireContext()).apply { + setTitle(R.string.warning) + setMessage(R.string.settings_lock_remove_message) + + setPositiveButton(android.R.string.yes) { _, _ -> + lockManager.remove(Lock.Type.PIN) + onResume() + } + setNegativeButton(android.R.string.no) { _, _ -> } + }.show() + } else { + val intent = Intent(requireContext(), LockActivity::class.java).apply { + putExtra("mode", "add_lock") + putExtra("type", "pin") + } + + startActivity(intent) + } + + true + } + } + + with(findPreference("lock_fingerprint")) { + this!! + + setOnPreferenceChangeListener { _, newValue -> + this as SwitchPreferenceCompat + + if (newValue == true && LockManager(requireContext()).isEmpty()) { + isChecked = false + + Toast.makeText(requireContext(), R.string.settings_lock_fingerprint_without_lock, Toast.LENGTH_SHORT).show() + } else + isChecked = newValue as Boolean + + false + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt new file mode 100644 index 00000000..b058840d --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt @@ -0,0 +1,53 @@ +/* + * Pupil, Hitomi.la viewer for Android + * Copyright (C) 2020 tom5079 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package xyz.quaver.pupil.ui.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.andrognito.pinlockview.PinLockListener +import kotlinx.android.synthetic.main.fragment_pin_lock.view.* +import xyz.quaver.pupil.R + +class PINLockFragment : Fragment(), PinLockListener { + + var onPINEntered: ((String) -> Unit)? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_pin_lock, container, false).apply { + pin_lock_view.attachIndicatorDots(indicator_dots) + pin_lock_view.setPinLockListener(this@PINLockFragment) + } + } + + override fun onComplete(pin: String?) { + onPINEntered?.invoke(pin!!) + } + + override fun onEmpty() { + + } + + override fun onPinChange(pinLength: Int, intermediatePin: String?) { + + } + +} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt index 7f6b8004..d975355d 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt @@ -19,11 +19,11 @@ package xyz.quaver.pupil.ui.fragment import android.Manifest -import android.content.Intent -import android.content.SharedPreferences +import android.content.* import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.ActivityCompat @@ -53,16 +53,12 @@ class SettingsFragment : Preference.OnPreferenceChangeListener, SharedPreferences.OnSharedPreferenceChangeListener { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this) - } + lateinit var sharedPreference: SharedPreferences override fun onResume() { super.onResume() - val lockManager = LockManager(context!!) + val lockManager = LockManager(requireContext()) findPreference("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) { getString(R.string.settings_lock_none) @@ -92,9 +88,9 @@ class SettingsFragment : checkUpdate(activity as SettingsActivity, true) } "delete_cache" -> { - val dir = File(context.cacheDir, "imageCache") + val dir = File(requireContext().cacheDir, "imageCache") - AlertDialog.Builder(context).apply { + AlertDialog.Builder(requireContext()).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_cache_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> @@ -107,9 +103,9 @@ class SettingsFragment : }.show() } "delete_downloads" -> { - val dir = getDownloadDirectory(context) + val dir = getDownloadDirectory(requireContext()) - AlertDialog.Builder(context).apply { + AlertDialog.Builder(requireContext()).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_downloads_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> @@ -122,9 +118,9 @@ class SettingsFragment : }.show() } "clear_history" -> { - val histories = (context.applicationContext as Pupil).histories + val histories = (requireContext().applicationContext as Pupil).histories - AlertDialog.Builder(context).apply { + AlertDialog.Builder(requireContext()).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_history_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> @@ -135,10 +131,10 @@ class SettingsFragment : }.show() } "dl_location" -> { - DownloadLocationDialog(activity!!).show() + DownloadLocationDialog(requireActivity()).show() } "default_query" -> { - DefaultQueryDialog(context).apply { + DefaultQueryDialog(requireContext()).apply { onPositiveButtonClickListener = { newTags -> sharedPreferences.edit().putString("default_query", newTags.toString()).apply() summary = newTags.toString() @@ -146,20 +142,23 @@ class SettingsFragment : }.show() } "app_lock" -> { - val intent = Intent(context, LockActivity::class.java) + val intent = Intent(requireContext(), LockActivity::class.java) activity?.startActivityForResult(intent, REQUEST_LOCK) } "mirrors" -> { - MirrorDialog(context) + MirrorDialog(requireContext()) .show() } "proxy" -> { - ProxyDialog(context) + ProxyDialog(requireContext()) .show() } + "nomedia" -> { + File(getDownloadDirectory(context), ".nomedia").createNewFile() + } "backup" -> { - File(ContextCompat.getDataDir(context), "favorites.json").copyTo( - File(getDownloadDirectory(context), "favorites.json"), + File(ContextCompat.getDataDir(requireContext()), "favorites.json").copyTo( + File(getDownloadDirectory(requireContext()), "favorites.json"), true ) @@ -177,8 +176,8 @@ class SettingsFragment : "old_import_galleries" -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) - ActivityCompat.requestPermissions(activity!!, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) + ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) else { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { putExtra("android.content.extra.SHOW_ADVANCED", true) @@ -192,13 +191,19 @@ class SettingsFragment : .allowNewDirectoryNameModification(true) .build() - val intent = Intent(context, DirectoryChooserActivity::class.java).apply { + val intent = Intent(requireContext(), DirectoryChooserActivity::class.java).apply { putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) } activity?.startActivityForResult(intent, REQUEST_IMPORT_OLD_GALLERIES_OLD) } } + "user_id" -> { + (context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip( + ClipData.newPlainText("user_id", sharedPreference.getString("user_id", "")) + ) + Toast.makeText(context, R.string.settings_user_id_toast, Toast.LENGTH_SHORT).show() + } else -> return false } } @@ -232,10 +237,10 @@ class SettingsFragment : when (key) { "proxy" -> { - summary = getProxyInfo(context).type.name + summary = getProxyInfo(requireContext()).type.name } "dl_location" -> { - summary = getDownloadDirectory(context!!).canonicalPath + summary = getDownloadDirectory(requireContext()).canonicalPath } } } @@ -244,6 +249,9 @@ class SettingsFragment : override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.root_preferences, rootKey) + sharedPreference = PreferenceManager.getDefaultSharedPreferences(requireContext()) + sharedPreference.registerOnSharedPreferenceChangeListener(this) + initPreferences() } @@ -260,42 +268,42 @@ class SettingsFragment : when (key) { "app_version" -> { - val manager = context.packageManager - val info = manager.getPackageInfo(context.packageName, 0) - summary = context.getString(R.string.settings_app_version_description, info.versionName) + val manager = requireContext().packageManager + val info = manager.getPackageInfo(requireContext().packageName, 0) + summary = requireContext().getString(R.string.settings_app_version_description, info.versionName) onPreferenceClickListener = this@SettingsFragment } "delete_cache" -> { - val dir = File(context.cacheDir, "imageCache") + val dir = File(requireContext().cacheDir, "imageCache") summary = getDirSize(dir) onPreferenceClickListener = this@SettingsFragment } "delete_downloads" -> { - val dir = getDownloadDirectory(context) + val dir = getDownloadDirectory(requireContext()) summary = getDirSize(dir) onPreferenceClickListener = this@SettingsFragment } "clear_history" -> { - val histories = (activity!!.application as Pupil).histories + val histories = (requireActivity().application as Pupil).histories summary = getString(R.string.settings_clear_history_summary, histories.size) onPreferenceClickListener = this@SettingsFragment } "dl_location" -> { - summary = getDownloadDirectory(context).canonicalPath + summary = getDownloadDirectory(requireContext()).canonicalPath onPreferenceClickListener = this@SettingsFragment } "default_query" -> { - summary = PreferenceManager.getDefaultSharedPreferences(context).getString("default_query", "") ?: "" + summary = sharedPreference.getString("default_query", "") ?: "" onPreferenceClickListener = this@SettingsFragment } "app_lock" -> { - val lockManager = LockManager(context) + val lockManager = LockManager(requireContext()) summary = if (lockManager.locks.isNullOrEmpty()) { getString(R.string.settings_lock_none) @@ -315,13 +323,16 @@ class SettingsFragment : onPreferenceClickListener = this@SettingsFragment } "proxy" -> { - summary = getProxyInfo(context).type.name + summary = getProxyInfo(requireContext()).type.name onPreferenceClickListener = this@SettingsFragment } "dark_mode" -> { onPreferenceChangeListener = this@SettingsFragment } + "nomedia" -> { + onPreferenceClickListener = this@SettingsFragment + } "backup" -> { onPreferenceClickListener = this@SettingsFragment } @@ -331,6 +342,10 @@ class SettingsFragment : "old_import_galleries" -> { onPreferenceClickListener = this@SettingsFragment } + "user_id" -> { + summary = sharedPreference.getString("user_id", "") + onPreferenceClickListener = this@SettingsFragment + } } } diff --git a/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt b/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt index 617d3dd3..deb4c25c 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt @@ -24,7 +24,7 @@ import android.util.Base64 import android.util.Log import android.util.SparseArray import androidx.preference.PreferenceManager -import com.crashlytics.android.Crashlytics +import com.google.firebase.crashlytics.FirebaseCrashlytics import kotlinx.coroutines.* import xyz.quaver.Code import xyz.quaver.hitomi.GalleryBlock @@ -34,11 +34,10 @@ import xyz.quaver.pupil.util.getCachedGallery import xyz.quaver.pupil.util.getDownloadDirectory import xyz.quaver.pupil.util.isParentOf import xyz.quaver.pupil.util.json -import java.io.BufferedInputStream import java.io.File import java.io.FileOutputStream -import java.io.InputStream import java.net.URL +import java.util.* import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock @@ -46,6 +45,7 @@ class Cache(context: Context) : ContextWrapper(context) { companion object { private val moving = mutableListOf() + private val readers = SparseArray() } private val locks = SparseArray() @@ -67,7 +67,7 @@ class Cache(context: Context) : ContextWrapper(context) { // Search in this order // Download -> Cache fun getCachedGallery(galleryID: Int) = getCachedGallery(this, galleryID).also { - if (!it.exists()) + if (!it.exists() && !preference.getBoolean("cache_disable", false)) it.mkdirs() } @@ -87,6 +87,9 @@ class Cache(context: Context) : ContextWrapper(context) { } fun setCachedMetadata(galleryID: Int, metadata: Metadata) { + if (preference.getBoolean("cache_disable", false)) + return + val file = File(getCachedGallery(galleryID), ".metadata").also { if (!it.exists()) it.createNewFile() @@ -98,6 +101,7 @@ class Cache(context: Context) : ContextWrapper(context) { suspend fun getThumbnail(galleryID: Int): String? { val metadata = Cache(this).getCachedMetadata(galleryID) + @Suppress("BlockingMethodInNonBlockingContext") val thumbnail = if (metadata?.thumbnail == null) withContext(Dispatchers.IO) { val thumbnails = getGalleryBlock(galleryID)?.thumbnails @@ -158,7 +162,7 @@ class Cache(context: Context) : ContextWrapper(context) { } fun getReaderOrNull(galleryID: Int): Reader? { - return getCachedMetadata(galleryID)?.reader + return readers[galleryID] ?: getCachedMetadata(galleryID)?.reader } suspend fun getReader(galleryID: Int): Reader? { @@ -179,15 +183,21 @@ class Cache(context: Context) : ContextWrapper(context) { it } - val reader = if (metadata?.reader == null) { - CoroutineScope(Dispatchers.IO).async { + val reader = + if (readers[galleryID] != null) + return readers[galleryID] + else if (metadata?.reader == null) { var retval: Reader? = null for (source in sources) { retval = try { - source.value.invoke() + withContext(Dispatchers.IO) { + withTimeoutOrNull(1000) { + source.value.invoke() + } + } } catch (e: Exception) { - Crashlytics.logException(e) + FirebaseCrashlytics.getInstance().recordException(e) null } @@ -196,9 +206,10 @@ class Cache(context: Context) : ContextWrapper(context) { } retval - }.await() ?: return null - } else - metadata.reader + } else + metadata.reader + + readers.put(galleryID, reader) setCachedMetadata( galleryID, @@ -239,18 +250,28 @@ class Cache(context: Context) : ContextWrapper(context) { } - fun putImage(galleryID: Int, index: Int, ext: String, data: InputStream) { + fun putImage(galleryID: Int, index: Int, ext: String, data: ByteArray) { + if (preference.getBoolean("cache_disable", false)) + return + val cache = File(getCachedGallery(galleryID), "%05d.$ext".format(index)).also { if (!it.exists()) it.createNewFile() } - BufferedInputStream(data).use { - it.copyTo(FileOutputStream(cache)) + try { + FileOutputStream(cache).use { + it.write(data) + } + } catch (e: Exception) { + cache.delete() } } fun moveToDownload(galleryID: Int) { + if (preference.getBoolean("cache_disable", false)) + return + if (moving.contains(galleryID)) return diff --git a/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt b/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt index 5c279c3b..587a51c8 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt @@ -29,8 +29,7 @@ import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.app.TaskStackBuilder import androidx.preference.PreferenceManager -import com.crashlytics.android.Crashlytics -import io.fabric.sdk.android.Fabric +import com.google.firebase.crashlytics.FirebaseCrashlytics import kotlinx.coroutines.* import okhttp3.* import okio.* @@ -77,7 +76,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont private var bufferedSource : BufferedSource? = null override fun contentLength() = responseBody.contentLength() - override fun contentType() = responseBody.contentType() ?: null + override fun contentType() = responseBody.contentType() override fun source(): BufferedSource { if (bufferedSource == null) @@ -144,6 +143,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont * null -> Download in progress / Loading */ val exception = SparseArray?>() + val results = SparseArray?>() val notification = SparseArray() private val loop = loop() @@ -151,11 +151,18 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont val interceptor = Interceptor { chain -> val request = chain.request() - val response = chain.proceed(request) + var response = chain.proceed(request) + + var retry = 5 + while (!response.isSuccessful && retry > 0) { + response = chain.proceed(request) + retry-- + } response.newBuilder() - .body(ProgressResponseBody(request.tag(), response.body(), progressListener)) - .build() + .body(response.body()?.let { + ProgressResponseBody(request.tag(), it, progressListener) + }).build() } val client = @@ -189,6 +196,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont progress.clear() exception.clear() + results.clear() notification.clear() notificationManager.cancelAll() } @@ -205,6 +213,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont progress.remove(galleryID) exception.remove(galleryID) + results.remove(galleryID) notification.remove(galleryID) notificationManager.cancel(galleryID) @@ -253,6 +262,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont if (reader == null) { progress.put(galleryID, null) exception.put(galleryID, null) + results.put(galleryID, null) Cache(this@DownloadWorker).setDownloading(galleryID, false) return@launch @@ -267,6 +277,9 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont 0F }.toMutableList()) exception.put(galleryID, reader.galleryInfo.files.map { null }.toMutableList()) + results.put(galleryID, reader.galleryInfo.files.indices.map { index -> + cache?.firstOrNull { it?.nameWithoutExtension?.toIntOrNull() == index }?.readBytes() + }.toMutableList()) if (notification[galleryID] == null) initNotification(galleryID) @@ -289,8 +302,8 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont val callback = object : Callback { override fun onFailure(call: Call, e: IOException) { Log.i("PUPILD", "FAIL ${call.request().tag()} (${e.message})") - if (Fabric.isInitialized() && e.message != "Canceled") - Crashlytics.logException(e) + if (e.message?.contains("cancel", true) != true) + FirebaseCrashlytics.getInstance().recordException(e) progress[galleryID]?.set(i, Float.NaN) exception[galleryID]?.set(i, e) @@ -316,13 +329,19 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont try { response.body().use { - Cache(this@DownloadWorker).putImage(galleryID, i, ext, it.byteStream()) + it!! + + results[galleryID]?.set(i, it.source().readByteArray()) } progress[galleryID]?.set(i, Float.POSITIVE_INFINITY) notify(galleryID) CoroutineScope(Dispatchers.IO).launch { + results[galleryID]?.get(i)?.also { + Cache(this@DownloadWorker).putImage(galleryID, i, ext, it) + } + if (isCompleted(galleryID)) { with(Cache(this@DownloadWorker)) { if (isDownloading(galleryID)) { diff --git a/app/src/main/java/xyz/quaver/pupil/util/proxy.kt b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt index 229c5e90..c471d992 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/proxy.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt @@ -42,7 +42,7 @@ data class ProxyInfo( } fun authenticator() = Authenticator { _, response -> - val credential = Credentials.basic(username, password) + val credential = Credentials.basic(username ?: "", password ?: "") response.request().newBuilder() .header("Proxy-Authorization", credential) 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 f56a0540..406837cd 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt @@ -50,7 +50,6 @@ import java.io.File import java.io.IOException import java.net.URL import java.util.* -import java.util.concurrent.Executors import java.util.concurrent.TimeUnit fun getReleases(url: String) : JsonArray { @@ -320,7 +319,7 @@ fun importOldGalleries(context: Context, folder: File) = CoroutineScope(Dispatch @Suppress("NAME_SHADOWING") val index = it.nameWithoutExtension.toIntOrNull() ?: return@forEach - Cache(context).putImage(galleryID, index, it.extension, it.inputStream()) + Cache(context).putImage(galleryID, index, it.extension, it.readBytes()) } } diff --git a/app/src/main/res/anim/shake.xml b/app/src/main/res/anim/shake.xml new file mode 100644 index 00000000..323768dd --- /dev/null +++ b/app/src/main/res/anim/shake.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/shake_cycle.xml b/app/src/main/res/anim/shake_cycle.xml new file mode 100644 index 00000000..13dcab54 --- /dev/null +++ b/app/src/main/res/anim/shake_cycle.xml @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/color/lock_fab.xml b/app/src/main/res/color/lock_fab.xml new file mode 100644 index 00000000..197313e3 --- /dev/null +++ b/app/src/main/res/color/lock_fab.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_account_group.png b/app/src/main/res/drawable-hdpi/ic_account_group.png deleted file mode 100644 index 2e8279db..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_account_group.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_account_star.png b/app/src/main/res/drawable-hdpi/ic_account_star.png deleted file mode 100644 index 53b16e5d..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_account_star.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_book_open.png b/app/src/main/res/drawable-hdpi/ic_book_open.png deleted file mode 100644 index 144febb1..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_book_open.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_brush.png b/app/src/main/res/drawable-hdpi/ic_brush.png deleted file mode 100644 index 5316c732..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_brush.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_gender_female.png b/app/src/main/res/drawable-hdpi/ic_gender_female.png deleted file mode 100644 index 76a7d4c4..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_gender_female.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_gender_male.png b/app/src/main/res/drawable-hdpi/ic_gender_male.png deleted file mode 100644 index 4ee6cd07..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_gender_male.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_tag.png b/app/src/main/res/drawable-hdpi/ic_tag.png deleted file mode 100644 index aa3b8750..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_tag.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_translate.png b/app/src/main/res/drawable-hdpi/ic_translate.png deleted file mode 100644 index 1a8f4365..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_translate.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_account_group.png b/app/src/main/res/drawable-ldpi/ic_account_group.png deleted file mode 100644 index c7cbb8cb..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_account_group.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_account_star.png b/app/src/main/res/drawable-ldpi/ic_account_star.png deleted file mode 100644 index 4373f45f..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_account_star.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_book_open.png b/app/src/main/res/drawable-ldpi/ic_book_open.png deleted file mode 100644 index 1b1c6020..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_book_open.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_brush.png b/app/src/main/res/drawable-ldpi/ic_brush.png deleted file mode 100644 index 48baadd4..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_brush.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_gender_female.png b/app/src/main/res/drawable-ldpi/ic_gender_female.png deleted file mode 100644 index 1070b7d4..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_gender_female.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_gender_male.png b/app/src/main/res/drawable-ldpi/ic_gender_male.png deleted file mode 100644 index fd054d81..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_gender_male.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_tag.png b/app/src/main/res/drawable-ldpi/ic_tag.png deleted file mode 100644 index 39459491..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_tag.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_translate.png b/app/src/main/res/drawable-ldpi/ic_translate.png deleted file mode 100644 index ffe6baf7..00000000 Binary files a/app/src/main/res/drawable-ldpi/ic_translate.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_account_group.png b/app/src/main/res/drawable-mdpi/ic_account_group.png deleted file mode 100644 index 314120c4..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_account_group.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_account_star.png b/app/src/main/res/drawable-mdpi/ic_account_star.png deleted file mode 100644 index 48b75fa6..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_account_star.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_book_open.png b/app/src/main/res/drawable-mdpi/ic_book_open.png deleted file mode 100644 index b76cd538..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_book_open.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_brush.png b/app/src/main/res/drawable-mdpi/ic_brush.png deleted file mode 100644 index 48ec2743..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_brush.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_gender_female.png b/app/src/main/res/drawable-mdpi/ic_gender_female.png deleted file mode 100644 index 7000159c..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_gender_female.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_gender_male.png b/app/src/main/res/drawable-mdpi/ic_gender_male.png deleted file mode 100644 index 211cee7a..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_gender_male.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_tag.png b/app/src/main/res/drawable-mdpi/ic_tag.png deleted file mode 100644 index 42e8255f..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_tag.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_translate.png b/app/src/main/res/drawable-mdpi/ic_translate.png deleted file mode 100644 index 1d4c32d6..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_translate.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_account_group.png b/app/src/main/res/drawable-xhdpi/ic_account_group.png deleted file mode 100644 index 4e6389bc..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_account_group.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_account_star.png b/app/src/main/res/drawable-xhdpi/ic_account_star.png deleted file mode 100644 index a8dc7cc7..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_account_star.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_book_open.png b/app/src/main/res/drawable-xhdpi/ic_book_open.png deleted file mode 100644 index dc925c77..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_book_open.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_brush.png b/app/src/main/res/drawable-xhdpi/ic_brush.png deleted file mode 100644 index 01fde729..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_brush.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_gender_female.png b/app/src/main/res/drawable-xhdpi/ic_gender_female.png deleted file mode 100644 index 734e0d99..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_gender_female.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_gender_male.png b/app/src/main/res/drawable-xhdpi/ic_gender_male.png deleted file mode 100644 index 89a1948d..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_gender_male.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_tag.png b/app/src/main/res/drawable-xhdpi/ic_tag.png deleted file mode 100644 index 23658b82..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_tag.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_translate.png b/app/src/main/res/drawable-xhdpi/ic_translate.png deleted file mode 100644 index 73a5393b..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_translate.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_account_group.png b/app/src/main/res/drawable-xxhdpi/ic_account_group.png deleted file mode 100644 index 2080d107..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_account_group.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_account_star.png b/app/src/main/res/drawable-xxhdpi/ic_account_star.png deleted file mode 100644 index ca802350..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_account_star.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_book_open.png b/app/src/main/res/drawable-xxhdpi/ic_book_open.png deleted file mode 100644 index fc7ea0d5..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_book_open.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_brush.png b/app/src/main/res/drawable-xxhdpi/ic_brush.png deleted file mode 100644 index 2a5a71a2..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_brush.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_gender_female.png b/app/src/main/res/drawable-xxhdpi/ic_gender_female.png deleted file mode 100644 index f2cb8663..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_gender_female.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_gender_male.png b/app/src/main/res/drawable-xxhdpi/ic_gender_male.png deleted file mode 100644 index 3ba80a52..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_gender_male.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_tag.png b/app/src/main/res/drawable-xxhdpi/ic_tag.png deleted file mode 100644 index 10494383..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_tag.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_translate.png b/app/src/main/res/drawable-xxhdpi/ic_translate.png deleted file mode 100644 index 49d105a1..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_translate.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_account_group.png b/app/src/main/res/drawable-xxxhdpi/ic_account_group.png deleted file mode 100644 index 7ad2921a..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_account_group.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_account_star.png b/app/src/main/res/drawable-xxxhdpi/ic_account_star.png deleted file mode 100644 index 2fa56e16..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_account_star.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_book_open.png b/app/src/main/res/drawable-xxxhdpi/ic_book_open.png deleted file mode 100644 index db934527..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_book_open.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_brush.png b/app/src/main/res/drawable-xxxhdpi/ic_brush.png deleted file mode 100644 index fa47de51..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_brush.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_gender_female.png b/app/src/main/res/drawable-xxxhdpi/ic_gender_female.png deleted file mode 100644 index 6b0c3dcd..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_gender_female.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_gender_male.png b/app/src/main/res/drawable-xxxhdpi/ic_gender_male.png deleted file mode 100644 index d7251b2b..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_gender_male.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_tag.png b/app/src/main/res/drawable-xxxhdpi/ic_tag.png deleted file mode 100644 index d6804b45..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_tag.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_translate.png b/app/src/main/res/drawable-xxxhdpi/ic_translate.png deleted file mode 100644 index 078e846a..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_translate.png and /dev/null differ diff --git a/app/src/main/res/drawable/account_group.xml b/app/src/main/res/drawable/account_group.xml new file mode 100644 index 00000000..9e5f4d81 --- /dev/null +++ b/app/src/main/res/drawable/account_group.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/account_star.xml b/app/src/main/res/drawable/account_star.xml new file mode 100644 index 00000000..dc8e4492 --- /dev/null +++ b/app/src/main/res/drawable/account_star.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/backspace_outline.xml b/app/src/main/res/drawable/backspace_outline.xml new file mode 100644 index 00000000..201e2e9b --- /dev/null +++ b/app/src/main/res/drawable/backspace_outline.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/book_open.xml b/app/src/main/res/drawable/book_open.xml new file mode 100644 index 00000000..66c81594 --- /dev/null +++ b/app/src/main/res/drawable/book_open.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/brush.xml b/app/src/main/res/drawable/brush.xml new file mode 100644 index 00000000..87b7c4c3 --- /dev/null +++ b/app/src/main/res/drawable/brush.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/fingerprint.xml b/app/src/main/res/drawable/fingerprint.xml index ffa8a34b..3418d25d 100644 --- a/app/src/main/res/drawable/fingerprint.xml +++ b/app/src/main/res/drawable/fingerprint.xml @@ -1,8 +1,10 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_gender_female_white.xml b/app/src/main/res/drawable/gender_female.xml similarity index 100% rename from app/src/main/res/drawable/ic_gender_female_white.xml rename to app/src/main/res/drawable/gender_female.xml diff --git a/app/src/main/res/drawable/ic_gender_male_white.xml b/app/src/main/res/drawable/gender_male.xml similarity index 91% rename from app/src/main/res/drawable/ic_gender_male_white.xml rename to app/src/main/res/drawable/gender_male.xml index a6e1a428..eb3750bb 100644 --- a/app/src/main/res/drawable/ic_gender_male_white.xml +++ b/app/src/main/res/drawable/gender_male.xml @@ -1,4 +1,4 @@ - + - + \ 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 index f1be51c2..f88355fb 100644 --- a/app/src/main/res/drawable/lock_pattern.xml +++ b/app/src/main/res/drawable/lock_pattern.xml @@ -4,5 +4,5 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/pin_filled.xml b/app/src/main/res/drawable/pin_filled.xml new file mode 100644 index 00000000..98fe185c --- /dev/null +++ b/app/src/main/res/drawable/pin_filled.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/refresh.xml b/app/src/main/res/drawable/refresh.xml new file mode 100644 index 00000000..cfa890d9 --- /dev/null +++ b/app/src/main/res/drawable/refresh.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tag.xml b/app/src/main/res/drawable/tag.xml new file mode 100644 index 00000000..47689267 --- /dev/null +++ b/app/src/main/res/drawable/tag.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/translate.xml b/app/src/main/res/drawable/translate.xml new file mode 100644 index 00000000..f357ae5f --- /dev/null +++ b/app/src/main/res/drawable/translate.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 index 00cd2898..db5b51be 100644 --- a/app/src/main/res/layout/activity_lock.xml +++ b/app/src/main/res/layout/activity_lock.xml @@ -36,7 +36,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" - android:layout_marginBottom="32dp" android:gravity="center" app:layout_constraintTop_toBottomOf="@id/lock_content" app:layout_constraintBottom_toTopOf="@id/lock_button_layout"> @@ -46,9 +45,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/fingerprint" + app:backgroundTint="@color/lock_fab" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" - app:backgroundTint="@color/dark_gray" + app:tint="@null" app:fabSize="mini"/> @@ -67,26 +67,29 @@ android:id="@+id/lock_pattern" android:layout_width="wrap_content" android:layout_height="wrap_content" + app:tint="@null" app:srcCompat="@drawable/lock_pattern" - app:backgroundTint="@color/colorPrimary" + app:backgroundTint="@color/lock_fab" app:fabSize="mini"/> diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml index e3ce7e65..f427226b 100644 --- a/app/src/main/res/layout/activity_main_content.xml +++ b/app/src/main/res/layout/activity_main_content.xml @@ -118,11 +118,17 @@ - + app:floatingSearch_close_search_on_keyboard_dismiss="true" + tools:ignore="NewApi" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 303eb3bc..dba09170 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -75,6 +75,13 @@ app:fab_label="@string/reader_fab_download" app:fab_size="mini"/> + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_pin_lock.xml b/app/src/main/res/layout/fragment_pin_lock.xml new file mode 100644 index 00000000..7099e499 --- /dev/null +++ b/app/src/main/res/layout/fragment_pin_lock.xml @@ -0,0 +1,42 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_galleryblock.xml b/app/src/main/res/layout/item_galleryblock.xml index bef8a183..5ba0e685 100644 --- a/app/src/main/res/layout/item_galleryblock.xml +++ b/app/src/main/res/layout/item_galleryblock.xml @@ -197,7 +197,8 @@ android:paddingLeft="8dp" android:paddingRight="8dp" android:paddingBottom="8dp" - android:orientation="horizontal"> + android:orientation="horizontal" + android:gravity="center_vertical"> + + + + タグ サムネイル おすすめ - イメージをギャラリーから見えなくする イメージを隠す ヘルプ 削除 @@ -141,4 +140,16 @@ 旧ギャラリーインポート中… インポート完了 ランダムギャラリーを開く + 予備のロックが設定されていないと指紋ロックは使用できません + Pupil指紋ロック™ + こうかはばつぐんだ! + 登場人物を全て18歳以上にする + キャッシュを使用しない + キャッシュを使用しないため、ダウンロードできません + (Korean only) + (Korean only) + ユーザーID + ユーザーIDをクリップボードにコピーしました + ダウンロードエラーが発生しました。リトライしますか? + リトライ \ 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 598da2cc..e4321f2c 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -97,7 +97,6 @@ 태그 관련 갤러리 미리보기 - 갤러리에서 이미지 검색이 되지 않도록 합니다 이미지 숨기기 도움말 삭제 @@ -141,4 +140,16 @@ 이전 버전 갤러리 가져오는 중… 가져오기 완료 무작위 갤러리 열기 + 지문 잠금은 다른 잠금 방식이 활성화 되어 있을 때만 사용 가능합니다 + Pupil 지문 인식™ + 힘세고 강한 지문 인식 + 판사님 저는 페도가 아닙니다 + 캐시 비활성화 + 캐시를 활성화 해야 다운로드를 진행할 수 있습니다 + 아청법 대응 옵션 추가 + 경찰서 정모 확률을 줄여보고자 캐시 비활성화/태그 필터를 추가하였습니다. 적용하시겠습니까? + 유저 ID + 유저 ID를 클립보드에 복사했습니다 + 다운로드 에러가 발생했습니다. 재시도 하시겠습니까? + 재시도 \ 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 f21275ad..3028ed1a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,6 +27,9 @@ (Korean only) (Korean only) + (Korean only) + (Korean only) + Update failed Please install manually by visiting github release page :{ (or try again!) Cannot auto update because permission is denied. Please download manually from the webpage. @@ -107,18 +110,22 @@ Series: %1$s Type: %1$s Language: %1$s + %dP Loading Go to page - Fullscreen + Fullscreen> + Retry Background download Cancel background download Downloading… Download complete Download error + Download Error occurred. Retry? + Help @@ -152,6 +159,8 @@ %s available Custom Location This folder is not writable. Please select another folder. + Disable Cache + Download is disabled when the cache is disabled Low quality images Load low quality images to improve load speed and data usage @@ -170,7 +179,6 @@ Dark mode Protect yourself against light attacks! Hide image from gallery - Hides image from gallery Backup favorites Backup file created Check out @@ -178,6 +186,8 @@ Restore failed %1$d entries restored Import old galleries + User ID + User ID is copied to clipboard @@ -187,6 +197,8 @@ Password Biometrics Fingerprint + Fingerprint can be only enabled if one of the other locks are enabled + Pupil Fingerprint Lock™ Enabled Input same lock once more to confirm Lock Do you want to remove lock? @@ -198,6 +210,7 @@ Language: Filter BL Filter Guro + I\'m not a pedophile Any Mirrors @@ -215,5 +228,6 @@ Importing old galleries… %1$d/%2$d Importing completed + Ah Shit, Here we go again diff --git a/app/src/main/res/xml/lock_preferences.xml b/app/src/main/res/xml/lock_preferences.xml index 3c3baab3..f17e5c01 100644 --- a/app/src/main/res/xml/lock_preferences.xml +++ b/app/src/main/res/xml/lock_preferences.xml @@ -17,7 +17,7 @@ - diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index cd28fb7b..dff10800 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -47,6 +47,10 @@ app:key="dl_location" app:title="@string/settings_dl_location"/> + + - + app:title="@string/settings_nomedia_title"/> + + - + \ No newline at end of file diff --git a/build.gradle b/build.gradle index ad7f92dd..5eb988a2 100644 --- a/build.gradle +++ b/build.gradle @@ -5,17 +5,16 @@ buildscript { repositories { google() jcenter() - maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' + classpath 'com.android.tools.build:gradle:4.0.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath 'com.google.gms:google-services:4.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files - classpath 'io.fabric.tools:gradle:1.31.0' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0' classpath 'com.google.firebase:perf-plugin:1.3.1' } } @@ -25,7 +24,7 @@ allprojects { google() jcenter() maven { url "https://jitpack.io" } - maven { url 'http://guardian.github.com/maven/repo-releases' } + maven { url 'https://guardian.github.com/maven/repo-releases' } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff8fd741..29e5e6d4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Feb 29 09:07:20 KST 2020 +#Thu Jun 18 15:48:09 KST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/libpupil/build.gradle b/libpupil/build.gradle index b886c59e..f943ef77 100644 --- a/libpupil/build.gradle +++ b/libpupil/build.gradle @@ -5,9 +5,9 @@ apply plugin: 'kotlinx-serialization' dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7' implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0" - implementation 'org.jsoup:jsoup:1.12.1' + implementation 'org.jsoup:jsoup:1.13.1' testImplementation 'junit:junit:4.13' } diff --git a/libpupil/src/main/java/xyz/quaver/Utils.kt b/libpupil/src/main/java/xyz/quaver/Utils.kt index c598f697..86fd5b9e 100644 --- a/libpupil/src/main/java/xyz/quaver/Utils.kt +++ b/libpupil/src/main/java/xyz/quaver/Utils.kt @@ -20,7 +20,7 @@ import kotlinx.serialization.UnstableDefault import kotlinx.serialization.json.Json import java.net.Proxy -var proxy = Proxy.NO_PROXY +var proxy : Proxy = Proxy.NO_PROXY @OptIn(UnstableDefault::class) var json = Json { diff --git a/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt b/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt index 6b324ce9..72e4cf48 100644 --- a/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt +++ b/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt @@ -16,31 +16,54 @@ package xyz.quaver.hiyobi -import org.jsoup.Jsoup +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.intOrNull import xyz.quaver.Code import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.protocol +import xyz.quaver.json import xyz.quaver.proxy +import java.net.URL +import javax.net.ssl.HttpsURLConnection fun getGalleryBlock(galleryID: Int) : GalleryBlock? { - val url = "$protocol//$hiyobi/info/$galleryID" + val url = "$protocol//api.$hiyobi/gallery/$galleryID" - val doc = Jsoup.connect(url).proxy(proxy).get() + val galleryBlock = with (URL(url).openConnection(proxy) as HttpsURLConnection) { + setRequestProperty("User-Agent", user_agent) + setRequestProperty("Cookie", cookie) + connectTimeout = 1000 + connect() - val galleryBlock = doc.selectFirst(".gallery-content") + inputStream.bufferedReader().use { it.readText() } + }.let { + json.parseJson(it).jsonObject + } - val galleryUrl = galleryBlock.selectFirst("a").attr("href") + val galleryUrl = "reader/$galleryID" - val thumbnails = listOf(galleryBlock.selectFirst("img").attr("abs:src")) + val thumbnails = listOf("$protocol//cdn.$hiyobi/tn/$galleryID.jpg") - val title = galleryBlock.selectFirst("b").text() - val artists = galleryBlock.select("tr:matches(작가) a[href~=artist]").map { it.text() } - val series = galleryBlock.select("tr:matches(원작) a").map { it.attr("href").substringAfter("series:").replace('_', ' ') } - val type = galleryBlock.selectFirst("tr:matches(종류) a").attr("href").substringAfter("type:").replace('_', ' ') + val title = galleryBlock["title"]?.contentOrNull ?: "" + val artists = galleryBlock["artists"]?.jsonArray?.mapNotNull { + it.jsonObject["value"]?.contentOrNull + } ?: listOf() + val series = galleryBlock["parodys"]?.jsonArray?.mapNotNull { + it.jsonObject["value"]?.contentOrNull + } ?: listOf() + val type = when (galleryBlock["type"]?.intOrNull) { + 1 -> "doujinshi" + 2 -> "manga" + 3 -> "artistcg" + 4 -> "gamecg" + else -> "" + } val language = "korean" - val relatedTags = galleryBlock.select("tr:matches(태그) a").map { it.attr("href").substringAfterLast('/').replace('_', ' ') } + val relatedTags = galleryBlock["tags"]?.jsonArray?.mapNotNull { + it.jsonObject["value"]?.contentOrNull + } ?: listOf() return GalleryBlock(Code.HIYOBI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) } \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt b/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt index 07babd9d..5ed65661 100644 --- a/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt +++ b/libpupil/src/main/java/xyz/quaver/hiyobi/reader.kt @@ -18,7 +18,7 @@ package xyz.quaver.hiyobi import kotlinx.serialization.UnstableDefault import kotlinx.serialization.builtins.list -import org.jsoup.Jsoup +import kotlinx.serialization.json.contentOrNull import xyz.quaver.Code import xyz.quaver.hitomi.GalleryFiles import xyz.quaver.hitomi.GalleryInfo @@ -64,17 +64,26 @@ fun renewCookie() : String { @OptIn(UnstableDefault::class) fun getReader(galleryID: Int) : Reader { - val reader = "https://$hiyobi/reader/$galleryID" - val url = "https://cdn.hiyobi.me/data/json/${galleryID}_list.json" + val data = "https://cdn.$hiyobi/data/json/$galleryID.json" + val list = "https://cdn.$hiyobi/data/json/${galleryID}_list.json" - val title = Jsoup.connect(reader).proxy(proxy).get().title() + val title = with(URL(data).openConnection(proxy) as HttpsURLConnection) { + setRequestProperty("User-Agent", user_agent) + setRequestProperty("Cookie", cookie) + connectTimeout = 1000 + connect() + + inputStream.bufferedReader().use { it.readText() } + }.let { + json.parseJson(it).jsonObject["n"]?.contentOrNull + } val galleryFiles = json.parse( GalleryFiles.serializer().list, - with(URL(url).openConnection(proxy) as HttpsURLConnection) { + with(URL(list).openConnection(proxy) as HttpsURLConnection) { setRequestProperty("User-Agent", user_agent) setRequestProperty("Cookie", cookie) - connectTimeout = 2000 + connectTimeout = 1000 connect() inputStream.bufferedReader().use { it.readText() } diff --git a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt index bd3661a6..b818b7fb 100644 --- a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt +++ b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt @@ -82,7 +82,7 @@ class UnitTest { @Test fun test_hiyobi() { - val reader = xyz.quaver.hiyobi.getReader(1574736) + val reader = xyz.quaver.hiyobi.getReader(1664762) print(reader) }