Compare commits
16 Commits
5.1.6-hotf
...
5.1.7-hotf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ad7effa0 | ||
|
|
a032beecbf | ||
|
|
46ec9e48d9 | ||
|
|
26bcef1cc0 | ||
|
|
bfb2f44f8f | ||
|
|
28b19b6774 | ||
|
|
8d72f4a3aa | ||
|
|
9c62e0399d | ||
|
|
65ea09854e | ||
|
|
9f9a4c81b3 | ||
|
|
d567b30f4b | ||
|
|
6d7c4ce0ab | ||
|
|
e062b8f9e9 | ||
|
|
08403b7a4e | ||
|
|
c6ed5d35e7 | ||
|
|
dba3460b60 |
2
.idea/copyright/profiles_settings.xml
generated
2
.idea/copyright/profiles_settings.xml
generated
@@ -1,7 +1,7 @@
|
|||||||
<component name="CopyrightManager">
|
<component name="CopyrightManager">
|
||||||
<settings>
|
<settings>
|
||||||
<module2copyright>
|
<module2copyright>
|
||||||
<element module="Pupil" copyright="GPL" />
|
<element module="Project Files" copyright="GPL" />
|
||||||
</module2copyright>
|
</module2copyright>
|
||||||
</settings>
|
</settings>
|
||||||
</component>
|
</component>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
*Pupil, Hitomi.la viewer for Android*
|
*Pupil, Hitomi.la viewer for Android*
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/tom5079/Pupil/releases/download/5.1.6-hotfix7/Pupil-v5.1.6-hotfix7.apk)
|
[](https://github.com/tom5079/Pupil/releases/download/5.1.7-hotfix1/Pupil-v5.1.7-hotfix1.apk)
|
||||||
[](https://discord.gg/Stj4b5v)
|
[](https://discord.gg/Stj4b5v)
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
apply plugin: "com.android.application"
|
apply plugin: "com.android.application"
|
||||||
apply plugin: "kotlin-android"
|
apply plugin: "kotlin-android"
|
||||||
apply plugin: "kotlin-kapt"
|
apply plugin: "kotlin-kapt"
|
||||||
apply plugin: "kotlin-android-extensions"
|
apply plugin: "kotlin-parcelize"
|
||||||
apply plugin: "kotlinx-serialization"
|
apply plugin: "kotlinx-serialization"
|
||||||
apply plugin: "com.google.android.gms.oss-licenses-plugin"
|
apply plugin: "com.google.android.gms.oss-licenses-plugin"
|
||||||
|
|
||||||
if (file("google-services.json").exists() && file("src/debug/google-services.json").exists()) {
|
if (file("google-services.json").exists()) {
|
||||||
logger.lifecycle("Firebase Enabled")
|
logger.lifecycle("Firebase Enabled")
|
||||||
apply plugin: "com.google.gms.google-services"
|
apply plugin: "com.google.gms.google-services"
|
||||||
apply plugin: "com.google.firebase.crashlytics"
|
apply plugin: "com.google.firebase.crashlytics"
|
||||||
@@ -37,8 +37,8 @@ android {
|
|||||||
applicationId "xyz.quaver.pupil"
|
applicationId "xyz.quaver.pupil"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 63
|
versionCode 64
|
||||||
versionName "5.1.6-hotfix7"
|
versionName "5.1.7-hotfix1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
@@ -63,6 +63,9 @@ android {
|
|||||||
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding true
|
||||||
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
freeCompilerArgs += "-Xuse-experimental=kotlin.Experimental"
|
freeCompilerArgs += "-Xuse-experimental=kotlin.Experimental"
|
||||||
@@ -77,27 +80,27 @@ 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-android:1.4.0-M1"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||||
implementation "androidx.activity:activity-ktx:1.2.0-beta01"
|
implementation "androidx.activity:activity-ktx:1.2.0-beta01"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.3.0-beta01"
|
implementation "androidx.fragment:fragment-ktx:1.3.0-beta01"
|
||||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.0.2"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||||
implementation "androidx.biometric:biometric:1.0.1"
|
implementation "androidx.biometric:biometric:1.0.1"
|
||||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||||
|
|
||||||
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-alpha03"
|
implementation "com.google.android.material:material:1.3.0-alpha04"
|
||||||
|
|
||||||
implementation "com.google.firebase:firebase-core:17.5.1"
|
implementation "com.google.firebase:firebase-core:18.0.0"
|
||||||
implementation "com.google.firebase:firebase-analytics:17.6.0"
|
implementation "com.google.firebase:firebase-analytics:18.0.0"
|
||||||
implementation "com.google.firebase:firebase-crashlytics:17.2.2"
|
implementation "com.google.firebase:firebase-crashlytics:17.3.0"
|
||||||
implementation "com.google.firebase:firebase-perf:19.0.9"
|
implementation "com.google.firebase:firebase-perf:19.0.10"
|
||||||
|
|
||||||
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"
|
||||||
@@ -127,13 +130,9 @@ dependencies {
|
|||||||
implementation "xyz.quaver:documentfilex:0.4-alpha02"
|
implementation "xyz.quaver:documentfilex:0.4-alpha02"
|
||||||
implementation "xyz.quaver:floatingsearchview:1.0.7"
|
implementation "xyz.quaver:floatingsearchview:1.0.7"
|
||||||
|
|
||||||
testImplementation "junit:junit:4.13"
|
testImplementation "junit:junit:4.13.1"
|
||||||
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
androidTestImplementation "androidx.test:rules:1.3.0"
|
androidTestImplementation "androidx.test:rules:1.3.0"
|
||||||
androidTestImplementation "androidx.test:runner:1.3.0"
|
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0"
|
androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0"
|
||||||
}
|
|
||||||
|
|
||||||
androidExtensions {
|
|
||||||
experimental = true
|
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
{
|
{
|
||||||
"type": "SINGLE",
|
"type": "SINGLE",
|
||||||
"filters": [],
|
"filters": [],
|
||||||
"versionCode": 63,
|
"versionCode": 64,
|
||||||
"versionName": "5.1.6-hotfix7",
|
"versionName": "5.1.7-hotfix1",
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,10 +6,11 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="21"/>
|
<uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="21" />
|
<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||||
|
|||||||
@@ -125,8 +125,13 @@ class Pupil : Application() {
|
|||||||
favoriteTags = SavedSet(File(ContextCompat.getDataDir(this), "favorites_tags.json"), Tag.parse(""))
|
favoriteTags = SavedSet(File(ContextCompat.getDataDir(this), "favorites_tags.json"), Tag.parse(""))
|
||||||
searchHistory = SavedSet(File(ContextCompat.getDataDir(this), "search_histories.json"), "")
|
searchHistory = SavedSet(File(ContextCompat.getDataDir(this), "search_histories.json"), "")
|
||||||
|
|
||||||
|
favoriteTags.filter { it.tag.contains('_') }.forEach {
|
||||||
|
favoriteTags.remove(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false)
|
FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false)*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ProviderInstaller.installIfNeeded(this)
|
ProviderInstaller.installIfNeeded(this)
|
||||||
|
|||||||
@@ -22,14 +22,10 @@ import android.content.ClipData
|
|||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
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.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.Toast
|
import android.widget.Toast
|
||||||
import androidx.cardview.widget.CardView
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
|
||||||
@@ -38,15 +34,16 @@ import com.daimajia.swipe.SwipeLayout
|
|||||||
import com.daimajia.swipe.adapters.RecyclerSwipeAdapter
|
import com.daimajia.swipe.adapters.RecyclerSwipeAdapter
|
||||||
import com.daimajia.swipe.interfaces.SwipeAdapterInterface
|
import com.daimajia.swipe.interfaces.SwipeAdapterInterface
|
||||||
import com.github.piasy.biv.loader.ImageLoader
|
import com.github.piasy.biv.loader.ImageLoader
|
||||||
import kotlinx.android.synthetic.main.item_galleryblock.view.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import xyz.quaver.hitomi.getGallery
|
import xyz.quaver.hitomi.getGallery
|
||||||
import xyz.quaver.hitomi.getReader
|
import xyz.quaver.hitomi.getReader
|
||||||
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.databinding.GalleryblockItemBinding
|
||||||
import xyz.quaver.pupil.favoriteTags
|
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.ProgressCard
|
||||||
import xyz.quaver.pupil.util.Preferences
|
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
|
||||||
@@ -55,340 +52,260 @@ import java.io.File
|
|||||||
|
|
||||||
class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapter<RecyclerView.ViewHolder>(), SwipeAdapterInterface {
|
class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapter<RecyclerView.ViewHolder>(), SwipeAdapterInterface {
|
||||||
|
|
||||||
enum class ViewType {
|
|
||||||
NEXT,
|
|
||||||
GALLERY,
|
|
||||||
PREV
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateAll = true
|
var updateAll = true
|
||||||
var thin: Boolean = Preferences["thin"]
|
var thin: Boolean = Preferences["thin"]
|
||||||
|
|
||||||
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
inner class GalleryViewHolder(val binding: GalleryblockItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
private var galleryID: Int = 0
|
private var galleryID: Int = 0
|
||||||
|
|
||||||
init {
|
init {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
while (updateAll) {
|
while (updateAll) {
|
||||||
updateProgress(view.context)
|
updateProgress(itemView.context)
|
||||||
delay(1000)
|
delay(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateProgress(context: Context) {
|
private fun updateProgress(context: Context) = CoroutineScope(Dispatchers.Main).launch {
|
||||||
val cache = Cache.getInstance(context, galleryID)
|
with(binding.galleryblockCard) {
|
||||||
|
val imageList = Cache.getInstance(context, galleryID).metadata.imageList
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
if (imageList == null) {
|
||||||
if (cache.metadata.reader == null) {
|
max = 0
|
||||||
view.galleryblock_progressbar_layout.visibility = View.GONE
|
return@with
|
||||||
view.galleryblock_progress_complete.visibility = View.INVISIBLE
|
|
||||||
return@launch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.galleryblock_progressbar) {
|
progress = imageList.count { it != null }
|
||||||
val imageList = cache.metadata.imageList!!
|
max = imageList.size
|
||||||
|
|
||||||
progress = imageList.count { it != null }
|
this@GalleryViewHolder.binding.galleryblockId.setOnClickListener {
|
||||||
max = imageList.size
|
(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip(
|
||||||
|
ClipData.newPlainText("gallery_id", galleryID.toString())
|
||||||
with(view.galleryblock_progressbar_layout) {
|
)
|
||||||
if (visibility == View.GONE)
|
Toast.makeText(context, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||||
visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
view.galleryblock_id.setOnClickListener {
|
|
||||||
(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip(
|
|
||||||
ClipData.newPlainText("gallery_id", galleryID.toString())
|
|
||||||
)
|
|
||||||
Toast.makeText(context, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!imageList.contains(null)) {
|
|
||||||
val downloadManager = DownloadManager.getInstance(context)
|
|
||||||
|
|
||||||
if (completeFlag.get(galleryID, false)) {
|
|
||||||
with(view.galleryblock_progress_complete) {
|
|
||||||
setImageResource(
|
|
||||||
if (downloadManager.getDownloadFolder(galleryID) != null)
|
|
||||||
R.drawable.ic_progressbar
|
|
||||||
else R.drawable.ic_progressbar_cache
|
|
||||||
)
|
|
||||||
visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
with(view.galleryblock_progress_complete) {
|
|
||||||
setImageDrawable(AnimatedVectorDrawableCompat.create(context,
|
|
||||||
if (downloadManager.getDownloadFolder(galleryID) != null)
|
|
||||||
R.drawable.ic_progressbar_complete
|
|
||||||
else R.drawable.ic_progressbar_complete_cache
|
|
||||||
).apply {
|
|
||||||
this?.start()
|
|
||||||
})
|
|
||||||
visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
completeFlag.put(galleryID, true)
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
view.galleryblock_progress_complete.visibility = View.INVISIBLE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type = if (!imageList.contains(null)) {
|
||||||
|
val downloadManager = DownloadManager.getInstance(context)
|
||||||
|
|
||||||
|
if (downloadManager.getDownloadFolder(galleryID) == null)
|
||||||
|
ProgressCard.Type.CACHE
|
||||||
|
else
|
||||||
|
ProgressCard.Type.DOWNLOAD
|
||||||
|
} else
|
||||||
|
ProgressCard.Type.LOADING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(galleryID: Int) {
|
fun bind(galleryID: Int) {
|
||||||
this.galleryID = galleryID
|
this.galleryID = galleryID
|
||||||
updateProgress(view.context)
|
updateProgress(itemView.context)
|
||||||
|
|
||||||
val cache = Cache.getInstance(view.context, galleryID)
|
val cache = Cache.getInstance(itemView.context, galleryID)
|
||||||
|
|
||||||
val galleryBlock = runBlocking {
|
val galleryBlock = runBlocking {
|
||||||
cache.getGalleryBlock()
|
cache.getGalleryBlock()
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
with(view) {
|
val resources = itemView.context.resources
|
||||||
val resources = context.resources
|
val languages = resources.getStringArray(R.array.languages).map {
|
||||||
val languages = resources.getStringArray(R.array.languages).map {
|
it.split("|").let { split ->
|
||||||
it.split("|").let { split ->
|
Pair(split[0], split[1])
|
||||||
Pair(split[0], split[1])
|
|
||||||
}
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
val artists = galleryBlock.artists
|
|
||||||
val series = galleryBlock.series
|
|
||||||
|
|
||||||
galleryblock_thumbnail.apply {
|
|
||||||
setOnClickListener {
|
|
||||||
view.performClick()
|
|
||||||
}
|
|
||||||
setOnLongClickListener {
|
|
||||||
view.performLongClick()
|
|
||||||
}
|
|
||||||
setFailureImage(ContextCompat.getDrawable(context, R.drawable.image_broken_variant))
|
|
||||||
setImageLoaderCallback(object: ImageLoader.Callback {
|
|
||||||
override fun onFail(error: Exception?) {
|
|
||||||
Cache.getInstance(context, galleryID).let { cache ->
|
|
||||||
cache.cacheFolder.getChild(".thumbnail").let { if (it.exists()) it.delete() }
|
|
||||||
cache.downloadFolder?.getChild(".thumbnail")?.let { if (it.exists()) it.delete() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCacheHit(imageType: Int, image: File?) {}
|
|
||||||
override fun onCacheMiss(imageType: Int, image: File?) {}
|
|
||||||
override fun onFinish() {}
|
|
||||||
override fun onProgress(progress: Int) {}
|
|
||||||
override fun onStart() {}
|
|
||||||
override fun onSuccess(image: File?) {}
|
|
||||||
})
|
|
||||||
ssiv?.recycle()
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
cache.getThumbnail().let { launch(Dispatchers.Main) {
|
|
||||||
showImage(it)
|
|
||||||
} }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
galleryblock_title.text = galleryBlock.title
|
val artists = galleryBlock.artists
|
||||||
with(galleryblock_artist) {
|
val series = galleryBlock.series
|
||||||
text = artists.joinToString { it.wordCapitalize() }
|
|
||||||
visibility = when {
|
|
||||||
artists.isNotEmpty() -> View.VISIBLE
|
|
||||||
else -> View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
binding.galleryblockThumbnail.apply {
|
||||||
val gallery = runCatching {
|
setOnClickListener {
|
||||||
getGallery(galleryID)
|
itemView.performClick()
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
if (gallery?.groups?.isNotEmpty() != true)
|
|
||||||
return@launch
|
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
text = context.getString(
|
|
||||||
R.string.galleryblock_artist_with_group,
|
|
||||||
artists.joinToString { it.wordCapitalize() },
|
|
||||||
gallery.groups.joinToString { it.wordCapitalize() }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
with(galleryblock_series) {
|
setOnLongClickListener {
|
||||||
text =
|
itemView.performLongClick()
|
||||||
resources.getString(
|
|
||||||
R.string.galleryblock_series,
|
|
||||||
series.joinToString(", ") { it.wordCapitalize() })
|
|
||||||
visibility = when {
|
|
||||||
series.isNotEmpty() -> View.VISIBLE
|
|
||||||
else -> View.GONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
galleryblock_type.text = resources.getString(R.string.galleryblock_type, galleryBlock.type).wordCapitalize()
|
setFailureImage(ContextCompat.getDrawable(context, R.drawable.image_broken_variant))
|
||||||
with(galleryblock_language) {
|
setImageLoaderCallback(object: ImageLoader.Callback {
|
||||||
text =
|
override fun onFail(error: Exception?) {
|
||||||
resources.getString(R.string.galleryblock_language, languages[galleryBlock.language])
|
Cache.getInstance(context, galleryID).let { cache ->
|
||||||
visibility = when {
|
cache.cacheFolder.getChild(".thumbnail").let { if (it.exists()) it.delete() }
|
||||||
galleryBlock.language.isNotEmpty() -> View.VISIBLE
|
cache.downloadFolder?.getChild(".thumbnail")?.let { if (it.exists()) it.delete() }
|
||||||
else -> View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(galleryblock_tag_group) {
|
|
||||||
onClickListener = {
|
|
||||||
onChipClickedHandler.forEach { callback ->
|
|
||||||
callback.invoke(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tags.clear()
|
override fun onCacheHit(imageType: Int, image: File?) {}
|
||||||
|
override fun onCacheMiss(imageType: Int, image: File?) {}
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
override fun onFinish() {}
|
||||||
tags.addAll(
|
override fun onProgress(progress: Int) {}
|
||||||
galleryBlock.relatedTags.sortedBy {
|
override fun onStart() {}
|
||||||
val tag = Tag.parse(it)
|
override fun onSuccess(image: File?) {}
|
||||||
|
})
|
||||||
if (favoriteTags.contains(tag))
|
ssiv?.recycle()
|
||||||
-1
|
|
||||||
else
|
|
||||||
when(Tag.parse(it).area) {
|
|
||||||
"female" -> 0
|
|
||||||
"male" -> 1
|
|
||||||
else -> 2
|
|
||||||
}
|
|
||||||
}.map {
|
|
||||||
Tag.parse(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
galleryblock_id.text = galleryBlock.id.toString()
|
|
||||||
galleryblock_pagecount.text = "-"
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val pageCount = kotlin.runCatching {
|
cache.getThumbnail().let { launch(Dispatchers.Main) {
|
||||||
getReader(galleryBlock.id).galleryInfo.files.size
|
showImage(it)
|
||||||
}.getOrNull() ?: return@launch
|
} }
|
||||||
withContext(Dispatchers.Main) {
|
}
|
||||||
galleryblock_pagecount.text = context.getString(R.string.galleryblock_pagecount, pageCount)
|
}
|
||||||
|
|
||||||
|
binding.galleryblockTitle.text = galleryBlock.title
|
||||||
|
with(binding.galleryblockArtist) {
|
||||||
|
text = artists.joinToString { it.wordCapitalize() }
|
||||||
|
visibility = when {
|
||||||
|
artists.isNotEmpty() -> View.VISIBLE
|
||||||
|
else -> View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val gallery = runCatching {
|
||||||
|
getGallery(galleryID)
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
|
if (gallery?.groups?.isNotEmpty() != true)
|
||||||
|
return@launch
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
text = context.getString(
|
||||||
|
R.string.galleryblock_artist_with_group,
|
||||||
|
artists.joinToString { it.wordCapitalize() },
|
||||||
|
gallery.groups.joinToString { it.wordCapitalize() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with(binding.galleryblockSeries) {
|
||||||
|
text =
|
||||||
|
resources.getString(
|
||||||
|
R.string.galleryblock_series,
|
||||||
|
series.joinToString(", ") { it.wordCapitalize() })
|
||||||
|
visibility = when {
|
||||||
|
series.isNotEmpty() -> View.VISIBLE
|
||||||
|
else -> View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.galleryblockType.text = resources.getString(R.string.galleryblock_type, galleryBlock.type).wordCapitalize()
|
||||||
|
with(binding.galleryblockLanguage) {
|
||||||
|
text =
|
||||||
|
resources.getString(R.string.galleryblock_language, languages[galleryBlock.language])
|
||||||
|
visibility = when {
|
||||||
|
galleryBlock.language.isNotEmpty() -> View.VISIBLE
|
||||||
|
else -> View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(binding.galleryblockTagGroup) {
|
||||||
|
onClickListener = {
|
||||||
|
onChipClickedHandler.forEach { callback ->
|
||||||
|
callback.invoke(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(galleryblock_favorite) {
|
tags.clear()
|
||||||
setImageResource(if (favorites.contains(galleryBlock.id)) R.drawable.ic_star_filled else R.drawable.ic_star_empty)
|
|
||||||
setOnClickListener {
|
|
||||||
when {
|
|
||||||
favorites.contains(galleryBlock.id) -> {
|
|
||||||
favorites.remove(galleryBlock.id)
|
|
||||||
|
|
||||||
setImageResource(R.drawable.ic_star_empty)
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
}
|
tags.addAll(
|
||||||
else -> {
|
galleryBlock.relatedTags.sortedBy {
|
||||||
favorites.add(galleryBlock.id)
|
val tag = Tag.parse(it)
|
||||||
|
|
||||||
setImageDrawable(AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star).apply {
|
if (favoriteTags.contains(tag))
|
||||||
this ?: return@apply
|
-1
|
||||||
|
else
|
||||||
|
when(Tag.parse(it).area) {
|
||||||
|
"female" -> 0
|
||||||
|
"male" -> 1
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
}.map {
|
||||||
|
Tag.parse(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
registerAnimationCallback(object: Animatable2Compat.AnimationCallback() {
|
launch(Dispatchers.Main) {
|
||||||
override fun onAnimationEnd(drawable: Drawable?) {
|
refresh()
|
||||||
setImageResource(R.drawable.ic_star_filled)
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
start()
|
|
||||||
|
binding.galleryblockId.text = galleryBlock.id.toString()
|
||||||
|
binding.galleryblockPagecount.text = "-"
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val pageCount = kotlin.runCatching {
|
||||||
|
getReader(galleryBlock.id).galleryInfo.files.size
|
||||||
|
}.getOrNull() ?: return@launch
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.galleryblockPagecount.text = itemView.context.getString(R.string.galleryblock_pagecount, pageCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(binding.galleryblockFavorite) {
|
||||||
|
setImageResource(if (favorites.contains(galleryBlock.id)) R.drawable.ic_star_filled else R.drawable.ic_star_empty)
|
||||||
|
setOnClickListener {
|
||||||
|
when {
|
||||||
|
favorites.contains(galleryBlock.id) -> {
|
||||||
|
favorites.remove(galleryBlock.id)
|
||||||
|
|
||||||
|
setImageResource(R.drawable.ic_star_empty)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
favorites.add(galleryBlock.id)
|
||||||
|
|
||||||
|
setImageDrawable(AnimatedVectorDrawableCompat.create(context, R.drawable.avd_star).apply {
|
||||||
|
this ?: return@apply
|
||||||
|
|
||||||
|
registerAnimationCallback(object: Animatable2Compat.AnimationCallback() {
|
||||||
|
override fun onAnimationEnd(drawable: Drawable?) {
|
||||||
|
setImageResource(R.drawable.ic_star_filled)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
start()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Make some views invisible to make it thinner
|
// Make some views invisible to make it thinner
|
||||||
if (thin) {
|
if (thin) {
|
||||||
galleryblock_tag_group.visibility = View.GONE
|
binding.galleryblockTagGroup.visibility = View.GONE
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class NextViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
|
|
||||||
class PrevViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
|
|
||||||
|
|
||||||
class ViewHolderFactory {
|
|
||||||
companion object {
|
|
||||||
fun getLayoutID(type: Int): Int {
|
|
||||||
return when(ViewType.values()[type]) {
|
|
||||||
ViewType.NEXT -> R.layout.item_next
|
|
||||||
ViewType.PREV -> R.layout.item_prev
|
|
||||||
ViewType.GALLERY -> R.layout.item_galleryblock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val completeFlag = SparseBooleanArray()
|
|
||||||
|
|
||||||
val onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
|
val onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
|
||||||
var onDownloadClickedHandler: ((Int) -> Unit)? = null
|
var onDownloadClickedHandler: ((Int) -> Unit)? = null
|
||||||
var onDeleteClickedHandler: ((Int) -> Unit)? = null
|
var onDeleteClickedHandler: ((Int) -> Unit)? = null
|
||||||
|
|
||||||
var showNext = false
|
|
||||||
var showPrev = false
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
return GalleryViewHolder(GalleryblockItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||||
fun getViewHolder(type: Int, view: View): RecyclerView.ViewHolder {
|
|
||||||
return when(ViewType.values()[type]) {
|
|
||||||
ViewType.NEXT -> NextViewHolder(view as LinearLayout)
|
|
||||||
ViewType.PREV -> PrevViewHolder(view as LinearLayout)
|
|
||||||
ViewType.GALLERY -> GalleryViewHolder(view as CardView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getViewHolder(
|
|
||||||
viewType,
|
|
||||||
LayoutInflater.from(parent.context).inflate(
|
|
||||||
ViewHolderFactory.getLayoutID(viewType),
|
|
||||||
parent,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
if (holder is GalleryViewHolder) {
|
if (holder is GalleryViewHolder) {
|
||||||
val galleryID = galleries[position-(if (showPrev) 1 else 0)]
|
val galleryID = galleries[position]
|
||||||
|
|
||||||
holder.bind(galleryID)
|
holder.bind(galleryID)
|
||||||
|
|
||||||
with(holder.view.galleryblock_primary) {
|
holder.binding.galleryblockCard.binding.download.setOnClickListener {
|
||||||
setOnClickListener {
|
|
||||||
holder.view.performClick()
|
|
||||||
}
|
|
||||||
setOnLongClickListener {
|
|
||||||
holder.view.performLongClick()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.view.galleryblock_download.setOnClickListener {
|
|
||||||
onDownloadClickedHandler?.invoke(position)
|
onDownloadClickedHandler?.invoke(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.view.galleryblock_delete.setOnClickListener {
|
holder.binding.galleryblockCard.binding.delete.setOnClickListener {
|
||||||
onDeleteClickedHandler?.invoke(position)
|
onDeleteClickedHandler?.invoke(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
mItemManger.bindView(holder.view, position)
|
mItemManger.bindView(holder.binding.root, position)
|
||||||
|
|
||||||
holder.view.galleryblock_swipe_layout.addSwipeListener(object: SwipeLayout.SwipeListener {
|
holder.binding.galleryblockCard.binding.swipeLayout.addSwipeListener(object: SwipeLayout.SwipeListener {
|
||||||
override fun onStartOpen(layout: SwipeLayout?) {
|
override fun onStartOpen(layout: SwipeLayout?) {
|
||||||
mItemManger.closeAllExcept(layout)
|
mItemManger.closeAllExcept(layout)
|
||||||
|
|
||||||
holder.view.galleryblock_download.text =
|
holder.binding.galleryblockCard.binding.download.text =
|
||||||
if (DownloadManager.getInstance(holder.view.context).isDownloading(galleryID))
|
if (DownloadManager.getInstance(holder.binding.root.context).isDownloading(galleryID))
|
||||||
holder.view.context.getString(android.R.string.cancel)
|
holder.binding.root.context.getString(android.R.string.cancel)
|
||||||
else
|
else
|
||||||
holder.view.context.getString(R.string.main_download)
|
holder.binding.root.context.getString(R.string.main_download)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClose(layout: SwipeLayout?) {}
|
override fun onClose(layout: SwipeLayout?) {}
|
||||||
@@ -400,18 +317,7 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() =
|
override fun getItemCount() = galleries.size
|
||||||
galleries.size +
|
|
||||||
(if (showNext) 1 else 0) +
|
|
||||||
(if (showPrev) 1 else 0)
|
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getSwipeLayoutResourceId(position: Int) = R.id.swipe_layout
|
||||||
return when {
|
|
||||||
showPrev && position == 0 -> ViewType.PREV
|
|
||||||
showNext && position == galleries.size+(if (showPrev) 1 else 0) -> ViewType.NEXT
|
|
||||||
else -> ViewType.GALLERY
|
|
||||||
}.ordinal
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSwipeLayoutResourceId(position: Int) = R.id.galleryblock_swipe_layout
|
|
||||||
}
|
}
|
||||||
@@ -22,17 +22,29 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.android.synthetic.main.item_mirrors.view.*
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.MirrorsItemBinding
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class MirrorAdapter(context: Context) : RecyclerView.Adapter<MirrorAdapter.ViewHolder>() {
|
class MirrorAdapter(context: Context) : RecyclerView.Adapter<MirrorAdapter.ViewHolder>() {
|
||||||
|
|
||||||
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view)
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
inner class ViewHolder(val binding: MirrorsItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
init {
|
||||||
|
binding.mirrorButton.setOnTouchListener { _, event ->
|
||||||
|
if (event.action == MotionEvent.ACTION_DOWN)
|
||||||
|
onStartDrag?.invoke(this)
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun bind(mirror: String) {
|
||||||
|
binding.mirrorName.text = mirror
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val mirrors = context.resources.getStringArray(R.array.mirrors).map {
|
val mirrors = context.resources.getStringArray(R.array.mirrors).map {
|
||||||
it.split('|').let { split ->
|
it.split('|').let { split ->
|
||||||
@@ -62,23 +74,11 @@ class MirrorAdapter(context: Context) : RecyclerView.Adapter<MirrorAdapter.ViewH
|
|||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
with(holder.view) {
|
holder.bind(mirrors[list.elementAt(position)] ?: error(""))
|
||||||
mirror_name.text = mirrors[list.elementAt(position)]
|
|
||||||
mirror_button.setOnTouchListener { _, event ->
|
|
||||||
if (event.action == MotionEvent.ACTION_DOWN)
|
|
||||||
onStartDrag?.invoke(holder)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
return LayoutInflater.from(parent.context).inflate(
|
return ViewHolder(MirrorsItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||||
R.layout.item_mirrors, parent, false
|
|
||||||
).let {
|
|
||||||
ViewHolder(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() = mirrors.size
|
override fun getItemCount() = mirrors.size
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ import com.facebook.imagepipeline.image.ImageInfo
|
|||||||
import com.github.piasy.biv.view.BigImageView
|
import com.github.piasy.biv.view.BigImageView
|
||||||
import com.github.piasy.biv.view.ImageShownCallback
|
import com.github.piasy.biv.view.ImageShownCallback
|
||||||
import com.github.piasy.biv.view.ImageViewFactory
|
import com.github.piasy.biv.view.ImageViewFactory
|
||||||
import kotlinx.android.synthetic.main.item_reader.view.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import xyz.quaver.hitomi.Reader
|
import xyz.quaver.hitomi.Reader
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.ReaderItemBinding
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
import xyz.quaver.pupil.util.downloader.Cache
|
import xyz.quaver.pupil.util.downloader.Cache
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -52,16 +52,93 @@ class ReaderAdapter(
|
|||||||
private val activity: ReaderActivity,
|
private val activity: ReaderActivity,
|
||||||
private val galleryID: Int
|
private val galleryID: Int
|
||||||
) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<ReaderAdapter.ViewHolder>() {
|
||||||
|
|
||||||
var reader: Reader? = null
|
var reader: Reader? = null
|
||||||
|
|
||||||
var isFullScreen = false
|
var isFullScreen = false
|
||||||
|
|
||||||
var onItemClickListener : (() -> (Unit))? = null
|
var onItemClickListener : (() -> (Unit))? = null
|
||||||
|
|
||||||
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(private val binding: ReaderItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
init {
|
||||||
|
with (binding.image) {
|
||||||
|
setImageViewFactory(FrescoImageViewFactory().apply {
|
||||||
|
updateView = { imageInfo ->
|
||||||
|
binding.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
|
dimensionRatio = "${imageInfo.width}:${imageInfo.height}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setImageShownCallback(object : ImageShownCallback {
|
||||||
|
override fun onMainImageShown() {
|
||||||
|
binding.image.mainView.let { v ->
|
||||||
|
when (v) {
|
||||||
|
is SubsamplingScaleImageView ->
|
||||||
|
if (!isFullScreen) binding.image.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onThumbnailShown() {}
|
||||||
|
})
|
||||||
|
|
||||||
|
setFailureImage(ContextCompat.getDrawable(itemView.context, R.drawable.image_broken_variant))
|
||||||
|
setOnClickListener {
|
||||||
|
onItemClickListener?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
onItemClickListener?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(position: Int) {
|
||||||
|
if (cache == null)
|
||||||
|
cache = Cache.getInstance(itemView.context, galleryID)
|
||||||
|
|
||||||
|
if (!isFullScreen) {
|
||||||
|
binding.root.setBackgroundResource(R.drawable.reader_item_boundary)
|
||||||
|
binding.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
|
height = 0
|
||||||
|
dimensionRatio =
|
||||||
|
"${reader!!.galleryInfo.files[position].width}:${reader!!.galleryInfo.files[position].height}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.root.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
binding.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
|
height = ConstraintLayout.LayoutParams.MATCH_PARENT
|
||||||
|
dimensionRatio = null
|
||||||
|
}
|
||||||
|
binding.root.background = null
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.readerIndex.text = (position+1).toString()
|
||||||
|
|
||||||
|
val image = cache!!.getImage(position)
|
||||||
|
val progress = activity.downloader?.progress?.get(galleryID)?.get(position)
|
||||||
|
|
||||||
|
if (progress?.isInfinite() == true && image != null) {
|
||||||
|
binding.progressGroup.visibility = View.INVISIBLE
|
||||||
|
binding.image.showImage(image.uri)
|
||||||
|
} else {
|
||||||
|
binding.progressGroup.visibility = View.VISIBLE
|
||||||
|
binding.readerItemProgressbar.progress =
|
||||||
|
if (progress?.isInfinite() == true)
|
||||||
|
100
|
||||||
|
else
|
||||||
|
progress?.roundToInt() ?: 0
|
||||||
|
|
||||||
|
clear()
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
delay(1000)
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
view.image.mainView.let {
|
binding.image.mainView.let {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SubsamplingScaleImageView ->
|
is SubsamplingScaleImageView ->
|
||||||
it.recycle()
|
it.recycle()
|
||||||
@@ -73,88 +150,12 @@ class ReaderAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
return LayoutInflater.from(parent.context).inflate(
|
return ViewHolder(ReaderItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||||
R.layout.item_reader, parent, false
|
|
||||||
).let {
|
|
||||||
with(it) {
|
|
||||||
image.setImageViewFactory(FrescoImageViewFactory().apply {
|
|
||||||
updateView = { imageInfo ->
|
|
||||||
it.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
dimensionRatio = "${imageInfo.width}:${imageInfo.height}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
image.setImageShownCallback(object : ImageShownCallback {
|
|
||||||
override fun onMainImageShown() {
|
|
||||||
it.image.mainView.let { v ->
|
|
||||||
when (v) {
|
|
||||||
is SubsamplingScaleImageView ->
|
|
||||||
if (!isFullScreen) it.image.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onThumbnailShown() {}
|
|
||||||
})
|
|
||||||
image.setFailureImage(ContextCompat.getDrawable(context, R.drawable.image_broken_variant))
|
|
||||||
image.setOnClickListener {
|
|
||||||
this.performClick()
|
|
||||||
}
|
|
||||||
setOnClickListener {
|
|
||||||
onItemClickListener?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewHolder(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cache: Cache? = null
|
private var cache: Cache? = null
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.view as ConstraintLayout
|
holder.bind(position)
|
||||||
|
|
||||||
if (cache == null)
|
|
||||||
cache = Cache.getInstance(holder.view.context, galleryID)
|
|
||||||
|
|
||||||
if (!isFullScreen) {
|
|
||||||
holder.view.setBackgroundResource(R.drawable.reader_item_boundary)
|
|
||||||
holder.view.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
height = 0
|
|
||||||
dimensionRatio =
|
|
||||||
"${reader!!.galleryInfo.files[position].width}:${reader!!.galleryInfo.files[position].height}"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
holder.view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
holder.view.image.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
|
||||||
height = ConstraintLayout.LayoutParams.MATCH_PARENT
|
|
||||||
dimensionRatio = null
|
|
||||||
}
|
|
||||||
holder.view.background = null
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.view.reader_index.text = (position+1).toString()
|
|
||||||
|
|
||||||
val image = cache!!.getImage(position)
|
|
||||||
val progress = activity.downloader?.progress?.get(galleryID)?.get(position)
|
|
||||||
|
|
||||||
if (progress?.isInfinite() == true && image != null) {
|
|
||||||
holder.view.progress_group.visibility = View.INVISIBLE
|
|
||||||
holder.view.image.showImage(image.uri)
|
|
||||||
} else {
|
|
||||||
holder.view.progress_group.visibility = View.VISIBLE
|
|
||||||
holder.view.reader_item_progressbar.progress =
|
|
||||||
if (progress?.isInfinite() == true)
|
|
||||||
100
|
|
||||||
else
|
|
||||||
progress?.roundToInt() ?: 0
|
|
||||||
|
|
||||||
holder.clear()
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
delay(1000)
|
|
||||||
notifyItemChanged(position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() = reader?.galleryInfo?.files?.size ?: 0
|
override fun getItemCount() = reader?.galleryInfo?.files?.size ?: 0
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ 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.*
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.log10
|
import kotlin.math.log10
|
||||||
@@ -203,6 +202,8 @@ class DownloadService : Service() {
|
|||||||
private val callback = object: Callback {
|
private val callback = object: Callback {
|
||||||
|
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
|
||||||
if (e.message?.contains("cancel", true) == false) {
|
if (e.message?.contains("cancel", true) == false) {
|
||||||
val galleryID = (call.request().tag() as Tag).galleryID
|
val galleryID = (call.request().tag() as Tag).galleryID
|
||||||
|
|
||||||
@@ -235,6 +236,7 @@ class DownloadService : Service() {
|
|||||||
startId?.let { stopSelf(it) }
|
startId?.let { stopSelf(it) }
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
it.printStackTrace()
|
||||||
cancel(galleryID)
|
cancel(galleryID)
|
||||||
download(galleryID)
|
download(galleryID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.types
|
package xyz.quaver.pupil.types
|
||||||
|
|
||||||
import kotlinx.android.parcel.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.hitomi.Suggestion
|
import xyz.quaver.hitomi.Suggestion
|
||||||
import xyz.quaver.pupil.util.translations
|
import xyz.quaver.pupil.util.translations
|
||||||
|
|||||||
@@ -29,10 +29,8 @@ import androidx.biometric.BiometricPrompt
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.andrognito.patternlockview.PatternLockView
|
import com.andrognito.patternlockview.PatternLockView
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.activity_lock.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_pattern_lock.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_pin_lock.*
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.LockActivityBinding
|
||||||
import xyz.quaver.pupil.ui.fragment.PINLockFragment
|
import xyz.quaver.pupil.ui.fragment.PINLockFragment
|
||||||
import xyz.quaver.pupil.ui.fragment.PatternLockFragment
|
import xyz.quaver.pupil.ui.fragment.PatternLockFragment
|
||||||
import xyz.quaver.pupil.util.Lock
|
import xyz.quaver.pupil.util.Lock
|
||||||
@@ -45,6 +43,8 @@ class LockActivity : AppCompatActivity() {
|
|||||||
private lateinit var lockManager: LockManager
|
private lateinit var lockManager: LockManager
|
||||||
private var mode: String? = null
|
private var mode: String? = null
|
||||||
|
|
||||||
|
private lateinit var binding: LockActivityBinding
|
||||||
|
|
||||||
private val patternLockFragment = PatternLockFragment().apply {
|
private val patternLockFragment = PatternLockFragment().apply {
|
||||||
var lastPass = ""
|
var lastPass = ""
|
||||||
onPatternDrawn = {
|
onPatternDrawn = {
|
||||||
@@ -57,7 +57,7 @@ class LockActivity : AppCompatActivity() {
|
|||||||
setResult(Activity.RESULT_OK)
|
setResult(Activity.RESULT_OK)
|
||||||
finish()
|
finish()
|
||||||
} else
|
} else
|
||||||
lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG)
|
binding.patternLockView.setViewMode(PatternLockView.PatternViewMode.WRONG)
|
||||||
}
|
}
|
||||||
"add_lock" -> {
|
"add_lock" -> {
|
||||||
if (lastPass.isEmpty()) {
|
if (lastPass.isEmpty()) {
|
||||||
@@ -69,7 +69,7 @@ class LockActivity : AppCompatActivity() {
|
|||||||
LockManager(context!!).add(Lock.generate(Lock.Type.PATTERN, it))
|
LockManager(context!!).add(Lock.generate(Lock.Type.PATTERN, it))
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG)
|
binding.patternLockView.setViewMode(PatternLockView.PatternViewMode.WRONG)
|
||||||
lastPass = ""
|
lastPass = ""
|
||||||
|
|
||||||
Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show()
|
||||||
@@ -92,15 +92,15 @@ class LockActivity : AppCompatActivity() {
|
|||||||
setResult(Activity.RESULT_OK)
|
setResult(Activity.RESULT_OK)
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
indicator_dots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply {
|
binding.indicatorDots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply {
|
||||||
setAnimationListener(object: Animation.AnimationListener {
|
setAnimationListener(object: Animation.AnimationListener {
|
||||||
override fun onAnimationEnd(animation: Animation?) {
|
override fun onAnimationEnd(animation: Animation?) {
|
||||||
pin_lock_view.resetPinLockView()
|
binding.pinLockView.resetPinLockView()
|
||||||
pin_lock_view.isEnabled = true
|
binding.pinLockView.isEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationStart(animation: Animation?) {
|
override fun onAnimationStart(animation: Animation?) {
|
||||||
pin_lock_view.isEnabled = false
|
binding.pinLockView.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationRepeat(animation: Animation?) {
|
override fun onAnimationRepeat(animation: Animation?) {
|
||||||
@@ -114,22 +114,22 @@ class LockActivity : AppCompatActivity() {
|
|||||||
if (lastPass.isEmpty()) {
|
if (lastPass.isEmpty()) {
|
||||||
lastPass = it
|
lastPass = it
|
||||||
|
|
||||||
pin_lock_view.resetPinLockView()
|
binding.pinLockView.resetPinLockView()
|
||||||
Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show()
|
||||||
} else {
|
} else {
|
||||||
if (lastPass == it) {
|
if (lastPass == it) {
|
||||||
LockManager(context!!).add(Lock.generate(Lock.Type.PIN, it))
|
LockManager(context!!).add(Lock.generate(Lock.Type.PIN, it))
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
indicator_dots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply {
|
binding.indicatorDots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply {
|
||||||
setAnimationListener(object: Animation.AnimationListener {
|
setAnimationListener(object: Animation.AnimationListener {
|
||||||
override fun onAnimationEnd(animation: Animation?) {
|
override fun onAnimationEnd(animation: Animation?) {
|
||||||
pin_lock_view.resetPinLockView()
|
binding.pinLockView.resetPinLockView()
|
||||||
pin_lock_view.isEnabled = true
|
binding.pinLockView.isEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationStart(animation: Animation?) {
|
override fun onAnimationStart(animation: Animation?) {
|
||||||
pin_lock_view.isEnabled = false
|
binding.pinLockView.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationRepeat(animation: Animation?) {
|
override fun onAnimationRepeat(animation: Animation?) {
|
||||||
@@ -173,7 +173,8 @@ class LockActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_lock)
|
binding = LockActivityBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
lockManager = try {
|
lockManager = try {
|
||||||
LockManager(this)
|
LockManager(this)
|
||||||
@@ -210,7 +211,7 @@ class LockActivity : AppCompatActivity() {
|
|||||||
Preferences["lock_fingerprint"]
|
Preferences["lock_fingerprint"]
|
||||||
&& BiometricManager.from(this).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS
|
&& BiometricManager.from(this).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS
|
||||||
) {
|
) {
|
||||||
lock_fingerprint.apply {
|
binding.fingerprintBtn.apply {
|
||||||
isEnabled = true
|
isEnabled = true
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
showBiometricPrompt()
|
showBiometricPrompt()
|
||||||
@@ -219,7 +220,7 @@ class LockActivity : AppCompatActivity() {
|
|||||||
showBiometricPrompt()
|
showBiometricPrompt()
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_pattern.apply {
|
binding.patternBtn.apply {
|
||||||
isEnabled = lockManager.contains(Lock.Type.PATTERN)
|
isEnabled = lockManager.contains(Lock.Type.PATTERN)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
supportFragmentManager.beginTransaction().replace(
|
supportFragmentManager.beginTransaction().replace(
|
||||||
@@ -227,7 +228,7 @@ class LockActivity : AppCompatActivity() {
|
|||||||
).commit()
|
).commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock_pin.apply {
|
binding.pinBtn.apply {
|
||||||
isEnabled = lockManager.contains(Lock.Type.PIN)
|
isEnabled = lockManager.contains(Lock.Type.PIN)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
supportFragmentManager.beginTransaction().replace(
|
supportFragmentManager.beginTransaction().replace(
|
||||||
@@ -235,7 +236,7 @@ class LockActivity : AppCompatActivity() {
|
|||||||
).commit()
|
).commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock_password.isEnabled = false
|
binding.passwordBtn.isEnabled = false
|
||||||
|
|
||||||
when (lockManager.locks!!.first().type) {
|
when (lockManager.locks!!.first().type) {
|
||||||
Lock.Type.PIN -> {
|
Lock.Type.PIN -> {
|
||||||
@@ -253,20 +254,20 @@ class LockActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"add_lock" -> {
|
"add_lock" -> {
|
||||||
lock_pattern.isEnabled = false
|
binding.patternBtn.isEnabled = false
|
||||||
lock_pin.isEnabled = false
|
binding.pinBtn.isEnabled = false
|
||||||
lock_fingerprint.isEnabled = false
|
binding.fingerprintBtn.isEnabled = false
|
||||||
lock_password.isEnabled = false
|
binding.passwordBtn.isEnabled = false
|
||||||
|
|
||||||
when(intent.getStringExtra("type")!!) {
|
when(intent.getStringExtra("type")!!) {
|
||||||
"pattern" -> {
|
"pattern" -> {
|
||||||
lock_pattern.isEnabled = true
|
binding.patternBtn.isEnabled = true
|
||||||
supportFragmentManager.beginTransaction().add(
|
supportFragmentManager.beginTransaction().add(
|
||||||
R.id.lock_content, patternLockFragment
|
R.id.lock_content, patternLockFragment
|
||||||
).commit()
|
).commit()
|
||||||
}
|
}
|
||||||
"pin" -> {
|
"pin" -> {
|
||||||
lock_pin.isEnabled = true
|
binding.pinBtn.isEnabled = true
|
||||||
supportFragmentManager.beginTransaction().add(
|
supportFragmentManager.beginTransaction().add(
|
||||||
R.id.lock_content, pinLockFragment
|
R.id.lock_content, pinLockFragment
|
||||||
).commit()
|
).commit()
|
||||||
|
|||||||
@@ -21,27 +21,25 @@ package xyz.quaver.pupil.ui
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.text.util.Linkify
|
import android.text.util.Linkify
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.animation.DecelerateInterpolator
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_main_content.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import xyz.quaver.floatingsearchview.FloatingSearchView
|
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
@@ -52,10 +50,13 @@ import xyz.quaver.hitomi.getGalleryIDsFromNozomi
|
|||||||
import xyz.quaver.hitomi.getSuggestionsForQuery
|
import xyz.quaver.hitomi.getSuggestionsForQuery
|
||||||
import xyz.quaver.pupil.*
|
import xyz.quaver.pupil.*
|
||||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||||
|
import xyz.quaver.pupil.databinding.MainActivityBinding
|
||||||
import xyz.quaver.pupil.services.DownloadService
|
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.ui.view.MainView
|
||||||
|
import xyz.quaver.pupil.ui.view.ProgressCard
|
||||||
import xyz.quaver.pupil.util.ItemClickSupport
|
import xyz.quaver.pupil.util.ItemClickSupport
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
import xyz.quaver.pupil.util.checkUpdate
|
import xyz.quaver.pupil.util.checkUpdate
|
||||||
@@ -63,10 +64,7 @@ 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 xyz.quaver.pupil.util.restore
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.math.abs
|
import kotlin.math.*
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.min
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class MainActivity :
|
class MainActivity :
|
||||||
BaseActivity(),
|
BaseActivity(),
|
||||||
@@ -105,18 +103,20 @@ class MainActivity :
|
|||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
private var currentPage = 0
|
private var currentPage = 0
|
||||||
|
|
||||||
|
private lateinit var binding: MainActivityBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
binding = MainActivityBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
if (intent.action == Intent.ACTION_VIEW) {
|
if (intent.action == Intent.ACTION_VIEW) {
|
||||||
intent.dataString?.let { url ->
|
intent.dataString?.let { url ->
|
||||||
restore(url,
|
restore(url,
|
||||||
onFailure = {
|
onFailure = {
|
||||||
Snackbar.make(this.main_recyclerview, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.contents.recyclerview, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
||||||
}, onSuccess = {
|
}, onSuccess = {
|
||||||
Snackbar.make(this.main_recyclerview, getString(R.string.settings_restore_success, it.size), Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.contents.recyclerview, getString(R.string.settings_restore_success, it.size), Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -127,13 +127,28 @@ class MainActivity :
|
|||||||
|
|
||||||
checkUpdate(this)
|
checkUpdate(this)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||||
|
!Preferences["download_folder_ignore_warning", false] &&
|
||||||
|
ContextCompat.getExternalFilesDirs(this, null).map { Uri.fromFile(it).toString() }
|
||||||
|
.contains(Preferences["download_folder", ""])
|
||||||
|
) {
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.warning)
|
||||||
|
.setMessage(R.string.unaccessible_download_folder)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
DownloadLocationDialogFragment().show(supportFragmentManager, "Download Location Dialog")
|
||||||
|
}.setNegativeButton(R.string.ignore) { _, _ ->
|
||||||
|
Preferences["download_folder_ignore_warning"] = true
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
initView()
|
initView()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
when {
|
when {
|
||||||
main_drawer_layout.isDrawerOpen(GravityCompat.START) -> main_drawer_layout.closeDrawer(GravityCompat.START)
|
binding.drawer.isDrawerOpen(GravityCompat.START) -> binding.drawer.closeDrawer(GravityCompat.START)
|
||||||
queryStack.removeLastOrNull() != null && queryStack.isNotEmpty() -> runOnUiThread {
|
queryStack.removeLastOrNull() != null && queryStack.isNotEmpty() -> runOnUiThread {
|
||||||
query = queryStack.last()
|
query = queryStack.last()
|
||||||
|
|
||||||
@@ -149,7 +164,7 @@ class MainActivity :
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
||||||
(main_recyclerview?.adapter as? GalleryBlockAdapter)?.updateAll = false
|
(binding.contents.recyclerview.adapter as? GalleryBlockAdapter)?.updateAll = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
@@ -190,36 +205,36 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
var prevP1 = 0
|
binding.contents.recyclerview.addOnScrollListener(object: RecyclerView.OnScrollListener() {
|
||||||
main_appbar_layout.addOnOffsetChangedListener(
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
AppBarLayout.OnOffsetChangedListener { _, p1 ->
|
// -height of the search view < translationY < 0
|
||||||
main_searchview.translationY = p1.toFloat()
|
binding.contents.searchview.translationY =
|
||||||
main_recyclerview.scrollBy(0, prevP1 - p1)
|
min(
|
||||||
|
max(
|
||||||
|
binding.contents.searchview.translationY - dy,
|
||||||
|
-binding.contents.searchview.findViewById<CardView>(R.id.search_query_section).height.toFloat()
|
||||||
|
), 0F)
|
||||||
|
|
||||||
with(main_fab) {
|
if (dy > 0)
|
||||||
if (prevP1 > p1)
|
binding.contents.fab.hideMenuButton(true)
|
||||||
hideMenuButton(true)
|
else if (dy < 0)
|
||||||
else if (prevP1 < p1)
|
binding.contents.fab.showMenuButton(true)
|
||||||
showMenuButton(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
prevP1 = p1
|
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
Linkify.addLinks(main_noresult, Pattern.compile(getString(R.string.https_text)), null, null, { _, _ -> getString(R.string.https) })
|
Linkify.addLinks(binding.contents.noresult, Pattern.compile(getString(R.string.https_text)), null, null, { _, _ -> getString(R.string.https) })
|
||||||
|
|
||||||
//NavigationView
|
//NavigationView
|
||||||
main_nav_view.setNavigationItemSelectedListener(this)
|
binding.navView.setNavigationItemSelectedListener(this)
|
||||||
|
|
||||||
with(main_fab_cancel) {
|
with(binding.contents.cancelFab) {
|
||||||
setImageResource(R.drawable.cancel)
|
setImageResource(R.drawable.cancel)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
DownloadService.cancel(this@MainActivity)
|
DownloadService.cancel(this@MainActivity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(main_fab_jump) {
|
with(binding.contents.jumpFab) {
|
||||||
setImageResource(R.drawable.ic_jump)
|
setImageResource(R.drawable.ic_jump)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val perPage = Preferences["per_page", "25"].toInt()
|
val perPage = Preferences["per_page", "25"].toInt()
|
||||||
@@ -247,7 +262,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(main_fab_random) {
|
with(binding.contents.randomFab) {
|
||||||
setImageResource(R.drawable.shuffle_variant)
|
setImageResource(R.drawable.shuffle_variant)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
@@ -277,7 +292,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(main_fab_id) {
|
with(binding.contents.idFab) {
|
||||||
setImageResource(R.drawable.numeric)
|
setImageResource(R.drawable.numeric)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val editText = EditText(context).apply {
|
val editText = EditText(context).apply {
|
||||||
@@ -310,6 +325,44 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with(binding.contents.view) {
|
||||||
|
setOnPageTurnListener(object: MainView.OnPageTurnListener {
|
||||||
|
override fun onPrev(page: Int) {
|
||||||
|
currentPage--
|
||||||
|
|
||||||
|
// disable pageturn until the contents are loaded
|
||||||
|
setCurrentPage(1, false)
|
||||||
|
|
||||||
|
ViewCompat.animate(binding.contents.searchview)
|
||||||
|
.setDuration(100)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.translationY(0F)
|
||||||
|
|
||||||
|
cancelFetch()
|
||||||
|
clearGalleries()
|
||||||
|
fetchGalleries(query, sortMode)
|
||||||
|
loadBlocks()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(page: Int) {
|
||||||
|
currentPage++
|
||||||
|
|
||||||
|
// disable pageturn until the contents are loaded
|
||||||
|
setCurrentPage(1, false)
|
||||||
|
|
||||||
|
ViewCompat.animate(binding.contents.searchview)
|
||||||
|
.setDuration(100)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.translationY(0F)
|
||||||
|
|
||||||
|
cancelFetch()
|
||||||
|
clearGalleries()
|
||||||
|
fetchGalleries(query, sortMode)
|
||||||
|
loadBlocks()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
setupSearchBar()
|
setupSearchBar()
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
fetchGalleries(query, sortMode)
|
fetchGalleries(query, sortMode)
|
||||||
@@ -318,7 +371,7 @@ class MainActivity :
|
|||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
with(main_recyclerview) {
|
with(binding.contents.recyclerview) {
|
||||||
adapter = GalleryBlockAdapter(galleries).apply {
|
adapter = GalleryBlockAdapter(galleries).apply {
|
||||||
onChipClickedHandler.add {
|
onChipClickedHandler.add {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
@@ -359,14 +412,12 @@ class MainActivity :
|
|||||||
loadBlocks()
|
loadBlocks()
|
||||||
}
|
}
|
||||||
|
|
||||||
completeFlag.put(galleryID, false)
|
|
||||||
|
|
||||||
closeAllItems()
|
closeAllItems()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemClickSupport.addTo(this).apply {
|
ItemClickSupport.addTo(this).apply {
|
||||||
onItemClickListener = listener@{ _, position, v ->
|
onItemClickListener = listener@{ _, position, v ->
|
||||||
if (v !is CardView)
|
if (v !is ProgressCard)
|
||||||
return@listener
|
return@listener
|
||||||
|
|
||||||
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
||||||
@@ -377,7 +428,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
onItemLongClickListener = listener@{ _, position, v ->
|
onItemLongClickListener = listener@{ _, position, v ->
|
||||||
if (v !is CardView)
|
if (v !is ProgressCard)
|
||||||
return@listener false
|
return@listener false
|
||||||
|
|
||||||
val galleryID = galleries.getOrNull(position) ?: return@listener true
|
val galleryID = galleries.getOrNull(position) ?: return@listener true
|
||||||
@@ -400,207 +451,6 @@ class MainActivity :
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var origin = 0f
|
|
||||||
var target = -1
|
|
||||||
val perPage = Preferences["per_page", "25"].toInt()
|
|
||||||
setOnTouchListener { _, event ->
|
|
||||||
when(event.action) {
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
origin = 0f
|
|
||||||
|
|
||||||
with(main_recyclerview.adapter as GalleryBlockAdapter) {
|
|
||||||
if(showPrev) {
|
|
||||||
showPrev = false
|
|
||||||
|
|
||||||
val prev = main_recyclerview.layoutManager?.getChildAt(0)
|
|
||||||
|
|
||||||
if (prev is LinearLayout) {
|
|
||||||
val icon = prev.findViewById<ImageView>(R.id.icon_prev)
|
|
||||||
prev.layoutParams.height = 1
|
|
||||||
icon.layoutParams.height = 1
|
|
||||||
icon.rotation = 180f
|
|
||||||
}
|
|
||||||
|
|
||||||
prev?.requestLayout()
|
|
||||||
|
|
||||||
notifyItemRemoved(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(showNext) {
|
|
||||||
showNext = false
|
|
||||||
|
|
||||||
val next = main_recyclerview.layoutManager?.let {
|
|
||||||
getChildAt(childCount-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next is LinearLayout) {
|
|
||||||
val icon = next.findViewById<ImageView>(R.id.icon_next)
|
|
||||||
next.layoutParams.height = 1
|
|
||||||
icon.layoutParams.height = 1
|
|
||||||
icon.rotation = 0f
|
|
||||||
}
|
|
||||||
|
|
||||||
next?.requestLayout()
|
|
||||||
|
|
||||||
notifyItemRemoved(itemCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target != -1) {
|
|
||||||
currentPage = target
|
|
||||||
|
|
||||||
runOnUiThread {
|
|
||||||
cancelFetch()
|
|
||||||
clearGalleries()
|
|
||||||
loadBlocks()
|
|
||||||
}
|
|
||||||
|
|
||||||
target = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_DOWN -> origin = event.y
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
if (origin == 0f)
|
|
||||||
origin = event.y
|
|
||||||
|
|
||||||
val dist = event.y - origin
|
|
||||||
|
|
||||||
when {
|
|
||||||
!canScrollVertically(-1) -> {
|
|
||||||
//TOP
|
|
||||||
|
|
||||||
//Scrolling UP
|
|
||||||
if (dist > 0 && currentPage != 0) {
|
|
||||||
with(main_recyclerview.adapter as GalleryBlockAdapter) {
|
|
||||||
if(!showPrev) {
|
|
||||||
showPrev = true
|
|
||||||
notifyItemInserted(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val prev = main_recyclerview.layoutManager?.getChildAt(0)
|
|
||||||
|
|
||||||
if (prev is LinearLayout) {
|
|
||||||
val icon = prev.findViewById<ImageView>(R.id.icon_prev)
|
|
||||||
val text = prev.findViewById<TextView>(R.id.text_prev).apply {
|
|
||||||
text = getString(R.string.main_move, currentPage)
|
|
||||||
}
|
|
||||||
if (dist < 360) {
|
|
||||||
prev.layoutParams.height = (dist/2).roundToInt()
|
|
||||||
icon.layoutParams.height = (dist/2).roundToInt()
|
|
||||||
icon.rotation = dist+180
|
|
||||||
text.layoutParams.width = dist.roundToInt()
|
|
||||||
|
|
||||||
target = -1
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
prev.layoutParams.height = 180
|
|
||||||
icon.layoutParams.height = 180
|
|
||||||
icon.rotation = 180f
|
|
||||||
text.layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
|
|
||||||
target = currentPage-1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prev?.requestLayout()
|
|
||||||
|
|
||||||
return@setOnTouchListener true
|
|
||||||
} else {
|
|
||||||
with(main_recyclerview.adapter as GalleryBlockAdapter) {
|
|
||||||
if(showPrev) {
|
|
||||||
showPrev = false
|
|
||||||
|
|
||||||
val prev = main_recyclerview.layoutManager?.getChildAt(0)
|
|
||||||
|
|
||||||
if (prev is LinearLayout) {
|
|
||||||
val icon = prev.findViewById<ImageView>(R.id.icon_prev)
|
|
||||||
prev.layoutParams.height = 1
|
|
||||||
icon.layoutParams.height = 1
|
|
||||||
icon.rotation = 180f
|
|
||||||
}
|
|
||||||
|
|
||||||
prev?.requestLayout()
|
|
||||||
|
|
||||||
notifyItemRemoved(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
!canScrollVertically(1) -> {
|
|
||||||
//BOTTOM
|
|
||||||
|
|
||||||
//Scrolling DOWN
|
|
||||||
if (dist < 0 && currentPage != ceil(totalItems.toDouble()/perPage).roundToInt()-1) {
|
|
||||||
with(main_recyclerview.adapter as GalleryBlockAdapter) {
|
|
||||||
if(!showNext) {
|
|
||||||
showNext = true
|
|
||||||
notifyItemInserted(itemCount-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val next = main_recyclerview.layoutManager?.let {
|
|
||||||
getChildAt(childCount-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val absDist = abs(dist)
|
|
||||||
|
|
||||||
if (next is LinearLayout) {
|
|
||||||
val icon = next.findViewById<ImageView>(R.id.icon_next)
|
|
||||||
val text = next.findViewById<TextView>(R.id.text_next).apply {
|
|
||||||
text = getString(R.string.main_move, currentPage+2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (absDist < 360) {
|
|
||||||
next.layoutParams.height = (absDist/2).roundToInt()
|
|
||||||
icon.layoutParams.height = (absDist/2).roundToInt()
|
|
||||||
icon.rotation = -absDist
|
|
||||||
text.layoutParams.width = absDist.roundToInt()
|
|
||||||
|
|
||||||
target = -1
|
|
||||||
} else {
|
|
||||||
next.layoutParams.height = 180
|
|
||||||
icon.layoutParams.height = 180
|
|
||||||
icon.rotation = 0f
|
|
||||||
text.layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
|
|
||||||
target = currentPage+1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next?.requestLayout()
|
|
||||||
|
|
||||||
return@setOnTouchListener true
|
|
||||||
} else {
|
|
||||||
with(main_recyclerview.adapter as GalleryBlockAdapter) {
|
|
||||||
if(showNext) {
|
|
||||||
showNext = false
|
|
||||||
|
|
||||||
val next = main_recyclerview.layoutManager?.let {
|
|
||||||
getChildAt(childCount-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next is LinearLayout) {
|
|
||||||
val icon = next.findViewById<ImageView>(R.id.icon_next)
|
|
||||||
next.layoutParams.height = 1
|
|
||||||
icon.layoutParams.height = 1
|
|
||||||
icon.rotation = 180f
|
|
||||||
}
|
|
||||||
|
|
||||||
next?.requestLayout()
|
|
||||||
|
|
||||||
notifyItemRemoved(itemCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,10 +471,10 @@ class MainActivity :
|
|||||||
|
|
||||||
private var suggestionJob : Job? = null
|
private var suggestionJob : Job? = null
|
||||||
private fun setupSearchBar() {
|
private fun setupSearchBar() {
|
||||||
with(main_searchview as xyz.quaver.pupil.ui.view.FloatingSearchView) {
|
with(binding.contents.searchview) {
|
||||||
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
||||||
override fun onMenuOpened() {
|
override fun onMenuOpened() {
|
||||||
(this@MainActivity.main_recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
|
(binding.contents.recyclerview.adapter as GalleryBlockAdapter).closeAllItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuClosed() {
|
override fun onMenuClosed() {
|
||||||
@@ -708,7 +558,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attachNavigationDrawerToMenuButton(main_drawer_layout)
|
attachNavigationDrawerToMenuButton(binding.drawer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,7 +569,7 @@ class MainActivity :
|
|||||||
val thin = !item.isChecked
|
val thin = !item.isChecked
|
||||||
|
|
||||||
item.isChecked = thin
|
item.isChecked = thin
|
||||||
main_recyclerview.apply {
|
binding.contents.recyclerview.apply {
|
||||||
(adapter as GalleryBlockAdapter).apply {
|
(adapter as GalleryBlockAdapter).apply {
|
||||||
this.thin = thin
|
this.thin = thin
|
||||||
|
|
||||||
@@ -760,7 +610,7 @@ class MainActivity :
|
|||||||
|
|
||||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
main_drawer_layout.closeDrawers()
|
binding.drawer.closeDrawers()
|
||||||
|
|
||||||
when(item.itemId) {
|
when(item.itemId) {
|
||||||
R.id.main_drawer_home -> {
|
R.id.main_drawer_home -> {
|
||||||
@@ -829,19 +679,17 @@ class MainActivity :
|
|||||||
loadingJob?.cancel()
|
loadingJob?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearGalleries() {
|
private fun clearGalleries() = CoroutineScope(Dispatchers.Main).launch {
|
||||||
galleries.clear()
|
galleries.clear()
|
||||||
|
|
||||||
with(main_recyclerview.adapter as GalleryBlockAdapter?) {
|
with(binding.contents.recyclerview.adapter as GalleryBlockAdapter?) {
|
||||||
this ?: return@with
|
this ?: return@with
|
||||||
|
|
||||||
this.completeFlag.clear()
|
|
||||||
this.notifyDataSetChanged()
|
this.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
main_appbar_layout.setExpanded(true)
|
binding.contents.noresult.visibility = View.INVISIBLE
|
||||||
main_noresult.visibility = View.INVISIBLE
|
binding.contents.progressbar.show()
|
||||||
main_progressbar.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchGalleries(query: String, sortMode: SortMode) {
|
private fun fetchGalleries(query: String, sortMode: SortMode) {
|
||||||
@@ -856,7 +704,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (query.isNotEmpty() && mode != Mode.SEARCH) {
|
if (query.isNotEmpty() && mode != Mode.SEARCH) {
|
||||||
Snackbar.make(this@MainActivity.main_recyclerview, R.string.search_all, Snackbar.LENGTH_SHORT).apply {
|
Snackbar.make(binding.contents.recyclerview, R.string.search_all, Snackbar.LENGTH_SHORT).apply {
|
||||||
setAction(android.R.string.ok) {
|
setAction(android.R.string.ok) {
|
||||||
cancelFetch()
|
cancelFetch()
|
||||||
clearGalleries()
|
clearGalleries()
|
||||||
@@ -953,13 +801,17 @@ class MainActivity :
|
|||||||
FirebaseCrashlytics.getInstance().recordException(e)
|
FirebaseCrashlytics.getInstance().recordException(e)
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
main_noresult.visibility = View.VISIBLE
|
binding.contents.noresult.visibility = View.VISIBLE
|
||||||
main_progressbar.hide()
|
binding.contents.progressbar.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
binding.contents.view.setCurrentPage(currentPage + 1, galleryIDs.size > (currentPage+1)*perPage)
|
||||||
|
}
|
||||||
|
|
||||||
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size)).chunked(5).let { chunks ->
|
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size)).chunked(5).let { chunks ->
|
||||||
for (chunk in chunks)
|
for (chunk in chunks)
|
||||||
chunk.map { galleryID ->
|
chunk.map { galleryID ->
|
||||||
@@ -971,10 +823,10 @@ class MainActivity :
|
|||||||
}.forEach {
|
}.forEach {
|
||||||
it.await()?.also {
|
it.await()?.also {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
main_progressbar.hide()
|
binding.contents.progressbar.hide()
|
||||||
|
|
||||||
galleries.add(it)
|
galleries.add(it)
|
||||||
main_recyclerview.adapter!!.notifyItemInserted(galleries.size - 1)
|
binding.contents.recyclerview.adapter!!.notifyItemInserted(galleries.size - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import com.google.mlkit.vision.face.Face
|
import com.google.mlkit.vision.face.Face
|
||||||
import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
||||||
import kotlinx.android.synthetic.main.activity_reader.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_reader.view.*
|
|
||||||
import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
|
||||||
import kotlinx.android.synthetic.main.reader_eye_card.view.*
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -56,6 +52,8 @@ import kotlinx.coroutines.launch
|
|||||||
import xyz.quaver.Code
|
import xyz.quaver.Code
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.adapters.ReaderAdapter
|
import xyz.quaver.pupil.adapters.ReaderAdapter
|
||||||
|
import xyz.quaver.pupil.databinding.NumberpickerDialogBinding
|
||||||
|
import xyz.quaver.pupil.databinding.ReaderActivityBinding
|
||||||
import xyz.quaver.pupil.favorites
|
import xyz.quaver.pupil.favorites
|
||||||
import xyz.quaver.pupil.services.DownloadService
|
import xyz.quaver.pupil.services.DownloadService
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
@@ -75,7 +73,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
|
|
||||||
(reader_recyclerview.adapter as ReaderAdapter).isFullScreen = value
|
(binding.recyclerview.adapter as ReaderAdapter).isFullScreen = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var cache: Cache
|
private lateinit var cache: Cache
|
||||||
@@ -118,9 +116,12 @@ class ReaderActivity : BaseActivity() {
|
|||||||
private var eyeType: Eye? = null
|
private var eyeType: Eye? = null
|
||||||
private var eyeTime: Long = 0L
|
private var eyeTime: Long = 0L
|
||||||
|
|
||||||
|
private lateinit var binding: ReaderActivityBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_reader)
|
binding = ReaderActivityBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
title = getString(R.string.reader_loading)
|
title = getString(R.string.reader_loading)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||||
@@ -178,17 +179,19 @@ class ReaderActivity : BaseActivity() {
|
|||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when(item.itemId) {
|
when(item.itemId) {
|
||||||
R.id.reader_menu_page_indicator -> {
|
R.id.reader_menu_page_indicator -> {
|
||||||
val view = LayoutInflater.from(this).inflate(R.layout.dialog_numberpicker, reader_layout, false)
|
// TODO: Switch to DialogFragment
|
||||||
with(view.dialog_number_picker) {
|
val binding = NumberpickerDialogBinding.inflate(layoutInflater, binding.root, false)
|
||||||
|
|
||||||
|
with(binding.numberPicker) {
|
||||||
minValue = 1
|
minValue = 1
|
||||||
maxValue = cache.metadata.reader?.galleryInfo?.files?.size ?: 0
|
maxValue = cache.metadata.reader?.galleryInfo?.files?.size ?: 0
|
||||||
value = currentPage
|
value = currentPage
|
||||||
}
|
}
|
||||||
val dialog = AlertDialog.Builder(this).apply {
|
val dialog = AlertDialog.Builder(this).apply {
|
||||||
setView(view)
|
setView(binding.root)
|
||||||
}.create()
|
}.create()
|
||||||
view.dialog_ok.setOnClickListener {
|
binding.okButton.setOnClickListener {
|
||||||
(reader_recyclerview.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(view.dialog_number_picker.value-1, 0)
|
(this@ReaderActivity.binding.recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(binding.numberPicker.value-1, 0)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,12 +261,12 @@ class ReaderActivity : BaseActivity() {
|
|||||||
//currentPage is 1-based
|
//currentPage is 1-based
|
||||||
return when(keyCode) {
|
return when(keyCode) {
|
||||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||||
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-2, 0)
|
(binding.recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-2, 0)
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||||
(reader_recyclerview.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(currentPage, 0)
|
(binding.recyclerview.layoutManager as LinearLayoutManager?)?.scrollToPositionWithOffset(currentPage, 0)
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -285,21 +288,21 @@ class ReaderActivity : BaseActivity() {
|
|||||||
if (downloader.progress[galleryID]?.isEmpty() == true) { //Gallery not found
|
if (downloader.progress[galleryID]?.isEmpty() == true) { //Gallery not found
|
||||||
update = false
|
update = false
|
||||||
Snackbar
|
Snackbar
|
||||||
.make(reader_layout, R.string.reader_failed_to_find_gallery, Snackbar.LENGTH_INDEFINITE)
|
.make(binding.root, R.string.reader_failed_to_find_gallery, Snackbar.LENGTH_INDEFINITE)
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
reader_download_progressbar.max = reader_recyclerview.adapter?.itemCount ?: 0
|
binding.downloadProgressbar.max = binding.recyclerview.adapter?.itemCount ?: 0
|
||||||
reader_download_progressbar.progress =
|
binding.downloadProgressbar.progress =
|
||||||
downloader.progress[galleryID]?.count { it.isInfinite() } ?: 0
|
downloader.progress[galleryID]?.count { it.isInfinite() } ?: 0
|
||||||
|
|
||||||
if (title == getString(R.string.reader_loading)) {
|
if (title == getString(R.string.reader_loading)) {
|
||||||
val reader = cache.metadata.reader
|
val reader = cache.metadata.reader
|
||||||
|
|
||||||
if (reader != null) {
|
if (reader != null) {
|
||||||
with(reader_recyclerview.adapter as ReaderAdapter) {
|
with(binding.recyclerview.adapter as ReaderAdapter) {
|
||||||
this.reader = reader
|
this.reader = reader
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -320,7 +323,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (downloader.isCompleted(galleryID)) { //Download finished
|
if (downloader.isCompleted(galleryID)) { //Download finished
|
||||||
reader_download_progressbar.visibility = View.GONE
|
binding.downloadProgressbar.visibility = View.GONE
|
||||||
|
|
||||||
animateDownloadFAB(false)
|
animateDownloadFAB(false)
|
||||||
}
|
}
|
||||||
@@ -329,7 +332,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
with(reader_recyclerview) {
|
with(binding.recyclerview) {
|
||||||
adapter = ReaderAdapter(this@ReaderActivity, galleryID).apply {
|
adapter = ReaderAdapter(this@ReaderActivity, galleryID).apply {
|
||||||
onItemClickListener = {
|
onItemClickListener = {
|
||||||
if (isScroll) {
|
if (isScroll) {
|
||||||
@@ -339,7 +342,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
scrollMode(false)
|
scrollMode(false)
|
||||||
fullscreen(true)
|
fullscreen(true)
|
||||||
} else {
|
} else {
|
||||||
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage, 0) //Moves to next page because currentPage is 1-based indexing
|
(binding.recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage, 0) //Moves to next page because currentPage is 1-based indexing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,9 +352,9 @@ class ReaderActivity : BaseActivity() {
|
|||||||
super.onScrolled(recyclerView, dx, dy)
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
|
||||||
if (dy < 0)
|
if (dy < 0)
|
||||||
this@ReaderActivity.reader_fab.showMenuButton(true)
|
binding.fab.showMenuButton(true)
|
||||||
else if (dy > 0)
|
else if (dy > 0)
|
||||||
this@ReaderActivity.reader_fab.hideMenuButton(true)
|
binding.fab.hideMenuButton(true)
|
||||||
|
|
||||||
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
||||||
|
|
||||||
@@ -363,7 +366,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
with(reader_fab_download) {
|
with(binding.downloadFab) {
|
||||||
animateDownloadFAB(DownloadManager.getInstance(this@ReaderActivity).getDownloadFolder(galleryID) != null) //If download in progress, animate button
|
animateDownloadFAB(DownloadManager.getInstance(this@ReaderActivity).getDownloadFolder(galleryID) != null) //If download in progress, animate button
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
@@ -380,14 +383,14 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(reader_fab_retry) {
|
with(binding.retryFab) {
|
||||||
setImageResource(R.drawable.refresh)
|
setImageResource(R.drawable.refresh)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
DownloadService.download(context, galleryID)
|
DownloadService.download(context, galleryID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(reader_fab_auto) {
|
with(binding.autoFab) {
|
||||||
setImageResource(R.drawable.eye_white)
|
setImageResource(R.drawable.eye_white)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
when {
|
when {
|
||||||
@@ -407,13 +410,13 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(reader_fab_fullscreen) {
|
with(binding.fullscreenFab) {
|
||||||
setImageResource(R.drawable.ic_fullscreen)
|
setImageResource(R.drawable.ic_fullscreen)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
isFullscreen = true
|
isFullscreen = true
|
||||||
fullscreen(isFullscreen)
|
fullscreen(isFullscreen)
|
||||||
|
|
||||||
this@ReaderActivity.reader_fab.close(true)
|
binding.fab.close(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,8 +426,8 @@ class ReaderActivity : BaseActivity() {
|
|||||||
if (isFullscreen) {
|
if (isFullscreen) {
|
||||||
flags = flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
|
flags = flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||||
supportActionBar?.hide()
|
supportActionBar?.hide()
|
||||||
this@ReaderActivity.reader_fab.visibility = View.INVISIBLE
|
binding.fab.visibility = View.INVISIBLE
|
||||||
this@ReaderActivity.scroller.let {
|
binding.scroller.let {
|
||||||
it.handleWidth = resources.getDimensionPixelSize(R.dimen.thumb_height)
|
it.handleWidth = resources.getDimensionPixelSize(R.dimen.thumb_height)
|
||||||
it.handleHeight = resources.getDimensionPixelSize(R.dimen.thumb_width)
|
it.handleHeight = resources.getDimensionPixelSize(R.dimen.thumb_width)
|
||||||
it.handleDrawable = ContextCompat.getDrawable(this@ReaderActivity, R.drawable.thumb_horizontal)
|
it.handleDrawable = ContextCompat.getDrawable(this@ReaderActivity, R.drawable.thumb_horizontal)
|
||||||
@@ -433,8 +436,8 @@ class ReaderActivity : BaseActivity() {
|
|||||||
} else {
|
} else {
|
||||||
flags = flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
|
flags = flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
|
||||||
supportActionBar?.show()
|
supportActionBar?.show()
|
||||||
this@ReaderActivity.reader_fab.visibility = View.VISIBLE
|
binding.fab.visibility = View.VISIBLE
|
||||||
this@ReaderActivity.scroller.let {
|
binding.scroller.let {
|
||||||
it.handleWidth = resources.getDimensionPixelSize(R.dimen.thumb_width)
|
it.handleWidth = resources.getDimensionPixelSize(R.dimen.thumb_width)
|
||||||
it.handleHeight = resources.getDimensionPixelSize(R.dimen.thumb_height)
|
it.handleHeight = resources.getDimensionPixelSize(R.dimen.thumb_height)
|
||||||
it.handleDrawable = ContextCompat.getDrawable(this@ReaderActivity, R.drawable.thumb)
|
it.handleDrawable = ContextCompat.getDrawable(this@ReaderActivity, R.drawable.thumb)
|
||||||
@@ -445,27 +448,27 @@ class ReaderActivity : BaseActivity() {
|
|||||||
window.attributes = this
|
window.attributes = this
|
||||||
}
|
}
|
||||||
|
|
||||||
reader_recyclerview.adapter = reader_recyclerview.adapter // Force to redraw
|
binding.recyclerview.adapter = binding.recyclerview.adapter // Force to redraw
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollMode(isScroll: Boolean) {
|
private fun scrollMode(isScroll: Boolean) {
|
||||||
if (isScroll) {
|
if (isScroll) {
|
||||||
snapHelper.attachToRecyclerView(null)
|
snapHelper.attachToRecyclerView(null)
|
||||||
reader_recyclerview.layoutManager = LinearLayoutManager(this)
|
binding.recyclerview.layoutManager = LinearLayoutManager(this)
|
||||||
} else {
|
} else {
|
||||||
snapHelper.attachToRecyclerView(reader_recyclerview)
|
snapHelper.attachToRecyclerView(binding.recyclerview)
|
||||||
reader_recyclerview.layoutManager = object: LinearLayoutManager(this, HORIZONTAL, Preferences["rtl", false]) {
|
binding.recyclerview.layoutManager = object: LinearLayoutManager(this, HORIZONTAL, Preferences["rtl", false]) {
|
||||||
override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
|
override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
|
||||||
extraLayoutSpace.fill(600)
|
extraLayoutSpace.fill(600)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0)
|
(binding.recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun animateDownloadFAB(animate: Boolean) {
|
private fun animateDownloadFAB(animate: Boolean) {
|
||||||
with(reader_fab_download) {
|
with(binding.downloadFab) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
val icon = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_downloading)
|
val icon = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_downloading)
|
||||||
|
|
||||||
@@ -494,7 +497,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val cameraCallback: (List<Face>) -> Unit = callback@{ faces ->
|
val cameraCallback: (List<Face>) -> Unit = callback@{ faces ->
|
||||||
eye_card.dot.let {
|
binding.eyeCard.dot.let {
|
||||||
it.visibility = View.VISIBLE
|
it.visibility = View.VISIBLE
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
delay(50)
|
delay(50)
|
||||||
@@ -504,9 +507,9 @@ class ReaderActivity : BaseActivity() {
|
|||||||
|
|
||||||
if (faces.size != 1)
|
if (faces.size != 1)
|
||||||
ContextCompat.getDrawable(this, R.drawable.eye_off).let {
|
ContextCompat.getDrawable(this, R.drawable.eye_off).let {
|
||||||
with(eye_card) {
|
with(binding.eyeCard) {
|
||||||
left_eye.setImageDrawable(it)
|
leftEye.setImageDrawable(it)
|
||||||
right_eye.setImageDrawable(it)
|
rightEye.setImageDrawable(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
return@callback
|
return@callback
|
||||||
@@ -517,16 +520,16 @@ class ReaderActivity : BaseActivity() {
|
|||||||
faces[0].leftEyeOpenProbability?.let { it > 0.4 } == true
|
faces[0].leftEyeOpenProbability?.let { it > 0.4 } == true
|
||||||
)
|
)
|
||||||
|
|
||||||
with(eye_card) {
|
with(binding.eyeCard) {
|
||||||
left_eye.setImageDrawable(
|
leftEye.setImageDrawable(
|
||||||
ContextCompat.getDrawable(
|
ContextCompat.getDrawable(
|
||||||
context,
|
leftEye.context,
|
||||||
if (left) R.drawable.eye else R.drawable.eye_closed
|
if (left) R.drawable.eye else R.drawable.eye_closed
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
right_eye.setImageDrawable(
|
rightEye.setImageDrawable(
|
||||||
ContextCompat.getDrawable(
|
ContextCompat.getDrawable(
|
||||||
context,
|
rightEye.context,
|
||||||
if (right) R.drawable.eye else R.drawable.eye_closed
|
if (right) R.drawable.eye else R.drawable.eye_closed
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -553,7 +556,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (eyeType != null && System.currentTimeMillis() - eyeTime > 100) {
|
if (eyeType != null && System.currentTimeMillis() - eyeTime > 100) {
|
||||||
(this@ReaderActivity.reader_recyclerview.layoutManager as LinearLayoutManager).let {
|
(binding.recyclerview.layoutManager as LinearLayoutManager).let {
|
||||||
it.scrollToPositionWithOffset(when(eyeType!!) {
|
it.scrollToPositionWithOffset(when(eyeType!!) {
|
||||||
Eye.RIGHT -> {
|
Eye.RIGHT -> {
|
||||||
if (it.reverseLayout) currentPage - 2 else currentPage
|
if (it.reverseLayout) currentPage - 2 else currentPage
|
||||||
@@ -569,11 +572,11 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleCamera() {
|
private fun toggleCamera() {
|
||||||
val eyes = this@ReaderActivity.eye_card
|
val eyes = binding.eyeCard.root
|
||||||
when (camera) {
|
when (camera) {
|
||||||
null -> {
|
null -> {
|
||||||
reader_fab_auto.labelText = getString(R.string.reader_fab_auto_cancel)
|
binding.autoFab.labelText = getString(R.string.reader_fab_auto_cancel)
|
||||||
reader_fab_auto.setImageResource(R.drawable.eye_off_white)
|
binding.autoFab.setImageResource(R.drawable.eye_off_white)
|
||||||
eyes.apply {
|
eyes.apply {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
TranslateAnimation(0F, 0F, -100F, 0F).apply {
|
TranslateAnimation(0F, 0F, -100F, 0F).apply {
|
||||||
@@ -586,8 +589,8 @@ class ReaderActivity : BaseActivity() {
|
|||||||
cameraEnabled = true
|
cameraEnabled = true
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
reader_fab_auto.labelText = getString(R.string.reader_fab_auto)
|
binding.autoFab.labelText = getString(R.string.reader_fab_auto)
|
||||||
reader_fab_auto.setImageResource(R.drawable.eye_white)
|
binding.autoFab.setImageResource(R.drawable.eye_white)
|
||||||
eyes.apply {
|
eyes.apply {
|
||||||
TranslateAnimation(0F, 0F, 0F, -100F).apply {
|
TranslateAnimation(0F, 0F, 0F, -100F).apply {
|
||||||
duration = 500
|
duration = 500
|
||||||
|
|||||||
@@ -18,30 +18,30 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui.dialog
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import kotlinx.android.synthetic.main.dialog_default_query.*
|
import androidx.fragment.app.DialogFragment
|
||||||
import kotlinx.android.synthetic.main.dialog_default_query.view.*
|
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.DefaultQueryDialogBinding
|
||||||
import xyz.quaver.pupil.types.Tags
|
import xyz.quaver.pupil.types.Tags
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
|
|
||||||
class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
class DefaultQueryDialog : DialogFragment() {
|
||||||
|
|
||||||
private val languages = context.resources.getStringArray(R.array.languages).map {
|
private val languages: Map<String, String> by lazy {
|
||||||
it.split("|").let { split ->
|
requireContext().resources.getStringArray(R.array.languages).map {
|
||||||
Pair(split[0], split[1])
|
it.split("|").let { split ->
|
||||||
}
|
Pair(split[0], split[1])
|
||||||
}.toMap()
|
}
|
||||||
private val reverseLanguages = languages.entries.associate { (k, v) -> v to k }
|
}.toMap()
|
||||||
|
}
|
||||||
|
private val reverseLanguages: Map<String, String> by lazy {
|
||||||
|
languages.entries.associate { (k, v) -> v to k }
|
||||||
|
}
|
||||||
|
|
||||||
private val excludeBL = "-male:yaoi"
|
private val excludeBL = "-male:yaoi"
|
||||||
private val excludeGuro = listOf("-female:guro", "-male:guro")
|
private val excludeGuro = listOf("-female:guro", "-male:guro")
|
||||||
@@ -49,46 +49,15 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
|||||||
|
|
||||||
var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null
|
var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
private var _binding: DefaultQueryDialogBinding? = null
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
private val binding get() = _binding!!
|
||||||
setTitle(R.string.default_query_dialog_title)
|
|
||||||
setView(build())
|
|
||||||
setButton(Dialog.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ ->
|
|
||||||
val newTags = Tags.parse(default_query_dialog_edittext.text.toString())
|
|
||||||
|
|
||||||
with(default_query_dialog_language_selector) {
|
private fun initView() {
|
||||||
if (selectedItemPosition != 0)
|
|
||||||
newTags.add("language:${reverseLanguages[selectedItem]}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (default_query_dialog_BL_checkbox.isChecked)
|
|
||||||
newTags.add(excludeBL)
|
|
||||||
|
|
||||||
if (default_query_dialog_guro_checkbox.isChecked)
|
|
||||||
excludeGuro.forEach { tag ->
|
|
||||||
newTags.add(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (default_query_dialog_loli_checkbox.isChecked)
|
|
||||||
excludeLoli.forEach { tag ->
|
|
||||||
newTags.add(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
onPositiveButtonClickListener?.invoke(newTags)
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
|
||||||
private fun build() : View {
|
|
||||||
val tags = Tags.parse(
|
val tags = Tags.parse(
|
||||||
Preferences["default_query"]
|
Preferences["default_query"]
|
||||||
)
|
)
|
||||||
|
|
||||||
val view = LayoutInflater.from(context).inflate(R.layout.dialog_default_query, null)
|
with(binding.languageSelector) {
|
||||||
|
|
||||||
with(view.default_query_dialog_language_selector) {
|
|
||||||
adapter =
|
adapter =
|
||||||
ArrayAdapter(
|
ArrayAdapter(
|
||||||
context,
|
context,
|
||||||
@@ -111,13 +80,13 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.default_query_dialog_BL_checkbox) {
|
with(binding.BLCheckbox) {
|
||||||
isChecked = tags.contains(excludeBL)
|
isChecked = tags.contains(excludeBL)
|
||||||
if (tags.contains(excludeBL))
|
if (tags.contains(excludeBL))
|
||||||
tags.remove(excludeBL)
|
tags.remove(excludeBL)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.default_query_dialog_guro_checkbox) {
|
with(binding.guroCheckbox) {
|
||||||
isChecked = excludeGuro.all { tags.contains(it) }
|
isChecked = excludeGuro.all { tags.contains(it) }
|
||||||
if (excludeGuro.all { tags.contains(it) })
|
if (excludeGuro.all { tags.contains(it) })
|
||||||
excludeGuro.forEach {
|
excludeGuro.forEach {
|
||||||
@@ -125,7 +94,7 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.default_query_dialog_loli_checkbox) {
|
with(binding.loliCheckbox) {
|
||||||
isChecked = excludeLoli.all { tags.contains(it) }
|
isChecked = excludeLoli.all { tags.contains(it) }
|
||||||
if (excludeLoli.all { tags.contains(it) })
|
if (excludeLoli.all { tags.contains(it) })
|
||||||
excludeLoli.forEach {
|
excludeLoli.forEach {
|
||||||
@@ -133,7 +102,7 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.default_query_dialog_edittext) {
|
with(binding.edittext) {
|
||||||
setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE)
|
setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE)
|
||||||
addTextChangedListener(object : TextWatcher {
|
addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(
|
override fun beforeTextChanged(
|
||||||
@@ -158,8 +127,45 @@ class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return view
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
_binding = DefaultQueryDialogBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
initView()
|
||||||
|
|
||||||
|
return AlertDialog.Builder(requireContext()).apply {
|
||||||
|
setTitle(R.string.default_query_dialog_title)
|
||||||
|
setView(binding.root)
|
||||||
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
val newTags = Tags.parse(binding.edittext.text.toString())
|
||||||
|
|
||||||
|
with(binding.languageSelector) {
|
||||||
|
if (selectedItemPosition != 0)
|
||||||
|
newTags.add("language:${reverseLanguages[selectedItem]}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding.BLCheckbox.isChecked)
|
||||||
|
newTags.add(excludeBL)
|
||||||
|
|
||||||
|
if (binding.guroCheckbox.isChecked)
|
||||||
|
excludeGuro.forEach { tag ->
|
||||||
|
newTags.add(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding.loliCheckbox.isChecked)
|
||||||
|
excludeLoli.forEach { tag ->
|
||||||
|
newTags.add(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositiveButtonClickListener?.invoke(newTags)
|
||||||
|
}
|
||||||
|
}.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,17 +18,15 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui.dialog
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
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.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.DownloadFolderNameDialogBinding
|
||||||
import xyz.quaver.pupil.util.Preferences
|
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.formatDownloadFolder
|
import xyz.quaver.pupil.util.formatDownloadFolder
|
||||||
@@ -37,38 +35,48 @@ import xyz.quaver.pupil.util.formatMap
|
|||||||
|
|
||||||
class DownloadFolderNameDialogFragment : DialogFragment() {
|
class DownloadFolderNameDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
private var _binding: DownloadFolderNameDialogBinding? = null
|
||||||
private fun build(): View {
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
_binding = DownloadFolderNameDialogBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
initView()
|
||||||
|
|
||||||
|
return Dialog(requireContext()).apply {
|
||||||
|
setContentView(binding.root)
|
||||||
|
window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
val galleryID = Cache.instances.let { if (it.size == 0) 1199708 else it.keys.elementAt((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()
|
||||||
}
|
}
|
||||||
|
|
||||||
return layoutInflater.inflate(R.layout.dialog_download_folder_name, null).apply {
|
binding.message.text = getString(R.string.settings_download_folder_name_message, formatMap.keys.toString(), galleryBlock?.formatDownloadFolder() ?: "")
|
||||||
message.text = getString(R.string.settings_download_folder_name_message, formatMap.keys.toString(), galleryBlock?.formatDownloadFolder() ?: "")
|
binding.edittext.setText(Preferences["download_folder_name", "[-id-] -title-"])
|
||||||
edittext.setText(Preferences["download_folder_name", "[-id-] -title-"])
|
binding.edittext.addTextChangedListener {
|
||||||
edittext.addTextChangedListener {
|
binding.message.text = requireContext().getString(R.string.settings_download_folder_name_message, formatMap.keys.toString(), galleryBlock?.formatDownloadFolderTest(it.toString()) ?: "")
|
||||||
message.text = getString(R.string.settings_download_folder_name_message, formatMap.keys.toString(), galleryBlock?.formatDownloadFolderTest(it.toString()) ?: "")
|
}
|
||||||
|
binding.okButton.setOnClickListener {
|
||||||
|
val newValue = binding.edittext.text.toString()
|
||||||
|
|
||||||
|
if ((newValue as? String)?.contains("/") != false) {
|
||||||
|
Snackbar.make(binding.root, R.string.settings_invalid_download_folder_name, Snackbar.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
ok_button.setOnClickListener {
|
|
||||||
val newValue = edittext.text.toString()
|
|
||||||
|
|
||||||
if ((newValue as? String)?.contains("/") != false) {
|
Preferences["download_folder_name"] = binding.edittext.text.toString()
|
||||||
Snackbar.make(this, R.string.settings_invalid_download_folder_name, Snackbar.LENGTH_SHORT).show()
|
|
||||||
return@setOnClickListener
|
|
||||||
}
|
|
||||||
|
|
||||||
Preferences["download_folder_name"] = edittext.text.toString()
|
dismiss()
|
||||||
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
|
|
||||||
Dialog(requireContext()).apply {
|
|
||||||
setContentView(build())
|
|
||||||
window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,27 +18,24 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui.dialog
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
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 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.io.util.toFile
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.DownloadLocationDialogBinding
|
||||||
|
import xyz.quaver.pupil.databinding.DownloadLocationItemBinding
|
||||||
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
|
||||||
@@ -46,24 +43,25 @@ import xyz.quaver.pupil.util.migrate
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class DownloadLocationDialogFragment : DialogFragment() {
|
class DownloadLocationDialogFragment : DialogFragment() {
|
||||||
private val entries = mutableMapOf<File?, View>()
|
|
||||||
|
private var _binding: DownloadLocationDialogBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private val entries = mutableMapOf<File?, DownloadLocationItemBinding>()
|
||||||
|
|
||||||
private val requestDownloadFolderLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
private val requestDownloadFolderLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
val activity = activity ?: return@registerForActivityResult
|
|
||||||
val context = context ?: return@registerForActivityResult
|
val context = context ?: return@registerForActivityResult
|
||||||
val dialog = dialog ?: return@registerForActivityResult
|
val dialog = dialog ?: return@registerForActivityResult
|
||||||
|
|
||||||
it.data?.data?.also { uri ->
|
it.data?.data?.also { uri ->
|
||||||
val takeFlags: Int =
|
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
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)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||||
context.contentResolver.takePersistableUriPermission(uri, takeFlags)
|
context.contentResolver.takePersistableUriPermission(uri, takeFlags)
|
||||||
|
|
||||||
if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) {
|
if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) {
|
||||||
entries[null]?.location_available?.text = uri.toFile(context)?.canonicalPath
|
entries[null]?.locationAvailable?.text = uri.toFile(context)?.canonicalPath
|
||||||
Preferences["download_folder"] = uri.toString()
|
Preferences["download_folder"] = uri.toString()
|
||||||
} else {
|
} else {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
@@ -75,7 +73,7 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
|||||||
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
||||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||||
entries[key]!!.button.isChecked = true
|
entries[key]!!.button.isChecked = true
|
||||||
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
if (key == null) entries[key]!!.locationAvailable.text = downloadFolder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,49 +96,44 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
|||||||
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
||||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||||
entries[key]!!.button.isChecked = true
|
entries[key]!!.button.isChecked = true
|
||||||
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
if (key == null) entries[key]!!.locationAvailable.text = downloadFolder
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entries[null]?.location_available?.text = directory
|
entries[null]?.locationAvailable?.text = directory
|
||||||
Preferences["download_folder"] = File(directory).toURI().toString()
|
Preferences["download_folder"] = File(directory).toURI().toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
private fun initView() {
|
||||||
private fun build() : View? {
|
val externalFilesDirs = ContextCompat.getExternalFilesDirs(requireContext(), null)
|
||||||
val context = context ?: return null
|
|
||||||
|
|
||||||
val view = layoutInflater.inflate(R.layout.dialog_download_folder, null) as LinearLayout
|
|
||||||
|
|
||||||
val externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null)
|
|
||||||
|
|
||||||
externalFilesDirs.forEachIndexed { index, dir ->
|
externalFilesDirs.forEachIndexed { index, dir ->
|
||||||
dir ?: return@forEachIndexed
|
dir ?: return@forEachIndexed
|
||||||
|
|
||||||
view.addView(layoutInflater.inflate(R.layout.item_download_folder, view, false).apply {
|
DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply {
|
||||||
location_type.text = context.getString(when (index) {
|
locationType.text = requireContext().getString(when (index) {
|
||||||
0 -> R.string.settings_download_folder_internal
|
0 -> R.string.settings_download_folder_internal
|
||||||
else -> R.string.settings_download_folder_removable
|
else -> R.string.settings_download_folder_removable
|
||||||
})
|
})
|
||||||
location_available.text = context.getString(
|
locationAvailable.text = requireContext().getString(
|
||||||
R.string.settings_download_folder_available,
|
R.string.settings_download_folder_available,
|
||||||
byteToString(dir.freeSpace)
|
byteToString(dir.freeSpace)
|
||||||
)
|
)
|
||||||
setOnClickListener {
|
root.setOnClickListener {
|
||||||
entries.values.forEach {
|
entries.values.forEach { _ ->
|
||||||
it.button.isChecked = false
|
button.isChecked = false
|
||||||
}
|
}
|
||||||
button.performClick()
|
button.performClick()
|
||||||
Preferences["download_folder"] = dir.toUri().toString()
|
Preferences["download_folder"] = dir.toUri().toString()
|
||||||
}
|
}
|
||||||
entries[dir] = this
|
entries[dir] = this
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view.addView(layoutInflater.inflate(R.layout.item_download_folder, view, false).apply {
|
DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply {
|
||||||
location_type.text = context.getString(R.string.settings_download_folder_custom)
|
locationType.text = requireContext().getString(R.string.settings_download_folder_custom)
|
||||||
setOnClickListener {
|
root.setOnClickListener {
|
||||||
entries.values.forEach {
|
entries.values.forEach {
|
||||||
it.button.isChecked = false
|
it.button.isChecked = false
|
||||||
}
|
}
|
||||||
@@ -166,31 +159,35 @@ class DownloadLocationDialogFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries[null] = this
|
entries[null] = this
|
||||||
})
|
}
|
||||||
|
|
||||||
val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath
|
val downloadFolder = DownloadManager.getInstance(requireContext()).downloadFolder.canonicalPath
|
||||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||||
entries[key]!!.button.isChecked = true
|
entries[key]!!.button.isChecked = true
|
||||||
if (key == null) entries[key]!!.location_available.text = downloadFolder
|
if (key == null) entries[key]!!.locationAvailable.text = downloadFolder
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val builder = AlertDialog.Builder(requireContext())
|
_binding = DownloadLocationDialogBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
builder
|
initView()
|
||||||
.setTitle(R.string.settings_download_folder)
|
|
||||||
.setView(build())
|
return AlertDialog.Builder(requireContext()).apply {
|
||||||
.setPositiveButton(requireContext().getText(android.R.string.ok)) { _, _ ->
|
setTitle(R.string.settings_download_folder)
|
||||||
|
setView(binding.root)
|
||||||
|
setPositiveButton(requireContext().getText(android.R.string.ok)) { _, _ ->
|
||||||
if (Preferences["download_folder", ""].isEmpty())
|
if (Preferences["download_folder", ""].isEmpty())
|
||||||
Preferences["download_folder"] = context?.getExternalFilesDir(null)?.toUri()?.toString() ?: ""
|
Preferences["download_folder"] = context.getExternalFilesDir(null)?.toUri()?.toString() ?: ""
|
||||||
|
|
||||||
DownloadManager.getInstance(requireContext()).migrate()
|
DownloadManager.getInstance(requireContext()).migrate()
|
||||||
}
|
}
|
||||||
|
|
||||||
isCancelable = false
|
isCancelable = false
|
||||||
|
}.create()
|
||||||
|
}
|
||||||
|
|
||||||
return builder.create()
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
_binding = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,6 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout.LayoutParams
|
import android.widget.LinearLayout.LayoutParams
|
||||||
@@ -32,10 +31,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.dialog_gallery.*
|
|
||||||
import kotlinx.android.synthetic.main.dialog_gallery_details.view.*
|
|
||||||
import kotlinx.android.synthetic.main.dialog_gallery_dotindicator.view.*
|
|
||||||
import kotlinx.android.synthetic.main.item_gallery_details.view.*
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -45,8 +40,8 @@ import xyz.quaver.hitomi.getGallery
|
|||||||
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.databinding.*
|
||||||
import xyz.quaver.pupil.favoriteTags
|
import xyz.quaver.pupil.favoriteTags
|
||||||
import xyz.quaver.pupil.histories
|
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
import xyz.quaver.pupil.ui.view.TagChip
|
import xyz.quaver.pupil.ui.view.TagChip
|
||||||
@@ -60,9 +55,12 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
|
|
||||||
val onChipClickedHandler = ArrayList<((Tag) -> (Unit))>()
|
val onChipClickedHandler = ArrayList<((Tag) -> (Unit))>()
|
||||||
|
|
||||||
|
private lateinit var binding: GalleryDialogBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.dialog_gallery)
|
binding = GalleryDialogBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
window?.attributes.apply {
|
window?.attributes.apply {
|
||||||
this ?: return@apply
|
this ?: return@apply
|
||||||
@@ -71,7 +69,7 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
height = LayoutParams.MATCH_PARENT
|
height = LayoutParams.MATCH_PARENT
|
||||||
}
|
}
|
||||||
|
|
||||||
with(gallery_fab) {
|
with(binding.fab) {
|
||||||
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right))
|
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right))
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
||||||
@@ -84,12 +82,12 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
try {
|
try {
|
||||||
val gallery = getGallery(galleryID)
|
val gallery = getGallery(galleryID)
|
||||||
|
|
||||||
gallery_cover.post {
|
launch (Dispatchers.Main) {
|
||||||
gallery_progressbar.visibility = View.GONE
|
binding.progressbar.visibility = View.GONE
|
||||||
gallery_title.text = gallery.title
|
binding.title.text = gallery.title
|
||||||
gallery_artist.text = gallery.artists.joinToString(", ") { it.wordCapitalize() }
|
binding.artist.text = gallery.artists.joinToString(", ") { it.wordCapitalize() }
|
||||||
|
|
||||||
with(gallery_type) {
|
with(binding.type) {
|
||||||
text = gallery.type.wordCapitalize()
|
text = gallery.type.wordCapitalize()
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
gallery.type.let {
|
gallery.type.let {
|
||||||
@@ -106,14 +104,14 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gallery_cover.showImage(Uri.parse(gallery.cover))
|
binding.cover.showImage(Uri.parse(gallery.cover))
|
||||||
|
|
||||||
addDetails(gallery)
|
addDetails(gallery)
|
||||||
addThumbnails(gallery)
|
addThumbnails(gallery)
|
||||||
addRelated(gallery)
|
addRelated(gallery)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Snackbar.make(gallery_layout, R.string.unable_to_connect, Snackbar.LENGTH_INDEFINITE).apply {
|
Snackbar.make(binding.root, R.string.unable_to_connect, Snackbar.LENGTH_INDEFINITE).apply {
|
||||||
if (Locale.getDefault().language == "ko")
|
if (Locale.getDefault().language == "ko")
|
||||||
setAction(context.getText(R.string.https_text)) {
|
setAction(context.getText(R.string.https_text)) {
|
||||||
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.https))))
|
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.https))))
|
||||||
@@ -124,10 +122,8 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addDetails(gallery: Gallery) {
|
private fun addDetails(gallery: Gallery) {
|
||||||
val inflater = LayoutInflater.from(context)
|
GalleryDialogDetailsBinding.inflate(layoutInflater, binding.contents, true).apply {
|
||||||
|
type.setText(R.string.gallery_details)
|
||||||
inflater.inflate(R.layout.dialog_gallery_details, gallery_contents, false).apply {
|
|
||||||
gallery_details.setText(R.string.gallery_details)
|
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
R.string.gallery_artists,
|
R.string.gallery_artists,
|
||||||
@@ -164,13 +160,13 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
).filter {
|
).filter {
|
||||||
(_, content) -> content.isNotEmpty()
|
(_, content) -> content.isNotEmpty()
|
||||||
}.forEach { (title, content) ->
|
}.forEach { (title, content) ->
|
||||||
inflater.inflate(R.layout.item_gallery_details, gallery_details_contents, false).apply {
|
GalleryDialogTagsBinding.inflate(layoutInflater, contents, true).apply {
|
||||||
gallery_details_type.setText(title)
|
type.setText(title)
|
||||||
|
|
||||||
content.forEach { tag ->
|
content.forEach { tag ->
|
||||||
gallery_details_tags.addView(
|
tags.addView(
|
||||||
TagChip(context, tag).apply {
|
TagChip(context, tag).apply {
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
onChipClickedHandler.forEach { handler ->
|
onChipClickedHandler.forEach { handler ->
|
||||||
@@ -180,42 +176,34 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.let {
|
|
||||||
gallery_details_contents.addView(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.let {
|
|
||||||
gallery_contents.addView(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addThumbnails(gallery: Gallery) {
|
private fun addThumbnails(gallery: Gallery) {
|
||||||
val inflater = LayoutInflater.from(context)
|
GalleryDialogDetailsBinding.inflate(layoutInflater, binding.contents, true).apply {
|
||||||
|
type.setText(R.string.gallery_thumbnails)
|
||||||
inflater.inflate(R.layout.dialog_gallery_details, gallery_contents, false).apply {
|
|
||||||
gallery_details.setText(R.string.gallery_thumbnails)
|
|
||||||
|
|
||||||
val pager = ViewPager2(context).apply {
|
val pager = ViewPager2(context).apply {
|
||||||
adapter = ThumbnailPageAdapter(gallery.thumbnails)
|
adapter = ThumbnailPageAdapter(gallery.thumbnails)
|
||||||
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
gallery_details_contents.addView(
|
contents.addView(
|
||||||
pager,
|
pager,
|
||||||
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
||||||
)
|
)
|
||||||
|
|
||||||
LayoutInflater.from(context).inflate(R.layout.dialog_gallery_dotindicator, gallery_details_contents)
|
// TODO: Change to direct allocation
|
||||||
|
GalleryDialogDotindicatorBinding.inflate(layoutInflater, contents, true).apply {
|
||||||
gallery_dotindicator.setViewPager2(pager)
|
dotindicator.setViewPager2(pager)
|
||||||
}.let {
|
}
|
||||||
gallery_contents.addView(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addRelated(gallery: Gallery) {
|
private fun addRelated(gallery: Gallery) {
|
||||||
val inflater = LayoutInflater.from(context)
|
val galleries = mutableListOf<Int>()
|
||||||
val galleries = ArrayList<Int>()
|
|
||||||
|
|
||||||
val adapter = GalleryBlockAdapter(galleries).apply {
|
val adapter = GalleryBlockAdapter(galleries).apply {
|
||||||
onChipClickedHandler.add { tag ->
|
onChipClickedHandler.add { tag ->
|
||||||
@@ -225,10 +213,10 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inflater.inflate(R.layout.dialog_gallery_details, gallery_contents, false).apply {
|
GalleryDialogDetailsBinding.inflate(layoutInflater, binding.contents, true).apply {
|
||||||
gallery_details.setText(R.string.gallery_related)
|
type.setText(R.string.gallery_related)
|
||||||
|
|
||||||
RecyclerView(context).apply {
|
contents.addView(RecyclerView(context).apply {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
this.adapter = adapter
|
this.adapter = adapter
|
||||||
|
|
||||||
@@ -248,22 +236,18 @@ class GalleryDialog(context: Context, private val galleryID: Int) : AlertDialog(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.let {
|
})
|
||||||
gallery_details_contents.addView(it, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))
|
|
||||||
}
|
|
||||||
}.let {
|
|
||||||
gallery_contents.addView(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
gallery.related.forEach { galleryID ->
|
gallery.related.forEach { galleryID ->
|
||||||
Cache.getInstance(context, galleryID).getGalleryBlock()?.let {
|
Cache.getInstance(context, galleryID).getGalleryBlock()?.let {
|
||||||
galleries.add(galleryID)
|
galleries.add(galleryID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
adapter.notifyDataSetChanged()
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,23 +18,19 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui.dialog
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import kotlinx.android.synthetic.main.dialog_proxy.view.*
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.client
|
import xyz.quaver.pupil.client
|
||||||
import xyz.quaver.pupil.clientBuilder
|
import xyz.quaver.pupil.clientBuilder
|
||||||
import xyz.quaver.pupil.clientHolder
|
import xyz.quaver.pupil.clientHolder
|
||||||
|
import xyz.quaver.pupil.databinding.ProxyDialogBinding
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
import xyz.quaver.pupil.util.ProxyInfo
|
import xyz.quaver.pupil.util.ProxyInfo
|
||||||
import xyz.quaver.pupil.util.getProxyInfo
|
import xyz.quaver.pupil.util.getProxyInfo
|
||||||
@@ -43,33 +39,35 @@ import java.net.Proxy
|
|||||||
|
|
||||||
class ProxyDialog(context: Context) : AlertDialog(context) {
|
class ProxyDialog(context: Context) : AlertDialog(context) {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
private lateinit var binding: ProxyDialogBinding
|
||||||
setView(build())
|
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
binding = ProxyDialogBinding.inflate(layoutInflater)
|
||||||
|
setView(binding.root)
|
||||||
|
|
||||||
|
initView()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
private fun initView() {
|
||||||
private fun build() : View {
|
|
||||||
val proxyInfo = getProxyInfo()
|
val proxyInfo = getProxyInfo()
|
||||||
|
|
||||||
val view = LayoutInflater.from(context).inflate(R.layout.dialog_proxy, null)
|
|
||||||
|
|
||||||
val enabler = { enable: Boolean ->
|
val enabler = { enable: Boolean ->
|
||||||
view?.proxy_addr?.isEnabled = enable
|
binding.addr.isEnabled = enable
|
||||||
view?.proxy_port?.isEnabled = enable
|
binding.port.isEnabled = enable
|
||||||
view?.proxy_username?.isEnabled = enable
|
binding.username.isEnabled = enable
|
||||||
view?.proxy_password?.isEnabled = enable
|
binding.password.isEnabled = enable
|
||||||
|
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
view?.proxy_addr?.text = null
|
binding.addr.text = null
|
||||||
view?.proxy_port?.text = null
|
binding.port.text = null
|
||||||
view?.proxy_username?.text = null
|
binding.username.text = null
|
||||||
view?.proxy_password?.text = null
|
binding.password.text = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(view.proxy_type_selector) {
|
with(binding.typeSelector) {
|
||||||
adapter = ArrayAdapter(
|
adapter = ArrayAdapter(
|
||||||
context,
|
context,
|
||||||
android.R.layout.simple_spinner_dropdown_item,
|
android.R.layout.simple_spinner_dropdown_item,
|
||||||
@@ -87,29 +85,29 @@ class ProxyDialog(context: Context) : AlertDialog(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view.proxy_addr.setText(proxyInfo.host)
|
binding.addr.setText(proxyInfo.host)
|
||||||
view.proxy_port.setText(proxyInfo.port?.toString())
|
binding.port.setText(proxyInfo.port?.toString())
|
||||||
view.proxy_username.setText(proxyInfo.username)
|
binding.username.setText(proxyInfo.username)
|
||||||
view.proxy_password.setText(proxyInfo.password)
|
binding.password.setText(proxyInfo.password)
|
||||||
|
|
||||||
enabler.invoke(proxyInfo.type != Proxy.Type.DIRECT)
|
enabler.invoke(proxyInfo.type != Proxy.Type.DIRECT)
|
||||||
|
|
||||||
view.proxy_cancel.setOnClickListener {
|
binding.cancelButton.setOnClickListener {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.proxy_ok.setOnClickListener {
|
binding.okButton.setOnClickListener {
|
||||||
val type = Proxy.Type.values()[view.proxy_type_selector.selectedItemPosition]
|
val type = Proxy.Type.values()[binding.typeSelector.selectedItemPosition]
|
||||||
val addr = view.proxy_addr.text?.toString()
|
val addr = binding.addr.text?.toString()
|
||||||
val port = view.proxy_port.text?.toString()?.toIntOrNull()
|
val port = binding.port.text?.toString()?.toIntOrNull()
|
||||||
val username = view.proxy_username.text?.toString()
|
val username = binding.username.text?.toString()
|
||||||
val password = view.proxy_password.text?.toString()
|
val password = binding.password.text?.toString()
|
||||||
|
|
||||||
if (type != Proxy.Type.DIRECT) {
|
if (type != Proxy.Type.DIRECT) {
|
||||||
if (addr == null || addr.isEmpty())
|
if (addr == null || addr.isEmpty())
|
||||||
view.proxy_addr.error = context.getText(R.string.proxy_dialog_error)
|
binding.addr.error = context.getText(R.string.proxy_dialog_error)
|
||||||
if (port == null)
|
if (port == null)
|
||||||
view.proxy_port.error = context.getText(R.string.proxy_dialog_error)
|
binding.port.error = context.getText(R.string.proxy_dialog_error)
|
||||||
|
|
||||||
if (addr == null || addr.isEmpty() || port == null)
|
if (addr == null || addr.isEmpty() || port == null)
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
@@ -126,8 +124,6 @@ class ProxyDialog(context: Context) : AlertDialog(context) {
|
|||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,12 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dir.exists())
|
if (dir.exists())
|
||||||
dir.listFiles()?.forEach { (it as? FileX)?.deleteRecursively() }
|
dir.listFiles()?.forEach {
|
||||||
|
when (it) {
|
||||||
|
is FileX -> it.deleteRecursively()
|
||||||
|
else -> it.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
job = launch {
|
job = launch {
|
||||||
var size = 0L
|
var size = 0L
|
||||||
|
|||||||
@@ -24,30 +24,34 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.andrognito.pinlockview.PinLockListener
|
import com.andrognito.pinlockview.PinLockListener
|
||||||
import kotlinx.android.synthetic.main.fragment_pin_lock.view.*
|
import xyz.quaver.pupil.databinding.PinLockFragmentBinding
|
||||||
import xyz.quaver.pupil.R
|
|
||||||
|
|
||||||
class PINLockFragment : Fragment(), PinLockListener {
|
class PINLockFragment : Fragment() {
|
||||||
|
|
||||||
|
private var _binding: PinLockFragmentBinding? = null
|
||||||
|
val binding get() = _binding!!
|
||||||
|
|
||||||
var onPINEntered: ((String) -> Unit)? = null
|
var onPINEntered: ((String) -> Unit)? = null
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
return inflater.inflate(R.layout.fragment_pin_lock, container, false).apply {
|
_binding = PinLockFragmentBinding.inflate(inflater, container, false)
|
||||||
pin_lock_view.attachIndicatorDots(indicator_dots)
|
|
||||||
pin_lock_view.setPinLockListener(this@PINLockFragment)
|
binding.pinLockView.attachIndicatorDots(binding.indicatorDots)
|
||||||
}
|
binding.pinLockView.setPinLockListener(object: PinLockListener {
|
||||||
|
override fun onComplete(p0: String?) {
|
||||||
|
onPINEntered?.invoke(p0 ?: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEmpty() {}
|
||||||
|
override fun onPinChange(p0: Int, p1: String?) {}
|
||||||
|
})
|
||||||
|
|
||||||
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onComplete(pin: String?) {
|
override fun onDestroy() {
|
||||||
onPINEntered?.invoke(pin!!)
|
super.onDestroy()
|
||||||
}
|
_binding = null
|
||||||
|
|
||||||
override fun onEmpty() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPinChange(pinLength: Int, intermediatePin: String?) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -26,38 +26,36 @@ import androidx.fragment.app.Fragment
|
|||||||
import com.andrognito.patternlockview.PatternLockView
|
import com.andrognito.patternlockview.PatternLockView
|
||||||
import com.andrognito.patternlockview.listener.PatternLockViewListener
|
import com.andrognito.patternlockview.listener.PatternLockViewListener
|
||||||
import com.andrognito.patternlockview.utils.PatternLockUtils
|
import com.andrognito.patternlockview.utils.PatternLockUtils
|
||||||
import kotlinx.android.synthetic.main.fragment_pattern_lock.*
|
import xyz.quaver.pupil.databinding.PatternLockFragmentBinding
|
||||||
import kotlinx.android.synthetic.main.fragment_pattern_lock.view.*
|
|
||||||
import xyz.quaver.pupil.R
|
|
||||||
|
|
||||||
class PatternLockFragment : Fragment(), PatternLockViewListener {
|
class PatternLockFragment : Fragment() {
|
||||||
|
|
||||||
|
private var _binding: PatternLockFragmentBinding? = null
|
||||||
|
val binding get() = _binding!!
|
||||||
|
|
||||||
var onPatternDrawn: ((String) -> Unit)? = null
|
var onPatternDrawn: ((String) -> Unit)? = null
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View {
|
||||||
return inflater.inflate(R.layout.fragment_pattern_lock, container, false).apply {
|
_binding = PatternLockFragmentBinding.inflate(inflater, container, false)
|
||||||
lock_pattern_view.addPatternLockListener(this@PatternLockFragment)
|
binding.patternLockView.addPatternLockListener(object: PatternLockViewListener {
|
||||||
}
|
override fun onComplete(pattern: MutableList<PatternLockView.Dot>?) {
|
||||||
|
val password = PatternLockUtils.patternToMD5(binding.patternLockView, pattern)
|
||||||
|
onPatternDrawn?.invoke(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {}
|
||||||
|
override fun onProgress(progressPattern: MutableList<PatternLockView.Dot>?) {}
|
||||||
|
override fun onStarted() {}
|
||||||
|
})
|
||||||
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
}
|
_binding = null
|
||||||
|
|
||||||
override fun onComplete(pattern: MutableList<PatternLockView.Dot>?) {
|
|
||||||
val password = PatternLockUtils.patternToMD5(lock_pattern_view, pattern)
|
|
||||||
onPatternDrawn?.invoke(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onProgress(progressPattern: MutableList<PatternLockView.Dot>?) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStarted() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ class SettingsFragment :
|
|||||||
DownloadLocationDialogFragment().show(parentFragmentManager, "Download Location Dialog")
|
DownloadLocationDialogFragment().show(parentFragmentManager, "Download Location Dialog")
|
||||||
}
|
}
|
||||||
"default_query" -> {
|
"default_query" -> {
|
||||||
DefaultQueryDialog(requireContext()).apply {
|
DefaultQueryDialog().apply {
|
||||||
onPositiveButtonClickListener = { newTags ->
|
onPositiveButtonClickListener = { newTags ->
|
||||||
Preferences["default_query"] = newTags.toString()
|
Preferences["default_query"] = newTags.toString()
|
||||||
summary = newTags.toString()
|
summary = newTags.toString()
|
||||||
}
|
}
|
||||||
}.show()
|
}.show(parentFragmentManager, "Default Query Dialog")
|
||||||
}
|
}
|
||||||
"app_lock" -> {
|
"app_lock" -> {
|
||||||
val intent = Intent(requireContext(), LockActivity::class.java).apply {
|
val intent = Intent(requireContext(), LockActivity::class.java).apply {
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import android.content.Context
|
|||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.graphics.PorterDuffColorFilter
|
import android.graphics.PorterDuffColorFilter
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.os.Parcelable
|
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
@@ -38,8 +38,6 @@ import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
|||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
import xyz.quaver.floatingsearchview.FloatingSearchView
|
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.floatingsearchview.util.MenuPopupHelper
|
|
||||||
import xyz.quaver.floatingsearchview.util.view.MenuView
|
|
||||||
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
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
|
||||||
@@ -113,7 +111,7 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
|
|||||||
) {
|
) {
|
||||||
when(item) {
|
when(item) {
|
||||||
is TagSuggestion -> {
|
is TagSuggestion -> {
|
||||||
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
val tag = "${item.n}:${item.s}"
|
||||||
|
|
||||||
leftIcon?.setImageDrawable(
|
leftIcon?.setImageDrawable(
|
||||||
ResourcesCompat.getDrawable(
|
ResourcesCompat.getDrawable(
|
||||||
|
|||||||
462
app/src/main/java/xyz/quaver/pupil/ui/view/MainView.java
Normal file
462
app/src/main/java/xyz/quaver/pupil/ui/view/MainView.java
Normal file
@@ -0,0 +1,462 @@
|
|||||||
|
/*
|
||||||
|
* Pupil, Hitomi.la viewer for Android
|
||||||
|
* Copyright (C) 2020 tom5079
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package xyz.quaver.pupil.ui.view;
|
||||||
|
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.view.NestedScrollingChild;
|
||||||
|
import androidx.core.view.NestedScrollingChildHelper;
|
||||||
|
import androidx.core.view.NestedScrollingParent;
|
||||||
|
import androidx.core.view.NestedScrollingParentHelper;
|
||||||
|
import androidx.core.view.ViewCompat;
|
||||||
|
import androidx.core.widget.TextViewCompat;
|
||||||
|
|
||||||
|
import xyz.quaver.pupil.R;
|
||||||
|
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
|
public class MainView extends ViewGroup implements NestedScrollingChild, NestedScrollingParent {
|
||||||
|
|
||||||
|
private static final int PAGE_TURN_LAYOUT_SIZE = 48;
|
||||||
|
private static final int PAGE_TURN_ANIM_DURATION = 500;
|
||||||
|
private static final int PREV_OFFSET = 64;
|
||||||
|
private static final int RIPPLE_GIVE = 4;
|
||||||
|
|
||||||
|
private final float adjustedPageTurnLayoutSize;
|
||||||
|
private final float adjustedPrevOffset;
|
||||||
|
private final float adjustedRippleGive;
|
||||||
|
|
||||||
|
final private NestedScrollingParentHelper mNestedScrollingParentHelper;
|
||||||
|
final private NestedScrollingChildHelper mNestedScrollingChildHelper;
|
||||||
|
|
||||||
|
final private Vibrator mVibrator;
|
||||||
|
|
||||||
|
private View mTarget;
|
||||||
|
|
||||||
|
private TextView mPrev;
|
||||||
|
private TextView mNext;
|
||||||
|
|
||||||
|
private final Paint mRipplePaint = new Paint();
|
||||||
|
private final Rect mRippleBound = new Rect();
|
||||||
|
|
||||||
|
private int mRippleSize = 0;
|
||||||
|
private final int mRippleTargetSize;
|
||||||
|
private final ValueAnimator mRippleAnimator = new ValueAnimator();
|
||||||
|
|
||||||
|
private int mCurrentOverScroll = 0;
|
||||||
|
|
||||||
|
private int mCurrentPage = 1;
|
||||||
|
private boolean mShowPrev;
|
||||||
|
private boolean mShowNext;
|
||||||
|
|
||||||
|
private OnPageTurnListener mOnPageTurnListener;
|
||||||
|
|
||||||
|
public MainView(@NonNull Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainView(@NonNull Context context, AttributeSet attr) {
|
||||||
|
this(context, attr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainView(@NonNull Context context, AttributeSet attr, int defStyle) {
|
||||||
|
super(context, attr, defStyle);
|
||||||
|
|
||||||
|
setWillNotDraw(false);
|
||||||
|
|
||||||
|
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||||
|
|
||||||
|
adjustedPageTurnLayoutSize = PAGE_TURN_LAYOUT_SIZE * metrics.density;
|
||||||
|
adjustedPrevOffset = PREV_OFFSET * metrics.density;
|
||||||
|
adjustedRippleGive = RIPPLE_GIVE * metrics.density;
|
||||||
|
|
||||||
|
mRippleTargetSize = metrics.widthPixels;
|
||||||
|
|
||||||
|
mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
|
||||||
|
mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
|
||||||
|
|
||||||
|
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
|
||||||
|
mRippleAnimator.addUpdateListener(animation -> {
|
||||||
|
mRippleSize = (int) animation.getAnimatedValue();
|
||||||
|
invalidate();
|
||||||
|
});
|
||||||
|
mRippleAnimator.setDuration(PAGE_TURN_ANIM_DURATION);
|
||||||
|
|
||||||
|
initPageTurnView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentPage(int currentPage, boolean showNext) {
|
||||||
|
mCurrentPage = currentPage;
|
||||||
|
|
||||||
|
mShowPrev = currentPage > 1;
|
||||||
|
mShowNext = showNext;
|
||||||
|
|
||||||
|
mPrev.setText(getContext().getString(R.string.main_move_to_page, mCurrentPage-1));
|
||||||
|
mNext.setText(getContext().getString(R.string.main_move_to_page, mCurrentPage+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnPageTurnListener(OnPageTurnListener listener) {
|
||||||
|
mOnPageTurnListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initPageTurnView() {
|
||||||
|
TextView prev = new TextView(getContext());
|
||||||
|
TextView next = new TextView(getContext());
|
||||||
|
|
||||||
|
prev.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
next.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
|
prev.setCompoundDrawablesWithIntrinsicBounds(R.drawable.navigate_prev, 0, 0, 0);
|
||||||
|
next.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.navigate_next, 0);
|
||||||
|
|
||||||
|
TextViewCompat.setCompoundDrawableTintList(prev, AppCompatResources.getColorStateList(getContext(), R.color.colorAccent));
|
||||||
|
TextViewCompat.setCompoundDrawableTintList(next, AppCompatResources.getColorStateList(getContext(), R.color.colorAccent));
|
||||||
|
|
||||||
|
prev.setVisibility(View.INVISIBLE);
|
||||||
|
next.setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
|
mPrev = prev;
|
||||||
|
mNext = next;
|
||||||
|
|
||||||
|
addView(mPrev);
|
||||||
|
addView(mNext);
|
||||||
|
|
||||||
|
setCurrentPage(1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureTarget() {
|
||||||
|
if (mTarget == null) {
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
|
||||||
|
if (!child.equals(mNext) && !child.equals(mPrev)) {
|
||||||
|
mTarget = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
|
final int width = getMeasuredWidth();
|
||||||
|
final int height = getMeasuredHeight();
|
||||||
|
|
||||||
|
if (getChildCount() == 0)
|
||||||
|
return;
|
||||||
|
if (mTarget == null)
|
||||||
|
ensureTarget();
|
||||||
|
if (mTarget == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mTarget.layout(
|
||||||
|
getPaddingLeft(),
|
||||||
|
getPaddingTop(),
|
||||||
|
width - getPaddingRight(),
|
||||||
|
height - getPaddingBottom()
|
||||||
|
);
|
||||||
|
|
||||||
|
final int prevWidth = mPrev.getMeasuredWidth();
|
||||||
|
mPrev.layout(
|
||||||
|
width / 2 - prevWidth / 2,
|
||||||
|
getPaddingTop() + (int) adjustedPrevOffset,
|
||||||
|
width / 2 + prevWidth / 2,
|
||||||
|
getPaddingTop() + (int) adjustedPrevOffset + mPrev.getMeasuredHeight()
|
||||||
|
);
|
||||||
|
|
||||||
|
final int nextWidth = mNext.getMeasuredWidth();
|
||||||
|
mNext.layout(
|
||||||
|
width / 2 - nextWidth / 2,
|
||||||
|
height - getPaddingBottom() - mNext.getMeasuredHeight(),
|
||||||
|
width / 2 + nextWidth / 2,
|
||||||
|
height - getPaddingBottom()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
if (mTarget == null)
|
||||||
|
ensureTarget();
|
||||||
|
if (mTarget == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mTarget.measure(
|
||||||
|
MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
|
||||||
|
MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)
|
||||||
|
);
|
||||||
|
|
||||||
|
mPrev.measure(
|
||||||
|
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST),
|
||||||
|
MeasureSpec.makeMeasureSpec((int) adjustedPageTurnLayoutSize, MeasureSpec.EXACTLY)
|
||||||
|
);
|
||||||
|
|
||||||
|
mNext.measure(
|
||||||
|
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST),
|
||||||
|
MeasureSpec.makeMeasureSpec((int) adjustedPageTurnLayoutSize, MeasureSpec.EXACTLY)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
if (mCurrentOverScroll == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mCurrentOverScroll > 0) {
|
||||||
|
mRippleBound.set(
|
||||||
|
getPaddingLeft(),
|
||||||
|
(int) (getPaddingTop() - adjustedRippleGive),
|
||||||
|
getMeasuredWidth() - getPaddingRight(),
|
||||||
|
(int) (getPaddingTop() + adjustedPrevOffset + mPrev.getMeasuredHeight() + adjustedRippleGive)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentOverScroll < 0) {
|
||||||
|
final int height = getMeasuredHeight();
|
||||||
|
mRippleBound.set(
|
||||||
|
getPaddingLeft(),
|
||||||
|
(int) (height - getPaddingBottom() - mNext.getMeasuredHeight() - adjustedRippleGive),
|
||||||
|
getMeasuredWidth() - getPaddingRight(),
|
||||||
|
height - getPaddingBottom()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRipplePaint.reset();
|
||||||
|
mRipplePaint.setStyle(Paint.Style.FILL);
|
||||||
|
|
||||||
|
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
|
||||||
|
switch (currentNightMode) {
|
||||||
|
case Configuration.UI_MODE_NIGHT_YES:
|
||||||
|
mRipplePaint.setColor(ContextCompat.getColor(getContext(), R.color.material_light_blue_700));
|
||||||
|
break;
|
||||||
|
case Configuration.UI_MODE_NIGHT_NO:
|
||||||
|
mRipplePaint.setColor(ContextCompat.getColor(getContext(), R.color.material_light_blue_300));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawCircle(
|
||||||
|
(mRippleBound.left + mRippleBound.right) / 2F,
|
||||||
|
mCurrentOverScroll > 0 ? mRippleBound.bottom : mRippleBound.top,
|
||||||
|
mRippleSize,
|
||||||
|
mRipplePaint
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOverscroll(int overscroll) {
|
||||||
|
if (mTarget == null)
|
||||||
|
ensureTarget();
|
||||||
|
if (mTarget == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mCurrentOverScroll = overscroll;
|
||||||
|
|
||||||
|
if (overscroll > 0) {
|
||||||
|
mPrev.setVisibility(View.VISIBLE);
|
||||||
|
mNext.setVisibility(View.INVISIBLE);
|
||||||
|
} else if (overscroll < 0) {
|
||||||
|
mPrev.setVisibility(View.INVISIBLE);
|
||||||
|
mNext.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
mPrev.setVisibility(View.INVISIBLE);
|
||||||
|
mNext.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(overscroll) >= adjustedPageTurnLayoutSize) {
|
||||||
|
if (!mRippleAnimator.isStarted() && mRippleSize != mRippleTargetSize) {
|
||||||
|
mVibrator.vibrate(10);
|
||||||
|
|
||||||
|
mRippleAnimator.setIntValues(mRippleSize, mRippleTargetSize);
|
||||||
|
mRippleAnimator.start();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!mRippleAnimator.isStarted() && mRippleSize != 0) {
|
||||||
|
mRippleAnimator.setIntValues(mRippleSize, 0);
|
||||||
|
mRippleAnimator.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float clippedOverScrollTop = (overscroll > 0 ? 1 : -1) * Math.min(Math.abs(overscroll), adjustedPageTurnLayoutSize);
|
||||||
|
mTarget.setTranslationY(clippedOverScrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOverscrollEnd(int overscroll) {
|
||||||
|
if (mTarget == null)
|
||||||
|
ensureTarget();
|
||||||
|
if (mTarget == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mRippleAnimator.cancel();
|
||||||
|
mRippleAnimator.setIntValues(mRippleSize, 0);
|
||||||
|
mRippleAnimator.start();
|
||||||
|
|
||||||
|
mPrev.setVisibility(View.INVISIBLE);
|
||||||
|
mNext.setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
|
ViewCompat.animate(mTarget)
|
||||||
|
.setDuration(PAGE_TURN_ANIM_DURATION)
|
||||||
|
.setInterpolator(new DecelerateInterpolator())
|
||||||
|
.translationY(0);
|
||||||
|
|
||||||
|
if (Math.abs(overscroll) > adjustedPageTurnLayoutSize && mOnPageTurnListener != null) {
|
||||||
|
if (overscroll > 0)
|
||||||
|
mOnPageTurnListener.onPrev(mCurrentPage-1);
|
||||||
|
if (overscroll < 0)
|
||||||
|
mOnPageTurnListener.onNext(mCurrentPage+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NestedScrollingParent
|
||||||
|
|
||||||
|
private int mTotalUnconsumed = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
|
||||||
|
return isEnabled() && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNestedScrollAccepted(View child, View target, int axes) {
|
||||||
|
mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
|
||||||
|
startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
|
||||||
|
|
||||||
|
mTotalUnconsumed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
|
||||||
|
if (mTotalUnconsumed != 0 && dy > 0 == mTotalUnconsumed > 0) {
|
||||||
|
if (Math.abs(dy) > Math.abs(mTotalUnconsumed)) {
|
||||||
|
consumed[1] = dy - mTotalUnconsumed;
|
||||||
|
mTotalUnconsumed = 0;
|
||||||
|
} else {
|
||||||
|
mTotalUnconsumed -= dy;
|
||||||
|
consumed[1] = dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
onOverscroll(mTotalUnconsumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int[] parentConsumed = new int[2];
|
||||||
|
if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
|
||||||
|
consumed[0] += parentConsumed[0];
|
||||||
|
consumed[1] += parentConsumed[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
|
||||||
|
final int[] mParentOffsetInWindow = new int[2];
|
||||||
|
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, mParentOffsetInWindow);
|
||||||
|
|
||||||
|
final int dy = dyUnconsumed + mParentOffsetInWindow[1];
|
||||||
|
|
||||||
|
if (mTotalUnconsumed == 0 && ((dy < 0 && !mShowPrev) || (dy > 0 && !mShowNext)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dy != 0) {
|
||||||
|
mTotalUnconsumed -= dy;
|
||||||
|
onOverscroll(mTotalUnconsumed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopNestedScroll(View child) {
|
||||||
|
mNestedScrollingParentHelper.onStopNestedScroll(child);
|
||||||
|
|
||||||
|
if (Math.abs(mTotalUnconsumed) > 0) {
|
||||||
|
onOverscrollEnd(mTotalUnconsumed);
|
||||||
|
mTotalUnconsumed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopNestedScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NestedScrollingChild
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNestedScrollingEnabled(boolean enabled) {
|
||||||
|
mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNestedScrollingEnabled() {
|
||||||
|
return mNestedScrollingChildHelper.isNestedScrollingEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean startNestedScroll(int axes) {
|
||||||
|
return mNestedScrollingChildHelper.startNestedScroll(axes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopNestedScroll() {
|
||||||
|
mNestedScrollingChildHelper.stopNestedScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNestedScrollingParent() {
|
||||||
|
return mNestedScrollingChildHelper.hasNestedScrollingParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
|
||||||
|
return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
|
||||||
|
return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
|
||||||
|
return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
|
||||||
|
return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnPageTurnListener {
|
||||||
|
void onPrev(int page);
|
||||||
|
void onNext(int page);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
app/src/main/java/xyz/quaver/pupil/ui/view/ProgressCard.kt
Normal file
72
app/src/main/java/xyz/quaver/pupil/ui/view/ProgressCard.kt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package xyz.quaver.pupil.ui.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.cardview.widget.CardView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.ProgressCardViewBinding
|
||||||
|
|
||||||
|
class ProgressCard @JvmOverloads constructor(context: Context, attr: AttributeSet? = null, defStyle: Int = R.attr.cardViewStyle) : CardView(context, attr, defStyle) {
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
LOADING,
|
||||||
|
CACHE,
|
||||||
|
DOWNLOAD
|
||||||
|
}
|
||||||
|
|
||||||
|
var type: Type = Type.LOADING
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
|
||||||
|
when (field) {
|
||||||
|
Type.LOADING -> R.color.colorAccent
|
||||||
|
Type.CACHE -> R.color.material_blue_700
|
||||||
|
Type.DOWNLOAD -> R.color.material_green_a700
|
||||||
|
}.let {
|
||||||
|
val color = ContextCompat.getColor(context, it)
|
||||||
|
DrawableCompat.setTint(binding.progressbar.progressDrawable, color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var progress: Int
|
||||||
|
get() = binding.progressbar.progress
|
||||||
|
set(value) {
|
||||||
|
binding.progressbar.progress = value
|
||||||
|
}
|
||||||
|
var max: Int
|
||||||
|
get() = binding.progressbar.max
|
||||||
|
set(value) {
|
||||||
|
binding.progressbar.max = value
|
||||||
|
|
||||||
|
binding.progressbar.visibility =
|
||||||
|
if (value == 0)
|
||||||
|
GONE
|
||||||
|
else
|
||||||
|
VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
val binding = ProgressCardViewBinding.inflate(LayoutInflater.from(context), this)
|
||||||
|
|
||||||
|
init {
|
||||||
|
binding.content.setOnClickListener {
|
||||||
|
performClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.content.setOnLongClickListener {
|
||||||
|
performLongClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
|
||||||
|
if (childCount == 0)
|
||||||
|
super.addView(child, index, params)
|
||||||
|
else
|
||||||
|
binding.content.addView(child, index, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ import xyz.quaver.pupil.types.Tags
|
|||||||
class TagChipGroup @JvmOverloads constructor(context: Context, attr: AttributeSet? = null, attrStyle: Int = R.attr.chipGroupStyle, val tags: Tags = Tags()) : ChipGroup(context, attr, attrStyle), MutableSet<Tag> by tags {
|
class TagChipGroup @JvmOverloads constructor(context: Context, attr: AttributeSet? = null, attrStyle: Int = R.attr.chipGroupStyle, val tags: Tags = Tags()) : ChipGroup(context, attr, attrStyle), MutableSet<Tag> by tags {
|
||||||
|
|
||||||
object Defaults {
|
object Defaults {
|
||||||
val maxChipSize = 10
|
const val maxChipSize = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxChipSize: Int = Defaults.maxChipSize
|
var maxChipSize: Int = Defaults.maxChipSize
|
||||||
@@ -86,7 +86,7 @@ class TagChipGroup @JvmOverloads constructor(context: Context, attr: AttributeSe
|
|||||||
addView(it.await())
|
addView(it.await())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxChipSize > 0 && tags.size > maxChipSize && parent == null)
|
if (maxChipSize > 0 && tags.size > maxChipSize)
|
||||||
addView(moreView)
|
addView(moreView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.*
|
||||||
import kotlinx.serialization.json.jsonArray
|
|
||||||
import kotlinx.serialization.json.jsonObject
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import xyz.quaver.Code
|
import xyz.quaver.Code
|
||||||
@@ -137,4 +135,11 @@ operator fun JsonElement.get(index: Int) =
|
|||||||
this.jsonArray[index]
|
this.jsonArray[index]
|
||||||
|
|
||||||
operator fun JsonElement.get(tag: String) =
|
operator fun JsonElement.get(tag: String) =
|
||||||
this.jsonObject[tag]
|
this.jsonObject[tag]
|
||||||
|
|
||||||
|
fun JsonElement.getOrNull(tag: String) = kotlin.runCatching {
|
||||||
|
this.jsonObject.getOrDefault(tag, null)
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
|
val JsonElement.content
|
||||||
|
get() = this.jsonPrimitive.contentOrNull
|
||||||
@@ -181,7 +181,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
|
|||||||
Preferences["update_download_id"] = it
|
Preferences["update_download_id"] = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setNegativeButton(if (force) android.R.string.cancel else R.string.ignore_update) { _, _ ->
|
setNegativeButton(if (force) android.R.string.cancel else R.string.ignore) { _, _ ->
|
||||||
if (!force)
|
if (!force)
|
||||||
preferences.edit()
|
preferences.edit()
|
||||||
.putLong("ignore_update_until", System.currentTimeMillis() + 604800000)
|
.putLong("ignore_update_until", System.currentTimeMillis() + 604800000)
|
||||||
@@ -256,6 +256,13 @@ fun xyz.quaver.pupil.util.downloader.DownloadManager.migrate() {
|
|||||||
|
|
||||||
job?.cancel()
|
job?.cancel()
|
||||||
job = CoroutineScope(Dispatchers.IO).launch {
|
job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val images = listOf(
|
||||||
|
"jpg",
|
||||||
|
"png",
|
||||||
|
"gif",
|
||||||
|
"webp"
|
||||||
|
)
|
||||||
|
|
||||||
val downloadFolders = downloadFolder.listFiles { folder ->
|
val downloadFolders = downloadFolder.listFiles { folder ->
|
||||||
folder.isDirectory && !downloadFolderMap.values.contains(folder.name)
|
folder.isDirectory && !downloadFolderMap.values.contains(folder.name)
|
||||||
}?.map {
|
}?.map {
|
||||||
@@ -273,52 +280,56 @@ fun xyz.quaver.pupil.util.downloader.DownloadManager.migrate() {
|
|||||||
.setProgress(index, downloadFolders.size, false)
|
.setProgress(index, downloadFolders.size, false)
|
||||||
notificationManager.notify(R.id.notification_id_import, notification.build())
|
notificationManager.notify(R.id.notification_id_import, notification.build())
|
||||||
|
|
||||||
kotlin.runCatching {
|
val metadata = kotlin.runCatching {
|
||||||
val metadata = kotlin.runCatching {
|
folder.getChild(".metadata").readText()?.let { Json.parseToJsonElement(it) }
|
||||||
folder.getChild(".metadata").readText()?.let { Json.parseToJsonElement(it).jsonObject }
|
}.getOrNull()
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
val galleryID = folder.name.toIntOrNull() ?: return@runCatching
|
val galleryID = metadata?.getOrNull("reader")?.getOrNull("galleryInfo")?.getOrNull("id")?.content?.toIntOrNull()
|
||||||
|
?: folder.name.toIntOrNull() ?: return@forEachIndexed
|
||||||
|
|
||||||
val galleryBlock: GalleryBlock? = kotlin.runCatching {
|
val galleryBlock: GalleryBlock? = kotlin.runCatching {
|
||||||
metadata?.get("galleryBlock")?.let { Json.decodeFromJsonElement<GalleryBlock>(it) }
|
metadata?.getOrNull("galleryBlock")?.let { Json.decodeFromJsonElement<GalleryBlock>(it) }
|
||||||
}.getOrNull() ?: getGalleryBlock(galleryID)
|
}.getOrNull() ?: kotlin.runCatching {
|
||||||
val reader: Reader? = kotlin.runCatching {
|
getGalleryBlock(galleryID)
|
||||||
metadata?.get("reader")?.let { Json.decodeFromJsonElement<Reader>(it) }
|
}.getOrNull() ?: kotlin.runCatching {
|
||||||
}.getOrNull() ?: getReader(galleryID)
|
xyz.quaver.hiyobi.getGalleryBlock(galleryID)
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
metadata?.get("thumbnail")?.jsonPrimitive?.contentOrNull?.also { thumbnail ->
|
val reader: Reader? = kotlin.runCatching {
|
||||||
val file = folder.getChild(".thumbnail").also {
|
metadata?.getOrNull("reader")?.let { Json.decodeFromJsonElement<Reader>(it) }
|
||||||
if (it.exists())
|
}.getOrNull() ?: kotlin.runCatching {
|
||||||
it.delete()
|
getReader(galleryID)
|
||||||
it.createNewFile()
|
}.getOrNull() ?: kotlin.runCatching {
|
||||||
}
|
xyz.quaver.hiyobi.getReader(galleryID)
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
file.writeBytes(Base64.decode(thumbnail, Base64.DEFAULT))
|
metadata?.getOrNull("thumbnail")?.jsonPrimitive?.contentOrNull?.also { thumbnail ->
|
||||||
|
val file = folder.getChild(".thumbnail").also {
|
||||||
|
if (it.exists())
|
||||||
|
it.delete()
|
||||||
|
it.createNewFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
val list: MutableList<String?> =
|
file.writeBytes(Base64.decode(thumbnail, Base64.DEFAULT))
|
||||||
MutableList(reader!!.galleryInfo.files.size) { null }
|
|
||||||
|
|
||||||
folder.listFiles { file ->
|
|
||||||
file?.nameWithoutExtension?.let {
|
|
||||||
Regex("""\d{5}""").matches(it) && it.toIntOrNull() != null
|
|
||||||
} == true
|
|
||||||
}?.forEach {
|
|
||||||
list[it.nameWithoutExtension.toInt()] = it.name
|
|
||||||
}
|
|
||||||
|
|
||||||
folder.getChild(".metadata").also { if (it.exists()) it.delete(); it.createNewFile() }.writeText(
|
|
||||||
Json.encodeToString(Metadata(galleryBlock, reader, list))
|
|
||||||
)
|
|
||||||
|
|
||||||
synchronized(Cache) {
|
|
||||||
Cache.delete(this@migrate, galleryID)
|
|
||||||
}
|
|
||||||
downloadFolderMap[galleryID] = folder.name
|
|
||||||
|
|
||||||
downloadFolder.getChild(".download").let { if (!it.exists()) it.createNewFile(); it.writeText(Json.encodeToString(downloadFolderMap)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val list: MutableList<String?> =
|
||||||
|
MutableList(reader!!.galleryInfo.files.size) { null }
|
||||||
|
|
||||||
|
folder.list { _, name ->
|
||||||
|
name?.substringAfterLast('.') in images
|
||||||
|
}?.sorted()?.take(list.size)?.forEachIndexed { i, name ->
|
||||||
|
list[i] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.getChild(".metadata").also { if (it.exists()) it.delete(); it.createNewFile() }.writeText(
|
||||||
|
Json.encodeToString(Metadata(galleryBlock, reader, list))
|
||||||
|
)
|
||||||
|
|
||||||
|
Cache.delete(this@migrate, galleryID)
|
||||||
|
downloadFolderMap[galleryID] = folder.name
|
||||||
|
|
||||||
|
downloadFolder.getChild(".download").let { if (!it.exists()) it.createNewFile(); it.writeText(Json.encodeToString(downloadFolderMap)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
notification
|
notification
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
|
||||||
<path android:fillColor="#FF000000" android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
<path android:fillColor="#FF000000" android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||||
</vector>
|
</vector>
|
||||||
6
app/src/main/res/drawable/navigate_prev.xml
Normal file
6
app/src/main/res/drawable/navigate_prev.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
|
||||||
|
<group android:pivotX="12" android:scaleX="-1">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Pupil, Hitomi.la viewer for Android
|
|
||||||
~ Copyright (C) 2020 tom5079
|
|
||||||
~
|
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
|
||||||
~ it under the terms of the GNU General Public License as published by
|
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
|
||||||
~ (at your option) any later version.
|
|
||||||
~
|
|
||||||
~ This program is distributed in the hope that it will be useful,
|
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU General Public License for more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License
|
|
||||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<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="@android: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="@android:color/transparent"
|
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<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="@android: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>
|
|
||||||
|
|
||||||
<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:gravity="center"
|
|
||||||
android:text="@string/main_no_result"
|
|
||||||
android:linksClickable="true"
|
|
||||||
android:visibility="invisible"/>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<xyz.quaver.pupil.ui.view.FloatingSearchView
|
|
||||||
android:id="@+id/main_searchview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:searchBarMarginLeft="6dp"
|
|
||||||
app:searchBarMarginRight="6dp"
|
|
||||||
app:searchBarMarginTop="6dp"
|
|
||||||
app:searchHint="@string/search_hint"
|
|
||||||
app:suggestionAnimDuration="250"
|
|
||||||
app:showSearchKey="true"
|
|
||||||
app:leftActionMode="showHamburger"
|
|
||||||
app:menu="@menu/main"
|
|
||||||
app:dismissOnOutsideTouch="true"
|
|
||||||
app:close_search_on_keyboard_dismiss="false"
|
|
||||||
tools:ignore="NewApi" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
tools:ignore="Autofill"
|
tools:ignore="Autofill"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:hint="@string/settings_default_query"
|
android:hint="@string/settings_default_query"
|
||||||
android:id="@+id/default_query_dialog_edittext"
|
android:id="@+id/edittext"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
@@ -36,10 +36,10 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/default_query_dialog_language_layout"
|
android:id="@+id/language_layout"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/default_query_dialog_edittext"
|
app:layout_constraintTop_toBottomOf="@id/edittext"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
@@ -49,14 +49,14 @@
|
|||||||
android:text="@string/default_query_dialog_language"/>
|
android:text="@string/default_query_dialog_language"/>
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/default_query_dialog_language_selector"
|
android:id="@+id/language_selector"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/default_query_dialog_BL_layout"
|
android:id="@+id/BL_layout"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
android:paddingStart="0dp"
|
android:paddingStart="0dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:paddingRight="8dp"
|
android:paddingRight="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/default_query_dialog_language_layout"
|
app:layout_constraintTop_toBottomOf="@id/language_layout"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
@@ -75,14 +75,14 @@
|
|||||||
android:text="@string/default_query_dialog_filter_BL"/>
|
android:text="@string/default_query_dialog_filter_BL"/>
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/default_query_dialog_BL_checkbox"
|
android:id="@+id/BL_checkbox"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/default_query_dialog_guro_layout"
|
android:id="@+id/guro_layout"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
android:paddingStart="0dp"
|
android:paddingStart="0dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:paddingRight="8dp"
|
android:paddingRight="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/default_query_dialog_BL_layout"
|
app:layout_constraintTop_toBottomOf="@id/BL_layout"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
android:text="@string/default_query_dialog_filter_guro"/>
|
android:text="@string/default_query_dialog_filter_guro"/>
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/default_query_dialog_guro_checkbox"
|
android:id="@+id/guro_checkbox"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
android:paddingStart="0dp"
|
android:paddingStart="0dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:paddingRight="8dp"
|
android:paddingRight="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/default_query_dialog_guro_layout"
|
app:layout_constraintTop_toBottomOf="@id/guro_layout"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
android:text="@string/default_query_dialog_filter_loli"/>
|
android:text="@string/default_query_dialog_filter_loli"/>
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/default_query_dialog_loli_checkbox"
|
android:id="@+id/loli_checkbox"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
@@ -19,14 +19,13 @@
|
|||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/gallery_layout"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/gallery_toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
@@ -41,34 +40,34 @@
|
|||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
<com.github.piasy.biv.view.BigImageView
|
<com.github.piasy.biv.view.BigImageView
|
||||||
android:id="@+id/gallery_cover"
|
android:id="@+id/cover"
|
||||||
android:layout_width="150dp"
|
android:layout_width="150dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toLeftOf="@id/gallery_title"
|
app:layout_constraintRight_toLeftOf="@id/title"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/gallery_title"
|
android:id="@+id/title"
|
||||||
style="@style/TextAppearance.AppCompat.Headline"
|
style="@style/TextAppearance.AppCompat.Headline"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintLeft_toRightOf="@id/gallery_cover"
|
app:layout_constraintLeft_toRightOf="@id/cover"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginStart="8dp"/>
|
android:layout_marginStart="8dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="@style/TextAppearance.AppCompat.Medium"
|
style="@style/TextAppearance.AppCompat.Medium"
|
||||||
android:id="@+id/gallery_artist"
|
android:id="@+id/artist"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/gallery_title"
|
app:layout_constraintTop_toBottomOf="@id/title"
|
||||||
app:layout_constraintLeft_toRightOf="@id/gallery_cover"
|
app:layout_constraintLeft_toRightOf="@id/cover"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginStart="8dp"/>
|
android:layout_marginStart="8dp"/>
|
||||||
@@ -76,15 +75,15 @@
|
|||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/gallery_artist"
|
app:layout_constraintTop_toBottomOf="@id/artist"
|
||||||
app:layout_constraintBottom_toTopOf="@id/gallery_type"/>
|
app:layout_constraintBottom_toTopOf="@id/type"/>
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
<com.google.android.material.chip.Chip
|
||||||
android:id="@+id/gallery_type"
|
android:id="@+id/type"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toRightOf="@id/gallery_cover"
|
app:layout_constraintLeft_toRightOf="@id/cover"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginStart="8dp"/>
|
android:layout_marginStart="8dp"/>
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@
|
|||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gallery_contents"
|
android:id="@+id/contents"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"/>
|
android:orientation="vertical"/>
|
||||||
@@ -112,7 +111,7 @@
|
|||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/gallery_progressbar"
|
android:id="@+id/progressbar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
@@ -123,11 +122,11 @@
|
|||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/gallery_fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
app:layout_anchor="@id/gallery_toolbar"
|
app:layout_anchor="@id/toolbar"
|
||||||
app:layout_anchorGravity="bottom|end"/>
|
app:layout_anchorGravity="bottom|end"/>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -25,14 +25,14 @@
|
|||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/gallery_details"
|
android:id="@+id/type"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
android:textColor="@color/colorAccent"/>
|
android:textColor="@color/colorAccent"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gallery_details_contents"
|
android:id="@+id/contents"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"/>
|
android:orientation="vertical"/>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
android:layout_margin="8dp">
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
|
<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
|
||||||
android:id="@+id/gallery_dotindicator"
|
android:id="@+id/dotindicator"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
@@ -26,13 +26,13 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
android:id="@+id/gallery_details_type"
|
android:id="@+id/type"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="8dp"/>
|
android:paddingBottom="8dp"/>
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/gallery_details_tags"
|
android:id="@+id/tags"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:chipSpacingVertical="4dp"/>
|
app:chipSpacingVertical="4dp"/>
|
||||||
160
app/src/main/res/layout/galleryblock_item.xml
Normal file
160
app/src/main/res/layout/galleryblock_item.xml
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xyz.quaver.pupil.ui.view.ProgressCard
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/galleryblock_card"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipChildren="true"
|
||||||
|
app:cardCornerRadius="4dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
app:cardUseCompatPadding="true"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.github.piasy.biv.view.BigImageView
|
||||||
|
android:id="@+id/galleryblock_thumbnail"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:contentDescription="@string/galleryblock_thumbnail_description"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:clickable="false"
|
||||||
|
app:layout_constraintHeight_default="spread"
|
||||||
|
app:layout_constraintHeight_min="200dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/barrier"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.AppCompat.Headline"
|
||||||
|
android:id="@+id/galleryblock_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:id="@+id/galleryblock_artist"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/galleryblock_title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/galleryblock_series"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/galleryblock_artist"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/galleryblock_type"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/galleryblock_series"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/galleryblock_language"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
|
||||||
|
|
||||||
|
<xyz.quaver.pupil.ui.view.TagChipGroup
|
||||||
|
android:id="@+id/galleryblock_tag_group"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
app:chipSpacing="4dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
android:id="@+id/barrier"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:barrierDirection="bottom"
|
||||||
|
app:constraint_referenced_ids="galleryblock_thumbnail, galleryblock_tag_group"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/barrier"
|
||||||
|
android:layout_margin="8dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/galleryblock_id"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/divider"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/galleryblock_pagecount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/divider"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/galleryblock_favorite"
|
||||||
|
android:contentDescription="@string/app_name"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:srcCompat="@drawable/ic_star_empty"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/divider"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</xyz.quaver.pupil.ui.view.ProgressCard>
|
||||||
@@ -1,233 +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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
app:cardCornerRadius="8dp"
|
|
||||||
android:clipChildren="true"
|
|
||||||
tools:ignore="RtlHardcoded">
|
|
||||||
|
|
||||||
<com.daimajia.swipe.SwipeLayout
|
|
||||||
android:id="@+id/galleryblock_swipe_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:drag_edge="right"
|
|
||||||
app:show_mode="pull_out">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_download"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:minWidth="70dp"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:background="@android:color/holo_blue_dark"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:text="@string/main_download"
|
|
||||||
android:foreground="?android:attr/selectableItemBackground"
|
|
||||||
android:focusable="true"
|
|
||||||
android:clickable="true"
|
|
||||||
tools:ignore="UnusedAttribute" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_delete"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:minWidth="70dp"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:background="@android:color/holo_red_dark"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:text="@string/main_delete"
|
|
||||||
android:foreground="?android:attr/selectableItemBackground"
|
|
||||||
android:focusable="true"
|
|
||||||
android:clickable="true"
|
|
||||||
tools:ignore="UnusedAttribute" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/galleryblock_primary"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?android:attr/selectableItemBackground"
|
|
||||||
android:focusable="true"
|
|
||||||
android:clickable="true">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/galleryblock_progressbar_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="4dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<androidx.core.widget.ContentLoadingProgressBar
|
|
||||||
style="?android:attr/progressBarStyleHorizontal"
|
|
||||||
android:id="@+id/galleryblock_progressbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="-4dp"
|
|
||||||
android:layout_marginTop="-4dp"
|
|
||||||
android:progress="50"
|
|
||||||
android:layout_gravity="center_vertical"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/galleryblock_progress_complete"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="4dp"
|
|
||||||
android:visibility="invisible"
|
|
||||||
android:scaleType="fitXY"
|
|
||||||
android:contentDescription="@string/reader_imageview_description"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<com.github.piasy.biv.view.BigImageView
|
|
||||||
android:id="@+id/galleryblock_thumbnail"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:contentDescription="@string/galleryblock_thumbnail_description"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
app:layout_constraintHeight_default="spread"
|
|
||||||
app:layout_constraintHeight_min="200dp"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_progressbar_layout"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/barrier"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/TextAppearance.AppCompat.Headline"
|
|
||||||
android:id="@+id/galleryblock_title"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_progressbar_layout"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/TextAppearance.AppCompat.Medium"
|
|
||||||
android:id="@+id/galleryblock_artist"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_title"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_series"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_artist"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_type"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_series"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_language"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
|
|
||||||
|
|
||||||
<xyz.quaver.pupil.ui.view.TagChipGroup
|
|
||||||
android:id="@+id/galleryblock_tag_group"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
app:chipSpacing="4dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"/>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/barrier"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="bottom"
|
|
||||||
app:constraint_referenced_ids="galleryblock_thumbnail, galleryblock_tag_group"/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/divider"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?android:attr/listDivider"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier"
|
|
||||||
android:layout_margin="8dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_id"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/divider"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/galleryblock_pagecount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/divider"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/galleryblock_favorite"
|
|
||||||
android:contentDescription="@string/app_name"
|
|
||||||
android:layout_width="32dp"
|
|
||||||
android:layout_height="32dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:srcCompat="@drawable/ic_star_empty"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/divider"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</com.daimajia.swipe.SwipeLayout>
|
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
|
||||||
@@ -1,54 +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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/icon_next"
|
|
||||||
android:contentDescription="@string/page_indicator_placeholder"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_navigate_next_black_24dp"
|
|
||||||
app:tint="@color/colorAccent"
|
|
||||||
android:rotation="180"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_next"
|
|
||||||
android:layout_width="1dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="end" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,54 +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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/icon_prev"
|
|
||||||
android:contentDescription="@string/page_indicator_placeholder"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_navigate_next_black_24dp"
|
|
||||||
app:tint="@color/colorAccent"
|
|
||||||
android:rotation="180"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_prev"
|
|
||||||
android:layout_width="1dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="end" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
app:layout_constraintBottom_toTopOf="@id/lock_button_layout">
|
app:layout_constraintBottom_toTopOf="@id/lock_button_layout">
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/lock_fingerprint"
|
android:id="@+id/fingerprint_btn"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/fingerprint"
|
app:srcCompat="@drawable/fingerprint"
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/lock_pattern"
|
android:id="@+id/pattern_btn"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:tint="@null"
|
app:tint="@null"
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
app:fabSize="mini"/>
|
app:fabSize="mini"/>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/lock_pin"
|
android:id="@+id/pin_btn"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:tint="@null"
|
app:tint="@null"
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
app:fabSize="mini"/>
|
app:fabSize="mini"/>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/lock_password"
|
android:id="@+id/password_btn"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:tint="@null"
|
app:tint="@null"
|
||||||
@@ -21,17 +21,18 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
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"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main_drawer_layout"
|
android:id="@+id/drawer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:openDrawer="start">
|
tools:openDrawer="start">
|
||||||
|
|
||||||
<include layout="@layout/activity_main_content"
|
<include android:id="@+id/contents"
|
||||||
|
layout="@layout/main_activity_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
<com.google.android.material.navigation.NavigationView
|
<com.google.android.material.navigation.NavigationView
|
||||||
android:id="@+id/main_nav_view"
|
android:id="@+id/nav_view"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
127
app/src/main/res/layout/main_activity_content.xml
Normal file
127
app/src/main/res/layout/main_activity_content.xml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Pupil, Hitomi.la viewer for Android
|
||||||
|
~ Copyright (C) 2020 tom5079
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">
|
||||||
|
|
||||||
|
<xyz.quaver.pupil.ui.view.MainView
|
||||||
|
android:id="@+id/view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<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="@android:color/transparent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/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>
|
||||||
|
|
||||||
|
</xyz.quaver.pupil.ui.view.MainView>
|
||||||
|
|
||||||
|
<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:id="@+id/progressbar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminate="true"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noresult"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/main_no_result"
|
||||||
|
android:linksClickable="true"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
|
<com.github.clans.fab.FloatingActionMenu
|
||||||
|
android:id="@+id/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/cancel_fab"
|
||||||
|
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/jump_fab"
|
||||||
|
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/random_fab"
|
||||||
|
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/id_fab"
|
||||||
|
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>
|
||||||
|
|
||||||
|
<xyz.quaver.pupil.ui.view.FloatingSearchView
|
||||||
|
android:id="@+id/searchview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:searchBarMarginLeft="6dp"
|
||||||
|
app:searchBarMarginRight="6dp"
|
||||||
|
app:searchBarMarginTop="6dp"
|
||||||
|
app:searchHint="@string/search_hint"
|
||||||
|
app:suggestionAnimDuration="250"
|
||||||
|
app:showSearchKey="true"
|
||||||
|
app:leftActionMode="showHamburger"
|
||||||
|
app:menu="@menu/main"
|
||||||
|
app:dismissOnOutsideTouch="true"
|
||||||
|
app:close_search_on_keyboard_dismiss="false" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="?android:textAppearanceLarge"
|
style="?android:textAppearanceLarge"
|
||||||
android:id="@+id/dialog_title"
|
android:id="@+id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/reader_go_to_page"
|
android:text="@string/reader_go_to_page"
|
||||||
@@ -33,20 +33,20 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"/>
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
<NumberPicker
|
<NumberPicker
|
||||||
android:id="@+id/dialog_number_picker"
|
android:id="@+id/number_picker"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/dialog_title"
|
app:layout_constraintTop_toBottomOf="@id/title"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/dialog_ok"
|
android:id="@+id/ok_button"
|
||||||
style="?borderlessButtonStyle"
|
style="?borderlessButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@android:string/ok"
|
android:text="@android:string/ok"
|
||||||
app:layout_constraintTop_toBottomOf="@id/dialog_number_picker"
|
app:layout_constraintTop_toBottomOf="@id/number_picker"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
tools:context=".ui.fragment.PatternLockFragment">
|
tools:context=".ui.fragment.PatternLockFragment">
|
||||||
|
|
||||||
<com.andrognito.patternlockview.PatternLockView
|
<com.andrognito.patternlockview.PatternLockView
|
||||||
android:id="@+id/lock_pattern_view"
|
android:id="@+id/pattern_lock_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
75
app/src/main/res/layout/progress_card_view.xml
Normal file
75
app/src/main/res/layout/progress_card_view.xml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<merge
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:parentTag="androidx.cardview.widget.CardView">
|
||||||
|
|
||||||
|
<com.daimajia.swipe.SwipeLayout
|
||||||
|
android:id="@+id/swipe_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:drag_edge="right"
|
||||||
|
app:show_mode="pull_out">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/download"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:minWidth="70dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@android:color/holo_blue_dark"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:text="@string/main_download"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="true"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/delete"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:minWidth="70dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@android:color/holo_red_dark"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:text="@string/main_delete"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="true"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:id="@+id/progressbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:progress="50"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.daimajia.swipe.SwipeLayout>
|
||||||
|
|
||||||
|
</merge>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/proxy_title"
|
android:id="@+id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="16dp"
|
android:paddingBottom="16dp"
|
||||||
@@ -35,46 +35,46 @@
|
|||||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
app:layout_constraintLeft_toLeftOf="parent"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/proxy_type_text"
|
android:id="@+id/type_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_title"
|
app:layout_constraintTop_toBottomOf="@id/title"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:text="@string/proxy_dialog_type"
|
android:text="@string/proxy_dialog_type"
|
||||||
android:textAppearance="?android:attr/listSeparatorTextViewStyle"/>
|
android:textAppearance="?android:attr/listSeparatorTextViewStyle"/>
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/proxy_type_selector"
|
android:id="@+id/type_selector"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_type_text"/>
|
app:layout_constraintTop_toBottomOf="@id/type_text"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/proxy_server_text"
|
android:id="@+id/server_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_type_selector"
|
app:layout_constraintTop_toBottomOf="@id/type_selector"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:text="@string/proxy_dialog_server"
|
android:text="@string/proxy_dialog_server"
|
||||||
android:textAppearance="?android:attr/listSeparatorTextViewStyle"/>
|
android:textAppearance="?android:attr/listSeparatorTextViewStyle"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/proxy_address_layout"
|
android:id="@+id/address_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_server_text">
|
app:layout_constraintTop_toBottomOf="@id/server_text">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatEditText
|
<androidx.appcompat.widget.AppCompatEditText
|
||||||
android:id="@+id/proxy_addr"
|
android:id="@+id/addr"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="2"
|
android:layout_weight="2"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/proxy_dialog_addr_hint"/>
|
android:hint="@string/proxy_dialog_addr_hint"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatEditText
|
<androidx.appcompat.widget.AppCompatEditText
|
||||||
android:id="@+id/proxy_port"
|
android:id="@+id/port"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -83,39 +83,39 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatEditText
|
<androidx.appcompat.widget.AppCompatEditText
|
||||||
android:id="@+id/proxy_username"
|
android:id="@+id/username"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_address_layout"
|
app:layout_constraintTop_toBottomOf="@id/address_layout"
|
||||||
android:hint="@string/proxy_dialog_username_hint"
|
android:hint="@string/proxy_dialog_username_hint"
|
||||||
android:enabled="false"/>
|
android:enabled="false"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatEditText
|
<androidx.appcompat.widget.AppCompatEditText
|
||||||
android:id="@+id/proxy_password"
|
android:id="@+id/password"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_username"
|
app:layout_constraintTop_toBottomOf="@id/username"
|
||||||
android:hint="@string/proxy_dialog_password_hint"
|
android:hint="@string/proxy_dialog_password_hint"
|
||||||
android:enabled="false"/>
|
android:enabled="false"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/proxy_cancel"
|
android:id="@+id/cancel_button"
|
||||||
style="?borderlessButtonStyle"
|
style="?borderlessButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@android:string/cancel"
|
android:text="@android:string/cancel"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_password"
|
app:layout_constraintTop_toBottomOf="@id/password"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/proxy_ok"
|
app:layout_constraintEnd_toStartOf="@id/ok_button"
|
||||||
app:layout_constraintRight_toLeftOf="@id/proxy_ok"/>
|
app:layout_constraintRight_toLeftOf="@id/ok_button"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/proxy_ok"
|
android:id="@+id/ok_button"
|
||||||
style="?borderlessButtonStyle"
|
style="?borderlessButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@android:string/ok"
|
android:text="@android:string/ok"
|
||||||
app:layout_constraintTop_toBottomOf="@id/proxy_password"
|
app:layout_constraintTop_toBottomOf="@id/password"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"/>
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/reader_layout"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -40,7 +39,7 @@
|
|||||||
app:popupDrawable="@android:color/transparent">
|
app:popupDrawable="@android:color/transparent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/reader_recyclerview"
|
android:id="@+id/recyclerview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||||
@@ -56,13 +55,13 @@
|
|||||||
android:layout_margin="8dp"/>
|
android:layout_margin="8dp"/>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/reader_download_progressbar"
|
android:id="@+id/download_progressbar"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="4dp"/>
|
android:layout_height="4dp"/>
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionMenu
|
<com.github.clans.fab.FloatingActionMenu
|
||||||
android:id="@+id/reader_fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
@@ -70,7 +69,7 @@
|
|||||||
app:menu_colorNormal="@color/colorAccent">
|
app:menu_colorNormal="@color/colorAccent">
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
<com.github.clans.fab.FloatingActionButton
|
||||||
android:id="@+id/reader_fab_download"
|
android:id="@+id/download_fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/ic_download"
|
app:srcCompat="@drawable/ic_download"
|
||||||
@@ -78,7 +77,7 @@
|
|||||||
app:fab_size="mini"/>
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
<com.github.clans.fab.FloatingActionButton
|
||||||
android:id="@+id/reader_fab_retry"
|
android:id="@+id/retry_fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/refresh"
|
app:srcCompat="@drawable/refresh"
|
||||||
@@ -86,7 +85,7 @@
|
|||||||
app:fab_size="mini"/>
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
<com.github.clans.fab.FloatingActionButton
|
||||||
android:id="@+id/reader_fab_auto"
|
android:id="@+id/auto_fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/eye_white"
|
app:srcCompat="@drawable/eye_white"
|
||||||
@@ -94,7 +93,7 @@
|
|||||||
app:fab_size="mini"/>
|
app:fab_size="mini"/>
|
||||||
|
|
||||||
<com.github.clans.fab.FloatingActionButton
|
<com.github.clans.fab.FloatingActionButton
|
||||||
android:id="@+id/reader_fab_fullscreen"
|
android:id="@+id/fullscreen_fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/ic_fullscreen"
|
app:srcCompat="@drawable/ic_fullscreen"
|
||||||
30
app/src/main/res/layout/swipe_pageturn_view.xml
Normal file
30
app/src/main/res/layout/swipe_pageturn_view.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:parentTag="android.widget.FrameLayout">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/prev"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top|center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
app:drawableStartCompat="@drawable/navigate_prev"
|
||||||
|
app:drawableLeftCompat="@drawable/navigate_prev"
|
||||||
|
app:drawableTint="@color/colorAccent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/next"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
app:drawableEndCompat="@drawable/navigate_next"
|
||||||
|
app:drawableRightCompat="@drawable/navigate_next"
|
||||||
|
app:drawableTint="@color/colorAccent" />
|
||||||
|
|
||||||
|
</merge>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<string name="main_jump_title">ページ移動</string>
|
<string name="main_jump_title">ページ移動</string>
|
||||||
<string name="main_jump_message">現ページ番号: %1$d\nページ数: %2$d</string>
|
<string name="main_jump_message">現ページ番号: %1$d\nページ数: %2$d</string>
|
||||||
<string name="unable_to_connect">hitomi.laに接続できません</string>
|
<string name="unable_to_connect">hitomi.laに接続できません</string>
|
||||||
<string name="main_move">%1$dページへ移動</string>
|
<string name="main_move_to_page">%1$dページへ移動</string>
|
||||||
<string name="settings_clear_downloads">ダウンロード削除</string>
|
<string name="settings_clear_downloads">ダウンロード削除</string>
|
||||||
<string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか?</string>
|
<string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか?</string>
|
||||||
<string name="settings_mirror_summary">ミラーサーバからイメージをロード</string>
|
<string name="settings_mirror_summary">ミラーサーバからイメージをロード</string>
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
<string name="main_menu_sort">ソート</string>
|
<string name="main_menu_sort">ソート</string>
|
||||||
<string name="main_menu_sort_newest">投稿日時順</string>
|
<string name="main_menu_sort_newest">投稿日時順</string>
|
||||||
<string name="main_menu_sort_popular">人気順</string>
|
<string name="main_menu_sort_popular">人気順</string>
|
||||||
<string name="ignore_update">無視</string>
|
<string name="ignore">無視</string>
|
||||||
<string name="lock_corrupted">ロックファイルが破損されています。Pupilを再再インストールしてください。</string>
|
<string name="lock_corrupted">ロックファイルが破損されています。Pupilを再再インストールしてください。</string>
|
||||||
<string name="settings_dark_mode_title">ダークモード</string>
|
<string name="settings_dark_mode_title">ダークモード</string>
|
||||||
<string name="settings_dark_mode_summary">夜にシコりたい方々へ</string>
|
<string name="settings_dark_mode_summary">夜にシコりたい方々へ</string>
|
||||||
@@ -155,4 +155,5 @@
|
|||||||
<string name="settings_tag_translation">タグ言語</string>
|
<string name="settings_tag_translation">タグ言語</string>
|
||||||
<string name="settings_tag_translation_message">Githubにて翻訳に参加できます</string>
|
<string name="settings_tag_translation_message">Githubにて翻訳に参加できます</string>
|
||||||
<string name="settings_concurrent_download">並列ダウンロード</string>
|
<string name="settings_concurrent_download">並列ダウンロード</string>
|
||||||
|
<string name="unaccessible_download_folder">アンドロイド11以上では外部からのアプリ内部空間接近が不可能です。ダウンロードフォルダを変更しますか?</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<string name="main_jump_title">페이지 이동</string>
|
<string name="main_jump_title">페이지 이동</string>
|
||||||
<string name="main_jump_message">현재 페이지: %1$d\n페이지 수: %2$d</string>
|
<string name="main_jump_message">현재 페이지: %1$d\n페이지 수: %2$d</string>
|
||||||
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
|
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
|
||||||
<string name="main_move">%1$d 페이지로 이동</string>
|
<string name="main_move_to_page">%1$d 페이지로 이동</string>
|
||||||
<string name="settings_clear_downloads">다운로드 삭제</string>
|
<string name="settings_clear_downloads">다운로드 삭제</string>
|
||||||
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
|
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
|
||||||
<string name="main_drawer_favorite">즐겨찾기</string>
|
<string name="main_drawer_favorite">즐겨찾기</string>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<string name="main_menu_sort">정렬</string>
|
<string name="main_menu_sort">정렬</string>
|
||||||
<string name="main_menu_sort_popular">인기순</string>
|
<string name="main_menu_sort_popular">인기순</string>
|
||||||
<string name="main_menu_sort_newest">시간순</string>
|
<string name="main_menu_sort_newest">시간순</string>
|
||||||
<string name="ignore_update">무시</string>
|
<string name="ignore">무시</string>
|
||||||
<string name="lock_corrupted">잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.</string>
|
<string name="lock_corrupted">잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.</string>
|
||||||
<string name="settings_dark_mode_title">다크 모드</string>
|
<string name="settings_dark_mode_title">다크 모드</string>
|
||||||
<string name="settings_dark_mode_summary">딥 다크한 모오드</string>
|
<string name="settings_dark_mode_summary">딥 다크한 모오드</string>
|
||||||
@@ -155,4 +155,5 @@
|
|||||||
<string name="settings_tag_translation">태그 언어</string>
|
<string name="settings_tag_translation">태그 언어</string>
|
||||||
<string name="settings_tag_translation_message">Github에서 번역에 참여하세요</string>
|
<string name="settings_tag_translation_message">Github에서 번역에 참여하세요</string>
|
||||||
<string name="settings_concurrent_download">병렬 다운로드</string>
|
<string name="settings_concurrent_download">병렬 다운로드</string>
|
||||||
|
<string name="unaccessible_download_folder">안드로이드 11 이상에서는 외부에서 현재 다운로드 폴더에 접근할 수 없습니다. 변경하시겠습니까?</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -21,4 +21,11 @@
|
|||||||
<declare-styleable name="TagChipGroup">
|
<declare-styleable name="TagChipGroup">
|
||||||
<attr name="maxTag" format="integer"/>
|
<attr name="maxTag" format="integer"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="RippleCircleStatus">
|
||||||
|
<attr name="half" format="enum">
|
||||||
|
<enum name="top" value="1"/>
|
||||||
|
<enum name="bottom" value="-1"/>
|
||||||
|
</attr>
|
||||||
|
</declare-styleable>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
<color name="colorPrimaryDark">#0093c4</color>
|
<color name="colorPrimaryDark">#0093c4</color>
|
||||||
<color name="colorAccent">#D81B60</color>
|
<color name="colorAccent">#D81B60</color>
|
||||||
|
|
||||||
|
<color name="material_light_blue_300">#4fc3f7</color>
|
||||||
|
<color name="material_light_blue_700">#0288d1</color>
|
||||||
<color name="material_pink_600">#d81b60</color>
|
<color name="material_pink_600">#d81b60</color>
|
||||||
<color name="material_blue_700">#1976d2</color>
|
<color name="material_blue_700">#1976d2</color>
|
||||||
<color name="material_green_a700">#00c853</color>
|
<color name="material_green_a700">#00c853</color>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<string name="warning">Warning</string>
|
<string name="warning">Warning</string>
|
||||||
<string name="error">Error</string>
|
<string name="error">Error</string>
|
||||||
|
|
||||||
<string name="ignore_update">Ignore</string>
|
<string name="ignore">Ignore</string>
|
||||||
|
|
||||||
<string name="copied_to_clipboard">Copied to clipboard</string>
|
<string name="copied_to_clipboard">Copied to clipboard</string>
|
||||||
|
|
||||||
@@ -47,6 +47,8 @@
|
|||||||
|
|
||||||
<string name="main_no_result">No result</string>
|
<string name="main_no_result">No result</string>
|
||||||
|
|
||||||
|
<string name="unaccessible_download_folder">From Android 11 and above, current Download folder cannot be accessed by outside apps. Would you like to change the download folder?</string>
|
||||||
|
|
||||||
<string name="main_drawer_home">Home</string>
|
<string name="main_drawer_home">Home</string>
|
||||||
<string name="main_drawer_history">History</string>
|
<string name="main_drawer_history">History</string>
|
||||||
<string name="main_drawer_downloads">Downloads</string>
|
<string name="main_drawer_downloads">Downloads</string>
|
||||||
@@ -71,7 +73,7 @@
|
|||||||
<string name="main_fab_random">Open a random gallery</string>
|
<string name="main_fab_random">Open a random gallery</string>
|
||||||
<string name="main_fab_cancel">Cancel all downloads</string>
|
<string name="main_fab_cancel">Cancel all downloads</string>
|
||||||
|
|
||||||
<string name="main_move">Move to page %1$d</string>
|
<string name="main_move_to_page">Move to page %1$d</string>
|
||||||
|
|
||||||
<string name="main_download">DOWNLOAD</string>
|
<string name="main_download">DOWNLOAD</string>
|
||||||
<string name="main_delete">DELETE</string>
|
<string name="main_delete">DELETE</string>
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||||
classpath "com.google.gms:google-services:4.3.3"
|
classpath "com.google.gms:google-services:4.3.4"
|
||||||
// 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.3.0"
|
classpath "com.google.firebase:firebase-crashlytics-gradle:2.4.1"
|
||||||
classpath "com.google.firebase:perf-plugin:1.3.2"
|
classpath "com.google.firebase:perf-plugin:1.3.4"
|
||||||
classpath "com.google.android.gms:oss-licenses-plugin:0.10.2"
|
classpath "com.google.android.gms:oss-licenses-plugin:0.10.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ kotlin.code.style=official
|
|||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
|
||||||
kotlin_version=1.4.10
|
kotlin_version=1.4.20
|
||||||
Reference in New Issue
Block a user