Compare commits
11 Commits
5.0.3-hotf
...
5.1-hotfix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
608c6e6a1d | ||
|
|
bb2c91145f | ||
|
|
db074df0f7 | ||
|
|
f7c45df9a6 | ||
|
|
44e3d16cd6 | ||
|
|
a973cdfe0b | ||
|
|
fca42c79a8 | ||
|
|
f236775599 | ||
|
|
360decd37c | ||
|
|
998433479b | ||
|
|
c7e75aacf0 |
5
.idea/jarRepositories.xml
generated
5
.idea/jarRepositories.xml
generated
@@ -61,5 +61,10 @@
|
|||||||
<option name="name" value="MavenLocal" />
|
<option name="name" value="MavenLocal" />
|
||||||
<option name="url" value="file:/$USER_HOME$/.m2/repository" />
|
<option name="url" value="file:/$USER_HOME$/.m2/repository" />
|
||||||
</remote-repository>
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="maven3" />
|
||||||
|
<option name="name" value="maven3" />
|
||||||
|
<option name="url" value="https://dl.bintray.com/tom5079/maven" />
|
||||||
|
</remote-repository>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -20,8 +20,8 @@ android {
|
|||||||
applicationId "xyz.quaver.pupil"
|
applicationId "xyz.quaver.pupil"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 59
|
versionCode 60
|
||||||
versionName "5.0.3-hotfix1"
|
versionName "5.1-hotfix3"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
@@ -60,57 +60,58 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
||||||
//implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0-RC2"
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||||
implementation "androidx.activity:activity-ktx:1.2.0-alpha08"
|
implementation "androidx.activity:activity-ktx:1.2.0-alpha08"
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha08'
|
implementation "androidx.fragment:fragment-ktx:1.3.0-alpha08"
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation "androidx.preference:preference:1.1.1"
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
implementation "androidx.constraintlayout:constraintlayout:2.0.1"
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||||
implementation "androidx.biometric:biometric:1.0.1"
|
implementation "androidx.biometric:biometric:1.0.1"
|
||||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||||
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
implementation "com.google.android.material:material:1.3.0-alpha02"
|
||||||
implementation 'com.google.firebase:firebase-core:17.5.0'
|
implementation "com.google.firebase:firebase-core:17.5.0"
|
||||||
implementation 'com.google.firebase:firebase-analytics:17.5.0'
|
implementation "com.google.firebase:firebase-analytics:17.5.0"
|
||||||
implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
implementation "com.google.firebase:firebase-crashlytics:17.2.1"
|
||||||
implementation 'com.google.firebase:firebase-perf:19.0.8'
|
implementation "com.google.firebase:firebase-perf:19.0.8"
|
||||||
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0'
|
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.1"
|
||||||
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
implementation "com.github.clans:fab:1.6.4"
|
||||||
implementation 'com.github.clans:fab:1.6.4'
|
//implementation "com.quiph.ui:recyclerviewfastscroller:0.2.1"
|
||||||
//implementation 'com.quiph.ui:recyclerviewfastscroller:0.2.1'
|
|
||||||
//noinspection GradleDependency
|
//noinspection GradleDependency
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
implementation "com.squareup.okhttp3:okhttp:3.12.12"
|
||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation "com.github.bumptech.glide:glide:4.11.0"
|
||||||
implementation ("com.github.bumptech.glide:okhttp3-integration:4.11.0") {
|
implementation ("com.github.bumptech.glide:okhttp3-integration:4.11.0") {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
implementation 'com.github.bumptech.glide:annotations:4.11.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") {
|
implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
implementation 'com.tbuonomo.andrui:viewpagerdotsindicator:4.1.2'
|
implementation "com.github.bumptech.glide:annotations:4.11.0"
|
||||||
implementation 'com.gu:option:1.3'
|
annotationProcessor "com.github.bumptech.glide:compiler:4.11.0"
|
||||||
implementation 'net.rdrei.android.dirchooser:library:3.2@aar'
|
kapt "com.github.bumptech.glide:compiler:4.11.0"
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
|
||||||
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
transitive = false
|
||||||
//implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
|
|
||||||
implementation "ru.noties.markwon:core:3.1.0"
|
|
||||||
implementation ("xyz.quaver:libpupil:1.6") {
|
|
||||||
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
|
|
||||||
}
|
}
|
||||||
|
implementation "com.tbuonomo.andrui:viewpagerdotsindicator:4.1.2"
|
||||||
|
implementation "com.gu:option:1.3"
|
||||||
|
implementation "net.rdrei.android.dirchooser:library:3.2@aar"
|
||||||
|
implementation "com.github.chrisbanes:PhotoView:2.3.0"
|
||||||
|
implementation "com.andrognito.patternlockview:patternlockview:1.0.0"
|
||||||
|
//implementation "com.andrognito.pinlockview:pinlockview:2.1.0"
|
||||||
|
implementation "ru.noties.markwon:core:3.1.0"
|
||||||
|
implementation "xyz.quaver:libpupil:1.7.2"
|
||||||
implementation "xyz.quaver:documentfilex:0.2.15"
|
implementation "xyz.quaver:documentfilex:0.2.15"
|
||||||
testImplementation 'junit:junit:4.13'
|
implementation "xyz.quaver:floatingsearchview:1.0.5"
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
testImplementation "junit:junit:4.13"
|
||||||
androidTestImplementation 'androidx.test:rules:1.3.0'
|
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
androidTestImplementation 'androidx.test:runner:1.3.0'
|
androidTestImplementation "androidx.test:rules:1.3.0"
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||||
|
androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
androidExtensions {
|
androidExtensions {
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -11,8 +11,8 @@
|
|||||||
"type": "SINGLE",
|
"type": "SINGLE",
|
||||||
"filters": [],
|
"filters": [],
|
||||||
"properties": [],
|
"properties": [],
|
||||||
"versionCode": 59,
|
"versionCode": 60,
|
||||||
"versionName": "5.0.3-hotfix1",
|
"versionName": "5.1-hotfix3",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
tools:replace="android:theme"
|
tools:replace="android:theme"
|
||||||
|
android:largeHeap="true"
|
||||||
tools:ignore="UnusedAttribute">
|
tools:ignore="UnusedAttribute">
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ package xyz.quaver.pupil.adapters
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.Log
|
|
||||||
import android.util.SparseBooleanArray
|
import android.util.SparseBooleanArray
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||||
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
||||||
@@ -49,6 +49,7 @@ import xyz.quaver.hitomi.getReader
|
|||||||
import xyz.quaver.io.util.getChild
|
import xyz.quaver.io.util.getChild
|
||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.BuildConfig
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.favoriteTags
|
||||||
import xyz.quaver.pupil.favorites
|
import xyz.quaver.pupil.favorites
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.ui.view.TagChip
|
import xyz.quaver.pupil.ui.view.TagChip
|
||||||
@@ -70,7 +71,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
|
|
||||||
val timer = Timer()
|
val timer = Timer()
|
||||||
|
|
||||||
var isThin = false
|
var thin: Boolean = Preferences["thin"]
|
||||||
|
|
||||||
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
var timerTask: TimerTask? = null
|
var timerTask: TimerTask? = null
|
||||||
@@ -88,7 +89,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
with(view.galleryblock_progressbar) {
|
with(view.galleryblock_progressbar) {
|
||||||
val imageList = cache.metadata.imageList!!
|
val imageList = cache.metadata.imageList!!
|
||||||
|
|
||||||
progress = imageList.filterNotNull().size
|
progress = imageList.count { it != null }
|
||||||
max = imageList.size
|
max = imageList.size
|
||||||
|
|
||||||
with(view.galleryblock_progressbar_layout) {
|
with(view.galleryblock_progressbar_layout) {
|
||||||
@@ -96,7 +97,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress == max) {
|
if (!imageList.contains(null)) {
|
||||||
val downloadManager = DownloadManager.getInstance(context)
|
val downloadManager = DownloadManager.getInstance(context)
|
||||||
|
|
||||||
if (completeFlag.get(galleryID, false)) {
|
if (completeFlag.get(galleryID, false)) {
|
||||||
@@ -143,7 +144,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
val artists = galleryBlock.artists
|
val artists = galleryBlock.artists
|
||||||
val series = galleryBlock.series
|
val series = galleryBlock.series
|
||||||
|
|
||||||
if (isThin)
|
if (thin)
|
||||||
galleryblock_thumbnail.layoutParams.width = context.resources.getDimensionPixelSize(
|
galleryblock_thumbnail.layoutParams.width = context.resources.getDimensionPixelSize(
|
||||||
R.dimen.galleryblock_thumbnail_thin
|
R.dimen.galleryblock_thumbnail_thin
|
||||||
)
|
)
|
||||||
@@ -223,7 +224,18 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
|
|
||||||
galleryblock_tag_group.removeAllViews()
|
galleryblock_tag_group.removeAllViews()
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
galleryBlock.relatedTags.map {
|
galleryBlock.relatedTags.sortedBy {
|
||||||
|
val tag = Tag.parse(it)
|
||||||
|
|
||||||
|
if (favoriteTags.contains(tag))
|
||||||
|
-1
|
||||||
|
else
|
||||||
|
when(Tag.parse(it).area) {
|
||||||
|
"female" -> 0
|
||||||
|
"male" -> 1
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
}.map {
|
||||||
TagChip(context, Tag.parse(it)).apply {
|
TagChip(context, Tag.parse(it)).apply {
|
||||||
setOnClickListener { view ->
|
setOnClickListener { view ->
|
||||||
for (callback in onChipClickedHandler)
|
for (callback in onChipClickedHandler)
|
||||||
@@ -273,7 +285,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
|
|
||||||
|
|
||||||
// Make some views invisible to make it thinner
|
// Make some views invisible to make it thinner
|
||||||
if (isThin) {
|
if (thin) {
|
||||||
galleryblock_language.visibility = View.GONE
|
galleryblock_language.visibility = View.GONE
|
||||||
galleryblock_type.visibility = View.GONE
|
galleryblock_type.visibility = View.GONE
|
||||||
galleryblock_tag_group.visibility = View.GONE
|
galleryblock_tag_group.visibility = View.GONE
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.app.PendingIntent
|
|||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.SparseArray
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.app.TaskStackBuilder
|
import androidx.core.app.TaskStackBuilder
|
||||||
@@ -43,13 +42,15 @@ import xyz.quaver.pupil.R
|
|||||||
import xyz.quaver.pupil.client
|
import xyz.quaver.pupil.client
|
||||||
import xyz.quaver.pupil.interceptors
|
import xyz.quaver.pupil.interceptors
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
import xyz.quaver.pupil.util.Preferences
|
|
||||||
import xyz.quaver.pupil.util.downloader.Cache
|
import xyz.quaver.pupil.util.downloader.Cache
|
||||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
import xyz.quaver.pupil.util.ellipsize
|
import xyz.quaver.pupil.util.ellipsize
|
||||||
import xyz.quaver.pupil.util.normalizeID
|
import xyz.quaver.pupil.util.normalizeID
|
||||||
import xyz.quaver.pupil.util.requestBuilders
|
import xyz.quaver.pupil.util.requestBuilders
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.log10
|
||||||
|
|
||||||
private typealias ProgressListener = (DownloadService.Tag, Long, Long, Boolean) -> Unit
|
private typealias ProgressListener = (DownloadService.Tag, Long, Long, Boolean) -> Unit
|
||||||
class DownloadService : Service() {
|
class DownloadService : Service() {
|
||||||
@@ -68,7 +69,7 @@ class DownloadService : Service() {
|
|||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val notification = SparseArray<NotificationCompat.Builder?>()
|
private val notification = ConcurrentHashMap<Int, NotificationCompat.Builder?>()
|
||||||
|
|
||||||
private fun initNotification(galleryID: Int) {
|
private fun initNotification(galleryID: Int) {
|
||||||
val intent = Intent(this, ReaderActivity::class.java)
|
val intent = Intent(this, ReaderActivity::class.java)
|
||||||
@@ -196,7 +197,7 @@ class DownloadService : Service() {
|
|||||||
* 0 <= value < 100 -> Download in progress
|
* 0 <= value < 100 -> Download in progress
|
||||||
* Float.POSITIVE_INFINITY -> Download completed
|
* Float.POSITIVE_INFINITY -> Download completed
|
||||||
*/
|
*/
|
||||||
val progress = SparseArray<MutableList<Float>?>()
|
val progress = ConcurrentHashMap<Int, MutableList<Float>>()
|
||||||
|
|
||||||
fun isCompleted(galleryID: Int) = progress[galleryID]?.toList()?.all { it == Float.POSITIVE_INFINITY } == true
|
fun isCompleted(galleryID: Int) = progress[galleryID]?.toList()?.all { it == Float.POSITIVE_INFINITY } == true
|
||||||
|
|
||||||
@@ -218,10 +219,11 @@ class DownloadService : Service() {
|
|||||||
|
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
val image = response.also { if (it.code() != 200) throw IOException() }.body()?.use { it.bytes() } ?: throw Exception()
|
val image = response.also { if (it.code() != 200) throw IOException() }.body()?.use { it.bytes() } ?: throw Exception()
|
||||||
|
val padding = ceil(progress[galleryID]?.size?.let { log10(it.toFloat()) } ?: 0F).toInt()
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
Cache.getInstance(this@DownloadService, galleryID).putImage(index, "$index.$ext", image)
|
Cache.getInstance(this@DownloadService, galleryID).putImage(index, "${index.toString().padStart(padding, '0')}.$ext", image)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
progress[galleryID]?.set(index, Float.POSITIVE_INFINITY)
|
progress[galleryID]?.set(index, Float.POSITIVE_INFINITY)
|
||||||
notify(galleryID)
|
notify(galleryID)
|
||||||
@@ -293,7 +295,7 @@ class DownloadService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun download(galleryID: Int, priority: Boolean = false, startId: Int? = null): Job = CoroutineScope(Dispatchers.IO).launch {
|
fun download(galleryID: Int, priority: Boolean = false, startId: Int? = null): Job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
if (progress.indexOfKey(galleryID) >= 0)
|
if (progress.containsKey(galleryID))
|
||||||
cancel(galleryID)
|
cancel(galleryID)
|
||||||
|
|
||||||
val cache = Cache.getInstance(this@DownloadService, galleryID)
|
val cache = Cache.getInstance(this@DownloadService, galleryID)
|
||||||
@@ -305,33 +307,13 @@ class DownloadService : Service() {
|
|||||||
// Gallery doesn't exist
|
// Gallery doesn't exist
|
||||||
if (reader == null) {
|
if (reader == null) {
|
||||||
delete(galleryID)
|
delete(galleryID)
|
||||||
progress.put(galleryID, null)
|
progress[galleryID] = mutableListOf()
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.put(galleryID, MutableList(reader.galleryInfo.files.size) { 0F })
|
progress[galleryID] = MutableList(reader.galleryInfo.files.size) { 0F }
|
||||||
|
|
||||||
FirebaseCrashlytics.getInstance().log(
|
|
||||||
"""
|
|
||||||
GALLERYID: $galleryID
|
|
||||||
CACHE: ${cache.findFile(".metadata")}
|
|
||||||
PATTERN: ${Preferences["download_folder_name", ""]}
|
|
||||||
READER ID: ${reader.galleryInfo.id}
|
|
||||||
READER SIZE: ${reader.galleryInfo.files.size}
|
|
||||||
CACHE READER ID: ${cache.metadata.reader?.galleryInfo?.id}}
|
|
||||||
CACHE READER SIZE: ${cache.metadata.reader?.galleryInfo?.files?.size}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
cache.metadata.imageList?.let {
|
cache.metadata.imageList?.let {
|
||||||
if (progress[galleryID]?.size != it.size) {
|
|
||||||
cache.metadata.imageList?.filterNotNull()?.forEach { file ->
|
|
||||||
cache.findFile(file)?.delete()
|
|
||||||
}
|
|
||||||
cache.metadata.imageList = MutableList(reader.galleryInfo.files.size) { null }
|
|
||||||
return@let
|
|
||||||
}
|
|
||||||
|
|
||||||
it.forEachIndexed { index, image ->
|
it.forEachIndexed { index, image ->
|
||||||
progress[galleryID]?.set(index, if (image != null) Float.POSITIVE_INFINITY else 0F)
|
progress[galleryID]?.set(index, if (image != null) Float.POSITIVE_INFINITY else 0F)
|
||||||
}
|
}
|
||||||
@@ -362,7 +344,7 @@ class DownloadService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reader.requestBuilders.forEachIndexed { index, it ->
|
reader.requestBuilders.forEachIndexed { index, it ->
|
||||||
if (progress[galleryID]?.get(index)?.isInfinite() != true) {
|
if (progress[galleryID]?.get(index)?.isInfinite() == false) {
|
||||||
val request = it.tag(Tag(galleryID, index, startId)).build()
|
val request = it.tag(Tag(galleryID, index, startId)).build()
|
||||||
client.newCall(request).enqueue(callback)
|
client.newCall(request).enqueue(callback)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,36 +18,28 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.types
|
package xyz.quaver.pupil.types
|
||||||
|
|
||||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
import kotlinx.android.parcel.IgnoredOnParcel
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.hitomi.Suggestion
|
import xyz.quaver.hitomi.Suggestion
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
|
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
|
||||||
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
|
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
|
||||||
|
|
||||||
override fun getBody(): String {
|
@IgnoredOnParcel
|
||||||
return s
|
override val body = s
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class Suggestion(val str: String) : SearchSuggestion {
|
class Suggestion(override val body: String) : SearchSuggestion
|
||||||
override fun getBody() = str
|
|
||||||
}
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class NoResultSuggestion(val str: String) : SearchSuggestion {
|
class NoResultSuggestion(override val body: String) : SearchSuggestion
|
||||||
override fun getBody() = str
|
|
||||||
}
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class LoadingSuggestion(val str: String) : SearchSuggestion {
|
class LoadingSuggestion(override val body: String) : SearchSuggestion
|
||||||
override fun getBody() = str
|
|
||||||
}
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Suppress("PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY")
|
@Suppress("PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY")
|
||||||
class FavoriteHistorySwitch(private val body: String) : SearchSuggestion {
|
class FavoriteHistorySwitch(override val body: String) : SearchSuggestion
|
||||||
override fun getBody() = body
|
|
||||||
}
|
|
||||||
@@ -23,6 +23,7 @@ import android.content.Intent
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.PersistableBundle
|
import android.os.PersistableBundle
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
@@ -34,6 +35,13 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private var locked: Boolean = true
|
private var locked: Boolean = true
|
||||||
|
|
||||||
|
private val lockLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK)
|
||||||
|
locked = false
|
||||||
|
else
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||||
super.onCreate(savedInstanceState, persistentState)
|
super.onCreate(savedInstanceState, persistentState)
|
||||||
@@ -53,20 +61,7 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||||
|
|
||||||
if (locked)
|
if (locked)
|
||||||
startActivityForResult(Intent(this, LockActivity::class.java), R.id.request_lock.normalizeID())
|
lockLauncher.launch(Intent(this, LockActivity::class.java))
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
when(requestCode) {
|
|
||||||
R.id.request_lock.normalizeID() -> {
|
|
||||||
if (resultCode == Activity.RESULT_OK)
|
|
||||||
locked = false
|
|
||||||
else
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -23,16 +23,15 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.view.*
|
import android.view.KeyEvent
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import com.arlib.floatingsearchview.FloatingSearchView
|
|
||||||
import com.arlib.floatingsearchview.FloatingSearchViewDayNight
|
|
||||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
|
||||||
import com.arlib.floatingsearchview.util.view.SearchInputView
|
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
@@ -41,6 +40,10 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.activity_main_content.*
|
import kotlinx.android.synthetic.main.activity_main_content.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||||
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
|
import xyz.quaver.floatingsearchview.util.view.MenuView
|
||||||
|
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
||||||
import xyz.quaver.hitomi.doSearch
|
import xyz.quaver.hitomi.doSearch
|
||||||
import xyz.quaver.hitomi.getGalleryIDsFromNozomi
|
import xyz.quaver.hitomi.getGalleryIDsFromNozomi
|
||||||
import xyz.quaver.hitomi.getSuggestionsForQuery
|
import xyz.quaver.hitomi.getSuggestionsForQuery
|
||||||
@@ -50,9 +53,12 @@ import xyz.quaver.pupil.services.DownloadService
|
|||||||
import xyz.quaver.pupil.types.*
|
import xyz.quaver.pupil.types.*
|
||||||
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialogFragment
|
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialogFragment
|
||||||
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
||||||
import xyz.quaver.pupil.util.*
|
import xyz.quaver.pupil.util.ItemClickSupport
|
||||||
|
import xyz.quaver.pupil.util.Preferences
|
||||||
|
import xyz.quaver.pupil.util.checkUpdate
|
||||||
import xyz.quaver.pupil.util.downloader.Cache
|
import xyz.quaver.pupil.util.downloader.Cache
|
||||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
|
import xyz.quaver.pupil.util.restore
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -60,7 +66,6 @@ import kotlin.math.roundToInt
|
|||||||
|
|
||||||
class MainActivity :
|
class MainActivity :
|
||||||
BaseActivity(),
|
BaseActivity(),
|
||||||
FloatingSearchView.OnMenuItemClickListener,
|
|
||||||
NavigationView.OnNavigationItemSelectedListener
|
NavigationView.OnNavigationItemSelectedListener
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -96,7 +101,6 @@ class MainActivity :
|
|||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
private var currentPage = 0
|
private var currentPage = 0
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -138,6 +142,17 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
runOnUiThread {
|
||||||
|
cancelFetch()
|
||||||
|
clearGalleries()
|
||||||
|
fetchGalleries(query, sortMode)
|
||||||
|
loadBlocks()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
||||||
@@ -181,20 +196,6 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
when(requestCode) {
|
|
||||||
R.id.request_settings.normalizeID() -> {
|
|
||||||
runOnUiThread {
|
|
||||||
cancelFetch()
|
|
||||||
clearGalleries()
|
|
||||||
fetchGalleries(query, sortMode)
|
|
||||||
loadBlocks()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
var prevP1 = 0
|
var prevP1 = 0
|
||||||
main_appbar_layout.addOnOffsetChangedListener(
|
main_appbar_layout.addOnOffsetChangedListener(
|
||||||
@@ -620,14 +621,14 @@ class MainActivity :
|
|||||||
else -> {
|
else -> {
|
||||||
searchHistory.map {
|
searchHistory.map {
|
||||||
Suggestion(it)
|
Suggestion(it)
|
||||||
}.takeLast(20) + FavoriteHistorySwitch(getString(R.string.search_show_tags))
|
}.takeLast(10) + FavoriteHistorySwitch(getString(R.string.search_show_tags))
|
||||||
}
|
}
|
||||||
}.reversed()
|
}.reversed()
|
||||||
|
|
||||||
private var suggestionJob : Job? = null
|
private var suggestionJob : Job? = null
|
||||||
private fun setupSearchBar() {
|
private fun setupSearchBar() {
|
||||||
with(main_searchview as FloatingSearchViewDayNight) {
|
with(main_searchview as xyz.quaver.pupil.ui.view.FloatingSearchView) {
|
||||||
setOnLeftMenuClickListener(object: FloatingSearchView.OnLeftMenuClickListener {
|
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
||||||
override fun onMenuOpened() {
|
override fun onMenuOpened() {
|
||||||
(this@MainActivity.main_recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
|
(this@MainActivity.main_recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
|
||||||
}
|
}
|
||||||
@@ -635,7 +636,15 @@ class MainActivity :
|
|||||||
override fun onMenuClosed() {
|
override fun onMenuClosed() {
|
||||||
//Do Nothing
|
//Do Nothing
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
findViewById<MenuView>(R.id.menu_view).menuItems.firstOrNull {
|
||||||
|
(it as MenuItem).itemId == R.id.main_menu_thin
|
||||||
|
}?.let {
|
||||||
|
(it as MenuItem).isChecked = Preferences["thin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onHistoryDeleteClickedListener = {
|
onHistoryDeleteClickedListener = {
|
||||||
searchHistory.remove(it)
|
searchHistory.remove(it)
|
||||||
@@ -646,9 +655,11 @@ class MainActivity :
|
|||||||
swapSuggestions(defaultSuggestions)
|
swapSuggestions(defaultSuggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
setOnMenuItemClickListener(this@MainActivity)
|
onMenuItemClickListener = {
|
||||||
|
onActionMenuItemSelected(it)
|
||||||
|
}
|
||||||
|
|
||||||
setOnQueryChangeListener { _, query ->
|
onQueryChangeListener = lambda@{ _, query ->
|
||||||
this@MainActivity.query = query
|
this@MainActivity.query = query
|
||||||
|
|
||||||
suggestionJob?.cancel()
|
suggestionJob?.cancel()
|
||||||
@@ -656,12 +667,14 @@ class MainActivity :
|
|||||||
if (query.isEmpty() or query.endsWith(' ')) {
|
if (query.isEmpty() or query.endsWith(' ')) {
|
||||||
swapSuggestions(defaultSuggestions)
|
swapSuggestions(defaultSuggestions)
|
||||||
|
|
||||||
return@setOnQueryChangeListener
|
return@lambda
|
||||||
}
|
}
|
||||||
|
|
||||||
swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString())))
|
swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString())))
|
||||||
|
|
||||||
val currentQuery = query.split(" ").last().replace('_', ' ')
|
val currentQuery = query.split(" ").last()
|
||||||
|
.replace(Regex("^-"), "")
|
||||||
|
.replace('_', ' ')
|
||||||
|
|
||||||
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val suggestions = kotlin.runCatching {
|
val suggestions = kotlin.runCatching {
|
||||||
@@ -682,7 +695,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOnFocusChangeListener(object: FloatingSearchView.OnFocusChangeListener {
|
onFocusChangeListener = object: FloatingSearchView.OnFocusChangeListener {
|
||||||
override fun onFocus() {
|
override fun onFocus() {
|
||||||
if (query.isEmpty() or query.endsWith(' '))
|
if (query.isEmpty() or query.endsWith(' '))
|
||||||
swapSuggestions(defaultSuggestions)
|
swapSuggestions(defaultSuggestions)
|
||||||
@@ -699,19 +712,24 @@ class MainActivity :
|
|||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
attachNavigationDrawerToMenuButton(main_drawer_layout)
|
attachNavigationDrawerToMenuButton(main_drawer_layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActionMenuItemSelected(item: MenuItem?) {
|
fun onActionMenuItemSelected(item: MenuItem?) {
|
||||||
when(item?.itemId) {
|
when(item?.itemId) {
|
||||||
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), R.id.request_settings.normalizeID())
|
R.id.main_menu_settings -> startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
|
||||||
R.id.main_menu_thin -> {
|
R.id.main_menu_thin -> {
|
||||||
|
val thin = !item.isChecked
|
||||||
|
|
||||||
|
item.isChecked = thin
|
||||||
main_recyclerview.apply {
|
main_recyclerview.apply {
|
||||||
(adapter as GalleryBlockAdapter).apply {
|
(adapter as GalleryBlockAdapter).apply {
|
||||||
isThin = !isThin
|
this.thin = thin
|
||||||
|
|
||||||
|
Preferences["thin"] = thin
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter = adapter // Force to redraw
|
adapter = adapter // Force to redraw
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ class ReaderActivity : BaseActivity() {
|
|||||||
var downloader: DownloadService? = null
|
var downloader: DownloadService? = null
|
||||||
private val conn = object: ServiceConnection {
|
private val conn = object: ServiceConnection {
|
||||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
downloader = (service as DownloadService.Binder).service
|
downloader = (service as DownloadService.Binder).service.also {
|
||||||
|
if (!it.progress.containsKey(galleryID))
|
||||||
|
DownloadService.download(this@ReaderActivity, galleryID, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
@@ -118,7 +121,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
|
|
||||||
private var cameraEnabled = false
|
private var cameraEnabled = false
|
||||||
private var eyeType: Eye? = null
|
private var eyeType: Eye? = null
|
||||||
private var eyeCount: Int = 0
|
|
||||||
private var eyeTime: Long = 0L
|
private var eyeTime: Long = 0L
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -167,7 +169,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
initDownloader()
|
initDownloadListener()
|
||||||
|
|
||||||
initView()
|
initView()
|
||||||
}
|
}
|
||||||
@@ -248,6 +250,8 @@ class ReaderActivity : BaseActivity() {
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
|
bindService(Intent(this, DownloadService::class.java), conn, BIND_AUTO_CREATE)
|
||||||
|
|
||||||
if (cameraEnabled)
|
if (cameraEnabled)
|
||||||
startCamera(this, cameraCallback)
|
startCamera(this, cameraCallback)
|
||||||
}
|
}
|
||||||
@@ -255,6 +259,12 @@ class ReaderActivity : BaseActivity() {
|
|||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
closeCamera()
|
closeCamera()
|
||||||
|
|
||||||
|
if (downloader != null)
|
||||||
|
unbindService(conn)
|
||||||
|
|
||||||
|
if (!DownloadManager.getInstance(this).isDownloading(galleryID))
|
||||||
|
DownloadService.cancel(this, galleryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
@@ -262,12 +272,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
|
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
(reader_recyclerview?.adapter as? ReaderAdapter)?.timer?.cancel()
|
(reader_recyclerview?.adapter as? ReaderAdapter)?.timer?.cancel()
|
||||||
|
|
||||||
if (!DownloadManager.getInstance(this).isDownloading(galleryID))
|
|
||||||
DownloadService.cancel(this, galleryID)
|
|
||||||
|
|
||||||
if (downloader != null)
|
|
||||||
unbindService(conn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
@@ -302,17 +306,14 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initDownloader() {
|
private fun initDownloadListener() {
|
||||||
DownloadService.download(this, galleryID, true)
|
|
||||||
bindService(Intent(this, DownloadService::class.java), conn, BIND_AUTO_CREATE)
|
|
||||||
|
|
||||||
timer.schedule(1000, 1000) {
|
timer.schedule(1000, 1000) {
|
||||||
val downloader = downloader ?: return@schedule
|
val downloader = downloader ?: return@schedule
|
||||||
|
|
||||||
if (downloader.progress.indexOfKey(galleryID) < 0) //loading
|
if (!downloader.progress.containsKey(galleryID)) //loading
|
||||||
return@schedule
|
return@schedule
|
||||||
|
|
||||||
if (downloader.progress[galleryID] == null) { //Gallery not found
|
if (downloader.progress[galleryID]?.isEmpty() == true) { //Gallery not found
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
Snackbar
|
Snackbar
|
||||||
.make(reader_layout, R.string.reader_failed_to_find_gallery, Snackbar.LENGTH_INDEFINITE)
|
.make(reader_layout, R.string.reader_failed_to_find_gallery, Snackbar.LENGTH_INDEFINITE)
|
||||||
@@ -564,28 +565,23 @@ class ReaderActivity : BaseActivity() {
|
|||||||
// Both closed / opened
|
// Both closed / opened
|
||||||
!left.xor(right) -> {
|
!left.xor(right) -> {
|
||||||
eyeType = null
|
eyeType = null
|
||||||
eyeCount = 0
|
|
||||||
eyeTime = 0L
|
eyeTime = 0L
|
||||||
}
|
}
|
||||||
!left -> {
|
!left -> {
|
||||||
if (eyeType != Eye.LEFT) {
|
if (eyeType != Eye.LEFT) {
|
||||||
eyeType = Eye.LEFT
|
eyeType = Eye.LEFT
|
||||||
eyeCount = 0
|
|
||||||
eyeTime = System.currentTimeMillis()
|
eyeTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
eyeCount++
|
|
||||||
}
|
}
|
||||||
!right -> {
|
!right -> {
|
||||||
if (eyeType != Eye.RIGHT) {
|
if (eyeType != Eye.RIGHT) {
|
||||||
eyeType = Eye.RIGHT
|
eyeType = Eye.RIGHT
|
||||||
eyeCount = 0
|
|
||||||
eyeTime = System.currentTimeMillis()
|
eyeTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
eyeCount++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eyeCount > 3 && System.currentTimeMillis() - eyeTime > 500) {
|
if (eyeType != null && System.currentTimeMillis() - eyeTime > 100) {
|
||||||
(this@ReaderActivity.reader_recyclerview.layoutManager as LinearLayoutManager).let {
|
(this@ReaderActivity.reader_recyclerview.layoutManager as LinearLayoutManager).let {
|
||||||
it.scrollToPositionWithOffset(when(eyeType!!) {
|
it.scrollToPositionWithOffset(when(eyeType!!) {
|
||||||
Eye.RIGHT -> {
|
Eye.RIGHT -> {
|
||||||
@@ -597,9 +593,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
eyeType = null
|
eyeTime = System.currentTimeMillis() + 500
|
||||||
eyeCount = 0
|
|
||||||
eyeTime = 0L
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,24 +18,10 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui
|
package xyz.quaver.pupil.ui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.favorites
|
|
||||||
import xyz.quaver.pupil.ui.fragment.LockSettingsFragment
|
|
||||||
import xyz.quaver.pupil.ui.fragment.SettingsFragment
|
import xyz.quaver.pupil.ui.fragment.SettingsFragment
|
||||||
import xyz.quaver.pupil.util.Preferences
|
|
||||||
import xyz.quaver.pupil.util.normalizeID
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
class SettingsActivity : BaseActivity() {
|
class SettingsActivity : BaseActivity() {
|
||||||
|
|
||||||
@@ -56,19 +42,4 @@ class SettingsActivity : BaseActivity() {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
||||||
when (requestCode) {
|
|
||||||
R.id.request_write_permission_and_saf.normalizeID() -> {
|
|
||||||
if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
|
|
||||||
putExtra("android.content.extra.SHOW_ADVANCED", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
startActivityForResult(intent, R.id.request_download_folder.normalizeID())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ class DownloadFolderNameDialogFragment : DialogFragment() {
|
|||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
private fun build(): View {
|
private fun build(): View {
|
||||||
val galleryID = Cache.instances.let { if (it.size() == 0) 1199708 else it.keyAt((0 until it.size()).random()) }
|
val galleryID = Cache.instances.let { if (it.size == 0) 1199708 else it.keys.elementAt((0 until it.size).random()) }
|
||||||
val galleryBlock = runBlocking {
|
val galleryBlock = runBlocking {
|
||||||
Cache.getInstance(requireContext(), galleryID).getGalleryBlock()
|
Cache.getInstance(requireContext(), galleryID).getGalleryBlock()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,26 +26,87 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import kotlinx.android.synthetic.main.dialog_download_folder_name.view.*
|
||||||
import kotlinx.android.synthetic.main.item_download_folder.view.*
|
import kotlinx.android.synthetic.main.item_download_folder.view.*
|
||||||
import net.rdrei.android.dirchooser.DirectoryChooserActivity
|
import net.rdrei.android.dirchooser.DirectoryChooserActivity
|
||||||
import net.rdrei.android.dirchooser.DirectoryChooserConfig
|
import net.rdrei.android.dirchooser.DirectoryChooserConfig
|
||||||
import xyz.quaver.io.FileX
|
import xyz.quaver.io.FileX
|
||||||
|
import xyz.quaver.io.util.toFile
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
import xyz.quaver.pupil.util.byteToString
|
import xyz.quaver.pupil.util.byteToString
|
||||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
import xyz.quaver.pupil.util.migrate
|
import xyz.quaver.pupil.util.migrate
|
||||||
import xyz.quaver.pupil.util.normalizeID
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class DownloadLocationDialogFragment : DialogFragment() {
|
class DownloadLocationDialogFragment : DialogFragment() {
|
||||||
private val entries = mutableMapOf<File?, View>()
|
private val entries = mutableMapOf<File?, View>()
|
||||||
|
|
||||||
|
private val requestDownloadFolderLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
|
val activity = activity ?: return@registerForActivityResult
|
||||||
|
val context = context ?: return@registerForActivityResult
|
||||||
|
val dialog = dialog ?: return@registerForActivityResult
|
||||||
|
|
||||||
|
it.data?.data?.also { uri ->
|
||||||
|
val takeFlags: Int =
|
||||||
|
activity.intent.flags and
|
||||||
|
(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||||
|
context.contentResolver.takePersistableUriPermission(uri, takeFlags)
|
||||||
|
|
||||||
|
if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) {
|
||||||
|
entries[null]?.location_available?.text = uri.toFile(context)?.canonicalPath
|
||||||
|
Preferences["download_folder"] = uri.toString()
|
||||||
|
} else {
|
||||||
|
Snackbar.make(
|
||||||
|
dialog.window!!.decorView.rootView,
|
||||||
|
R.string.settings_download_folder_not_writable,
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
|
||||||
|
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
||||||
|
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||||
|
entries[key]!!.button.isChecked = true
|
||||||
|
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val requestDownloadFolderOldLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
val context = context ?: return@registerForActivityResult
|
||||||
|
val dialog = dialog ?: return@registerForActivityResult
|
||||||
|
|
||||||
|
if (it.resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
|
||||||
|
val directory = it.data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!!
|
||||||
|
|
||||||
|
if (!File(directory).canWrite()) {
|
||||||
|
Snackbar.make(
|
||||||
|
dialog.window!!.decorView.rootView,
|
||||||
|
R.string.settings_download_folder_not_writable,
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
|
||||||
|
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
||||||
|
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||||
|
entries[key]!!.button.isChecked = true
|
||||||
|
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entries[null]?.location_available?.text = directory
|
||||||
|
Preferences["download_folder"] = File(directory).toURI().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
private fun build() : View? {
|
private fun build() : View? {
|
||||||
val context = context ?: return null
|
val context = context ?: return null
|
||||||
@@ -90,7 +151,7 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
|||||||
putExtra("android.content.extra.SHOW_ADVANCED", true)
|
putExtra("android.content.extra.SHOW_ADVANCED", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
startActivityForResult(intent, R.id.request_download_folder.normalizeID())
|
requestDownloadFolderLauncher.launch(intent)
|
||||||
} else { // Can't use SAF on old Androids!
|
} else { // Can't use SAF on old Androids!
|
||||||
val config = DirectoryChooserConfig.builder()
|
val config = DirectoryChooserConfig.builder()
|
||||||
.newDirectoryName("Pupil")
|
.newDirectoryName("Pupil")
|
||||||
@@ -101,7 +162,7 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
|||||||
putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config)
|
putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
startActivityForResult(intent, R.id.request_download_folder_old.normalizeID())
|
requestDownloadFolderOldLauncher.launch(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries[null] = this
|
entries[null] = this
|
||||||
@@ -132,65 +193,4 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
|||||||
|
|
||||||
return builder.create()
|
return builder.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
when (requestCode) {
|
|
||||||
R.id.request_download_folder.normalizeID() -> {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
val activity = activity ?: return
|
|
||||||
val context = context ?: return
|
|
||||||
val dialog = dialog ?: return
|
|
||||||
|
|
||||||
data?.data?.also { uri ->
|
|
||||||
val takeFlags: Int =
|
|
||||||
activity.intent.flags and
|
|
||||||
(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
|
||||||
context.contentResolver.takePersistableUriPermission(uri, takeFlags)
|
|
||||||
|
|
||||||
if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false))
|
|
||||||
Preferences["download_folder"] = uri.toString()
|
|
||||||
else {
|
|
||||||
Snackbar.make(
|
|
||||||
dialog.window!!.decorView.rootView,
|
|
||||||
R.string.settings_download_folder_not_writable,
|
|
||||||
Snackbar.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
|
|
||||||
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
|
||||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
|
||||||
entries[key]!!.button.isChecked = true
|
|
||||||
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
R.id.request_download_folder_old.normalizeID() -> {
|
|
||||||
val context = context ?: return
|
|
||||||
val dialog = dialog ?: return
|
|
||||||
|
|
||||||
if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
|
|
||||||
val directory = data?.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR)!!
|
|
||||||
|
|
||||||
if (!File(directory).canWrite()) {
|
|
||||||
Snackbar.make(
|
|
||||||
dialog.window!!.decorView.rootView,
|
|
||||||
R.string.settings_download_folder_not_writable,
|
|
||||||
Snackbar.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
|
|
||||||
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
|
||||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
|
||||||
entries[key]!!.button.isChecked = true
|
|
||||||
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Preferences["download_folder"] = File(directory).toURI().toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,7 @@ import xyz.quaver.pupil.BuildConfig
|
|||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||||
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
|
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
|
||||||
|
import xyz.quaver.pupil.favoriteTags
|
||||||
import xyz.quaver.pupil.histories
|
import xyz.quaver.pupil.histories
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
@@ -141,7 +142,18 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
|
|||||||
listOf(gallery.language).map { Tag("language", it) },
|
listOf(gallery.language).map { Tag("language", it) },
|
||||||
gallery.series.map { Tag("series", it) },
|
gallery.series.map { Tag("series", it) },
|
||||||
gallery.characters.map { Tag("character", it) },
|
gallery.characters.map { Tag("character", it) },
|
||||||
gallery.tags.map {
|
gallery.tags.sortedBy {
|
||||||
|
val tag = Tag.parse(it)
|
||||||
|
|
||||||
|
if (favoriteTags.contains(tag))
|
||||||
|
-1
|
||||||
|
else
|
||||||
|
when(Tag.parse(it).area) {
|
||||||
|
"female" -> 0
|
||||||
|
"male" -> 1
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
}.map {
|
||||||
Tag.parse(it).let { tag ->
|
Tag.parse(it).let { tag ->
|
||||||
when {
|
when {
|
||||||
tag.area != null -> tag
|
tag.area != null -> tag
|
||||||
|
|||||||
@@ -22,25 +22,21 @@ import android.app.Activity
|
|||||||
import android.content.*
|
import android.content.*
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceCategory
|
import androidx.preference.PreferenceCategory
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import xyz.quaver.io.FileX
|
import xyz.quaver.io.FileX
|
||||||
import xyz.quaver.io.util.getChild
|
import xyz.quaver.io.util.getChild
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.favorites
|
|
||||||
import xyz.quaver.pupil.ui.LockActivity
|
import xyz.quaver.pupil.ui.LockActivity
|
||||||
import xyz.quaver.pupil.ui.SettingsActivity
|
import xyz.quaver.pupil.ui.SettingsActivity
|
||||||
import xyz.quaver.pupil.ui.dialog.*
|
import xyz.quaver.pupil.ui.dialog.*
|
||||||
import xyz.quaver.pupil.util.*
|
import xyz.quaver.pupil.util.*
|
||||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
class SettingsFragment :
|
class SettingsFragment :
|
||||||
PreferenceFragmentCompat(),
|
PreferenceFragmentCompat(),
|
||||||
@@ -48,6 +44,16 @@ class SettingsFragment :
|
|||||||
Preference.OnPreferenceChangeListener,
|
Preference.OnPreferenceChangeListener,
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
private val lockLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
|
parentFragmentManager
|
||||||
|
.beginTransaction()
|
||||||
|
.replace(R.id.settings, LockSettingsFragment())
|
||||||
|
.addToBackStack("Lock")
|
||||||
|
.commitAllowingStateLoss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
@@ -89,7 +95,7 @@ class SettingsFragment :
|
|||||||
val intent = Intent(requireContext(), LockActivity::class.java).apply {
|
val intent = Intent(requireContext(), LockActivity::class.java).apply {
|
||||||
putExtra("force", true)
|
putExtra("force", true)
|
||||||
}
|
}
|
||||||
startActivityForResult(intent, R.id.request_lock.normalizeID())
|
lockLauncher.launch(intent)
|
||||||
}
|
}
|
||||||
"mirrors" -> {
|
"mirrors" -> {
|
||||||
MirrorDialog(requireContext())
|
MirrorDialog(requireContext())
|
||||||
@@ -267,19 +273,4 @@ class SettingsFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
when(requestCode) {
|
|
||||||
R.id.request_lock.normalizeID() -> {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
parentFragmentManager
|
|
||||||
.beginTransaction()
|
|
||||||
.replace(R.id.settings, LockSettingsFragment())
|
|
||||||
.addToBackStack("Lock")
|
|
||||||
.commitAllowingStateLoss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.arlib.floatingsearchview
|
package xyz.quaver.pupil.ui.view
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
@@ -36,21 +36,21 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
import com.arlib.floatingsearchview.suggestions.SearchSuggestionsAdapter
|
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import com.arlib.floatingsearchview.util.view.SearchInputView
|
import xyz.quaver.floatingsearchview.util.MenuPopupHelper
|
||||||
|
import xyz.quaver.floatingsearchview.util.view.MenuView
|
||||||
|
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.favoriteTags
|
import xyz.quaver.pupil.favoriteTags
|
||||||
import xyz.quaver.pupil.types.*
|
import xyz.quaver.pupil.types.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
FloatingSearchView(context, attrs),
|
FloatingSearchView(context, attrs),
|
||||||
FloatingSearchView.OnSearchListener,
|
FloatingSearchView.OnSearchListener,
|
||||||
SearchSuggestionsAdapter.OnBindSuggestionCallback,
|
|
||||||
TextWatcher
|
TextWatcher
|
||||||
{
|
{
|
||||||
|
|
||||||
private val searchInputView = findViewById<SearchInputView>(R.id.search_bar_text)
|
private val searchInputView = findViewById<SearchInputView>(R.id.search_bar_text)
|
||||||
|
|
||||||
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
|
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
|
||||||
@@ -60,8 +60,10 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
|
|||||||
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
||||||
|
|
||||||
searchInputView.addTextChangedListener(this)
|
searchInputView.addTextChangedListener(this)
|
||||||
setOnSearchListener(this)
|
onSearchListener = this
|
||||||
setOnBindSuggestionCallback(this)
|
onBindSuggestionCallback = { a, b, c, d, e ->
|
||||||
|
onBindSuggestion(a, b, c, d, e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||||
@@ -82,15 +84,18 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
|
|||||||
override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) {
|
override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) {
|
||||||
when (searchSuggestion) {
|
when (searchSuggestion) {
|
||||||
is TagSuggestion -> {
|
is TagSuggestion -> {
|
||||||
with(searchInputView.text) {
|
val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}"
|
||||||
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ')+1, length)
|
with(searchInputView.text!!) {
|
||||||
append("${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")} ")
|
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length)
|
||||||
|
|
||||||
|
if (!this.contains(tag))
|
||||||
|
append("$tag ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Suggestion -> {
|
is Suggestion -> {
|
||||||
with(searchInputView.text) {
|
with(searchInputView.text!!) {
|
||||||
clear()
|
clear()
|
||||||
append(searchSuggestion.str)
|
append(searchSuggestion.body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FavoriteHistorySwitch -> onFavoriteHistorySwitchClickListener?.invoke()
|
is FavoriteHistorySwitch -> onFavoriteHistorySwitchClickListener?.invoke()
|
||||||
@@ -99,14 +104,14 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
|
|||||||
|
|
||||||
override fun onSearchAction(currentQuery: String?) {}
|
override fun onSearchAction(currentQuery: String?) {}
|
||||||
|
|
||||||
override fun onBindSuggestion(
|
fun onBindSuggestion(
|
||||||
suggestionView: View?,
|
suggestionView: View?,
|
||||||
leftIcon: ImageView?,
|
leftIcon: ImageView?,
|
||||||
textView: TextView?,
|
textView: TextView?,
|
||||||
item: SearchSuggestion?,
|
item: SearchSuggestion?,
|
||||||
itemPosition: Int
|
itemPosition: Int
|
||||||
) {
|
) {
|
||||||
when(item) {
|
when(item) {
|
||||||
is TagSuggestion -> {
|
is TagSuggestion -> {
|
||||||
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
||||||
|
|
||||||
@@ -196,7 +201,7 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
|
|||||||
isClickable = true
|
isClickable = true
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
onHistoryDeleteClickedListener?.invoke(item.str)
|
onHistoryDeleteClickedListener?.invoke(item.body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,10 +217,4 @@ class FloatingSearchViewDayNight @JvmOverloads constructor(context: Context, att
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hack to remove color attributes which should not be reused
|
|
||||||
override fun onSaveInstanceState(): Parcelable? {
|
|
||||||
super.onSaveInstanceState()
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -23,17 +23,18 @@ import android.content.Context
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.favoriteTags
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.util.wordCapitalize
|
import xyz.quaver.pupil.util.wordCapitalize
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class TagChip(context: Context, tag: Tag) : Chip(context) {
|
class TagChip(context: Context, _tag: Tag) : Chip(context) {
|
||||||
|
|
||||||
val tag: Tag =
|
val tag: Tag =
|
||||||
tag.let {
|
_tag.let {
|
||||||
when {
|
when {
|
||||||
it.area != null -> it
|
it.area != null -> it
|
||||||
else -> Tag("tag", tag.tag)
|
else -> Tag("tag", _tag.tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,18 +45,47 @@ class TagChip(context: Context, tag: Tag) : Chip(context) {
|
|||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
chipIcon = when(tag.area) {
|
when(tag.area) {
|
||||||
"male" -> {
|
"male" -> {
|
||||||
setChipBackgroundColorResource(R.color.material_blue_700)
|
setChipBackgroundColorResource(R.color.material_blue_700)
|
||||||
setTextColor(ContextCompat.getColor(context, android.R.color.white))
|
setTextColor(ContextCompat.getColor(context, android.R.color.white))
|
||||||
ContextCompat.getDrawable(context, R.drawable.gender_male_white)
|
setCloseIconTintResource(android.R.color.white)
|
||||||
|
chipIcon = ContextCompat.getDrawable(context, R.drawable.gender_male_white)
|
||||||
}
|
}
|
||||||
"female" -> {
|
"female" -> {
|
||||||
setChipBackgroundColorResource(R.color.material_pink_600)
|
setChipBackgroundColorResource(R.color.material_pink_600)
|
||||||
setTextColor(ContextCompat.getColor(context, android.R.color.white))
|
setTextColor(ContextCompat.getColor(context, android.R.color.white))
|
||||||
ContextCompat.getDrawable(context, R.drawable.gender_female_white)
|
setCloseIconTintResource(android.R.color.white)
|
||||||
|
chipIcon = ContextCompat.getDrawable(context, R.drawable.gender_female_white)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (favoriteTags.contains(tag))
|
||||||
|
setChipBackgroundColorResource(R.color.material_orange_500)
|
||||||
|
|
||||||
|
isCloseIconVisible = true
|
||||||
|
closeIcon = ContextCompat.getDrawable(context,
|
||||||
|
if (favoriteTags.contains(tag))
|
||||||
|
R.drawable.ic_star_filled
|
||||||
|
else
|
||||||
|
R.drawable.ic_star_empty
|
||||||
|
)
|
||||||
|
|
||||||
|
setOnCloseIconClickListener {
|
||||||
|
if (favoriteTags.contains(tag)) {
|
||||||
|
favoriteTags.remove(tag)
|
||||||
|
closeIcon = ContextCompat.getDrawable(context, R.drawable.ic_star_empty)
|
||||||
|
|
||||||
|
when(tag.area) {
|
||||||
|
"male" -> setChipBackgroundColorResource(R.color.material_blue_700)
|
||||||
|
"female" -> setChipBackgroundColorResource(R.color.material_pink_600)
|
||||||
|
else -> chipBackgroundColor = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
favoriteTags.add(tag)
|
||||||
|
closeIcon = ContextCompat.getDrawable(context, R.drawable.ic_star_filled)
|
||||||
|
setChipBackgroundColorResource(R.color.material_orange_500)
|
||||||
}
|
}
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text = when (tag.area) {
|
text = when (tag.area) {
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
|||||||
override fun add(element: T): Boolean {
|
override fun add(element: T): Boolean {
|
||||||
load()
|
load()
|
||||||
|
|
||||||
|
set.remove(element)
|
||||||
|
|
||||||
return set.add(element).also {
|
return set.add(element).also {
|
||||||
save()
|
save()
|
||||||
}
|
}
|
||||||
@@ -67,6 +69,8 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
|||||||
override fun addAll(elements: Collection<T>): Boolean {
|
override fun addAll(elements: Collection<T>): Boolean {
|
||||||
load()
|
load()
|
||||||
|
|
||||||
|
set.removeAll(elements)
|
||||||
|
|
||||||
return set.addAll(elements).also {
|
return set.addAll(elements).also {
|
||||||
save()
|
save()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ package xyz.quaver.pupil.util.downloader
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.util.SparseArray
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -38,6 +37,7 @@ import xyz.quaver.io.util.*
|
|||||||
import xyz.quaver.pupil.client
|
import xyz.quaver.pupil.client
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Metadata(
|
data class Metadata(
|
||||||
@@ -51,7 +51,7 @@ data class Metadata(
|
|||||||
class Cache private constructor(context: Context, val galleryID: Int) : ContextWrapper(context) {
|
class Cache private constructor(context: Context, val galleryID: Int) : ContextWrapper(context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val instances = SparseArray<Cache>()
|
val instances = ConcurrentHashMap<Int, Cache>()
|
||||||
|
|
||||||
fun getInstance(context: Context, galleryID: Int) =
|
fun getInstance(context: Context, galleryID: Int) =
|
||||||
instances[galleryID] ?: synchronized(this) {
|
instances[galleryID] ?: synchronized(this) {
|
||||||
@@ -61,7 +61,7 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
|||||||
@Synchronized
|
@Synchronized
|
||||||
fun delete(galleryID: Int) {
|
fun delete(galleryID: Int) {
|
||||||
instances[galleryID]?.cacheFolder?.deleteRecursively()
|
instances[galleryID]?.cacheFolder?.deleteRecursively()
|
||||||
instances.delete(galleryID)
|
instances.remove(galleryID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,9 +200,36 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
|||||||
fun moveToDownload() = CoroutineScope(Dispatchers.IO).launch {
|
fun moveToDownload() = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val downloadFolder = downloadFolder ?: return@launch
|
val downloadFolder = downloadFolder ?: return@launch
|
||||||
|
|
||||||
if (downloadFolder.getChild(".metadata").exists())
|
val cacheMetadata = cacheFolder.getChild(".metadata")
|
||||||
|
val downloadMetadata = downloadFolder.getChild(".metadata")
|
||||||
|
|
||||||
|
if (downloadMetadata.exists() || !cacheMetadata.exists())
|
||||||
return@launch
|
return@launch
|
||||||
|
|
||||||
|
if (cacheMetadata.exists()) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
downloadMetadata.createNewFile()
|
||||||
|
downloadMetadata.writeText(Json.encodeToString(metadata))
|
||||||
|
|
||||||
|
cacheMetadata.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val cacheThumbnail = cacheFolder.getChild(".thumbnail")
|
||||||
|
val downloadThumbnail = downloadFolder.getChild(".thumbnail")
|
||||||
|
|
||||||
|
if (cacheThumbnail.exists() && !downloadThumbnail.exists()) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
if (!downloadThumbnail.exists())
|
||||||
|
downloadThumbnail.createNewFile()
|
||||||
|
|
||||||
|
downloadThumbnail.outputStream()?.use { target -> cacheThumbnail.inputStream()?.use { source ->
|
||||||
|
source.copyTo(target)
|
||||||
|
} }
|
||||||
|
cacheThumbnail.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
metadata.imageList?.forEach { imageName ->
|
metadata.imageList?.forEach { imageName ->
|
||||||
imageName ?: return@forEach
|
imageName ?: return@forEach
|
||||||
val target = downloadFolder.getChild(imageName)
|
val target = downloadFolder.getChild(imageName)
|
||||||
@@ -212,37 +239,13 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
|||||||
return@forEach
|
return@forEach
|
||||||
|
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
target.createNewFile()
|
if (!target.exists())
|
||||||
|
target.createNewFile()
|
||||||
|
|
||||||
target.outputStream()?.use { target -> source.inputStream()?.use { source ->
|
target.outputStream()?.use { target -> source.inputStream()?.use { source ->
|
||||||
source.copyTo(target)
|
source.copyTo(target)
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val cacheThumbnail = cacheFolder.getChild(".thumbnail")
|
|
||||||
val downloadThumbnail = downloadFolder.getChild(".thumbnail")
|
|
||||||
|
|
||||||
if (cacheThumbnail.exists() && !downloadThumbnail.exists()) {
|
|
||||||
kotlin.runCatching {
|
|
||||||
downloadThumbnail.createNewFile()
|
|
||||||
downloadThumbnail.outputStream()?.use { target -> cacheThumbnail.inputStream()?.use { source ->
|
|
||||||
source.copyTo(target)
|
|
||||||
} }
|
|
||||||
cacheThumbnail.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val cacheMetadata = cacheFolder.getChild(".metadata")
|
|
||||||
val downloadMetadata = downloadFolder.getChild(".metadata")
|
|
||||||
|
|
||||||
if (cacheMetadata.exists() && !downloadMetadata.exists()) {
|
|
||||||
kotlin.runCatching {
|
|
||||||
downloadMetadata.createNewFile()
|
|
||||||
downloadMetadata.writeText(Json.encodeToString(metadata))
|
|
||||||
cacheMetadata.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheFolder.delete()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,13 +27,11 @@ import android.content.Intent
|
|||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@@ -52,7 +50,9 @@ import xyz.quaver.hitomi.getGalleryBlock
|
|||||||
import xyz.quaver.hitomi.getReader
|
import xyz.quaver.hitomi.getReader
|
||||||
import xyz.quaver.io.FileX
|
import xyz.quaver.io.FileX
|
||||||
import xyz.quaver.io.util.getChild
|
import xyz.quaver.io.util.getChild
|
||||||
import xyz.quaver.io.util.*
|
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.BuildConfig
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.client
|
import xyz.quaver.pupil.client
|
||||||
@@ -160,7 +160,6 @@ fun checkUpdate(context: Context, force: Boolean = false) {
|
|||||||
val msg = extractReleaseNote(update, Locale.getDefault())
|
val msg = extractReleaseNote(update, Locale.getDefault())
|
||||||
setMessage(Markwon.create(context).toMarkdown(msg))
|
setMessage(Markwon.create(context).toMarkdown(msg))
|
||||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
|
||||||
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
|
||||||
//Cancel any download queued before
|
//Cancel any download queued before
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
|
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<stroke android:width="1dp" android:color="#555555"/>
|
<stroke android:width="1dp" android:color="#555555"/>
|
||||||
<solid android:color="@color/transparent"/>
|
<solid android:color="@android:color/transparent"/>
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|||||||
8
app/src/main/res/drawable/sort_variant.xml
Normal file
8
app/src/main/res/drawable/sort_variant.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!-- drawable/sort_variant.xml -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#000" android:pathData="M3,13H15V11H3M3,6V8H21V6M3,18H9V16H3V18Z" />
|
||||||
|
</vector>
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Pupil, Hitomi.la viewer for Android
|
|
||||||
~ Copyright (C) 2019 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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".ui.MainActivity">
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/main_appbar_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/transparent"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:visibility="invisible"
|
|
||||||
android:background="@color/transparent"
|
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<androidx.core.widget.ContentLoadingProgressBar
|
|
||||||
style="?android:attr/progressBarStyle"
|
|
||||||
android:id="@+id/main_progressbar"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:indeterminate="true"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/main_noresult"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="@string/main_no_result"
|
|
||||||
android:visibility="invisible"/>
|
|
||||||
|
|
||||||
<com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:handleDrawable="@drawable/thumb"
|
|
||||||
app:handleHasFixedSize="true"
|
|
||||||
app:handleHeight="72dp"
|
|
||||||
app:handleWidth="24dp"
|
|
||||||
app:disableTrack="true"
|
|
||||||
app:hideHandleAfter="1000"
|
|
||||||
app:trackMarginStart="64dp"
|
|
||||||
app:addLastItemPadding="true"
|
|
||||||
app:popupDrawable="@color/transparent">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/main_recyclerview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:paddingTop="64dp"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
|
||||||
|
|
||||||
</com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller>
|
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionMenu
|
|
||||||
android:id="@+id/main_fab"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
app:menu_colorNormal="@color/colorAccent">
|
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
|
||||||
android:id="@+id/main_fab_cancel"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fab_label="@string/main_fab_cancel"
|
|
||||||
app:fab_size="mini"/>
|
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
|
||||||
android:id="@+id/main_fab_jump"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fab_label="@string/main_jump_title"
|
|
||||||
app:fab_size="mini"/>
|
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
|
||||||
android:id="@+id/main_fab_random"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fab_label="@string/main_fab_random"
|
|
||||||
app:fab_size="mini"/>
|
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
|
||||||
android:id="@+id/main_fab_id"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fab_label="@string/main_open_gallery_by_id"
|
|
||||||
app:fab_size="mini"/>
|
|
||||||
|
|
||||||
</com.github.clans.fab.FloatingActionMenu>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
<com.arlib.floatingsearchview.FloatingSearchViewDayNight
|
|
||||||
android:id="@+id/main_searchview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:floatingSearch_backgroundColor="?android:attr/colorBackgroundFloating"
|
|
||||||
app:floatingSearch_leftActionColor="?attr/colorControlNormal"
|
|
||||||
app:floatingSearch_menuItemIconColor="?attr/colorControlNormal"
|
|
||||||
app:floatingSearch_actionMenuOverflowColor="?attr/colorControlNormal"
|
|
||||||
app:floatingSearch_clearBtnColor="?attr/colorControlNormal"
|
|
||||||
app:floatingSearch_viewTextColor="?android:attr/textColorPrimary"
|
|
||||||
app:floatingSearch_suggestionRightIconColor="@color/material_orange_500"
|
|
||||||
app:floatingSearch_searchBarMarginLeft="8dp"
|
|
||||||
app:floatingSearch_searchBarMarginRight="8dp"
|
|
||||||
app:floatingSearch_searchBarMarginTop="8dp"
|
|
||||||
app:floatingSearch_searchHint="@string/search_hint"
|
|
||||||
app:floatingSearch_suggestionsListAnimDuration="250"
|
|
||||||
app:floatingSearch_showSearchKey="true"
|
|
||||||
app:floatingSearch_leftActionMode="showHamburger"
|
|
||||||
app:floatingSearch_menu="@menu/main"
|
|
||||||
app:floatingSearch_dismissOnOutsideTouch="true"
|
|
||||||
app:floatingSearch_close_search_on_keyboard_dismiss="true"
|
|
||||||
tools:ignore="NewApi" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
~ Pupil, Hitomi.la viewer for Android
|
~ Pupil, Hitomi.la viewer for Android
|
||||||
~ Copyright (C) 2019 tom5079
|
~ Copyright (C) 2020 tom5079
|
||||||
~
|
~
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
~ 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
|
~ it under the terms of the GNU General Public License as published by
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
android:id="@+id/main_appbar_layout"
|
android:id="@+id/main_appbar_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent">
|
app:layout_constraintLeft_toLeftOf="parent">
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="64dp"
|
android:layout_height="64dp"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
android:background="@color/transparent"
|
android:background="@android:color/transparent"
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
app:layout_scrollFlags="scroll|enterAlways"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
app:hideHandleAfter="1000"
|
app:hideHandleAfter="1000"
|
||||||
app:trackMarginStart="64dp"
|
app:trackMarginStart="64dp"
|
||||||
app:addLastItemPadding="true"
|
app:addLastItemPadding="true"
|
||||||
app:popupDrawable="@color/transparent">
|
app:popupDrawable="@android:color/transparent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/main_recyclerview"
|
android:id="@+id/main_recyclerview"
|
||||||
@@ -126,21 +126,20 @@
|
|||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.arlib.floatingsearchview.FloatingSearchViewDayNight
|
<xyz.quaver.pupil.ui.view.FloatingSearchView
|
||||||
android:id="@+id/main_searchview"
|
android:id="@+id/main_searchview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:floatingSearch_suggestionRightIconColor="@color/material_orange_500"
|
app:searchBarMarginLeft="6dp"
|
||||||
app:floatingSearch_searchBarMarginLeft="8dp"
|
app:searchBarMarginRight="6dp"
|
||||||
app:floatingSearch_searchBarMarginRight="8dp"
|
app:searchBarMarginTop="6dp"
|
||||||
app:floatingSearch_searchBarMarginTop="8dp"
|
app:searchHint="@string/search_hint"
|
||||||
app:floatingSearch_searchHint="@string/search_hint"
|
app:suggestionAnimDuration="250"
|
||||||
app:floatingSearch_suggestionsListAnimDuration="250"
|
app:showSearchKey="true"
|
||||||
app:floatingSearch_showSearchKey="true"
|
app:leftActionMode="showHamburger"
|
||||||
app:floatingSearch_leftActionMode="showHamburger"
|
app:menu="@menu/main"
|
||||||
app:floatingSearch_menu="@menu/main"
|
app:dismissOnOutsideTouch="true"
|
||||||
app:floatingSearch_dismissOnOutsideTouch="true"
|
app:close_search_on_keyboard_dismiss="false"
|
||||||
app:floatingSearch_close_search_on_keyboard_dismiss="true"
|
|
||||||
tools:ignore="NewApi" />
|
tools:ignore="NewApi" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/dark_gray"
|
android:background="@android:color/darker_gray"
|
||||||
tools:context=".ui.ReaderActivity">
|
tools:context=".ui.ReaderActivity">
|
||||||
|
|
||||||
<com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
<com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
app:hideHandleAfter="1000"
|
app:hideHandleAfter="1000"
|
||||||
app:handleHasFixedSize="true"
|
app:handleHasFixedSize="true"
|
||||||
app:addLastItemPadding="true"
|
app:addLastItemPadding="true"
|
||||||
app:popupDrawable="@color/transparent">
|
app:popupDrawable="@android:color/transparent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/reader_recyclerview"
|
android:id="@+id/reader_recyclerview"
|
||||||
|
|||||||
@@ -162,16 +162,14 @@
|
|||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
|
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
|
||||||
app:layout_constraintBottom_toTopOf="@id/galleryblock_padding"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
|
||||||
|
|
||||||
<View
|
<androidx.constraintlayout.widget.Barrier
|
||||||
android:id="@+id/galleryblock_padding"
|
android:id="@+id/padding"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:barrierDirection="bottom"
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
|
app:constraint_referenced_ids="galleryblock_language"/>
|
||||||
app:layout_constraintBottom_toTopOf="@id/galleryblock_tag_group"/>
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/galleryblock_tag_group"
|
android:id="@+id/galleryblock_tag_group"
|
||||||
@@ -181,7 +179,7 @@
|
|||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
app:chipSpacing="4dp"
|
app:chipSpacing="4dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_padding"
|
app:layout_constraintTop_toBottomOf="@id/padding"
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
||||||
app:layout_constraintRight_toRightOf="parent"/>
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
|
||||||
@@ -196,7 +194,7 @@
|
|||||||
android:id="@+id/divider"
|
android:id="@+id/divider"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="@color/light_gray"
|
android:background="?android:attr/listDivider"
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier"
|
app:layout_constraintTop_toBottomOf="@id/barrier"
|
||||||
android:layout_margin="8dp"/>
|
android:layout_margin="8dp"/>
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,10 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<item android:id="@+id/main_menu_thin"
|
<item android:id="@+id/sort"
|
||||||
android:title="@string/main_menu_thin"/>
|
android:title="@string/main_menu_sort"
|
||||||
|
android:icon="@drawable/sort_variant"
|
||||||
<item android:title="@string/main_menu_sort">
|
app:showAsAction="ifRoom">
|
||||||
<menu>
|
<menu>
|
||||||
<group android:checkableBehavior="single">
|
<group android:checkableBehavior="single">
|
||||||
<item android:id="@+id/main_menu_sort_newest"
|
<item android:id="@+id/main_menu_sort_newest"
|
||||||
@@ -41,4 +41,9 @@
|
|||||||
android:title="@string/main_settings"
|
android:title="@string/main_settings"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
|
<item android:id="@+id/main_menu_thin"
|
||||||
|
android:title="@string/main_menu_thin"
|
||||||
|
app:showAsAction="never"
|
||||||
|
android:checkable="true"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
<string name="proxy_dialog_error">잘못된 값</string>
|
<string name="proxy_dialog_error">잘못된 값</string>
|
||||||
<string name="proxy_dialog_addr_hint">서버 주소</string>
|
<string name="proxy_dialog_addr_hint">서버 주소</string>
|
||||||
<string name="proxy_dialog_server">서버</string>
|
<string name="proxy_dialog_server">서버</string>
|
||||||
<string name="main_menu_thin">간단히 보기 모드</string>
|
<string name="main_menu_thin">간단히 보기</string>
|
||||||
<string name="main_fab_cancel">다운로드 모두 취소</string>
|
<string name="main_fab_cancel">다운로드 모두 취소</string>
|
||||||
<string name="channel_update">업데이트</string>
|
<string name="channel_update">업데이트</string>
|
||||||
<string name="channel_update_description">업데이트 진행상황 표시</string>
|
<string name="channel_update_description">업데이트 진행상황 표시</string>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
|
||||||
<dimen name="galleryblock_thumbnail_thin">100dp</dimen>
|
<dimen name="galleryblock_thumbnail_thin">100dp</dimen>
|
||||||
|
|
||||||
<dimen name="reader_max_height">2000dp</dimen>
|
<dimen name="reader_max_height" tools:ignore="PxUsage">2000px</dimen>
|
||||||
|
|
||||||
<dimen name="thumb_width">24dp</dimen>
|
<dimen name="thumb_width">24dp</dimen>
|
||||||
<dimen name="thumb_height">72dp</dimen>
|
<dimen name="thumb_height">72dp</dimen>
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<item name="item_click_support" type="id" />
|
<item name="item_click_support" type="id" />
|
||||||
<item name="request_settings" type="id" />
|
|
||||||
<item name="request_lock" type="id" />
|
|
||||||
<item name="request_restore" type="id" />
|
|
||||||
|
|
||||||
<item name="request_download_folder" type="id" />
|
|
||||||
<item name="request_download_folder_old" type="id" />
|
|
||||||
<item name="request_write_permission_and_saf" type="id" />
|
|
||||||
|
|
||||||
<item name="notification_id_update" type="id" />
|
<item name="notification_id_update" type="id" />
|
||||||
<item name="notification_id_import" type="id" />
|
<item name="notification_id_import" type="id" />
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<string name="main_drawer_group_contact_email">Email me!</string>
|
<string name="main_drawer_group_contact_email">Email me!</string>
|
||||||
<string name="main_drawer_grouop_contact_discord">Discord</string>
|
<string name="main_drawer_grouop_contact_discord">Discord</string>
|
||||||
|
|
||||||
<string name="main_menu_thin">Toggle Thin Mode</string>
|
<string name="main_menu_thin">Thin Mode</string>
|
||||||
|
|
||||||
<string name="main_menu_sort">Sort</string>
|
<string name="main_menu_sort">Sort</string>
|
||||||
<string name="main_menu_sort_newest">Newest</string>
|
<string name="main_menu_sort_newest">Newest</string>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ buildscript {
|
|||||||
classpath 'com.google.gms:google-services:4.3.3'
|
classpath 'com.google.gms:google-services:4.3.3'
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.1'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
|
||||||
classpath 'com.google.firebase:perf-plugin:1.3.1'
|
classpath 'com.google.firebase:perf-plugin:1.3.1'
|
||||||
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.2'
|
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.2'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user