Compare commits
39 Commits
5.1.7-hotf
...
5.1.14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34c074bf7b | ||
|
|
b4dc961cdc | ||
|
|
93374d2cfe | ||
|
|
4009b10549 | ||
|
|
db1864205f | ||
|
|
bf39ccabbd | ||
|
|
0e8e7767ee | ||
|
|
5b6c86e34f | ||
|
|
6bbaca3686 | ||
|
|
35eae90df1 | ||
|
|
488d43e076 | ||
|
|
7c5e93c171 | ||
|
|
a20ef783e1 | ||
|
|
8ae0dce0ed | ||
|
|
44aea606b7 | ||
|
|
a05dc8c661 | ||
|
|
1f80e36017 | ||
|
|
1efca40744 | ||
|
|
86e3131afa | ||
|
|
4910b4a4b0 | ||
|
|
9c7320c0a0 | ||
|
|
02c17c3b75 | ||
|
|
49a47f4b4f | ||
|
|
68280f4a62 | ||
|
|
0e3669b247 | ||
|
|
4c9aa29d46 | ||
|
|
66fbf10f2d | ||
|
|
15ad806eb8 | ||
|
|
b7f80b9c82 | ||
|
|
9b511d2f8f | ||
|
|
6ebce2deb3 | ||
|
|
95dade13f4 | ||
|
|
ba4449d003 | ||
|
|
7632fe5e86 | ||
|
|
2c56bcacee | ||
|
|
c8202db3c6 | ||
|
|
223d689b0c | ||
|
|
4f0e7d9696 | ||
|
|
f4ce911de9 |
17
.idea/deploymentTargetDropDown.xml
generated
Normal file
17
.idea/deploymentTargetDropDown.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetDropDown">
|
||||
<targetSelectedWithDropDown>
|
||||
<Target>
|
||||
<type value="QUICK_BOOT_TARGET" />
|
||||
<deviceKey>
|
||||
<Key>
|
||||
<type value="VIRTUAL_DEVICE_PATH" />
|
||||
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_30_x86.avd" />
|
||||
</Key>
|
||||
</deviceKey>
|
||||
</Target>
|
||||
</targetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2021-10-25T00:27:52.904947Z" />
|
||||
</component>
|
||||
</project>
|
||||
3
.idea/gradle.xml
generated
3
.idea/gradle.xml
generated
@@ -4,7 +4,7 @@
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
@@ -14,7 +14,6 @@
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
10
.idea/jarRepositories.xml
generated
10
.idea/jarRepositories.xml
generated
@@ -71,5 +71,15 @@
|
||||
<option name="name" value="maven3" />
|
||||
<option name="url" value="http://dl.bintray.com/piasy/maven" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://guardian.github.io/maven/repo-releases/" />
|
||||
</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>
|
||||
</project>
|
||||
12
.idea/runConfigurations.xml
generated
12
.idea/runConfigurations.xml
generated
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@@ -2,8 +2,8 @@
|
||||
*Pupil, Hitomi.la viewer for Android*
|
||||
|
||||

|
||||
[](https://github.com/tom5079/Pupil/releases/download/5.1.7-hotfix1/Pupil-v5.1.7-hotfix1.apk)
|
||||
[](https://discord.gg/Stj4b5v)
|
||||
[](https://github.com/tom5079/Pupil/releases/download/5.1.13/Pupil-v5.1.13.apk)
|
||||
[](https://discord.gg/Stj4b5v)
|
||||
|
||||
# Features
|
||||

|
||||
@@ -20,7 +20,7 @@ or Build app yourself
|
||||
|
||||
# Contribution
|
||||
|
||||
Any kind of contribution is appriciated. Feel free to leave PR!
|
||||
Any kind of contribution is appreciated. Feel free to leave PR!
|
||||
|
||||
## Tag Translation
|
||||
Head over to [tags branch](https://github.com/tom5079/Pupil/tree/tags)
|
||||
|
||||
@@ -37,22 +37,22 @@ android {
|
||||
applicationId "xyz.quaver.pupil"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
versionCode 64
|
||||
versionName "5.1.7-hotfix1"
|
||||
versionCode 67
|
||||
versionName "5.1.14"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
defaultConfig.minSdkVersion 21
|
||||
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
|
||||
debuggable true
|
||||
applicationIdSuffix ".debug"
|
||||
versionNameSuffix "-DEBUG"
|
||||
|
||||
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
|
||||
ext.enableCrashlytics = false
|
||||
ext.alwaysUpdateBuildId = false
|
||||
}
|
||||
@@ -74,44 +74,43 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
buildToolsVersion = "29.0.3"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.activity:activity-ktx:1.2.0-beta01"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.0-beta01"
|
||||
implementation "androidx.appcompat:appcompat:1.3.0"
|
||||
implementation "androidx.activity:activity-ktx:1.3.0-beta01"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.4"
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||
implementation "androidx.biometric:biometric:1.0.1"
|
||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||
implementation "androidx.biometric:biometric:1.1.0"
|
||||
implementation "androidx.work:work-runtime-ktx:2.6.0-beta01"
|
||||
|
||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||
|
||||
implementation "com.google.android.material:material:1.3.0-alpha04"
|
||||
implementation "com.google.android.material:material:1.3.0"
|
||||
|
||||
implementation "com.google.firebase:firebase-core:18.0.0"
|
||||
implementation "com.google.firebase:firebase-analytics:18.0.0"
|
||||
implementation "com.google.firebase:firebase-crashlytics:17.3.0"
|
||||
implementation "com.google.firebase:firebase-perf:19.0.10"
|
||||
implementation platform('com.google.firebase:firebase-bom:26.5.0')
|
||||
implementation "com.google.firebase:firebase-analytics-ktx"
|
||||
implementation "com.google.firebase:firebase-crashlytics-ktx"
|
||||
implementation "com.google.firebase:firebase-perf-ktx"
|
||||
|
||||
implementation "com.google.android.gms:play-services-oss-licenses:17.0.0"
|
||||
implementation "com.google.android.gms:play-services-mlkit-face-detection:16.1.1"
|
||||
implementation "com.google.android.gms:play-services-mlkit-face-detection:16.1.7"
|
||||
|
||||
implementation "com.github.clans:fab:1.6.4"
|
||||
|
||||
//implementation "com.quiph.ui:recyclerviewfastscroller:0.2.1"
|
||||
|
||||
implementation 'com.github.piasy:BigImageViewer:1.6.7'
|
||||
implementation 'com.github.piasy:FrescoImageLoader:1.6.7'
|
||||
implementation 'com.github.piasy:FrescoImageViewFactory:1.6.7'
|
||||
implementation 'com.github.piasy:BigImageViewer:1.8.1'
|
||||
implementation 'com.github.piasy:FrescoImageLoader:1.8.1'
|
||||
implementation 'com.github.piasy:FrescoImageViewFactory:1.8.1'
|
||||
|
||||
//noinspection GradleDependency
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||
@@ -126,9 +125,9 @@ dependencies {
|
||||
|
||||
implementation "ru.noties.markwon:core:3.1.0"
|
||||
|
||||
implementation "xyz.quaver:libpupil:1.8.16"
|
||||
implementation "xyz.quaver:documentfilex:0.4-alpha02"
|
||||
implementation "xyz.quaver:floatingsearchview:1.0.7"
|
||||
implementation "xyz.quaver:libpupil:2.1.7-DEV"
|
||||
implementation "xyz.quaver:documentfilex:0.6.1"
|
||||
implementation "xyz.quaver:floatingsearchview:1.1.7"
|
||||
|
||||
testImplementation "junit:junit:4.13.1"
|
||||
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "xyz.quaver.pupil",
|
||||
"variantName": "processReleaseResources",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"versionCode": 64,
|
||||
"versionName": "5.1.7-hotfix1",
|
||||
"versionCode": 67,
|
||||
"versionName": "5.1.14",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
@@ -34,8 +35,8 @@ import com.github.piasy.biv.loader.fresco.FrescoImageLoader
|
||||
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
|
||||
import com.google.android.gms.common.GooglePlayServicesRepairableException
|
||||
import com.google.android.gms.security.ProviderInstaller
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import okhttp3.Dispatcher
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
@@ -46,6 +47,7 @@ import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||
import xyz.quaver.setClient
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -96,6 +98,11 @@ class Pupil : Application() {
|
||||
val tag = request.tag() ?: return@addInterceptor chain.proceed(request)
|
||||
|
||||
interceptors[tag::class]?.invoke(chain) ?: chain.proceed(request)
|
||||
}.apply {
|
||||
(Preferences.get<String>("max_concurrent_download").toIntOrNull() ?: 0).let {
|
||||
if (it != 0)
|
||||
dispatcher(Dispatcher(Executors.newFixedThreadPool(it)))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -108,8 +115,6 @@ class Pupil : Application() {
|
||||
|
||||
if (!FileX(this, it).canWrite())
|
||||
throw Exception()
|
||||
|
||||
DownloadManager.getInstance(this).migrate()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Preferences.remove("download_folder")
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.daimajia.swipe.interfaces.SwipeAdapterInterface
|
||||
import com.github.piasy.biv.loader.ImageLoader
|
||||
import kotlinx.coroutines.*
|
||||
import xyz.quaver.hitomi.getGallery
|
||||
import xyz.quaver.hitomi.getGalleryInfo
|
||||
import xyz.quaver.hitomi.getReader
|
||||
import xyz.quaver.io.util.getChild
|
||||
import xyz.quaver.pupil.R
|
||||
@@ -231,7 +232,7 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
||||
binding.galleryblockPagecount.text = "-"
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val pageCount = kotlin.runCatching {
|
||||
getReader(galleryBlock.id).galleryInfo.files.size
|
||||
getGalleryInfo(galleryBlock.id).files.size
|
||||
}.getOrNull() ?: return@launch
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.galleryblockPagecount.text = itemView.context.getString(R.string.galleryblock_pagecount, pageCount)
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.databinding.MirrorsItemBinding
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import java.util.*
|
||||
|
||||
class MirrorAdapter(context: Context) : RecyclerView.Adapter<MirrorAdapter.ViewHolder>() {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
inner class ViewHolder(val binding: MirrorsItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
init {
|
||||
binding.mirrorButton.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN)
|
||||
onStartDrag?.invoke(this)
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
fun bind(mirror: String) {
|
||||
binding.mirrorName.text = mirror
|
||||
}
|
||||
}
|
||||
|
||||
val mirrors = context.resources.getStringArray(R.array.mirrors).map {
|
||||
it.split('|').let { split ->
|
||||
Pair(split.first(), split.last())
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
val list = mirrors.keys.toMutableList().apply {
|
||||
Preferences.get<String>("mirrors")
|
||||
.split(">")
|
||||
.reversed()
|
||||
.forEach {
|
||||
if (this.contains(it)) {
|
||||
this.remove(it)
|
||||
this.add(0, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onItemMove : ((Int, Int) -> Unit) = { from, to ->
|
||||
Collections.swap(list, from, to)
|
||||
notifyItemMoved(from, to)
|
||||
onItemMoved?.invoke(list)
|
||||
}
|
||||
var onStartDrag : ((ViewHolder) -> Unit)? = null
|
||||
var onItemMoved : ((List<String>) -> (Unit))? = null
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(mirrors[list.elementAt(position)] ?: error(""))
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(MirrorsItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||
}
|
||||
|
||||
override fun getItemCount() = mirrors.size
|
||||
|
||||
}
|
||||
@@ -40,7 +40,7 @@ import com.github.piasy.biv.view.BigImageView
|
||||
import com.github.piasy.biv.view.ImageShownCallback
|
||||
import com.github.piasy.biv.view.ImageViewFactory
|
||||
import kotlinx.coroutines.*
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.GalleryInfo
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.databinding.ReaderItemBinding
|
||||
import xyz.quaver.pupil.ui.ReaderActivity
|
||||
@@ -52,7 +52,7 @@ class ReaderAdapter(
|
||||
private val activity: ReaderActivity,
|
||||
private val galleryID: Int
|
||||
) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
||||
var reader: Reader? = null
|
||||
var galleryInfo: GalleryInfo? = null
|
||||
|
||||
var isFullScreen = false
|
||||
|
||||
@@ -101,7 +101,7 @@ class ReaderAdapter(
|
||||
binding.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = 0
|
||||
dimensionRatio =
|
||||
"${reader!!.galleryInfo.files[position].width}:${reader!!.galleryInfo.files[position].height}"
|
||||
"${galleryInfo!!.files[position].width}:${galleryInfo!!.files[position].height}"
|
||||
}
|
||||
} else {
|
||||
binding.root.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
@@ -158,7 +158,7 @@ class ReaderAdapter(
|
||||
holder.bind(position)
|
||||
}
|
||||
|
||||
override fun getItemCount() = reader?.galleryInfo?.files?.size ?: 0
|
||||
override fun getItemCount() = galleryInfo?.files?.size ?: 0
|
||||
|
||||
override fun onViewRecycled(holder: ViewHolder) {
|
||||
holder.clear()
|
||||
|
||||
@@ -54,7 +54,7 @@ class UpdateBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
val uri = downloadManager.query(query).use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)).let {
|
||||
cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))?.let {
|
||||
val uri = Uri.parse(it)
|
||||
|
||||
when (uri.scheme) {
|
||||
|
||||
@@ -305,10 +305,10 @@ class DownloadService : Service() {
|
||||
|
||||
initNotification(galleryID)
|
||||
|
||||
val reader = cache.getReader()
|
||||
val galleryInfo = cache.getGalleryInfo()
|
||||
|
||||
// Gallery doesn't exist
|
||||
if (reader == null) {
|
||||
if (galleryInfo == null) {
|
||||
delete(galleryID)
|
||||
progress[galleryID] = mutableListOf()
|
||||
return@launch
|
||||
@@ -316,7 +316,7 @@ class DownloadService : Service() {
|
||||
|
||||
histories.add(galleryID)
|
||||
|
||||
progress[galleryID] = MutableList(reader.galleryInfo.files.size) { 0F }
|
||||
progress[galleryID] = MutableList(galleryInfo.files.size) { 0F }
|
||||
|
||||
cache.metadata.imageList?.let {
|
||||
it.forEachIndexed { index, image ->
|
||||
@@ -334,7 +334,7 @@ class DownloadService : Service() {
|
||||
return@launch
|
||||
}
|
||||
|
||||
notification[galleryID]?.setContentTitle(reader.galleryInfo.title?.ellipsize(30))
|
||||
notification[galleryID]?.setContentTitle(galleryInfo.title?.ellipsize(30))
|
||||
notify(galleryID)
|
||||
|
||||
val queued = mutableSetOf<Int>()
|
||||
@@ -348,7 +348,7 @@ class DownloadService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
reader.requestBuilders.forEachIndexed { index, it ->
|
||||
galleryInfo.requestBuilders.forEachIndexed { index, it ->
|
||||
if (progress[galleryID]?.get(index)?.isInfinite() == false) {
|
||||
val request = it.tag(Tag(galleryID, index, startId)).build()
|
||||
client.newCall(request).enqueue(callback)
|
||||
|
||||
@@ -32,7 +32,6 @@ import android.view.animation.DecelerateInterpolator
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
@@ -125,11 +124,10 @@ class MainActivity :
|
||||
if (Preferences["download_folder", ""].isEmpty())
|
||||
DownloadLocationDialogFragment().show(supportFragmentManager, "Download Location Dialog")
|
||||
|
||||
checkUpdate(this)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
!Preferences["download_folder_ignore_warning", false] &&
|
||||
ContextCompat.getExternalFilesDirs(this, null).map { Uri.fromFile(it).toString() }
|
||||
ContextCompat.getExternalFilesDirs(this, null).filterNotNull().map { Uri.fromFile(it).toString() }
|
||||
.contains(Preferences["download_folder", ""])
|
||||
) {
|
||||
AlertDialog.Builder(this)
|
||||
@@ -145,6 +143,12 @@ class MainActivity :
|
||||
initView()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
checkUpdate(this)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override fun onBackPressed() {
|
||||
when {
|
||||
@@ -212,7 +216,7 @@ class MainActivity :
|
||||
min(
|
||||
max(
|
||||
binding.contents.searchview.translationY - dy,
|
||||
-binding.contents.searchview.findViewById<CardView>(R.id.search_query_section).height.toFloat()
|
||||
-binding.contents.searchview.binding.querySection.root.height.toFloat()
|
||||
), 0F)
|
||||
|
||||
if (dy > 0)
|
||||
@@ -474,7 +478,7 @@ class MainActivity :
|
||||
with(binding.contents.searchview) {
|
||||
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
||||
override fun onMenuOpened() {
|
||||
(binding.contents.recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
|
||||
(this@MainActivity.binding.contents.recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
|
||||
}
|
||||
|
||||
override fun onMenuClosed() {
|
||||
@@ -558,7 +562,7 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
|
||||
attachNavigationDrawerToMenuButton(binding.drawer)
|
||||
attachNavigationDrawerToMenuButton(this@MainActivity.binding.drawer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +801,7 @@ class MainActivity :
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
if (e.message != "No result")
|
||||
if (e !is CancellationException)
|
||||
FirebaseCrashlytics.getInstance().recordException(e)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
@@ -49,7 +49,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import xyz.quaver.Code
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.adapters.ReaderAdapter
|
||||
import xyz.quaver.pupil.databinding.NumberpickerDialogBinding
|
||||
@@ -184,7 +183,7 @@ class ReaderActivity : BaseActivity() {
|
||||
|
||||
with(binding.numberPicker) {
|
||||
minValue = 1
|
||||
maxValue = cache.metadata.reader?.galleryInfo?.files?.size ?: 0
|
||||
maxValue = cache.metadata.galleryInfo?.files?.size ?: 0
|
||||
value = currentPage
|
||||
}
|
||||
val dialog = AlertDialog.Builder(this).apply {
|
||||
@@ -299,26 +298,19 @@ class ReaderActivity : BaseActivity() {
|
||||
downloader.progress[galleryID]?.count { it.isInfinite() } ?: 0
|
||||
|
||||
if (title == getString(R.string.reader_loading)) {
|
||||
val reader = cache.metadata.reader
|
||||
val galleryInfo = cache.metadata.galleryInfo
|
||||
|
||||
if (reader != null) {
|
||||
if (galleryInfo != null) {
|
||||
with(binding.recyclerview.adapter as ReaderAdapter) {
|
||||
this.reader = reader
|
||||
this.galleryInfo = galleryInfo
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
title = reader.galleryInfo.title
|
||||
title = galleryInfo.title
|
||||
menu?.findItem(R.id.reader_menu_page_indicator)?.title =
|
||||
"$currentPage/${reader.galleryInfo.files.size}"
|
||||
"$currentPage/${galleryInfo.files.size}"
|
||||
|
||||
menu?.findItem(R.id.reader_type)?.icon = ContextCompat.getDrawable(
|
||||
this@ReaderActivity,
|
||||
when (reader.code) {
|
||||
Code.HITOMI -> R.drawable.hitomi
|
||||
Code.HIYOBI -> R.drawable.ic_hiyobi
|
||||
else -> android.R.color.transparent
|
||||
}
|
||||
)
|
||||
menu?.findItem(R.id.reader_type)?.icon = ContextCompat.getDrawable(this@ReaderActivity, R.drawable.hitomi)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import xyz.quaver.pupil.databinding.DownloadLocationItemBinding
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.byteToString
|
||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||
import xyz.quaver.pupil.util.migrate
|
||||
import java.io.File
|
||||
|
||||
class DownloadLocationDialogFragment : DialogFragment() {
|
||||
@@ -76,6 +75,15 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
||||
if (key == null) entries[key]!!.locationAvailable.text = downloadFolder
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val downloadFolder = DownloadManager.getInstance(context ?: return@registerForActivityResult).downloadFolder.canonicalPath
|
||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||
if (key == null)
|
||||
entries[key]!!.locationAvailable.text = downloadFolder
|
||||
else {
|
||||
entries[null]!!.button.isChecked = false
|
||||
entries[key]!!.button.isChecked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +129,8 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
||||
byteToString(dir.freeSpace)
|
||||
)
|
||||
root.setOnClickListener {
|
||||
entries.values.forEach { _ ->
|
||||
button.isChecked = false
|
||||
entries.values.forEach { entry ->
|
||||
entry.button.isChecked = false
|
||||
}
|
||||
button.performClick()
|
||||
Preferences["download_folder"] = dir.toUri().toString()
|
||||
@@ -134,8 +142,8 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
||||
DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply {
|
||||
locationType.text = requireContext().getString(R.string.settings_download_folder_custom)
|
||||
root.setOnClickListener {
|
||||
entries.values.forEach {
|
||||
it.button.isChecked = false
|
||||
entries.values.forEach { entry ->
|
||||
entry.button.isChecked = false
|
||||
}
|
||||
button.performClick()
|
||||
|
||||
@@ -178,8 +186,6 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
||||
setPositiveButton(requireContext().getText(android.R.string.ok)) { _, _ ->
|
||||
if (Preferences["download_folder", ""].isEmpty())
|
||||
Preferences["download_folder"] = context.getExternalFilesDir(null)?.toUri()?.toString() ?: ""
|
||||
|
||||
DownloadManager.getInstance(requireContext()).migrate()
|
||||
}
|
||||
|
||||
isCancelable = false
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.adapters.MirrorAdapter
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
|
||||
class MirrorDialog(context: Context) : AlertDialog(context) {
|
||||
|
||||
class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
|
||||
|
||||
var onMoveItem : ((Int, Int) -> (Unit))? = null
|
||||
|
||||
override fun getMovementFlags(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
) = makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0)
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
onMoveItem?.invoke(viewHolder.adapterPosition, target.adapterPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTitle(R.string.settings_mirror_title)
|
||||
setView(build())
|
||||
setButton(Dialog.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> }
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun build() : View {
|
||||
return RecyclerView(context).apply recyclerview@{
|
||||
addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = MirrorAdapter(context).apply adapter@{
|
||||
val itemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback().apply {
|
||||
onMoveItem = this@adapter.onItemMove
|
||||
}).apply {
|
||||
attachToRecyclerView(this@recyclerview)
|
||||
}
|
||||
|
||||
onStartDrag = {
|
||||
itemTouchHelper.startDrag(it)
|
||||
}
|
||||
|
||||
onItemMoved = {
|
||||
Preferences["mirrors"] = it.joinToString(">")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,12 +18,14 @@
|
||||
|
||||
package xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import xyz.quaver.pupil.R
|
||||
@@ -37,17 +39,19 @@ import xyz.quaver.pupil.util.getProxyInfo
|
||||
import xyz.quaver.pupil.util.proxyInfo
|
||||
import java.net.Proxy
|
||||
|
||||
class ProxyDialog(context: Context) : AlertDialog(context) {
|
||||
class ProxyDialogFragment : DialogFragment() {
|
||||
|
||||
private lateinit var binding: ProxyDialogBinding
|
||||
private var _binding: ProxyDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ProxyDialogBinding.inflate(layoutInflater)
|
||||
setView(binding.root)
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = ProxyDialogBinding.inflate(layoutInflater)
|
||||
|
||||
initView()
|
||||
|
||||
return AlertDialog.Builder(requireContext()).apply {
|
||||
setView(binding.root)
|
||||
}.create()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
@@ -105,9 +109,9 @@ class ProxyDialog(context: Context) : AlertDialog(context) {
|
||||
|
||||
if (type != Proxy.Type.DIRECT) {
|
||||
if (addr == null || addr.isEmpty())
|
||||
binding.addr.error = context.getText(R.string.proxy_dialog_error)
|
||||
binding.addr.error = requireContext().getText(R.string.proxy_dialog_error)
|
||||
if (port == null)
|
||||
binding.port.error = context.getText(R.string.proxy_dialog_error)
|
||||
binding.port.error = requireContext().getText(R.string.proxy_dialog_error)
|
||||
|
||||
if (addr == null || addr.isEmpty() || port == null)
|
||||
return@setOnClickListener
|
||||
@@ -29,15 +29,20 @@ import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.Dispatcher
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.getChild
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.client
|
||||
import xyz.quaver.pupil.clientBuilder
|
||||
import xyz.quaver.pupil.clientHolder
|
||||
import xyz.quaver.pupil.ui.LockActivity
|
||||
import xyz.quaver.pupil.ui.SettingsActivity
|
||||
import xyz.quaver.pupil.ui.dialog.*
|
||||
import xyz.quaver.pupil.util.*
|
||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class SettingsFragment :
|
||||
PreferenceFragmentCompat(),
|
||||
@@ -98,13 +103,8 @@ class SettingsFragment :
|
||||
}
|
||||
lockLauncher.launch(intent)
|
||||
}
|
||||
"mirrors" -> {
|
||||
MirrorDialog(requireContext())
|
||||
.show()
|
||||
}
|
||||
"proxy" -> {
|
||||
ProxyDialog(requireContext())
|
||||
.show()
|
||||
ProxyDialogFragment().show(parentFragmentManager, "Proxy Dialog")
|
||||
}
|
||||
"user_id" -> {
|
||||
(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip(
|
||||
@@ -168,6 +168,18 @@ class SettingsFragment :
|
||||
"download_folder_name" -> {
|
||||
summary = Preferences["download_folder_name", "[-id-] -title-"]
|
||||
}
|
||||
"max_concurrent_download" -> {
|
||||
val newValue = Preferences.get<String>(key).toIntOrNull() ?: 0
|
||||
|
||||
if (newValue == 0)
|
||||
clientBuilder.dispatcher(Dispatcher())
|
||||
else
|
||||
clientBuilder.dispatcher((Dispatcher(Executors.newFixedThreadPool(newValue))))
|
||||
|
||||
clientHolder = null
|
||||
client
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,6 +259,11 @@ class SettingsFragment :
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"proxy" -> {
|
||||
summary = getProxyInfo().type.name
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"tag_translation" -> {
|
||||
this as ListPreference
|
||||
|
||||
@@ -268,14 +285,6 @@ class SettingsFragment :
|
||||
onPreferenceChangeListener = this@SettingsFragment
|
||||
|
||||
}
|
||||
"mirrors" -> {
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"proxy" -> {
|
||||
summary = getProxyInfo().type.name
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"dark_mode" -> {
|
||||
onPreferenceChangeListener = this@SettingsFragment
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
|
||||
searchInputView.addTextChangedListener(this)
|
||||
onSearchListener = this
|
||||
onBindSuggestionCallback = { a, b, c, d, e ->
|
||||
onBindSuggestion(a, b, c, d, e)
|
||||
onBindSuggestionCallback = { binding, item, itemPosition ->
|
||||
onBindSuggestion(binding.root, binding.leftIcon, binding.body, item, itemPosition)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,13 @@
|
||||
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.serializer
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class SavedSet <T: Any> (private val file: File, private val any: T, private val set: MutableSet<T> = mutableSetOf()) : MutableSet<T> by set {
|
||||
|
||||
@@ -46,6 +48,8 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
Json.decodeFromString(serializer, file.readText())
|
||||
}.onSuccess {
|
||||
set.addAll(it)
|
||||
}.onFailure {
|
||||
FirebaseCrashlytics.getInstance().recordException(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +61,6 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
|
||||
@Synchronized
|
||||
override fun add(element: T): Boolean {
|
||||
load()
|
||||
|
||||
set.remove(element)
|
||||
|
||||
return set.add(element).also {
|
||||
@@ -68,8 +70,6 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
|
||||
@Synchronized
|
||||
override fun addAll(elements: Collection<T>): Boolean {
|
||||
load()
|
||||
|
||||
set.removeAll(elements)
|
||||
|
||||
return set.addAll(elements).also {
|
||||
@@ -79,8 +79,6 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
|
||||
@Synchronized
|
||||
override fun remove(element: T): Boolean {
|
||||
load()
|
||||
|
||||
return set.remove(element).also {
|
||||
save()
|
||||
}
|
||||
|
||||
@@ -32,24 +32,62 @@ import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Request
|
||||
import xyz.quaver.Code
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.GalleryInfo
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.*
|
||||
import xyz.quaver.pupil.client
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Serializable
|
||||
data class Metadata(
|
||||
var galleryBlock: GalleryBlock? = null,
|
||||
var reader: Reader? = null,
|
||||
data class OldGalleryBlock(
|
||||
val code: String,
|
||||
val id: Int,
|
||||
val galleryUrl: String,
|
||||
val thumbnails: List<String>,
|
||||
val title: String,
|
||||
val artists: List<String>,
|
||||
val series: List<String>,
|
||||
val type: String,
|
||||
val language: String,
|
||||
val relatedTags: List<String>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class OldReader(val code: String, val galleryInfo: GalleryInfo)
|
||||
|
||||
@Serializable
|
||||
data class OldMetadata(
|
||||
var galleryBlock: OldGalleryBlock? = null,
|
||||
var reader: OldReader? = null,
|
||||
var imageList: MutableList<String?>? = null
|
||||
) {
|
||||
fun copy(): Metadata = Metadata(galleryBlock, reader, imageList?.let { MutableList(it.size) { i -> it[i] } })
|
||||
fun copy(): OldMetadata = OldMetadata(galleryBlock, reader, imageList?.let { MutableList(it.size) { i -> it[i] } })
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Metadata(
|
||||
var galleryBlock: GalleryBlock? = null,
|
||||
var galleryInfo: GalleryInfo? = null,
|
||||
var imageList: MutableList<String?>? = null
|
||||
) {
|
||||
constructor(old: OldMetadata) : this(old.galleryBlock?.let { galleryBlock -> GalleryBlock(
|
||||
galleryBlock.id,
|
||||
galleryBlock.galleryUrl,
|
||||
galleryBlock.thumbnails,
|
||||
galleryBlock.title,
|
||||
galleryBlock.artists,
|
||||
galleryBlock.series,
|
||||
galleryBlock.type,
|
||||
galleryBlock.language,
|
||||
galleryBlock.relatedTags) },
|
||||
old.reader?.galleryInfo,
|
||||
old.imageList
|
||||
)
|
||||
|
||||
fun copy(): Metadata = Metadata(galleryBlock, galleryInfo, imageList?.let { MutableList(it.size) { i -> it[i] } })
|
||||
}
|
||||
|
||||
class Cache private constructor(context: Context, val galleryID: Int) : ContextWrapper(context) {
|
||||
@@ -74,8 +112,12 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
}
|
||||
|
||||
var metadata = kotlin.runCatching {
|
||||
findFile(".metadata")?.readText()?.let {
|
||||
Json.decodeFromString<Metadata>(it)
|
||||
findFile(".metadata")?.readText()?.let { metadata ->
|
||||
kotlin.runCatching {
|
||||
Json.decodeFromString<Metadata>(metadata)
|
||||
}.getOrElse {
|
||||
Metadata(Json.decodeFromString<OldMetadata>(metadata))
|
||||
}
|
||||
}
|
||||
}.getOrNull() ?: Metadata()
|
||||
|
||||
@@ -110,27 +152,13 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
}
|
||||
|
||||
suspend fun getGalleryBlock(): GalleryBlock? {
|
||||
val sources = listOf(
|
||||
{ xyz.quaver.hitomi.getGalleryBlock(galleryID) },
|
||||
{ xyz.quaver.hiyobi.getGalleryBlock(galleryID) }
|
||||
)
|
||||
|
||||
return metadata.galleryBlock
|
||||
?: withContext(Dispatchers.IO) {
|
||||
var galleryBlock: GalleryBlock? = null
|
||||
|
||||
for (source in sources) {
|
||||
galleryBlock = try {
|
||||
source.invoke()
|
||||
} catch (e: Exception) { null }
|
||||
|
||||
if (galleryBlock != null)
|
||||
break
|
||||
}
|
||||
|
||||
galleryBlock?.also {
|
||||
setMetadata { metadata -> metadata.galleryBlock = it }
|
||||
}
|
||||
try {
|
||||
xyz.quaver.hitomi.getGalleryBlock(galleryID).also {
|
||||
setMetadata { metadata -> metadata.galleryBlock = it }
|
||||
}
|
||||
} catch (e: Exception) { return@withContext null }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,41 +182,21 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
}.getOrNull()?.uri }
|
||||
} } ?: Uri.EMPTY
|
||||
|
||||
suspend fun getReader(): Reader? {
|
||||
val mirrors = Preferences.get<String>("mirrors").let { if (it.isEmpty()) emptyList() else it.split('>') }
|
||||
suspend fun getGalleryInfo(): GalleryInfo? {
|
||||
|
||||
val sources = mapOf(
|
||||
Code.HITOMI to { xyz.quaver.hitomi.getReader(galleryID) },
|
||||
Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) }
|
||||
).let {
|
||||
if (mirrors.isNotEmpty())
|
||||
it.toSortedMap{ o1, o2 -> mirrors.indexOf(o1.name) - mirrors.indexOf(o2.name) }
|
||||
else
|
||||
it
|
||||
}
|
||||
|
||||
return metadata.reader
|
||||
return metadata.galleryInfo
|
||||
?: withContext(Dispatchers.IO) {
|
||||
var reader: Reader? = null
|
||||
try {
|
||||
xyz.quaver.hitomi.getGalleryInfo(galleryID).also {
|
||||
setMetadata { metadata ->
|
||||
metadata.galleryInfo = it
|
||||
|
||||
for (source in sources) {
|
||||
reader = try {
|
||||
source.value.invoke()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
if (reader != null)
|
||||
break
|
||||
}
|
||||
|
||||
reader?.also {
|
||||
setMetadata { metadata ->
|
||||
metadata.reader = it
|
||||
|
||||
if (metadata.imageList == null)
|
||||
metadata.imageList = MutableList(reader.galleryInfo.files.size) { null }
|
||||
if (metadata.imageList == null)
|
||||
metadata.imageList = MutableList(it.files.size) { null }
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,13 @@
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.serialization.json.*
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import xyz.quaver.Code
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.GalleryInfo
|
||||
import xyz.quaver.hitomi.getReferer
|
||||
import xyz.quaver.hitomi.imageUrlFromImage
|
||||
import xyz.quaver.hiyobi.createImgList
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@@ -41,7 +35,7 @@ fun String.wordCapitalize() : String {
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
for (word in this.split(" "))
|
||||
result.add(word.capitalize(Locale.US))
|
||||
result.add(word.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() })
|
||||
|
||||
return result.joinToString(" ")
|
||||
}
|
||||
@@ -103,25 +97,15 @@ fun GalleryBlock.formatDownloadFolderTest(format: String): String =
|
||||
}
|
||||
}.replace(Regex("""[*\\|"?><:/]"""), "").ellipsize(127)
|
||||
|
||||
val Reader.requestBuilders: List<Request.Builder>
|
||||
val GalleryInfo.requestBuilders: List<Request.Builder>
|
||||
get() {
|
||||
val galleryID = this.galleryInfo.id ?: 0
|
||||
val galleryID = this.id ?: 0
|
||||
val lowQuality = Preferences["low_quality", true]
|
||||
|
||||
return when(code) {
|
||||
Code.HITOMI -> {
|
||||
this.galleryInfo.files.map {
|
||||
Request.Builder()
|
||||
.url(imageUrlFromImage(galleryID, it, !lowQuality))
|
||||
.header("Referer", getReferer(galleryID))
|
||||
}
|
||||
}
|
||||
Code.HIYOBI -> {
|
||||
createImgList(galleryID, this, lowQuality).map {
|
||||
Request.Builder()
|
||||
.url(it.path)
|
||||
}
|
||||
}
|
||||
return this.files.map {
|
||||
Request.Builder()
|
||||
.url(imageUrlFromImage(galleryID, it, !lowQuality))
|
||||
.header("Referer", getReferer(galleryID))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,48 +18,26 @@
|
||||
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.DownloadManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import android.webkit.URLUtil
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.*
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import ru.noties.markwon.Markwon
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.getGalleryBlock
|
||||
import xyz.quaver.hitomi.getReader
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.getChild
|
||||
import xyz.quaver.io.util.readText
|
||||
import xyz.quaver.io.util.writeBytes
|
||||
import xyz.quaver.io.util.writeText
|
||||
import xyz.quaver.pupil.BuildConfig
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.client
|
||||
import xyz.quaver.pupil.favorites
|
||||
import xyz.quaver.pupil.services.DownloadService
|
||||
import xyz.quaver.pupil.util.downloader.Cache
|
||||
import xyz.quaver.pupil.util.downloader.Metadata
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
@@ -220,127 +198,4 @@ fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((
|
||||
}.onFailure { onFailure?.invoke(it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private var job: Job? = null
|
||||
private val receiver = object: BroadcastReceiver() {
|
||||
val ACTION_CANCEL = "ACTION_IMPORT_CANCEL"
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
context ?: return
|
||||
|
||||
when (intent?.action) {
|
||||
ACTION_CANCEL -> {
|
||||
job?.cancel()
|
||||
NotificationManagerCompat.from(context).cancel(R.id.notification_id_import)
|
||||
context.unregisterReceiver(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun xyz.quaver.pupil.util.downloader.DownloadManager.migrate() {
|
||||
registerReceiver(receiver, IntentFilter().apply { addAction(receiver.ACTION_CANCEL) })
|
||||
|
||||
val notificationManager = NotificationManagerCompat.from(this)
|
||||
val action = NotificationCompat.Action.Builder(0, getText(android.R.string.cancel),
|
||||
PendingIntent.getBroadcast(this, R.id.notification_import_cancel_action.normalizeID(), Intent(receiver.ACTION_CANCEL), PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
).build()
|
||||
val notification = NotificationCompat.Builder(this, "import")
|
||||
.setContentTitle(getText(R.string.import_old_galleries_notification))
|
||||
.setProgress(0, 0, true)
|
||||
.addAction(action)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setOngoing(true)
|
||||
|
||||
DownloadService.cancel(this)
|
||||
|
||||
job?.cancel()
|
||||
job = CoroutineScope(Dispatchers.IO).launch {
|
||||
val images = listOf(
|
||||
"jpg",
|
||||
"png",
|
||||
"gif",
|
||||
"webp"
|
||||
)
|
||||
|
||||
val downloadFolders = downloadFolder.listFiles { folder ->
|
||||
folder.isDirectory && !downloadFolderMap.values.contains(folder.name)
|
||||
}?.map {
|
||||
if (it !is FileX)
|
||||
FileX(this@migrate, it)
|
||||
else
|
||||
it
|
||||
}
|
||||
|
||||
if (downloadFolders.isNullOrEmpty()) return@launch
|
||||
|
||||
downloadFolders.forEachIndexed { index, folder ->
|
||||
notification
|
||||
.setContentText(getString(R.string.import_old_galleries_notification_text, index, downloadFolders.size))
|
||||
.setProgress(index, downloadFolders.size, false)
|
||||
notificationManager.notify(R.id.notification_id_import, notification.build())
|
||||
|
||||
val metadata = kotlin.runCatching {
|
||||
folder.getChild(".metadata").readText()?.let { Json.parseToJsonElement(it) }
|
||||
}.getOrNull()
|
||||
|
||||
val galleryID = metadata?.getOrNull("reader")?.getOrNull("galleryInfo")?.getOrNull("id")?.content?.toIntOrNull()
|
||||
?: folder.name.toIntOrNull() ?: return@forEachIndexed
|
||||
|
||||
val galleryBlock: GalleryBlock? = kotlin.runCatching {
|
||||
metadata?.getOrNull("galleryBlock")?.let { Json.decodeFromJsonElement<GalleryBlock>(it) }
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
getGalleryBlock(galleryID)
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
xyz.quaver.hiyobi.getGalleryBlock(galleryID)
|
||||
}.getOrNull()
|
||||
|
||||
val reader: Reader? = kotlin.runCatching {
|
||||
metadata?.getOrNull("reader")?.let { Json.decodeFromJsonElement<Reader>(it) }
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
getReader(galleryID)
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
xyz.quaver.hiyobi.getReader(galleryID)
|
||||
}.getOrNull()
|
||||
|
||||
metadata?.getOrNull("thumbnail")?.jsonPrimitive?.contentOrNull?.also { thumbnail ->
|
||||
val file = folder.getChild(".thumbnail").also {
|
||||
if (it.exists())
|
||||
it.delete()
|
||||
it.createNewFile()
|
||||
}
|
||||
|
||||
file.writeBytes(Base64.decode(thumbnail, Base64.DEFAULT))
|
||||
}
|
||||
|
||||
val list: MutableList<String?> =
|
||||
MutableList(reader!!.galleryInfo.files.size) { null }
|
||||
|
||||
folder.list { _, name ->
|
||||
name?.substringAfterLast('.') in images
|
||||
}?.sorted()?.take(list.size)?.forEachIndexed { i, name ->
|
||||
list[i] = name
|
||||
}
|
||||
|
||||
folder.getChild(".metadata").also { if (it.exists()) it.delete(); it.createNewFile() }.writeText(
|
||||
Json.encodeToString(Metadata(galleryBlock, reader, list))
|
||||
)
|
||||
|
||||
Cache.delete(this@migrate, galleryID)
|
||||
downloadFolderMap[galleryID] = folder.name
|
||||
|
||||
downloadFolder.getChild(".download").let { if (!it.exists()) it.createNewFile(); it.writeText(Json.encodeToString(downloadFolderMap)) }
|
||||
}
|
||||
|
||||
notification
|
||||
.setContentText(getText(R.string.import_old_galleries_notification_done))
|
||||
.setProgress(0, 0, false)
|
||||
.setOngoing(false)
|
||||
.mActions.clear()
|
||||
notificationManager.notify(R.id.notification_id_import, notification.build())
|
||||
|
||||
kotlin.runCatching {
|
||||
unregisterReceiver(receiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 159 B |
@@ -151,9 +151,10 @@
|
||||
<string name="no_camera">この機器には前面カメラが装着されていません</string>
|
||||
<string name="error">エラー</string>
|
||||
<string name="settings_cache_limit">キャッシュサイズ制限</string>
|
||||
<string name="settings_cache_unlimited">制限なし</string>
|
||||
<string name="unlimited">制限なし</string>
|
||||
<string name="settings_tag_translation">タグ言語</string>
|
||||
<string name="settings_tag_translation_message">Githubにて翻訳に参加できます</string>
|
||||
<string name="settings_concurrent_download">並列ダウンロード</string>
|
||||
<string name="settings_max_concurrent_download">並列ダウンロード</string>
|
||||
<string name="unaccessible_download_folder">アンドロイド11以上では外部からのアプリ内部空間接近が不可能です。ダウンロードフォルダを変更しますか?</string>
|
||||
<string name="settings_networking">ネットワーク</string>
|
||||
</resources>
|
||||
@@ -151,9 +151,10 @@
|
||||
<string name="no_camera">이 장치에는 전면 카메라가 없습니다</string>
|
||||
<string name="error">오류</string>
|
||||
<string name="settings_cache_limit">캐시 크기 제한</string>
|
||||
<string name="settings_cache_unlimited">무제한</string>
|
||||
<string name="unlimited">무제한</string>
|
||||
<string name="settings_tag_translation">태그 언어</string>
|
||||
<string name="settings_tag_translation_message">Github에서 번역에 참여하세요</string>
|
||||
<string name="settings_concurrent_download">병렬 다운로드</string>
|
||||
<string name="settings_max_concurrent_download">병렬 다운로드</string>
|
||||
<string name="unaccessible_download_folder">안드로이드 11 이상에서는 외부에서 현재 다운로드 폴더에 접근할 수 없습니다. 변경하시겠습니까?</string>
|
||||
<string name="settings_networking">네트워크</string>
|
||||
</resources>
|
||||
@@ -48,11 +48,6 @@
|
||||
<item>japanese|日本語</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="mirrors">
|
||||
<item>HITOMI|hitomi.la</item>
|
||||
<item>HIYOBI|hiyobi.me</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="proxy_type">
|
||||
<item>Direct</item>
|
||||
<item>HTTP</item>
|
||||
@@ -70,7 +65,7 @@
|
||||
</string-array>
|
||||
|
||||
<string-array name="cache_size_text">
|
||||
<item>@string/settings_cache_unlimited</item>
|
||||
<item>@string/unlimited</item>
|
||||
<item>1G</item>
|
||||
<item>2G</item>
|
||||
<item>4G</item>
|
||||
@@ -79,4 +74,24 @@
|
||||
<item>32G</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="concurrent_download">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>4</item>
|
||||
<item>8</item>
|
||||
<item>16</item>
|
||||
<item>32</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="concurrent_download_text">
|
||||
<item>@string/unlimited</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>4</item>
|
||||
<item>8</item>
|
||||
<item>16</item>
|
||||
<item>32</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
<string name="ignore">Ignore</string>
|
||||
|
||||
<string name="unlimited">Unlimited</string>
|
||||
|
||||
<string name="copied_to_clipboard">Copied to clipboard</string>
|
||||
|
||||
<string name="channel_download">Download</string>
|
||||
@@ -166,7 +168,6 @@
|
||||
<string name="settings_download_folder_custom">Custom Location</string>
|
||||
<string name="settings_download_folder_not_writable">This folder is not writable. Please select another folder.</string>
|
||||
<string name="settings_cache_limit">Cache Limit</string>
|
||||
<string name="settings_cache_unlimited">Unlimited</string>
|
||||
<string name="settings_nomedia_title">Hide image from gallery</string>
|
||||
<string name="settings_low_quality">Low quality images</string>
|
||||
<string name="settings_low_quality_summary">Load low quality images to improve load speed and data usage</string>
|
||||
@@ -176,14 +177,17 @@
|
||||
<string name="settings_app_lock">App lock</string>
|
||||
<string name="settings_app_lock_type">App lock type</string>
|
||||
|
||||
<!-- SETTINGS/NETWORKING -->
|
||||
<string name="settings_networking">Networking</string>
|
||||
<string name="settings_mirror_summary">Load images from mirrors</string>
|
||||
<string name="settings_proxy_title">Proxy</string>
|
||||
<string name="settings_max_concurrent_download">Concurrent Download</string>
|
||||
|
||||
<!-- SETTINGS/MISCELLANEOUS -->
|
||||
|
||||
<string name="settings_miscellaneous_title">Miscellaneous</string>
|
||||
<string name="settings_tag_translation">Tag Language</string>
|
||||
<string name="settings_concurrent_download">Concurrent Download</string>
|
||||
<string name="settings_tag_translation_message">Participate in translation on Github</string>
|
||||
<string name="settings_mirror_summary">Load images from mirrors</string>
|
||||
<string name="settings_proxy_title">Proxy</string>
|
||||
<string name="settings_rtl">Turn pages Right-to-Left</string>
|
||||
<string name="settings_security_mode_title">Enable security mode</string>
|
||||
<string name="settings_security_mode_summary">Enable security mode to make the screen invisible on recent app window</string>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
app:key="app_version"
|
||||
@@ -72,6 +73,23 @@
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings_networking">
|
||||
|
||||
<Preference
|
||||
app:key="proxy"
|
||||
app:title="@string/settings_proxy_title"/>
|
||||
|
||||
<ListPreference
|
||||
app:key="max_concurrent_download"
|
||||
android:title="@string/settings_max_concurrent_download"
|
||||
app:entries="@array/concurrent_download_text"
|
||||
app:entryValues="@array/concurrent_download"
|
||||
android:defaultValue="0"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings_miscellaneous_title">
|
||||
|
||||
@@ -80,15 +98,6 @@
|
||||
app:title="@string/settings_tag_translation"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<Preference
|
||||
app:key="mirrors"
|
||||
app:title="@string/settings_mirror_title"
|
||||
app:summary="@string/settings_mirror_summary"/>
|
||||
|
||||
<Preference
|
||||
app:key="proxy"
|
||||
app:title="@string/settings_proxy_title"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:key="rtl"
|
||||
app:title="@string/settings_rtl"
|
||||
|
||||
17
build.gradle
17
build.gradle
@@ -3,29 +3,30 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath "com.google.gms:google-services:4.3.4"
|
||||
classpath "com.google.gms:google-services:4.3.8"
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
classpath "com.google.firebase:firebase-crashlytics-gradle:2.4.1"
|
||||
classpath "com.google.firebase:perf-plugin:1.3.4"
|
||||
classpath "com.google.android.gms:oss-licenses-plugin:0.10.2"
|
||||
classpath "com.google.firebase:firebase-crashlytics-gradle:2.7.0"
|
||||
classpath "com.google.firebase:perf-plugin:1.4.0"
|
||||
classpath "com.google.android.gms:oss-licenses-plugin:0.10.4"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url "http://dl.bintray.com/piasy/maven" }
|
||||
google()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://guardian.github.com/maven/repo-releases" }
|
||||
maven { url "https://guardian.github.io/maven/repo-releases/" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@ kotlin.code.style=official
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
kotlin_version=1.4.20
|
||||
kotlin_version=1.5.10
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
|
||||
|
||||
Reference in New Issue
Block a user