(Almost) Full OkHTTP implementation
This commit is contained in:
5
.idea/jarRepositories.xml
generated
5
.idea/jarRepositories.xml
generated
@@ -51,5 +51,10 @@
|
|||||||
<option name="name" value="maven4" />
|
<option name="name" value="maven4" />
|
||||||
<option name="url" value="https://maven.fabric.io/public" />
|
<option name="url" value="https://maven.fabric.io/public" />
|
||||||
</remote-repository>
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="MavenLocal" />
|
||||||
|
<option name="name" value="MavenLocal" />
|
||||||
|
<option name="url" value="file:/$USER_HOME$/.m2/repository/" />
|
||||||
|
</remote-repository>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -48,6 +48,7 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental'
|
freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental'
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@@ -68,7 +69,6 @@ dependencies {
|
|||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
implementation "androidx.biometric:biometric:1.0.1"
|
implementation "androidx.biometric:biometric:1.0.1"
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
||||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||||
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
||||||
@@ -78,8 +78,12 @@ dependencies {
|
|||||||
implementation 'com.google.firebase:firebase-perf:19.0.8'
|
implementation 'com.google.firebase:firebase-perf:19.0.8'
|
||||||
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
||||||
implementation 'com.github.clans:fab:1.6.4'
|
implementation 'com.github.clans:fab:1.6.4'
|
||||||
|
//noinspection GradleDependency
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||||
implementation "com.github.bumptech.glide:okhttp3-integration:4.11.0"
|
implementation ("com.github.bumptech.glide:okhttp3-integration:4.11.0") {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
implementation 'com.github.bumptech.glide:annotations:4.11.0'
|
implementation 'com.github.bumptech.glide:annotations:4.11.0'
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
@@ -92,7 +96,7 @@ dependencies {
|
|||||||
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
||||||
//implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
|
//implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
|
||||||
implementation "ru.noties.markwon:core:3.1.0"
|
implementation "ru.noties.markwon:core:3.1.0"
|
||||||
implementation ("xyz.quaver:libpupil:1.0") {
|
implementation ("xyz.quaver:libpupil:1.1") {
|
||||||
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
|
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
|
||||||
}
|
}
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
|
|||||||
@@ -37,8 +37,11 @@
|
|||||||
|
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<service android:name=".services.DownloadService"
|
||||||
|
android:exported="false"/>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".BroadcastReciever"
|
android:name=".reciever.UpdateBroadcastReciever"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil
|
package xyz.quaver.pupil
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
@@ -25,7 +26,6 @@ import android.content.Context
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.multidex.MultiDexApplication
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
|
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
|
||||||
import com.google.android.gms.common.GooglePlayServicesRepairableException
|
import com.google.android.gms.common.GooglePlayServicesRepairableException
|
||||||
@@ -35,16 +35,37 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import xyz.quaver.proxy
|
import okhttp3.Dispatcher
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Response
|
||||||
import xyz.quaver.pupil.util.GalleryList
|
import xyz.quaver.pupil.util.GalleryList
|
||||||
import xyz.quaver.pupil.util.getProxy
|
import xyz.quaver.pupil.util.getProxyInfo
|
||||||
|
import xyz.quaver.setClient
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class Pupil : MultiDexApplication() {
|
typealias PupilInterceptor = (Interceptor.Chain) -> Response
|
||||||
|
|
||||||
lateinit var histories: GalleryList
|
lateinit var histories: GalleryList
|
||||||
lateinit var favorites: GalleryList
|
private set
|
||||||
|
lateinit var favorites: GalleryList
|
||||||
|
private set
|
||||||
|
|
||||||
|
val interceptors = mutableMapOf<KClass<out Any>, PupilInterceptor>()
|
||||||
|
|
||||||
|
lateinit var clientBuilder: OkHttpClient.Builder
|
||||||
|
|
||||||
|
var clientHolder: OkHttpClient? = null
|
||||||
|
val client: OkHttpClient
|
||||||
|
get() = clientHolder ?: clientBuilder.build().also {
|
||||||
|
clientHolder = it
|
||||||
|
setClient(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Pupil : Application() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
@@ -63,7 +84,19 @@ class Pupil : MultiDexApplication() {
|
|||||||
|
|
||||||
FirebaseCrashlytics.getInstance().setUserId(userID)
|
FirebaseCrashlytics.getInstance().setUserId(userID)
|
||||||
|
|
||||||
proxy = getProxy(this)
|
val proxyInfo = getProxyInfo(this)
|
||||||
|
|
||||||
|
clientBuilder = OkHttpClient.Builder()
|
||||||
|
.connectTimeout(0, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(0, TimeUnit.SECONDS)
|
||||||
|
.proxy(proxyInfo.proxy())
|
||||||
|
.proxyAuthenticator(proxyInfo.authenticator())
|
||||||
|
.addInterceptor { chain ->
|
||||||
|
val request = chain.request()
|
||||||
|
val tag = request.tag() ?: return@addInterceptor chain.proceed(request)
|
||||||
|
|
||||||
|
interceptors[tag::class]?.invoke(chain) ?: chain.proceed(request)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
preference.getString("dl_location", null).also {
|
preference.getString("dl_location", null).also {
|
||||||
@@ -112,6 +145,13 @@ class Pupil : MultiDexApplication() {
|
|||||||
lockscreenVisibility = Notification.VISIBILITY_SECRET
|
lockscreenVisibility = Notification.VISIBILITY_SECRET
|
||||||
})
|
})
|
||||||
|
|
||||||
|
manager.createNotificationChannel(NotificationChannel("downloader", getString(R.string.channel_downloader), NotificationManager.IMPORTANCE_LOW).apply {
|
||||||
|
description = getString(R.string.channel_downloader_description)
|
||||||
|
enableLights(false)
|
||||||
|
enableVibration(false)
|
||||||
|
lockscreenVisibility = Notification.VISIBILITY_SECRET
|
||||||
|
})
|
||||||
|
|
||||||
manager.createNotificationChannel(NotificationChannel("update", getString(R.string.channel_update), NotificationManager.IMPORTANCE_HIGH).apply {
|
manager.createNotificationChannel(NotificationChannel("update", getString(R.string.channel_update), NotificationManager.IMPORTANCE_HIGH).apply {
|
||||||
description = getString(R.string.channel_update_description)
|
description = getString(R.string.channel_update_description)
|
||||||
enableLights(true)
|
enableLights(true)
|
||||||
@@ -127,7 +167,6 @@ class Pupil : MultiDexApplication() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
|
||||||
AppCompatDelegate.setDefaultNightMode(when (preference.getBoolean("dark_mode", false)) {
|
AppCompatDelegate.setDefaultNightMode(when (preference.getBoolean("dark_mode", false)) {
|
||||||
true -> AppCompatDelegate.MODE_NIGHT_YES
|
true -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
false -> AppCompatDelegate.MODE_NIGHT_NO
|
false -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class PupilGlideModule : AppGlideModule() {
|
|||||||
registry.append(
|
registry.append(
|
||||||
GlideUrl::class.java,
|
GlideUrl::class.java,
|
||||||
InputStream::class.java,
|
InputStream::class.java,
|
||||||
OkHttpUrlLoader.Factory(DownloadWorker.getInstance(context).client)
|
OkHttpUrlLoader.Factory(client)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import xyz.quaver.hitomi.getReader
|
|||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.BuildConfig
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.favorites
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.util.GalleryList
|
import xyz.quaver.pupil.util.GalleryList
|
||||||
import xyz.quaver.pupil.util.download.Cache
|
import xyz.quaver.pupil.util.download.Cache
|
||||||
@@ -68,8 +69,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
PREV
|
PREV
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var favorites: GalleryList
|
|
||||||
|
|
||||||
val timer = Timer()
|
val timer = Timer()
|
||||||
|
|
||||||
var isThin = false
|
var isThin = false
|
||||||
@@ -257,9 +256,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!::favorites.isInitialized)
|
|
||||||
favorites = (context.applicationContext as Pupil).favorites
|
|
||||||
|
|
||||||
with(galleryblock_favorite) {
|
with(galleryblock_favorite) {
|
||||||
setImageResource(if (favorites.contains(galleryBlock.id)) R.drawable.ic_star_filled else R.drawable.ic_star_empty)
|
setImageResource(if (favorites.contains(galleryBlock.id)) R.drawable.ic_star_filled else R.drawable.ic_star_empty)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package xyz.quaver.pupil
|
package xyz.quaver.pupil.reciever
|
||||||
|
|
||||||
import android.app.DownloadManager
|
import android.app.DownloadManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
@@ -29,15 +29,10 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class BroadcastReciever : BroadcastReceiver() {
|
class UpdateBroadcastReciever : BroadcastReceiver() {
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val ACTION_CANCEL_IMPORT = "ACTION_CANCEL_IMPORT"
|
|
||||||
|
|
||||||
const val EXTRA_IMPORT_NOTIFICATION_ID = "EXTRA_IMPORT_NOTIFICATION_ID"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
context ?: return
|
context ?: return
|
||||||
155
app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
Normal file
155
app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package xyz.quaver.pupil.services
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Binder
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.util.SparseArray
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import okio.*
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
|
|
||||||
|
private typealias ProgressListener = (Any?, Long, Long, Boolean) -> Unit
|
||||||
|
|
||||||
|
class Cache(context: Context) : ContextWrapper(context) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadService : Service() {
|
||||||
|
|
||||||
|
//region Notification
|
||||||
|
private val notificationManager by lazy {
|
||||||
|
NotificationManagerCompat.from(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val serviceNotification by lazy {
|
||||||
|
NotificationCompat.Builder(this, "downloader")
|
||||||
|
.setContentTitle(getString(R.string.downloader_running))
|
||||||
|
.setProgress(0, 0, false)
|
||||||
|
.setSmallIcon(R.drawable.ic_notification)
|
||||||
|
.setOngoing(true)
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region ProgressListener
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private val progressListener: ProgressListener = listener@{ tag, bytesRead, contentLength, done ->
|
||||||
|
val (galleryID, index) = (tag as? Pair<Int, Int>) ?: return@listener
|
||||||
|
|
||||||
|
if (!done && progress[galleryID]?.get(index)?.isFinite() == true)
|
||||||
|
progress[galleryID]?.set(index, bytesRead * 100F / contentLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProgressResponseBody(
|
||||||
|
val tag: Any?,
|
||||||
|
val responseBody: ResponseBody,
|
||||||
|
val progressListener : ProgressListener
|
||||||
|
) : ResponseBody() {
|
||||||
|
private var bufferedSource : BufferedSource? = null
|
||||||
|
|
||||||
|
override fun contentLength() = responseBody.contentLength()
|
||||||
|
override fun contentType() = responseBody.contentType()
|
||||||
|
|
||||||
|
override fun source(): BufferedSource {
|
||||||
|
if (bufferedSource == null)
|
||||||
|
bufferedSource = Okio.buffer(source(responseBody.source()))
|
||||||
|
|
||||||
|
return bufferedSource!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun source(source: Source) = object: ForwardingSource(source) {
|
||||||
|
var totalBytesRead = 0L
|
||||||
|
|
||||||
|
override fun read(sink: Buffer, byteCount: Long): Long {
|
||||||
|
val bytesRead = super.read(sink, byteCount)
|
||||||
|
|
||||||
|
totalBytesRead += if (bytesRead == -1L) 0L else bytesRead
|
||||||
|
progressListener.invoke(tag, totalBytesRead, responseBody.contentLength(), bytesRead == -1L)
|
||||||
|
|
||||||
|
return bytesRead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val interceptor = Interceptor { chain ->
|
||||||
|
val request = chain.request()
|
||||||
|
var response = chain.proceed(request)
|
||||||
|
|
||||||
|
var retry = 5
|
||||||
|
while (!response.isSuccessful && retry > 0) {
|
||||||
|
response = chain.proceed(request)
|
||||||
|
retry--
|
||||||
|
}
|
||||||
|
|
||||||
|
response.newBuilder()
|
||||||
|
.body(response.body()?.let {
|
||||||
|
ProgressResponseBody(request.tag(), it, progressListener)
|
||||||
|
}).build()
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEY
|
||||||
|
* primary galleryID
|
||||||
|
* secondary index
|
||||||
|
* PRIMARY VALUE
|
||||||
|
* MutableList -> Download in progress
|
||||||
|
* null -> Loading / Gallery doesn't exist
|
||||||
|
* SECONDARY VALUE
|
||||||
|
* 0 <= value < 100 -> Download in progress
|
||||||
|
* Float.POSITIVE_INFINITY -> Download completed
|
||||||
|
*/
|
||||||
|
val progress = SparseArray<MutableList<Float>?>()
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inner class Binder : android.os.Binder() {
|
||||||
|
val service = this@DownloadService
|
||||||
|
}
|
||||||
|
|
||||||
|
private val binder = Binder()
|
||||||
|
override fun onBind(p0: Intent?) = binder
|
||||||
|
|
||||||
|
fun load(galleryID: Int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,9 @@ import android.annotation.SuppressLint
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
|
import android.net.Proxy
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.*
|
import android.text.*
|
||||||
import android.text.style.AlignmentSpan
|
import android.text.style.AlignmentSpan
|
||||||
@@ -59,9 +61,11 @@ import xyz.quaver.hitomi.GalleryBlock
|
|||||||
import xyz.quaver.hitomi.doSearch
|
import xyz.quaver.hitomi.doSearch
|
||||||
import xyz.quaver.hitomi.getGalleryIDsFromNozomi
|
import xyz.quaver.hitomi.getGalleryIDsFromNozomi
|
||||||
import xyz.quaver.hitomi.getSuggestionsForQuery
|
import xyz.quaver.hitomi.getSuggestionsForQuery
|
||||||
import xyz.quaver.pupil.Pupil
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||||
|
import xyz.quaver.pupil.favorites
|
||||||
|
import xyz.quaver.pupil.histories
|
||||||
|
import xyz.quaver.pupil.services.DownloadService
|
||||||
import xyz.quaver.pupil.types.TagSuggestion
|
import xyz.quaver.pupil.types.TagSuggestion
|
||||||
import xyz.quaver.pupil.types.Tags
|
import xyz.quaver.pupil.types.Tags
|
||||||
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
||||||
@@ -110,9 +114,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
private var currentPage = 0
|
private var currentPage = 0
|
||||||
|
|
||||||
private lateinit var histories: GalleryList
|
|
||||||
private lateinit var favorites: GalleryList
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -147,11 +148,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(application as Pupil) {
|
|
||||||
this@MainActivity.histories = histories
|
|
||||||
this@MainActivity.favorites = favorites
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intent.action == Intent.ACTION_VIEW) {
|
if (intent.action == Intent.ACTION_VIEW) {
|
||||||
intent.dataString?.let { url ->
|
intent.dataString?.let { url ->
|
||||||
restore(favorites, url,
|
restore(favorites, url,
|
||||||
@@ -166,6 +162,15 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
Intent(this, DownloadService::class.java).let {
|
||||||
|
when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ->
|
||||||
|
startForegroundService(it)
|
||||||
|
else ->
|
||||||
|
startService(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkUpdate(this)
|
checkUpdate(this)
|
||||||
|
|
||||||
initView()
|
initView()
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ import xyz.quaver.Code
|
|||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.ReaderAdapter
|
import xyz.quaver.pupil.adapters.ReaderAdapter
|
||||||
|
import xyz.quaver.pupil.favorites
|
||||||
|
import xyz.quaver.pupil.histories
|
||||||
import xyz.quaver.pupil.util.GalleryList
|
import xyz.quaver.pupil.util.GalleryList
|
||||||
import xyz.quaver.pupil.util.download.Cache
|
import xyz.quaver.pupil.util.download.Cache
|
||||||
import xyz.quaver.pupil.util.download.DownloadWorker
|
import xyz.quaver.pupil.util.download.DownloadWorker
|
||||||
@@ -78,16 +80,12 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private var menu: Menu? = null
|
private var menu: Menu? = null
|
||||||
|
|
||||||
private lateinit var favorites: GalleryList
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
title = getString(R.string.reader_loading)
|
title = getString(R.string.reader_loading)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||||
|
|
||||||
favorites = (application as Pupil).favorites
|
|
||||||
|
|
||||||
window.setFlags(
|
window.setFlags(
|
||||||
WindowManager.LayoutParams.FLAG_SECURE,
|
WindowManager.LayoutParams.FLAG_SECURE,
|
||||||
WindowManager.LayoutParams.FLAG_SECURE)
|
WindowManager.LayoutParams.FLAG_SECURE)
|
||||||
@@ -96,7 +94,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
handleIntent(intent)
|
handleIntent(intent)
|
||||||
|
|
||||||
(application as Pupil).histories.add(galleryID)
|
histories.add(galleryID)
|
||||||
FirebaseCrashlytics.getInstance().setCustomKey("GalleryID", galleryID)
|
FirebaseCrashlytics.getInstance().setCustomKey("GalleryID", galleryID)
|
||||||
|
|
||||||
if (galleryID == 0) {
|
if (galleryID == 0) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import kotlinx.serialization.json.Json
|
|||||||
import net.rdrei.android.dirchooser.DirectoryChooserActivity
|
import net.rdrei.android.dirchooser.DirectoryChooserActivity
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.favorites
|
||||||
import xyz.quaver.pupil.ui.fragment.LockSettingsFragment
|
import xyz.quaver.pupil.ui.fragment.LockSettingsFragment
|
||||||
import xyz.quaver.pupil.ui.fragment.SettingsFragment
|
import xyz.quaver.pupil.ui.fragment.SettingsFragment
|
||||||
import xyz.quaver.pupil.util.*
|
import xyz.quaver.pupil.util.*
|
||||||
@@ -100,7 +101,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
inputStream.readBytes().toString(Charset.defaultCharset())
|
inputStream.readBytes().toString(Charset.defaultCharset())
|
||||||
}
|
}
|
||||||
|
|
||||||
(application as Pupil).favorites.addAll(Json.decodeFromString<List<Int>>(str).also {
|
favorites.addAll(Json.decodeFromString<List<Int>>(str).also {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
window.decorView,
|
window.decorView,
|
||||||
getString(R.string.settings_restore_success, it.size),
|
getString(R.string.settings_restore_success, it.size),
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import xyz.quaver.pupil.Pupil
|
|||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||||
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
|
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
|
||||||
|
import xyz.quaver.pupil.histories
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
import xyz.quaver.pupil.util.ItemClickSupport
|
import xyz.quaver.pupil.util.ItemClickSupport
|
||||||
@@ -81,7 +82,7 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
|
|||||||
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
||||||
putExtra("galleryID", galleryID)
|
putExtra("galleryID", galleryID)
|
||||||
})
|
})
|
||||||
(context.applicationContext as Pupil).histories.add(galleryID)
|
histories.add(galleryID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +265,7 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
|
|||||||
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
||||||
putExtra("galleryID", galleries[position].id)
|
putExtra("galleryID", galleries[position].id)
|
||||||
})
|
})
|
||||||
(context.applicationContext as Pupil).histories.add(galleries[position].id)
|
histories.add(galleries[position].id)
|
||||||
}
|
}
|
||||||
onItemLongClickListener = { _, position, _ ->
|
onItemLongClickListener = { _, position, _ ->
|
||||||
GalleryDialog(
|
GalleryDialog(
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ import androidx.preference.PreferenceManager
|
|||||||
import kotlinx.android.synthetic.main.dialog_proxy.view.*
|
import kotlinx.android.synthetic.main.dialog_proxy.view.*
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import xyz.quaver.proxy
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.client
|
||||||
|
import xyz.quaver.pupil.clientBuilder
|
||||||
|
import xyz.quaver.pupil.clientHolder
|
||||||
import xyz.quaver.pupil.util.ProxyInfo
|
import xyz.quaver.pupil.util.ProxyInfo
|
||||||
import xyz.quaver.pupil.util.getProxyInfo
|
import xyz.quaver.pupil.util.getProxyInfo
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
@@ -117,12 +119,15 @@ class ProxyDialog(context: Context) : Dialog(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProxyInfo(type, addr, port, username, password).let {
|
ProxyInfo(type, addr, port, username, password).let {
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy",
|
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy",
|
||||||
Json.encodeToString(it)
|
Json.encodeToString(it)
|
||||||
).apply()
|
).apply()
|
||||||
|
|
||||||
proxy = it.proxy()
|
clientBuilder
|
||||||
|
.proxy(it.proxy())
|
||||||
|
.proxyAuthenticator(it.authenticator())
|
||||||
|
clientHolder = null
|
||||||
|
client
|
||||||
}
|
}
|
||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.client
|
||||||
|
import xyz.quaver.pupil.favorites
|
||||||
import xyz.quaver.pupil.util.restore
|
import xyz.quaver.pupil.util.restore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@@ -52,7 +54,7 @@ class ManageFavoritesFragment : PreferenceFragmentCompat() {
|
|||||||
.build()
|
.build()
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
OkHttpClient().newCall(request).enqueue(object: Callback {
|
client.newCall(request).enqueue(object: Callback {
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
val view = view ?: return
|
val view = view ?: return
|
||||||
Snackbar.make(view, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
||||||
@@ -79,7 +81,6 @@ class ManageFavoritesFragment : PreferenceFragmentCompat() {
|
|||||||
.setTitle(R.string.settings_restore_title)
|
.setTitle(R.string.settings_restore_title)
|
||||||
.setView(editText)
|
.setView(editText)
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
val favorites = (activity?.application as? Pupil)?.favorites ?: return@setPositiveButton
|
|
||||||
restore(favorites, editText.text.toString(),
|
restore(favorites, editText.text.toString(),
|
||||||
onFailure = onFailure@{
|
onFailure = onFailure@{
|
||||||
val view = view ?: return@onFailure
|
val view = view ?: return@onFailure
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import net.rdrei.android.dirchooser.DirectoryChooserActivity
|
|||||||
import net.rdrei.android.dirchooser.DirectoryChooserConfig
|
import net.rdrei.android.dirchooser.DirectoryChooserConfig
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.histories
|
||||||
import xyz.quaver.pupil.ui.LockActivity
|
import xyz.quaver.pupil.ui.LockActivity
|
||||||
import xyz.quaver.pupil.ui.SettingsActivity
|
import xyz.quaver.pupil.ui.SettingsActivity
|
||||||
import xyz.quaver.pupil.ui.dialog.DefaultQueryDialog
|
import xyz.quaver.pupil.ui.dialog.DefaultQueryDialog
|
||||||
@@ -143,8 +144,6 @@ class SettingsFragment :
|
|||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
"clear_history" -> {
|
"clear_history" -> {
|
||||||
val histories = (requireContext().applicationContext as Pupil).histories
|
|
||||||
|
|
||||||
AlertDialog.Builder(requireContext()).apply {
|
AlertDialog.Builder(requireContext()).apply {
|
||||||
setTitle(R.string.warning)
|
setTitle(R.string.warning)
|
||||||
setMessage(R.string.settings_clear_history_alert_message)
|
setMessage(R.string.settings_clear_history_alert_message)
|
||||||
@@ -220,10 +219,10 @@ class SettingsFragment :
|
|||||||
|
|
||||||
when (key) {
|
when (key) {
|
||||||
"proxy" -> {
|
"proxy" -> {
|
||||||
summary = getProxyInfo(requireContext()).type.name
|
summary = context?.let { getProxyInfo(it).type.name }
|
||||||
}
|
}
|
||||||
"dl_location" -> {
|
"dl_location" -> {
|
||||||
summary = getDownloadDirectory(requireContext()).canonicalPath
|
summary = context?.let { getDownloadDirectory(it).canonicalPath }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,7 +285,6 @@ class SettingsFragment :
|
|||||||
onPreferenceClickListener = this@SettingsFragment
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
}
|
}
|
||||||
"clear_history" -> {
|
"clear_history" -> {
|
||||||
val histories = (requireActivity().application as Pupil).histories
|
|
||||||
summary = getString(R.string.settings_clear_history_summary, histories.size)
|
summary = getString(R.string.settings_clear_history_summary, histories.size)
|
||||||
|
|
||||||
onPreferenceClickListener = this@SettingsFragment
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
|||||||
@@ -28,14 +28,13 @@ import kotlinx.coroutines.*
|
|||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Dispatcher
|
|
||||||
import xyz.quaver.Code
|
import xyz.quaver.Code
|
||||||
import xyz.quaver.hitomi.GalleryBlock
|
import xyz.quaver.hitomi.GalleryBlock
|
||||||
import xyz.quaver.hitomi.Reader
|
import xyz.quaver.hitomi.Reader
|
||||||
import xyz.quaver.proxy
|
|
||||||
import xyz.quaver.pupil.util.getCachedGallery
|
import xyz.quaver.pupil.util.getCachedGallery
|
||||||
import xyz.quaver.pupil.util.getDownloadDirectory
|
import xyz.quaver.pupil.util.getDownloadDirectory
|
||||||
import xyz.quaver.pupil.util.isParentOf
|
import xyz.quaver.pupil.util.isParentOf
|
||||||
|
import xyz.quaver.readBytes
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
@@ -91,11 +90,12 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
val thumbnail = if (metadata?.thumbnail == null)
|
val thumbnail = if (metadata?.thumbnail == null)
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val thumbnails = getGalleryBlock(galleryID)?.thumbnails
|
val thumbnail = getGalleryBlock(galleryID)?.thumbnails?.firstOrNull() ?: return@withContext null
|
||||||
try {
|
try {
|
||||||
Base64.encodeToString(URL(thumbnails?.firstOrNull()).openConnection(proxy).getInputStream().use {
|
val data = URL(thumbnail).readBytes().apply {
|
||||||
it.readBytes()
|
if (isEmpty()) return@withContext null
|
||||||
}, Base64.DEFAULT)
|
}
|
||||||
|
Base64.encodeToString(data, Base64.DEFAULT)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ class Cache(context: Context) : ContextWrapper(context) {
|
|||||||
retval = try {
|
retval = try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
withTimeoutOrNull(1000) {
|
withTimeoutOrNull(1000) {
|
||||||
source.value.invoke()
|
source.value.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
@@ -40,13 +40,13 @@ import xyz.quaver.hitomi.imageUrlFromImage
|
|||||||
import xyz.quaver.hiyobi.cookie
|
import xyz.quaver.hiyobi.cookie
|
||||||
import xyz.quaver.hiyobi.createImgList
|
import xyz.quaver.hiyobi.createImgList
|
||||||
import xyz.quaver.hiyobi.user_agent
|
import xyz.quaver.hiyobi.user_agent
|
||||||
import xyz.quaver.proxy
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.client
|
||||||
|
import xyz.quaver.pupil.interceptors
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
|
class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
|
||||||
@@ -86,7 +86,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun source(source: Source) = object: ForwardingSource(source) {
|
private fun source(source: Source) = object: ForwardingSource(source) {
|
||||||
|
|
||||||
var totalBytesRead = 0L
|
var totalBytesRead = 0L
|
||||||
|
|
||||||
override fun read(sink: Buffer, byteCount: Long): Long {
|
override fun read(sink: Buffer, byteCount: Long): Long {
|
||||||
@@ -100,6 +99,24 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
interceptors[Pair::class] = { chain ->
|
||||||
|
val request = chain.request()
|
||||||
|
var response = chain.proceed(request)
|
||||||
|
|
||||||
|
var retry = 5
|
||||||
|
while (!response.isSuccessful && retry > 0) {
|
||||||
|
response = chain.proceed(request)
|
||||||
|
retry--
|
||||||
|
}
|
||||||
|
|
||||||
|
response.newBuilder()
|
||||||
|
.body(response.body()?.let {
|
||||||
|
ProgressResponseBody(request.tag(), it, progressListener)
|
||||||
|
}).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region Singleton
|
//region Singleton
|
||||||
@@ -135,34 +152,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
private val loop = loop()
|
private val loop = loop()
|
||||||
private val worker = SparseArray<Job?>()
|
private val worker = SparseArray<Job?>()
|
||||||
|
|
||||||
val interceptor = Interceptor { chain ->
|
|
||||||
val request = chain.request()
|
|
||||||
var response = chain.proceed(request)
|
|
||||||
|
|
||||||
var retry = 5
|
|
||||||
while (!response.isSuccessful && retry > 0) {
|
|
||||||
response = chain.proceed(request)
|
|
||||||
retry--
|
|
||||||
}
|
|
||||||
|
|
||||||
response.newBuilder()
|
|
||||||
.body(response.body()?.let {
|
|
||||||
ProgressResponseBody(request.tag(), it, progressListener)
|
|
||||||
}).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
val client : OkHttpClient =
|
|
||||||
OkHttpClient.Builder()
|
|
||||||
.connectTimeout(0, TimeUnit.SECONDS)
|
|
||||||
.addInterceptor(interceptor)
|
|
||||||
.readTimeout(0, TimeUnit.SECONDS)
|
|
||||||
.dispatcher(Dispatcher().apply {
|
|
||||||
maxRequests = 4
|
|
||||||
maxRequestsPerHost = 4
|
|
||||||
})
|
|
||||||
.proxy(proxy)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
queue.clear()
|
queue.clear()
|
||||||
|
|
||||||
@@ -300,8 +289,8 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
|
|||||||
val ext = call.request().url().encodedPath().split('.').last()
|
val ext = call.request().url().encodedPath().split('.').last()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response.body().use {
|
response.body()!!.use {
|
||||||
Cache(this@DownloadWorker).putImage(galleryID, i, ext, it!!.byteStream())
|
Cache(this@DownloadWorker).putImage(galleryID, i, ext, it.byteStream())
|
||||||
}
|
}
|
||||||
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
|
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ fun byteToString(byte: Long, precision : Int = 1) : String {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Convert android generated ID to requestCode
|
* Convert android generated ID to requestCode
|
||||||
* to prevent java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
|
* to prevent java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ import androidx.preference.PreferenceManager
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Authenticator
|
import okhttp3.*
|
||||||
import okhttp3.Credentials
|
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import okhttp3.*
|
|||||||
import ru.noties.markwon.Markwon
|
import ru.noties.markwon.Markwon
|
||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.BuildConfig
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.client
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@@ -187,7 +188,7 @@ fun restore(favorites: GalleryList, url: String, onFailure: ((Exception) -> Unit
|
|||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
OkHttpClient().newCall(request).enqueue(object: Callback {
|
client.newCall(request).enqueue(object: Callback {
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
onFailure?.invoke(e)
|
onFailure?.invoke(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,4 +140,7 @@
|
|||||||
<string name="settings_manage_favorites">ブックマーク管理</string>
|
<string name="settings_manage_favorites">ブックマーク管理</string>
|
||||||
<string name="settings_backup_failed">エラーが発生しました</string>
|
<string name="settings_backup_failed">エラーが発生しました</string>
|
||||||
<string name="settings_backup_share">バックアップ共有</string>
|
<string name="settings_backup_share">バックアップ共有</string>
|
||||||
|
<string name="channel_downloader">ダウンローダ</string>
|
||||||
|
<string name="channel_downloader_description">ダウンローダの状態を表示</string>
|
||||||
|
<string name="downloader_running">ダウンローダー起動中</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -140,4 +140,7 @@
|
|||||||
<string name="settings_manage_favorites">즐겨찾기 관리</string>
|
<string name="settings_manage_favorites">즐겨찾기 관리</string>
|
||||||
<string name="settings_backup_failed">업로드 실패</string>
|
<string name="settings_backup_failed">업로드 실패</string>
|
||||||
<string name="settings_backup_share">백업 공유</string>
|
<string name="settings_backup_share">백업 공유</string>
|
||||||
|
<string name="channel_downloader">다운로더</string>
|
||||||
|
<string name="channel_downloader_description">다운로더 작동 여부 표시</string>
|
||||||
|
<string name="downloader_running">다운로더 작동중…</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -10,4 +10,7 @@
|
|||||||
<item name="request_write_permission_and_saf" type="id" />
|
<item name="request_write_permission_and_saf" type="id" />
|
||||||
|
|
||||||
<item name="notification_id_update" type="id" />
|
<item name="notification_id_update" type="id" />
|
||||||
|
|
||||||
|
<item name="downloader_notification_id" type="id" />
|
||||||
|
<item name="downloader_notification_request" type="id" />
|
||||||
</resources>
|
</resources>
|
||||||
@@ -29,6 +29,9 @@
|
|||||||
<string name="channel_download">Download</string>
|
<string name="channel_download">Download</string>
|
||||||
<string name="channel_download_description">Shows download status</string>
|
<string name="channel_download_description">Shows download status</string>
|
||||||
|
|
||||||
|
<string name="channel_downloader">Downloader</string>
|
||||||
|
<string name="channel_downloader_description">Shows downloader status</string>
|
||||||
|
|
||||||
<string name="channel_update">Update</string>
|
<string name="channel_update">Update</string>
|
||||||
<string name="channel_update_description">Shows update progress</string>
|
<string name="channel_update_description">Shows update progress</string>
|
||||||
|
|
||||||
@@ -103,6 +106,9 @@
|
|||||||
<string name="reader_notification_text">Downloading…</string>
|
<string name="reader_notification_text">Downloading…</string>
|
||||||
<string name="reader_notification_complete">Download complete</string>
|
<string name="reader_notification_complete">Download complete</string>
|
||||||
|
|
||||||
|
<!-- DOWNLOADER -->
|
||||||
|
<string name="downloader_running">Downloader running…</string>
|
||||||
|
|
||||||
<!-- SETTINGS -->
|
<!-- SETTINGS -->
|
||||||
|
|
||||||
<string name="settings_title">Settings</string>
|
<string name="settings_title">Settings</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user