Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67abc15442 | ||
|
|
e94cddb86a | ||
|
|
700f7a33a5 | ||
|
|
41e952144d | ||
|
|
910ed65937 | ||
|
|
e06701a2fb | ||
|
|
62dce26c73 | ||
|
|
ac0cff62d4 | ||
|
|
655c060814 | ||
|
|
36d27895e7 |
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -3,7 +3,10 @@
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="../../../../layout/custom_preview.xml" value="0.2564814814814815" />
|
||||
<entry key="app/src/main/res/layout/reader_activity.xml" value="0.14351851851851852" />
|
||||
<entry key="app/src/main/res/xml/lock_preferences.xml" value="0.5119791666666667" />
|
||||
<entry key="app/src/main/res/xml/root_preferences.xml" value="0.5119791666666667" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*Pupil, Hitomi.la viewer for Android*
|
||||
|
||||

|
||||
[](https://github.com/tom5079/Pupil/releases/download/5.2.18/Pupil-v5.2.18.apk)
|
||||
[](https://github.com/tom5079/Pupil/releases/download/5.2.21/Pupil-v5.2.21.apk)
|
||||
[](https://discord.gg/Stj4b5v)
|
||||
|
||||
# Features
|
||||
|
||||
@@ -38,7 +38,7 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 31
|
||||
versionCode 69
|
||||
versionName "5.2.19"
|
||||
versionName "5.2.22"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
@@ -82,19 +82,20 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.4.0"
|
||||
implementation "androidx.appcompat:appcompat:1.4.1"
|
||||
implementation "androidx.activity:activity-ktx:1.4.0"
|
||||
implementation "androidx.fragment:fragment-ktx:1.4.0"
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.2"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
|
||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||
implementation "androidx.biometric:biometric:1.1.0"
|
||||
implementation "androidx.work:work-runtime-ktx:2.7.1"
|
||||
implementation 'androidx.webkit:webkit:1.4.0'
|
||||
|
||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||
|
||||
implementation "com.google.android.material:material:1.4.0"
|
||||
implementation "com.google.android.material:material:1.5.0"
|
||||
|
||||
implementation platform('com.google.firebase:firebase-bom:29.0.3')
|
||||
implementation "com.google.firebase:firebase-analytics-ktx"
|
||||
@@ -102,7 +103,7 @@ dependencies {
|
||||
implementation "com.google.firebase:firebase-perf-ktx"
|
||||
|
||||
implementation "com.google.android.gms:play-services-oss-licenses:17.0.0"
|
||||
implementation "com.google.android.gms:play-services-mlkit-face-detection:16.2.1"
|
||||
implementation "com.google.android.gms:play-services-mlkit-face-detection:17.0.0"
|
||||
|
||||
implementation "com.github.clans:fab:1.6.4"
|
||||
|
||||
@@ -128,8 +129,6 @@ dependencies {
|
||||
|
||||
implementation "org.jsoup:jsoup:1.14.3"
|
||||
|
||||
implementation "com.google.guava:guava:31.0.1-android"
|
||||
|
||||
implementation "xyz.quaver:documentfilex:0.7.2"
|
||||
implementation "xyz.quaver:floatingsearchview:1.1.7"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 69,
|
||||
"versionName": "5.2.19",
|
||||
"versionName": "5.2.22",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -29,10 +29,10 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.webkit.*
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.webkit.WebViewCompat
|
||||
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory
|
||||
import com.github.piasy.biv.BigImageViewer
|
||||
import com.github.piasy.biv.loader.fresco.FrescoImageLoader
|
||||
@@ -43,6 +43,8 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.*
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.pupil.hitomi.evaluationContext
|
||||
@@ -83,6 +85,7 @@ val _webViewFlow = MutableSharedFlow<Pair<String, String?>>()
|
||||
val webViewFlow = _webViewFlow.asSharedFlow()
|
||||
var webViewReady = false
|
||||
var webViewFailed = false
|
||||
var oldWebView = false
|
||||
private var reloadJob: Job? = null
|
||||
|
||||
fun reloadWebView() {
|
||||
@@ -91,6 +94,7 @@ fun reloadWebView() {
|
||||
reloadJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
webViewReady = false
|
||||
webViewFailed = false
|
||||
oldWebView = false
|
||||
|
||||
evaluationContext.cancelChildren(CancellationException("reload"))
|
||||
|
||||
@@ -121,7 +125,7 @@ private var htmlVersion: String = ""
|
||||
fun reloadWhenFailedOrUpdate() = CoroutineScope(Dispatchers.Default).launch {
|
||||
while (true) {
|
||||
if (
|
||||
webViewFailed ||
|
||||
(webViewFailed && !oldWebView) ||
|
||||
runCatching {
|
||||
URL(
|
||||
if (BuildConfig.DEBUG)
|
||||
@@ -156,7 +160,13 @@ fun initWebView(context: Context) {
|
||||
|
||||
webViewClient = object: WebViewClient() {
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
webViewReady = true
|
||||
webView.evaluateJavascript("self_test()") {
|
||||
val result: String = Json.decodeFromString(it)
|
||||
|
||||
oldWebView = result == "es2020_unsupported";
|
||||
webViewReady = result == "OK";
|
||||
webViewFailed = result != "OK";
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReceivedError(
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package xyz.quaver.pupil.hitomi
|
||||
|
||||
import android.util.Log
|
||||
import android.webkit.WebView
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -25,10 +26,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import xyz.quaver.pupil.webView
|
||||
import xyz.quaver.pupil.webViewFailed
|
||||
import xyz.quaver.pupil.webViewFlow
|
||||
import xyz.quaver.pupil.webViewReady
|
||||
import xyz.quaver.pupil.*
|
||||
import java.util.*
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
@@ -55,9 +53,11 @@ suspend inline fun <reified T> WebView.evaluate(script: String): T = coroutineSc
|
||||
|
||||
while (result == null) {
|
||||
try {
|
||||
result = withContext(evaluationContext) {
|
||||
while (webViewFailed || !webViewReady) yield()
|
||||
while (!oldWebView && !(webViewReady && !webViewFailed)) delay(100)
|
||||
|
||||
result = if (oldWebView)
|
||||
"null"
|
||||
else withContext(evaluationContext) {
|
||||
suspendCoroutine { continuation ->
|
||||
evaluateJavascript(script) {
|
||||
continuation.resume(it)
|
||||
@@ -82,9 +82,11 @@ suspend inline fun <reified T> WebView.evaluatePromise(
|
||||
|
||||
while (result == null) {
|
||||
try {
|
||||
result = withContext(evaluationContext) {
|
||||
while (webViewFailed || !webViewReady) yield()
|
||||
while (!oldWebView && !(webViewReady && !webViewFailed)) delay(100)
|
||||
|
||||
result = if (oldWebView)
|
||||
"null"
|
||||
else withContext(evaluationContext) {
|
||||
val uid = UUID.randomUUID().toString()
|
||||
|
||||
val flow: Flow<Pair<String, String?>> = webViewFlow.transformWhile { (currentUid, result) ->
|
||||
|
||||
@@ -29,7 +29,6 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.TaskStackBuilder
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.common.util.concurrent.RateLimiter
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -166,9 +165,6 @@ class DownloadService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
private val rateLimiter = RateLimiter.create(2.0)
|
||||
private val rateLimitHost = Regex("..?\\.hitomi.la")
|
||||
|
||||
private val interceptor: PupilInterceptor = { chain ->
|
||||
val request = chain.request()
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package xyz.quaver.pupil.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
@@ -37,6 +38,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.webkit.WebViewCompat
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
@@ -105,6 +107,8 @@ class MainActivity :
|
||||
|
||||
private lateinit var binding: MainActivityBinding
|
||||
|
||||
private var oldWebViewJob: Job? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = MainActivityBinding.inflate(layoutInflater)
|
||||
@@ -125,9 +129,40 @@ class MainActivity :
|
||||
if (Preferences["download_folder", ""].isEmpty())
|
||||
DownloadLocationDialogFragment().show(supportFragmentManager, "Download Location Dialog")
|
||||
|
||||
oldWebViewJob = CoroutineScope(Dispatchers.Unconfined).launch {
|
||||
do {
|
||||
delay(1000)
|
||||
if (oldWebView) {
|
||||
AlertDialog.Builder(this@MainActivity)
|
||||
.setTitle(android.R.string.dialog_alert_title)
|
||||
.setMessage(R.string.old_webview)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
WebViewCompat.getCurrentWebViewPackage(this@MainActivity)?.packageName?.let { packageName ->
|
||||
try {
|
||||
startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("market://details?id=$packageName")
|
||||
)
|
||||
)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://play.google.com/store/apps/details?id=$packageName")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.show()
|
||||
break
|
||||
}
|
||||
} while (isActive)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
!Preferences["download_folder_ignore_warning", false] &&
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Preferences["download_folder_ignore_warning", false] &&
|
||||
ContextCompat.getExternalFilesDirs(this, null).filterNotNull().map { Uri.fromFile(it).toString() }
|
||||
.contains(Preferences["download_folder", ""])
|
||||
) {
|
||||
@@ -169,6 +204,8 @@ class MainActivity :
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
oldWebViewJob?.cancel()
|
||||
|
||||
(binding.contents.recyclerview.adapter as? GalleryBlockAdapter)?.updateAll = false
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import xyz.quaver.pupil.hitomi.GalleryBlock
|
||||
import xyz.quaver.pupil.hitomi.GalleryInfo
|
||||
import xyz.quaver.pupil.hitomi.getReferer
|
||||
import xyz.quaver.pupil.hitomi.imageUrlFromImage
|
||||
import xyz.quaver.pupil.userAgent
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@@ -114,7 +115,7 @@ suspend fun GalleryInfo.getRequestBuilders(): List<Request.Builder> {
|
||||
.getOrDefault("https://a/")
|
||||
)
|
||||
.header("Referer", "https://hitomi.la/")
|
||||
.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36")
|
||||
.header("User-Agent", userAgent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
|
||||
setNegativeButton(if (force) android.R.string.cancel else R.string.ignore) { _, _ ->
|
||||
if (!force)
|
||||
preferences.edit()
|
||||
.putLong("ignore_update_until", System.currentTimeMillis() + 604800000)
|
||||
.putLong("ignore_update_until", System.currentTimeMillis() + 86400000)
|
||||
.apply()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,4 +157,5 @@
|
||||
<string name="settings_max_concurrent_download">並列ダウンロード</string>
|
||||
<string name="unaccessible_download_folder">アンドロイド11以上では外部からのアプリ内部空間接近が不可能です。ダウンロードフォルダを変更しますか?</string>
|
||||
<string name="settings_networking">ネットワーク</string>
|
||||
<string name="old_webview">WebViewのアップデートが必要です</string>
|
||||
</resources>
|
||||
@@ -157,4 +157,5 @@
|
||||
<string name="settings_max_concurrent_download">병렬 다운로드</string>
|
||||
<string name="unaccessible_download_folder">안드로이드 11 이상에서는 외부에서 현재 다운로드 폴더에 접근할 수 없습니다. 변경하시겠습니까?</string>
|
||||
<string name="settings_networking">네트워크</string>
|
||||
<string name="old_webview">WebView 업데이트가 필요합니다</string>
|
||||
</resources>
|
||||
@@ -51,6 +51,8 @@
|
||||
|
||||
<string name="unaccessible_download_folder">From Android 11 and above, current Download folder cannot be accessed by outside apps. Would you like to change the download folder?</string>
|
||||
|
||||
<string name="old_webview">You are using an old version of WebView. Please update it on PlayStore</string>
|
||||
|
||||
<string name="main_drawer_home">Home</string>
|
||||
<string name="main_drawer_history">History</string>
|
||||
<string name="main_drawer_downloads">Downloads</string>
|
||||
|
||||
@@ -6,7 +6,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath 'com.android.tools.build:gradle:7.1.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"
|
||||
@@ -14,7 +14,7 @@ buildscript {
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
classpath "com.google.firebase:firebase-crashlytics-gradle:2.8.1"
|
||||
classpath "com.google.firebase:perf-plugin:1.4.0"
|
||||
classpath "com.google.firebase:perf-plugin:1.4.1"
|
||||
classpath "com.google.android.gms:oss-licenses-plugin:0.10.4"
|
||||
}
|
||||
}
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
||||
|
||||
Reference in New Issue
Block a user