From 842148647f4b720e08bb7148c03314d0bd486032 Mon Sep 17 00:00:00 2001 From: Pupil Date: Thu, 13 Feb 2020 19:42:25 +0900 Subject: [PATCH 01/28] Changed to log fetchGallery exceptions --- app/build.gradle | 5 +- app/src/main/java/xyz/quaver/pupil/Pupil.kt | 4 + .../java/xyz/quaver/pupil/ui/MainActivity.kt | 10 ++- .../java/xyz/quaver/hitomi/galleryblock.kt | 84 +++++++++---------- .../src/main/java/xyz/quaver/hitomi/search.kt | 20 ++--- 5 files changed, 60 insertions(+), 63 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f0778fdf..4921c586 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,9 +57,6 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.gridlayout:gridlayout:1.0.0' - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' - implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation "androidx.biometric:biometric:1.0.1" implementation 'com.android.support:multidex:1.0.3' implementation "com.daimajia.swipelayout:library:1.2.0@aar" @@ -73,6 +70,8 @@ dependencies { implementation ("com.github.bumptech.glide:recyclerview-integration:4.10.0") { transitive = false } + implementation 'net.rdrei.android.dirchooser:library:3.2@aar' + implementation 'com.gu:option:1.3' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.andrognito.patternlockview:patternlockview:1.0.0' implementation "ru.noties.markwon:core:${markwonVersion}" diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index 126b68d9..a5512f9c 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -30,6 +30,7 @@ import androidx.preference.PreferenceManager 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 xyz.quaver.pupil.util.Histories import java.io.File @@ -54,6 +55,9 @@ class Pupil : MultiDexApplication() { histories = Histories(File(ContextCompat.getDataDir(this), "histories.json")) favorites = Histories(File(ContextCompat.getDataDir(this), "favorites.json")) + if (BuildConfig.DEBUG) + FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false) + val file = preference.getString("dl_location", null) if (file?.startsWith("content") == true) 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 d5f33096..0d62572b 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -45,7 +45,9 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import com.arlib.floatingsearchview.FloatingSearchView import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion import com.arlib.floatingsearchview.util.view.SearchInputView +import com.crashlytics.android.Crashlytics import com.google.android.material.appbar.AppBarLayout +import io.fabric.sdk.android.Fabric import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main_content.* import kotlinx.coroutines.* @@ -1004,9 +1006,13 @@ class MainActivity : AppCompatActivity() { val perPage = preference.getString("per_page", "25")?.toInt() ?: 25 loadingJob = CoroutineScope(Dispatchers.IO).launch { - val galleryIDs = galleryIDs?.await() + val galleryIDs = try { + galleryIDs!!.await() + } catch (e: Exception) { + + if (Fabric.isInitialized()) + Crashlytics.logException(e) - if (galleryIDs.isNullOrEmpty()) { //No result withContext(Dispatchers.Main) { main_noresult.visibility = View.VISIBLE main_progressbar.hide() diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt b/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt index f2b76f7e..e115f473 100644 --- a/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt +++ b/libpupil/src/main/java/xyz/quaver/hitomi/galleryblock.kt @@ -34,35 +34,31 @@ fun fetchNozomi(area: String? = null, tag: String = "index", language: String = else -> "$protocol//$domain/$area/$tag-$language$nozomiextension" } - try { - with(URL(url).openConnection() as HttpsURLConnection) { - requestMethod = "GET" + with(URL(url).openConnection() as HttpsURLConnection) { + requestMethod = "GET" - if (start != -1 && count != -1) { - val startByte = start*4 - val endByte = (start+count)*4-1 + if (start != -1 && count != -1) { + val startByte = start*4 + val endByte = (start+count)*4-1 - setRequestProperty("Range", "bytes=$startByte-$endByte") - } - - connect() - - val totalItems = getHeaderField("Content-Range") - .replace(Regex("^[Bb]ytes \\d+-\\d+/"), "").toInt() / 4 - - val nozomi = ArrayList() - - val arrayBuffer = ByteBuffer - .wrap(inputStream.readBytes()) - .order(ByteOrder.BIG_ENDIAN) - - while (arrayBuffer.hasRemaining()) - nozomi.add(arrayBuffer.int) - - return Pair(nozomi, totalItems) + setRequestProperty("Range", "bytes=$startByte-$endByte") } - } catch (e: Exception) { - return Pair(emptyList(), 0) + + connect() + + val totalItems = getHeaderField("Content-Range") + .replace(Regex("^[Bb]ytes \\d+-\\d+/"), "").toInt() / 4 + + val nozomi = ArrayList() + + val arrayBuffer = ByteBuffer + .wrap(inputStream.readBytes()) + .order(ByteOrder.BIG_ENDIAN) + + while (arrayBuffer.hasRemaining()) + nozomi.add(arrayBuffer.int) + + return Pair(nozomi, totalItems) } } @@ -82,30 +78,26 @@ data class GalleryBlock( fun getGalleryBlock(galleryID: Int) : GalleryBlock? { val url = "$protocol//$domain/$galleryblockdir/$galleryID$extension" - try { - val doc = Jsoup.connect(url).get() + val doc = Jsoup.connect(url).get() - val galleryUrl = doc.selectFirst(".lillie").attr("href") + val galleryUrl = doc.selectFirst(".lillie").attr("href") - val thumbnails = doc.select("img").map { protocol + it.attr("data-src") } + val thumbnails = doc.select("img").map { protocol + it.attr("data-src") } - val title = doc.selectFirst("h1.lillie > a").text() - val artists = doc.select("div.artist-list a").map{ it.text() } - val series = doc.select("a[href~=^/series/]").map { it.text() } - val type = doc.selectFirst("a[href~=^/type/]").text() + val title = doc.selectFirst("h1.lillie > a").text() + val artists = doc.select("div.artist-list a").map{ it.text() } + val series = doc.select("a[href~=^/series/]").map { it.text() } + val type = doc.selectFirst("a[href~=^/type/]").text() - val language = { - val href = doc.select("a[href~=^/index-.+-1.html]").attr("href") - href.slice(7 until href.indexOf("-1")) - }.invoke() + val language = { + val href = doc.select("a[href~=^/index-.+-1.html]").attr("href") + href.slice(7 until href.indexOf("-1")) + }.invoke() - val relatedTags = doc.select(".relatedtags a").map { - val href = URLDecoder.decode(it.attr("href"), "UTF-8") - href.slice(5 until href.indexOf("-all")) - } - - return GalleryBlock(Code.HITOMI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) - } catch (e: Exception) { - return null + val relatedTags = doc.select(".relatedtags a").map { + val href = URLDecoder.decode(it.attr("href"), "UTF-8") + href.slice(5 until href.indexOf("-all")) } + + return GalleryBlock(Code.HITOMI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) } \ No newline at end of file diff --git a/libpupil/src/main/java/xyz/quaver/hitomi/search.kt b/libpupil/src/main/java/xyz/quaver/hitomi/search.kt index fbcd4a66..8261fa0b 100644 --- a/libpupil/src/main/java/xyz/quaver/hitomi/search.kt +++ b/libpupil/src/main/java/xyz/quaver/hitomi/search.kt @@ -173,22 +173,18 @@ fun getGalleryIDsFromNozomi(area: String?, tag: String, language: String) : List else -> "$protocol//$domain/$compressed_nozomi_prefix/$area/$tag-$language$nozomiextension" } - try { - val bytes = URL(nozomiAddress).readBytes() + val bytes = URL(nozomiAddress).readBytes() - val nozomi = ArrayList() + val nozomi = ArrayList() - val arrayBuffer = ByteBuffer - .wrap(bytes) - .order(ByteOrder.BIG_ENDIAN) + val arrayBuffer = ByteBuffer + .wrap(bytes) + .order(ByteOrder.BIG_ENDIAN) - while (arrayBuffer.hasRemaining()) - nozomi.add(arrayBuffer.int) + while (arrayBuffer.hasRemaining()) + nozomi.add(arrayBuffer.int) - return nozomi - } catch (e: Exception) { - return emptyList() - } + return nozomi } fun getGalleryIDsFromData(data: Pair) : List { From bb63959678b2c8d86213d011cdf244d3322d74e8 Mon Sep 17 00:00:00 2001 From: Pupil Date: Thu, 13 Feb 2020 20:07:16 +0900 Subject: [PATCH 02/28] Allow download multiple galleries concurrently --- app/build.gradle | 4 +- .../pupil/util/download/DownloadWorker.kt | 59 +++++++++---------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4921c586..598bcaa4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,8 +19,8 @@ android { applicationId "xyz.quaver.pupil" minSdkVersion 16 targetSdkVersion 29 - versionCode 41 - versionName "4.5" + versionCode 42 + versionName "4.6-beta1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true 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 aa5dda63..9376f913 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 @@ -145,25 +145,21 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont private val loop = loop() private val worker = SparseArray() - @Volatile var nRunners = 0 + val clients = SparseArray() - private val client = OkHttpClient.Builder() - .addInterceptor { chain -> - val request = chain.request() - var response = chain.proceed(request) + val interceptor = Interceptor { chain -> + val request = chain.request() + val response = chain.proceed(request) - var retry = preferences.getInt("retry", 3) - while (!response.isSuccessful && retry > 0) { - response = chain.proceed(request) - retry-- - } - - response.newBuilder() - .body(ProgressResponseBody(request.tag(), response.body(), progressListener)) - .build() - } - .dispatcher(Dispatcher(Executors.newFixedThreadPool(4))) + response.newBuilder() + .body(ProgressResponseBody(request.tag(), response.body(), progressListener)) .build() + } + fun buildClient() = + OkHttpClient.Builder() + .addInterceptor(interceptor) + .dispatcher(Dispatcher(Executors.newFixedThreadPool(4))) + .build() fun stop() { queue.clear() @@ -176,29 +172,30 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont worker[galleryID]?.cancel() } - client.dispatcher().cancelAll() + for (i in 0 until clients.size()) { + clients.valueAt(i).dispatcher().cancelAll() + } + clients.clear() progress.clear() exception.clear() notification.clear() notificationManager.cancelAll() - - nRunners = 0 - } fun cancel(galleryID: Int) { queue.remove(galleryID) worker[galleryID]?.cancel() - client.dispatcher().queuedCalls() - .filter { + clients[galleryID]?.dispatcher()?.queuedCalls() + ?.filter { @Suppress("UNCHECKED_CAST") (it.request().tag() as? Pair)?.first == galleryID } - .forEach { + ?.forEach { it.cancel() } + clients.remove(galleryID) progress.remove(galleryID) exception.remove(galleryID) @@ -207,7 +204,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont if (progress.indexOfKey(galleryID) >= 0) { Cache(this@DownloadWorker).setDownloading(galleryID, false) - nRunners-- } } @@ -240,7 +236,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont tag(galleryID to index) }.build() - client.newCall(request).enqueue(callback) + clients[galleryID].newCall(request).enqueue(callback) } private fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch { @@ -252,7 +248,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont exception.put(galleryID, null) Cache(this@DownloadWorker).setDownloading(galleryID, false) - nRunners-- return@launch } @@ -279,11 +274,12 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont setDownloading(galleryID, false) } } - nRunners-- return@launch } + clients.put(galleryID, buildClient()) + for (i in reader.galleryInfo.indices) { val callback = object : Callback { override fun onFailure(call: Call, e: IOException) { @@ -302,7 +298,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont setDownloading(galleryID, false) } } - nRunners-- + clients.remove(galleryID) } } @@ -325,7 +321,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont setDownloading(galleryID, false) } } - nRunners-- + clients.remove(galleryID) } } } @@ -374,19 +370,18 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont private fun loop() = CoroutineScope(Dispatchers.Default).launch { while (true) { - if (queue.isEmpty() || nRunners > preferences.getInt("max_download", 4)) + if (queue.isEmpty() || clients.size() > preferences.getInt("max_download", 4)) continue val galleryID = queue.poll() ?: continue - if (progress.indexOfKey(galleryID) >= 0) // Gallery already downloading! + if (clients.indexOfKey(galleryID) >= 0) // Gallery already downloading! continue initNotification(galleryID) if (Cache(this@DownloadWorker).isDownloading(galleryID)) notificationManager.notify(galleryID, notification[galleryID].build()) worker.put(galleryID, download(galleryID)) - nRunners++ } } From d05c1e4d08e2efa267acecb610b61e92e7f155a6 Mon Sep 17 00:00:00 2001 From: Pupil Date: Thu, 13 Feb 2020 20:14:26 +0900 Subject: [PATCH 03/28] Improved galleryBlock loading logic --- .../xyz/quaver/pupil/util/download/Cache.kt | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) 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 6c75b55d..f7a659f6 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 @@ -102,21 +102,27 @@ class Cache(context: Context) : ContextWrapper(context) { suspend fun getGalleryBlock(galleryID: Int): GalleryBlock? { val metadata = Cache(this).getCachedMetadata(galleryID) - val source = mapOf( + val sources = mapOf( Code.HITOMI to { xyz.quaver.hitomi.getGalleryBlock(galleryID) }, Code.HIYOBI to { xyz.quaver.hiyobi.getGalleryBlock(galleryID) } ) - val galleryBlock = if (metadata?.galleryBlock == null) - source.entries.map { - CoroutineScope(Dispatchers.IO).async { - kotlin.runCatching { - it.value.invoke() - }.getOrNull() - } - }.firstOrNull { - it.await() != null - }?.await() + val galleryBlock = if (metadata?.galleryBlock == null) { + CoroutineScope(Dispatchers.IO).async { + var galleryBlock: GalleryBlock? = null + + for (source in sources) { + galleryBlock = kotlin.runCatching { + source.value.invoke() + }.getOrNull() + + if (galleryBlock != null) + break + } + + galleryBlock + }.await() ?: return null + } else metadata.galleryBlock @@ -164,15 +170,14 @@ class Cache(context: Context) : ContextWrapper(context) { } retval - }.await() + }.await() ?: return null } else metadata.reader - if (reader != null) - setCachedMetadata( - galleryID, - Metadata(Cache(this).getCachedMetadata(galleryID), readers = reader) - ) + setCachedMetadata( + galleryID, + Metadata(Cache(this).getCachedMetadata(galleryID), readers = reader) + ) return reader } From 04c500f3d87a569bb9547d463cc09f19396f7a1b Mon Sep 17 00:00:00 2001 From: Pupil Date: Thu, 13 Feb 2020 20:15:17 +0900 Subject: [PATCH 04/28] Improved galleryBlock loading logic --- app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 f7a659f6..dd36f28c 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 @@ -102,9 +102,9 @@ class Cache(context: Context) : ContextWrapper(context) { suspend fun getGalleryBlock(galleryID: Int): GalleryBlock? { val metadata = Cache(this).getCachedMetadata(galleryID) - val sources = mapOf( - Code.HITOMI to { xyz.quaver.hitomi.getGalleryBlock(galleryID) }, - Code.HIYOBI to { xyz.quaver.hiyobi.getGalleryBlock(galleryID) } + val sources = listOf( + { xyz.quaver.hitomi.getGalleryBlock(galleryID) }, + { xyz.quaver.hiyobi.getGalleryBlock(galleryID) } ) val galleryBlock = if (metadata?.galleryBlock == null) { @@ -113,7 +113,7 @@ class Cache(context: Context) : ContextWrapper(context) { for (source in sources) { galleryBlock = kotlin.runCatching { - source.value.invoke() + source.invoke() }.getOrNull() if (galleryBlock != null) From 49d87a08d275a00ae9fce18acfd95a9301bf58ba Mon Sep 17 00:00:00 2001 From: Pupil Date: Thu, 13 Feb 2020 20:29:45 +0900 Subject: [PATCH 05/28] Set download notifications non-dismissable --- .../main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt | 3 +++ app/src/main/java/xyz/quaver/pupil/util/update.kt | 3 +++ 2 files changed, 6 insertions(+) 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 9376f913..d020205a 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 @@ -338,7 +338,9 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont if (isCompleted(galleryID)) notification[galleryID] ?.setContentText(getString(R.string.reader_notification_complete)) + ?.setSmallIcon(android.R.drawable.stat_sys_download_done) ?.setProgress(0, 0, false) + ?.setOngoing(false) else notification[galleryID] ?.setProgress(max, progress, false) @@ -365,6 +367,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont setSmallIcon(android.R.drawable.stat_sys_download) // had to use this because old android doesn't support VectorDrawable on Notification :P setContentIntent(pendingIntent) setProgress(0, 0, true) + setOngoing(true) }) } 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 1d0c9091..6d7c8cfb 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt @@ -145,6 +145,7 @@ fun checkUpdate(context: AppCompatActivity, force: Boolean = false) { setContentTitle(context.getString(R.string.update_notification_description)) setSmallIcon(android.R.drawable.stat_sys_download) priority = NotificationCompat.PRIORITY_LOW + setOngoing(true) } CoroutineScope(Dispatchers.IO).launch io@{ @@ -160,6 +161,7 @@ fun checkUpdate(context: AppCompatActivity, force: Boolean = false) { setContentText(context.getString(R.string.update_failed)) setMessage(context.getString(R.string.update_failed_message)) setSmallIcon(android.R.drawable.stat_sys_download_done) + setOngoing(false) } notificationManager.cancel(UPDATE_NOTIFICATION_ID) @@ -179,6 +181,7 @@ fun checkUpdate(context: AppCompatActivity, force: Boolean = false) { setSmallIcon(android.R.drawable.stat_sys_download_done) setContentTitle(context.getString(R.string.update_download_completed)) setContentText(context.getString(R.string.update_download_completed_description)) + setOngoing(false) } notificationManager.cancel(UPDATE_NOTIFICATION_ID) From 275684c9ceaff8b696d1767a7d0b15c8534cdf76 Mon Sep 17 00:00:00 2001 From: Pupil Date: Fri, 14 Feb 2020 17:02:53 +0900 Subject: [PATCH 06/28] now able to install Debug and release builds in one device Fixed shrink serialization error --- app/build.gradle | 19 ++++++++++------ app/src/debug/res/values/strings.xml | 22 +++++++++++++++++++ .../java/xyz/quaver/pupil/ui/MainActivity.kt | 14 +++++------- .../xyz/quaver/pupil/ui/ReaderActivity.kt | 2 -- .../xyz/quaver/pupil/ui/SettingsActivity.kt | 10 ++++----- .../java/xyz/quaver/pupil/util/ConstValues.kt | 7 +++++- .../xyz/quaver/pupil/util/download/Cache.kt | 14 +++--------- .../java/xyz/quaver/pupil/util/history.kt | 16 ++++++-------- .../main/java/xyz/quaver/pupil/util/lock.kt | 9 ++++---- .../main/java/xyz/quaver/pupil/util/update.kt | 7 ++++-- build.gradle | 2 +- gradle.properties | 1 + 12 files changed, 70 insertions(+), 53 deletions(-) create mode 100644 app/src/debug/res/values/strings.xml diff --git a/app/build.gradle b/app/build.gradle index 598bcaa4..6d43957f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlinx-serialization' -if (file("google-services.json").exists()) { +if (file("src/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' @@ -20,18 +20,23 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 42 - versionName "4.6-beta1" + versionName "4.6-alpha1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true } buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + debug { + debuggable true + applicationIdSuffix ".debug" + versionNameSuffix "-DEBUG" + + buildConfigField('Boolean', 'CENSOR', 'false') } - buildTypes.each { - it.buildConfigField('boolean', 'CENSOR', 'false') + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } kotlinOptions { diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml new file mode 100644 index 00000000..944c7613 --- /dev/null +++ b/app/src/debug/res/values/strings.xml @@ -0,0 +1,22 @@ + + + + + Pupil-Debug + \ No newline at end of file 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 0d62572b..14f6c3a3 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -25,6 +25,7 @@ import android.net.Uri import android.os.Bundle import android.text.* import android.text.style.AlignmentSpan +import android.util.Log import android.view.KeyEvent import android.view.MotionEvent import android.view.View @@ -51,11 +52,7 @@ import io.fabric.sdk.android.Fabric import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main_content.* import kotlinx.coroutines.* -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.list -import kotlinx.serialization.stringify import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.doSearch import xyz.quaver.hitomi.getGalleryIDsFromNozomi @@ -123,6 +120,7 @@ class MainActivity : AppCompatActivity() { val lockManager = try { LockManager(this) } catch (e: Exception) { + Log.i("PUPILD", e.toString()) android.app.AlertDialog.Builder(this).apply { setTitle(R.string.warning) setMessage(R.string.lock_corrupted) @@ -181,7 +179,7 @@ class MainActivity : AppCompatActivity() { override fun onDestroy() { super.onDestroy() - (main_recyclerview.adapter as GalleryBlockAdapter).timer.cancel() + (main_recyclerview?.adapter as? GalleryBlockAdapter)?.timer?.cancel() } override fun onResume() { @@ -695,7 +693,6 @@ class MainActivity : AppCompatActivity() { } private var suggestionJob : Job? = null - @UseExperimental(ImplicitReflectionSerializer::class) private fun setupSearchBar() { val searchInputView = findViewById(R.id.search_bar_text) //Change upper case letters to lower case @@ -719,12 +716,11 @@ class MainActivity : AppCompatActivity() { with(main_searchview as FloatingSearchView) { val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json") - val json = Json(JsonConfiguration.Stable) val serializer = Tag.serializer().list if (!favoritesFile.exists()) { favoritesFile.createNewFile() - favoritesFile.writeText(json.stringify(Tags(listOf()))) + favoritesFile.writeText(json.stringify(serializer, Tags(listOf()))) } setOnMenuItemClickListener { @@ -842,7 +838,7 @@ class MainActivity : AppCompatActivity() { favorites.add(tag) } - favoritesFile.writeText(json.stringify(favorites)) + favoritesFile.writeText(json.stringify(serializer, favorites)) } } 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 7af22aec..bde9a89e 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt @@ -38,7 +38,6 @@ import io.fabric.sdk.android.Fabric import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.android.synthetic.main.activity_reader.view.* import kotlinx.android.synthetic.main.dialog_numberpicker.view.* -import kotlinx.serialization.ImplicitReflectionSerializer import xyz.quaver.Code import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.R @@ -141,7 +140,6 @@ class ReaderActivity : AppCompatActivity() { super.onResume() } - @UseExperimental(ImplicitReflectionSerializer::class) override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.reader, menu) 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 aa09d8a4..ebcdbb77 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt @@ -30,9 +30,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.preference.PreferenceManager import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.settings_activity.* -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.json.Json -import kotlinx.serialization.parseList +import kotlinx.serialization.list +import kotlinx.serialization.serializer import net.rdrei.android.dirchooser.DirectoryChooserActivity import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.R @@ -79,7 +78,6 @@ class SettingsActivity : AppCompatActivity() { return true } - @UseExperimental(ImplicitReflectionSerializer::class) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when(requestCode) { REQUEST_LOCK -> { @@ -96,13 +94,13 @@ class SettingsActivity : AppCompatActivity() { val uri = data?.data ?: return try { - val json = contentResolver.openInputStream(uri).use { inputStream -> + val str = contentResolver.openInputStream(uri).use { inputStream -> inputStream!! inputStream.readBytes().toString(Charset.defaultCharset()) } - (application as Pupil).favorites.addAll(Json.parseList(json).also { + (application as Pupil).favorites.addAll(json.parse(Int.serializer().list, str).also { Snackbar.make( window.decorView, getString(R.string.settings_restore_successful, it.size), diff --git a/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt b/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt index fecea791..38b24cf2 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt @@ -18,8 +18,13 @@ package xyz.quaver.pupil.util +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonConfiguration + const val REQUEST_LOCK = 38238 const val REQUEST_RESTORE = 16546 const val REQUEST_DOWNLOAD_FOLDER = 3874 const val REQUEST_DOWNLOAD_FOLDER_OLD = 3425 -const val REQUEST_WRITE_PERMISSION_AND_SAF = 13900 \ No newline at end of file +const val REQUEST_WRITE_PERMISSION_AND_SAF = 13900 + +val json = Json(JsonConfiguration.Stable) \ No newline at end of file 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 dd36f28c..46c94eeb 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 @@ -21,21 +21,17 @@ package xyz.quaver.pupil.util.download import android.content.Context import android.content.ContextWrapper import android.util.Base64 -import android.util.Log import androidx.preference.PreferenceManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.withContext -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.json.Json -import kotlinx.serialization.parse -import kotlinx.serialization.stringify import xyz.quaver.Code import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.Reader import xyz.quaver.pupil.util.getCachedGallery import xyz.quaver.pupil.util.getDownloadDirectory +import xyz.quaver.pupil.util.json import java.io.File import java.net.URL @@ -50,7 +46,6 @@ class Cache(context: Context) : ContextWrapper(context) { it.mkdirs() } - @UseExperimental(ImplicitReflectionSerializer::class) fun getCachedMetadata(galleryID: Int) : Metadata? { val file = File(getCachedGallery(galleryID), ".metadata") @@ -58,7 +53,7 @@ class Cache(context: Context) : ContextWrapper(context) { return null return try { - Json.parse(file.readText()) + json.parse(Metadata.serializer(), file.readText()) } catch (e: Exception) { //File corrupted file.delete() @@ -66,14 +61,13 @@ class Cache(context: Context) : ContextWrapper(context) { } } - @UseExperimental(ImplicitReflectionSerializer::class) fun setCachedMetadata(galleryID: Int, metadata: Metadata) { val file = File(getCachedGallery(galleryID), ".metadata").also { if (!it.exists()) it.createNewFile() } - file.writeText(Json.stringify(metadata)) + file.writeText(json.stringify(Metadata.serializer(), metadata)) } suspend fun getThumbnail(galleryID: Int): String? { @@ -183,12 +177,10 @@ class Cache(context: Context) : ContextWrapper(context) { } fun getImages(galleryID: Int): List? { - val started = System.currentTimeMillis() val gallery = getCachedGallery(galleryID) val reader = getReaderOrNull(galleryID) ?: return null val images = gallery.listFiles() ?: return null - Log.i("PUPILD", "${System.currentTimeMillis() - started} ms") return reader.galleryInfo.indices.map { index -> images.firstOrNull { file -> file.name.startsWith("%05d".format(index)) } } diff --git a/app/src/main/java/xyz/quaver/pupil/util/history.kt b/app/src/main/java/xyz/quaver/pupil/util/history.kt index 665ccdfe..cb13c226 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/history.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/history.kt @@ -18,15 +18,14 @@ package xyz.quaver.pupil.util -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonConfiguration -import kotlinx.serialization.parseList -import kotlinx.serialization.stringify +import kotlinx.serialization.list +import kotlinx.serialization.serializer import java.io.File class Histories(private val file: File) : ArrayList() { + val serializer = Int.serializer().list + init { if (!file.exists()) file.parentFile?.mkdirs() @@ -38,21 +37,20 @@ class Histories(private val file: File) : ArrayList() { } } - @UseExperimental(ImplicitReflectionSerializer::class) fun load() : Histories { return apply { super.clear() addAll( - Json(JsonConfiguration.Stable).parseList( + json.parse( + serializer, file.bufferedReader().use { it.readText() } ) ) } } - @UseExperimental(ImplicitReflectionSerializer::class) fun save() { - file.writeText(Json(JsonConfiguration.Stable).stringify(this)) + file.writeText(json.stringify(serializer, this)) } override fun add(element: Int): Boolean { diff --git a/app/src/main/java/xyz/quaver/pupil/util/lock.kt b/app/src/main/java/xyz/quaver/pupil/util/lock.kt index cba085c4..4f48b784 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/lock.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/lock.kt @@ -21,9 +21,10 @@ package xyz.quaver.pupil.util import android.content.Context import android.content.ContextWrapper import androidx.core.content.ContextCompat -import kotlinx.serialization.* +import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration +import kotlinx.serialization.list import java.io.File import java.security.MessageDigest @@ -73,7 +74,6 @@ class LockManager(base: Context): ContextWrapper(base) { load() } - @UseExperimental(ImplicitReflectionSerializer::class) private fun load() { val lock = File(ContextCompat.getDataDir(this), "lock.json") @@ -82,17 +82,16 @@ class LockManager(base: Context): ContextWrapper(base) { lock.writeText("[]") } - locks = ArrayList(Json(JsonConfiguration.Stable).parseList(lock.readText())) + locks = ArrayList(json.parse(Lock.serializer().list, lock.readText())) } - @UseExperimental(ImplicitReflectionSerializer::class) private fun save() { val lock = File(ContextCompat.getDataDir(this), "lock.json") if (!lock.exists()) lock.createNewFile() - lock.writeText(Json(JsonConfiguration.Stable).stringify(locks?.toList() ?: listOf())) + lock.writeText(json.stringify(Lock.serializer().list, locks?.toList() ?: listOf())) } fun add(lock: Lock) { 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 6d7c8cfb..94ae9ed1 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt @@ -32,7 +32,10 @@ import androidx.preference.PreferenceManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.serialization.json.* +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.content import ru.noties.markwon.Markwon import xyz.quaver.pupil.BuildConfig import xyz.quaver.pupil.R @@ -43,7 +46,7 @@ import java.util.* fun getReleases(url: String) : JsonArray { return try { URL(url).readText().let { - Json(JsonConfiguration.Stable).parse(JsonArray.serializer(), it) + json.parse(JsonArray.serializer(), it) } } catch (e: Exception) { JsonArray(emptyList()) diff --git a/build.gradle b/build.gradle index 495dc04c..a1f207cf 100644 --- a/build.gradle +++ b/build.gradle @@ -31,4 +31,4 @@ allprojects { task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index d5fb122a..dcb17194 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,3 +15,4 @@ kotlin.code.style=official android.enableJetifier=true org.gradle.jvmargs=-Xmx1024M -Dkotlin.daemon.jvm.options\="-Xmx1024M" android.useAndroidX=true +android.enableR8.fullMode=true \ No newline at end of file From ba069d8f8e676e17f0d3c341ca758e0c3c2c03c7 Mon Sep 17 00:00:00 2001 From: Pupil Date: Fri, 14 Feb 2020 20:10:04 +0900 Subject: [PATCH 07/28] Image loading optimization --- app/build.gradle | 11 +- app/proguard-rules.pro | 9 +- .../pupil/adapters/GalleryBlockAdapter.kt | 6 +- .../quaver/pupil/adapters/ReaderAdapter.kt | 103 ++++++++---------- app/src/main/res/layout/item_reader.xml | 2 + 5 files changed, 69 insertions(+), 62 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6d43957f..f07e94e3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,10 +32,13 @@ android { versionNameSuffix "-DEBUG" buildConfigField('Boolean', 'CENSOR', 'false') + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } release { minifyEnabled true shrinkResources true + + buildConfigField('Boolean', 'CENSOR', 'false') proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } @@ -71,16 +74,18 @@ dependencies { 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' - implementation ("com.github.bumptech.glide:recyclerview-integration:4.10.0") { + annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' + kapt 'com.github.bumptech.glide:compiler:4.11.0' + implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") { transitive = false } + implementation 'net.rdrei.android.dirchooser:library:3.2@aar' - implementation 'com.gu:option:1.3' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.andrognito.patternlockview:patternlockview:1.0.0' implementation "ru.noties.markwon:core:${markwonVersion}" - kapt 'com.github.bumptech.glide:compiler:4.11.0' testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test:rules:1.2.0' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb434..a9d9d7f4 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -18,4 +18,11 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} \ No newline at end of file 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 273e5958..6c1f637d 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt @@ -71,15 +71,15 @@ class GalleryBlockAdapter(context: Context, private val galleries: List() { + val glide = Glide.with(context) + //region Glide.RecyclerView - inner class SizeProvider : ListPreloader.PreloadSizeProvider { - - override fun getPreloadSize(item: File, adapterPosition: Int, itemPosition: Int): IntArray? { - return Cache(context).getReaderOrNull(galleryID)?.galleryInfo?.getOrNull(itemPosition)?.let { - arrayOf(it.width, it.height).toIntArray() - } + val sizeProvider = ListPreloader.PreloadSizeProvider { _, _, position -> + Cache(context).getReaderOrNull(galleryID)?.galleryInfo?.getOrNull(position)?.let { + arrayOf(it.width, it.height).toIntArray() } - } - - inner class ModelProvider : ListPreloader.PreloadModelProvider { - + val modelProvider = object: ListPreloader.PreloadModelProvider { override fun getPreloadItems(position: Int): MutableList { return listOf(Cache(context).getImages(galleryID)?.get(position)).filterNotNullTo(mutableListOf()) } @@ -76,18 +72,13 @@ class ReaderAdapter(private val context: Context, override(5, 8) } } - } + val preloader = RecyclerViewPreloader(glide, modelProvider, sizeProvider, 10) //endregion var reader: Reader? = null - val glide = Glide.with(context) val timer = Timer() - val sizeProvider = SizeProvider() - val modelProvider = ModelProvider() - val preloader = RecyclerViewPreloader(glide, modelProvider, sizeProvider, 10) - var isFullScreen = false var onItemClickListener : ((Int) -> (Unit))? = null @@ -114,10 +105,13 @@ class ReaderAdapter(private val context: Context, override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.view as ConstraintLayout - if (isFullScreen) + if (isFullScreen) { holder.view.layoutParams.height = RecyclerView.LayoutParams.MATCH_PARENT - else + holder.view.container.layoutParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT + } else { holder.view.layoutParams.height = RecyclerView.LayoutParams.WRAP_CONTENT + holder.view.container.layoutParams.height = 0 + } holder.view.image.setOnPhotoTapListener { _, _, _ -> onItemClickListener?.invoke(position) @@ -127,52 +121,51 @@ class ReaderAdapter(private val context: Context, onItemClickListener?.invoke(position) } - (holder.view.container.layoutParams as ConstraintLayout.LayoutParams) - .dimensionRatio = "${reader!!.galleryInfo[position].width}:${reader!!.galleryInfo[position].height}" + if (!isFullScreen) + (holder.view.container.layoutParams as ConstraintLayout.LayoutParams) + .dimensionRatio = "${reader!!.galleryInfo[position].width}:${reader!!.galleryInfo[position].height}" holder.view.reader_index.text = (position+1).toString() - CoroutineScope(Dispatchers.IO).launch { - val images = Cache(context).getImages(galleryID) + val images = Cache(context).getImages(galleryID) - launch(Dispatchers.Main) { - if (images?.get(position) != null) { - glide - .load(images[position]) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .error(R.drawable.image_broken_variant) - .apply { - if (BuildConfig.CENSOR) - override(5, 8) - } - .into(holder.view.image) - } else { - val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position) + if (images?.get(position) != null) { + glide + .load(images[position]) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .error(R.drawable.image_broken_variant) + .dontTransform() + .apply { + if (BuildConfig.CENSOR) + override(5, 8) + } + .into(holder.view.image) + } else { + val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position) - if (progress?.isNaN() == true) { + if (progress?.isNaN() == true) { + if (Fabric.isInitialized()) + Crashlytics.logException(DownloadWorker.getInstance(context).exception[galleryID]?.get(position)) - if (Fabric.isInitialized()) - Crashlytics.logException(DownloadWorker.getInstance(context).exception[galleryID]?.get(position)) + glide + .load(R.drawable.image_broken_variant) + .into(holder.view.image) - glide - .load(R.drawable.image_broken_variant) - .into(holder.view.image) - } else { - holder.view.reader_item_progressbar.progress = - if (progress?.isInfinite() == true) - 100 - else - progress?.roundToInt() ?: 0 + return + } else { + holder.view.reader_item_progressbar.progress = + if (progress?.isInfinite() == true) + 100 + else + progress?.roundToInt() ?: 0 - holder.view.image.setImageDrawable(null) - } + holder.view.image.setImageDrawable(null) + } - timer.schedule(1000) { - CoroutineScope(Dispatchers.Main).launch { - notifyItemChanged(position) - } - } + timer.schedule(1000) { + CoroutineScope(Dispatchers.Main).launch { + notifyItemChanged(position) } } } diff --git a/app/src/main/res/layout/item_reader.xml b/app/src/main/res/layout/item_reader.xml index d91faa03..60a1f261 100644 --- a/app/src/main/res/layout/item_reader.xml +++ b/app/src/main/res/layout/item_reader.xml @@ -62,6 +62,8 @@ From 066d73b217246c19b542e7ee3a15151dc10d4386 Mon Sep 17 00:00:00 2001 From: Pupil Date: Fri, 14 Feb 2020 20:13:26 +0900 Subject: [PATCH 08/28] Generated APK --- app/build.gradle | 2 +- app/release/output.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f07e94e3..e8be39e0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 42 - versionName "4.6-alpha1" + versionName "4.6-beta1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true diff --git a/app/release/output.json b/app/release/output.json index dd112837..d176db0a 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":41,"versionName":"4.5","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":42,"versionName":"4.6-beta1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] \ No newline at end of file From 85d01f60f1110194326560ea8ae7d72f5abb65a9 Mon Sep 17 00:00:00 2001 From: Pupil Date: Fri, 14 Feb 2020 20:31:10 +0900 Subject: [PATCH 09/28] Changed galleryblock retrieve url --- .../java/xyz/quaver/hiyobi/galleryblock.kt | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt b/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt index 1529dbad..756ae243 100644 --- a/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt +++ b/libpupil/src/main/java/xyz/quaver/hiyobi/galleryblock.kt @@ -22,28 +22,24 @@ import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.hitomi.protocol fun getGalleryBlock(galleryID: Int) : GalleryBlock? { - val url = "$protocol//$hiyobi/search/$galleryID" + val url = "$protocol//$hiyobi/info/$galleryID" - try { - val doc = Jsoup.connect(url).get() + val doc = Jsoup.connect(url).get() - val galleryBlock = doc.selectFirst(".gallery-content") + val galleryBlock = doc.selectFirst(".gallery-content") - val galleryUrl = galleryBlock.selectFirst("a").attr("href") + val galleryUrl = galleryBlock.selectFirst("a").attr("href") - val thumbnails = listOf(galleryBlock.selectFirst("img").attr("abs:src")) + val thumbnails = listOf(galleryBlock.selectFirst("img").attr("abs:src")) - 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.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 language = "korean" + val language = "korean" - val relatedTags = galleryBlock.select("tr:matches(태그) a").map { it.attr("href").substringAfterLast('/').replace('_', ' ') } + val relatedTags = galleryBlock.select("tr:matches(태그) a").map { it.attr("href").substringAfterLast('/').replace('_', ' ') } - return GalleryBlock(Code.HIYOBI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) - } catch (e: Exception) { - return null - } + return GalleryBlock(Code.HIYOBI, galleryID, galleryUrl, thumbnails, title, artists, series, type, language, relatedTags) } \ No newline at end of file From ca077c4feedcf6639226d2c4c4ee2538d7981b77 Mon Sep 17 00:00:00 2001 From: Pupil Date: Fri, 14 Feb 2020 20:37:48 +0900 Subject: [PATCH 10/28] Apk built --- app/proguard-rules.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index a9d9d7f4..5a516874 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,6 +20,8 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile +-dontobfuscate + -keep public class * implements com.bumptech.glide.module.GlideModule -keep public class * extends com.bumptech.glide.module.AppGlideModule -keep public enum com.bumptech.glide.load.ImageHeaderParser$** { From 4d5834821a91d1145c8bd0a1d94b589eeec1c5c0 Mon Sep 17 00:00:00 2001 From: Pupil Date: Fri, 14 Feb 2020 20:48:33 +0900 Subject: [PATCH 11/28] Fixed wrong radio button selected when download folder is not selected --- .../pupil/ui/dialog/DownloadLocationDialog.kt | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt index 3f24f0b0..b394b50a 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt @@ -36,10 +36,7 @@ import kotlinx.android.synthetic.main.item_dl_location.view.* import net.rdrei.android.dirchooser.DirectoryChooserActivity import net.rdrei.android.dirchooser.DirectoryChooserConfig import xyz.quaver.pupil.R -import xyz.quaver.pupil.util.REQUEST_DOWNLOAD_FOLDER -import xyz.quaver.pupil.util.REQUEST_DOWNLOAD_FOLDER_OLD -import xyz.quaver.pupil.util.REQUEST_WRITE_PERMISSION_AND_SAF -import xyz.quaver.pupil.util.byteToString +import xyz.quaver.pupil.util.* import java.io.File @SuppressLint("InflateParams") @@ -115,15 +112,11 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) { buttons.add(button to null) }) - val pref = preference.getString("dl_location", null) - val index = externalFilesDirs.indexOfFirst { - it.canonicalPath == pref - } - - if (index < 0) - buttons.last().first.isChecked = true - else + externalFilesDirs.indexOfFirst { + it.canonicalPath == getDownloadDirectory(context).canonicalPath + }.let { index -> buttons[index].first.isChecked = true + } setTitle(R.string.settings_dl_location) From 5c768d212156a6201eb008441035d18bcd1ed0f7 Mon Sep 17 00:00:00 2001 From: Pupil Date: Sat, 15 Feb 2020 00:25:59 +0900 Subject: [PATCH 12/28] Firebase enabled --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e8be39e0..55a0df93 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlinx-serialization' -if (file("src/google-services.json").exists() && file("src/debug/google-services.json").exists()) { +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' @@ -20,7 +20,7 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 42 - versionName "4.6-beta1" + versionName "4.6-beta2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true From 5dea35343be5da5d2d47b8d7092d9a57a20a98b1 Mon Sep 17 00:00:00 2001 From: Pupil Date: Sat, 15 Feb 2020 01:59:42 +0900 Subject: [PATCH 13/28] Fixed preference bug Version fix --- app/build.gradle | 2 +- app/release/output.json | 2 +- app/src/main/java/xyz/quaver/pupil/Pupil.kt | 7 +------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 55a0df93..ee89e59f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 42 - versionName "4.6-beta2" + versionName "4.6-beta3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true diff --git a/app/release/output.json b/app/release/output.json index d176db0a..6d4690c1 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":42,"versionName":"4.6-beta1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":42,"versionName":"4.6-beta3","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] \ 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 a5512f9c..3d88be27 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -47,7 +47,7 @@ class Pupil : MultiDexApplication() { val preference = PreferenceManager.getDefaultSharedPreferences(this) try { - PreferenceManager.getDefaultSharedPreferences(this).getInt("dl_location", 0) + preference.getString("dl_location", null) } catch (e: Exception) { preference.edit().remove("dl_location").apply() } @@ -58,11 +58,6 @@ class Pupil : MultiDexApplication() { if (BuildConfig.DEBUG) FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false) - val file = preference.getString("dl_location", null) - - if (file?.startsWith("content") == true) - preference.edit().remove("dl_location").apply() - try { ProviderInstaller.installIfNeeded(this) } catch (e: GooglePlayServicesRepairableException) { From 69a9d63e1d51213b4316c204519bdb8dab82e4af Mon Sep 17 00:00:00 2001 From: Pupil Date: Sat, 15 Feb 2020 12:40:10 +0900 Subject: [PATCH 14/28] Proxy added --- app/build.gradle | 2 +- .../pupil/ui/dialog/DefaultQueryDialog.kt | 20 ++- .../pupil/ui/dialog/DownloadLocationDialog.kt | 21 +-- .../quaver/pupil/ui/dialog/MirrorDialog.kt | 11 +- .../xyz/quaver/pupil/ui/dialog/ProxyDialog.kt | 127 ++++++++++++++++++ .../pupil/ui/fragment/SettingsFragment.kt | 28 +++- .../main/java/xyz/quaver/pupil/util/proxy.kt | 63 +++++++++ app/src/main/res/layout/dialog_proxy.xml | 123 +++++++++++++++++ app/src/main/res/values-ja/arrays.xml | 26 ++++ app/src/main/res/values-ja/strings.xml | 8 ++ app/src/main/res/values-ko/arrays.xml | 26 ++++ app/src/main/res/values-ko/strings.xml | 8 ++ app/src/main/res/values/arrays.xml | 6 + app/src/main/res/values/strings.xml | 10 ++ app/src/main/res/xml/root_preferences.xml | 4 + 15 files changed, 450 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt create mode 100644 app/src/main/java/xyz/quaver/pupil/util/proxy.kt create mode 100644 app/src/main/res/layout/dialog_proxy.xml create mode 100644 app/src/main/res/values-ja/arrays.xml create mode 100644 app/src/main/res/values-ko/arrays.xml diff --git a/app/build.gradle b/app/build.gradle index ee89e59f..d97d70da 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 42 - versionName "4.6-beta3" + versionName "4.6-beta4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true 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 125fa48b..3d39c6e4 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 @@ -46,16 +46,12 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { private val excludeBL = "-male:yaoi" private val excludeGuro = listOf("-female:guro", "-male:guro") - private lateinit var dialogView : View - var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null @SuppressLint("InflateParams") override fun onCreate(savedInstanceState: Bundle?) { - initDialog() - setTitle(R.string.default_query_dialog_title) - setView(dialogView) + setView(build()) setButton(Dialog.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> val newTags = Tags.parse(default_query_dialog_edittext.text.toString()) @@ -79,15 +75,15 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } @SuppressLint("InflateParams") - private fun initDialog() { + private fun build() : View { val preferences = PreferenceManager.getDefaultSharedPreferences(context) val tags = Tags.parse( preferences.getString("default_query", "") ?: "" ) - dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_default_query, null) + val view = LayoutInflater.from(context).inflate(R.layout.dialog_default_query, null) - with(dialogView.default_query_dialog_language_selector) { + with(view.default_query_dialog_language_selector) { adapter = ArrayAdapter( context, @@ -110,13 +106,13 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } } - with(dialogView.default_query_dialog_BL_checkbox) { + with(view.default_query_dialog_BL_checkbox) { isChecked = tags.contains(excludeBL) if (tags.contains(excludeBL)) tags.remove(excludeBL) } - with(dialogView.default_query_dialog_guro_checkbox) { + with(view.default_query_dialog_guro_checkbox) { isChecked = excludeGuro.all { tags.contains(it) } if (excludeGuro.all { tags.contains(it) }) excludeGuro.forEach { @@ -124,7 +120,7 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } } - with(dialogView.default_query_dialog_edittext) { + with(view.default_query_dialog_edittext) { setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE) addTextChangedListener(object : TextWatcher { override fun beforeTextChanged( @@ -149,6 +145,8 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) { } }) } + + return view } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt index b394b50a..d4f5a2a5 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialog.kt @@ -26,6 +26,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.view.View import android.widget.LinearLayout import android.widget.RadioButton import androidx.appcompat.app.AlertDialog @@ -46,6 +47,16 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) { private val buttons = mutableListOf>() override fun onCreate(savedInstanceState: Bundle?) { + setTitle(R.string.settings_dl_location) + + setView(build()) + + setButton(Dialog.BUTTON_POSITIVE, context.getText(android.R.string.ok)) { _, _ -> } + + super.onCreate(savedInstanceState) + } + + private fun build() : View { val view = layoutInflater.inflate(R.layout.dialog_dl_location, null) as LinearLayout val externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null) @@ -118,15 +129,7 @@ class DownloadLocationDialog(val activity: Activity) : AlertDialog(activity) { buttons[index].first.isChecked = true } - setTitle(R.string.settings_dl_location) - - setView(view) - - setButton(Dialog.BUTTON_POSITIVE, context.getText(android.R.string.ok)) { _, _ -> - dismiss() - } - - super.onCreate(savedInstanceState) + return view } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt index 1a2f0351..d20b61df 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/MirrorDialog.kt @@ -22,6 +22,7 @@ import android.annotation.SuppressLint import android.app.Dialog import android.content.Context import android.os.Bundle +import android.view.View import androidx.appcompat.app.AlertDialog import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration @@ -56,21 +57,17 @@ class MirrorDialog(context: Context) : AlertDialog(context) { } } - private lateinit var recyclerView: RecyclerView - @SuppressLint("InflateParams") override fun onCreate(savedInstanceState: Bundle?) { - initDialog() - setTitle(R.string.settings_mirror_title) - setView(recyclerView) + setView(build()) setButton(Dialog.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> } super.onCreate(savedInstanceState) } - private fun initDialog() { - recyclerView = RecyclerView(context).apply recyclerview@{ + private fun build() : View { + return RecyclerView(context).apply recyclerview@{ addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) layoutManager = LinearLayoutManager(context) adapter = MirrorAdapter(context).apply adapter@{ diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt new file mode 100644 index 00000000..645d6929 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt @@ -0,0 +1,127 @@ +/* + * 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.dialog + +import android.annotation.SuppressLint +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import androidx.preference.PreferenceManager +import kotlinx.android.synthetic.main.dialog_proxy.view.* +import xyz.quaver.pupil.R +import xyz.quaver.pupil.util.ProxyInfo +import xyz.quaver.pupil.util.getProxyInfo +import xyz.quaver.pupil.util.json +import java.net.Proxy + +class ProxyDialog(context: Context) : Dialog(context) { + + override fun onCreate(savedInstanceState: Bundle?) { + val view = build() + + setTitle(R.string.settings_proxy_title) + setContentView(view) + + window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT + + super.onCreate(savedInstanceState) + } + + @SuppressLint("InflateParams") + private fun build() : View { + val proxyInfo = getProxyInfo(context) + + val view = LayoutInflater.from(context).inflate(R.layout.dialog_proxy, null) + + val enabler = { enable: Boolean -> + view?.proxy_addr?.isEnabled = enable + view?.proxy_port?.isEnabled = enable + view?.proxy_username?.isEnabled = enable + view?.proxy_password?.isEnabled = enable + + if (!enable) { + view?.proxy_addr?.text = null + view?.proxy_port?.text = null + view?.proxy_username?.text = null + view?.proxy_password?.text = null + } + } + + with(view.proxy_type_selector) { + adapter = ArrayAdapter( + context, + android.R.layout.simple_spinner_dropdown_item, + context.resources.getStringArray(R.array.proxy_type) + ) + + setSelection(proxyInfo.type.ordinal) + + onItemSelectedListener = object: AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + enabler.invoke(position != 0) + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + } + + view.proxy_addr.setText(proxyInfo.host) + view.proxy_port.setText(proxyInfo.port?.toString()) + view.proxy_username.setText(proxyInfo.username) + view.proxy_password.setText(proxyInfo.password) + + enabler.invoke(proxyInfo.type != Proxy.Type.DIRECT) + + view.proxy_cancel.setOnClickListener { + dismiss() + } + + view.proxy_ok.setOnClickListener { + val type = Proxy.Type.values()[view.proxy_type_selector.selectedItemPosition] + val addr = view.proxy_addr.text?.toString() + val port = view.proxy_port.text?.toString()?.toIntOrNull() + val username = view.proxy_username.text?.toString() + val password = view.proxy_password.text?.toString() + + if (type != Proxy.Type.DIRECT) { + if (addr == null || addr.isEmpty()) + view.proxy_addr.error = context.getText(R.string.proxy_dialog_error) + if (port == null) + view.proxy_port.error = context.getText(R.string.proxy_dialog_error) + + if (addr == null || addr.isEmpty() || port == null) + return@setOnClickListener + } + + PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy", + json.stringify(ProxyInfo.serializer(), ProxyInfo(type, addr, port, username, password)) + ).apply() + + dismiss() + } + + return view + } + +} \ 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 f3d88dad..3a3bcdbd 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 @@ -36,6 +36,7 @@ import xyz.quaver.pupil.ui.SettingsActivity import xyz.quaver.pupil.ui.dialog.DefaultQueryDialog import xyz.quaver.pupil.ui.dialog.DownloadLocationDialog import xyz.quaver.pupil.ui.dialog.MirrorDialog +import xyz.quaver.pupil.ui.dialog.ProxyDialog import xyz.quaver.pupil.util.* import java.io.File @@ -146,6 +147,10 @@ class SettingsFragment : MirrorDialog(context) .show() } + "proxy" -> { + ProxyDialog(context) + .show() + } "backup" -> { File(ContextCompat.getDataDir(context), "favorites.json").copyTo( File(getDownloadDirectory(context), "favorites.json"), @@ -189,9 +194,18 @@ class SettingsFragment : } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - when (key) { - "dl_location" -> { - findPreference(key)?.summary = getDownloadDirectory(context!!).canonicalPath + key ?: return + + with(findPreference(key)) { + this ?: return + + when (key) { + "proxy" -> { + summary = getProxyInfo(context).type.name + } + "dl_location" -> { + summary = getDownloadDirectory(context!!).canonicalPath + } } } } @@ -245,8 +259,7 @@ class SettingsFragment : onPreferenceClickListener = this@SettingsFragment } "default_query" -> { - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - summary = preferences.getString("default_query", "") ?: "" + summary = PreferenceManager.getDefaultSharedPreferences(context).getString("default_query", "") ?: "" onPreferenceClickListener = this@SettingsFragment } @@ -270,6 +283,11 @@ class SettingsFragment : "mirrors" -> { onPreferenceClickListener = this@SettingsFragment } + "proxy" -> { + summary = getProxyInfo(context).type.name + + onPreferenceClickListener = this@SettingsFragment + } "dark_mode" -> { onPreferenceChangeListener = this@SettingsFragment } diff --git a/app/src/main/java/xyz/quaver/pupil/util/proxy.kt b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt new file mode 100644 index 00000000..229c5e90 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt @@ -0,0 +1,63 @@ +/* + * 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.util + +import android.content.Context +import androidx.preference.PreferenceManager +import kotlinx.serialization.Serializable +import okhttp3.Authenticator +import okhttp3.Credentials +import java.net.InetSocketAddress +import java.net.Proxy + +@Serializable +data class ProxyInfo( + val type: Proxy.Type, + val host: String? = null, + val port: Int? = null, + val username: String? = null, + val password: String? = null +) { + fun proxy() : Proxy { + return if (host == null || port == null) + return Proxy.NO_PROXY + else + Proxy(type, InetSocketAddress.createUnresolved(host, port)) + } + + fun authenticator() = Authenticator { _, response -> + val credential = Credentials.basic(username, password) + + response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build() + } + +} + +fun getProxy(context: Context) = + getProxyInfo(context).proxy() + +fun getProxyInfo(context: Context) = + PreferenceManager.getDefaultSharedPreferences(context).getString("proxy", null).let { + if (it == null) + ProxyInfo(Proxy.Type.DIRECT) + else + json.parse(ProxyInfo.serializer(), it) + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_proxy.xml b/app/src/main/res/layout/dialog_proxy.xml new file mode 100644 index 00000000..5765d86e --- /dev/null +++ b/app/src/main/res/layout/dialog_proxy.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +