Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331cbec5f1 | ||
|
|
7f02284285 | ||
|
|
ac2c3a6d97 | ||
|
|
c3bc80fec6 | ||
|
|
09779a0710 | ||
|
|
e82c6ef866 | ||
|
|
861ae9be64 | ||
|
|
96108bc1ec | ||
|
|
016f217db0 | ||
|
|
0688294f18 | ||
|
|
9ad008255d | ||
|
|
4c5a862dd6 | ||
|
|
b165a2308f | ||
|
|
8757b08cd2 | ||
|
|
3800543fba |
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@@ -14,6 +14,7 @@
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="AndroidLintNewerVersionAvailable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
@@ -2,7 +2,7 @@
|
||||
*Pupil, Hitomi.la viewer for Android*
|
||||
|
||||

|
||||
[](https://github.com/tom5079/Pupil/releases/download/5.1.4/Pupil-v5.1.4.apk)
|
||||
[](https://github.com/tom5079/Pupil/releases/download/5.1.5-hotfix2/Pupil-v5.1.5-hotfix2.apk)
|
||||
[](https://discord.gg/Stj4b5v)
|
||||
|
||||
# Features
|
||||
|
||||
@@ -38,7 +38,7 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
versionCode 63
|
||||
versionName "5.1.4"
|
||||
versionName "5.1.5-hotfix2"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
@@ -77,13 +77,13 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0-RC2"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0-M1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.activity:activity-ktx:1.2.0-beta01"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.0-beta01"
|
||||
implementation "androidx.preference:preference:1.1.1"
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.2"
|
||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||
implementation "androidx.biometric:biometric:1.0.1"
|
||||
@@ -123,7 +123,7 @@ dependencies {
|
||||
implementation "ru.noties.markwon:core:3.1.0"
|
||||
|
||||
implementation "xyz.quaver:libpupil:1.7.2"
|
||||
implementation "xyz.quaver:documentfilex:0.3.1"
|
||||
implementation "xyz.quaver:documentfilex:0.4-alpha02"
|
||||
implementation "xyz.quaver:floatingsearchview:1.0.7"
|
||||
|
||||
testImplementation "junit:junit:4.13"
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "xyz.quaver.pupil",
|
||||
"variantName": "release",
|
||||
"variantName": "processReleaseResources",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"properties": [],
|
||||
"versionCode": 63,
|
||||
"versionName": "5.1.4",
|
||||
"enabled": true,
|
||||
"versionName": "5.1.5-hotfix2",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
|
||||
package xyz.quaver.pupil
|
||||
|
||||
import android.app.*
|
||||
import android.app.Application
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
||||
@@ -20,6 +20,7 @@ package xyz.quaver.pupil.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Log
|
||||
import android.util.SparseBooleanArray
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -229,6 +230,8 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
||||
}
|
||||
|
||||
tags.clear()
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
tags.addAll(
|
||||
galleryBlock.relatedTags.sortedBy {
|
||||
val tag = Tag.parse(it)
|
||||
@@ -246,8 +249,11 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
||||
}
|
||||
)
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
galleryblock_id.text = galleryBlock.id.toString()
|
||||
galleryblock_pagecount.text = "-"
|
||||
|
||||
@@ -255,6 +255,7 @@ class SettingsFragment :
|
||||
isEnabled = false
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
kotlin.runCatching {
|
||||
val languages = getAvailableLanguages().distinct().toTypedArray()
|
||||
|
||||
entries = languages.map { Locale(it).let { loc -> loc.getDisplayLanguage(loc) } }.toTypedArray()
|
||||
@@ -264,6 +265,7 @@ class SettingsFragment :
|
||||
isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceChangeListener = this@SettingsFragment
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
var onFavoriteHistorySwitchClickListener: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
||||
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or searchInputView.imeOptions
|
||||
|
||||
searchInputView.addTextChangedListener(this)
|
||||
onSearchListener = this
|
||||
|
||||
@@ -21,8 +21,10 @@ package xyz.quaver.pupil.ui.view
|
||||
import android.content.Context
|
||||
import android.content.res.TypedArray
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import kotlinx.coroutines.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.types.Tag
|
||||
import xyz.quaver.pupil.types.Tags
|
||||
@@ -66,20 +68,28 @@ class TagChipGroup @JvmOverloads constructor(context: Context, attr: AttributeSe
|
||||
maxChipSize = attr.getInt(R.styleable.TagChipGroup_maxTag, Defaults.maxChipSize)
|
||||
}
|
||||
|
||||
private var refreshJob: Job? = null
|
||||
fun refresh() {
|
||||
refreshJob?.cancel()
|
||||
this.removeAllViews()
|
||||
|
||||
tags.take(maxChipSize).forEach {
|
||||
this.addView(TagChip(context, it).apply {
|
||||
refreshJob = CoroutineScope(Dispatchers.Main).launch {
|
||||
tags.take(maxChipSize).map {
|
||||
CoroutineScope(Dispatchers.Default).async {
|
||||
TagChip(context, it).apply {
|
||||
setOnClickListener {
|
||||
onClickListener?.invoke(this.tag)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}.forEach {
|
||||
addView(it.await())
|
||||
}
|
||||
|
||||
if (maxChipSize > 0 && this.size > maxChipSize)
|
||||
if (maxChipSize > 0 && tags.size > maxChipSize && parent == null)
|
||||
addView(moreView)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
applyAttributes(context.obtainStyledAttributes(attr, R.styleable.TagChipGroup))
|
||||
|
||||
@@ -24,7 +24,7 @@ import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class SavedSet <T: Any> (private val file: File, private val any: T, private val set: MutableSet<T> = Collections.synchronizedSet(mutableSetOf())) : MutableSet<T> by set {
|
||||
class SavedSet <T: Any> (private val file: File, private val any: T, private val set: MutableSet<T> = mutableSetOf()) : MutableSet<T> by set {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@@ -39,8 +39,8 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
load()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun load() {
|
||||
synchronized(this) {
|
||||
set.clear()
|
||||
kotlin.runCatching {
|
||||
Json.decodeFromString(serializer, file.readText())
|
||||
@@ -48,15 +48,14 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
set.addAll(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun save() {
|
||||
synchronized(this) {
|
||||
file.writeText(Json.encodeToString(serializer, set.toList()))
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun add(element: T): Boolean {
|
||||
load()
|
||||
|
||||
@@ -67,6 +66,7 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun addAll(elements: Collection<T>): Boolean {
|
||||
load()
|
||||
|
||||
@@ -77,6 +77,7 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun remove(element: T): Boolean {
|
||||
load()
|
||||
|
||||
@@ -85,6 +86,7 @@ class SavedSet <T: Any> (private val file: File, private val any: T, private val
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun clear() {
|
||||
set.clear()
|
||||
save()
|
||||
|
||||
@@ -80,7 +80,7 @@ class DownloadManager private constructor(context: Context) : ContextWrapper(con
|
||||
}.invoke()
|
||||
}
|
||||
|
||||
return downloadFolderMapInstance!!
|
||||
return downloadFolderMapInstance ?: mutableMapOf()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -55,11 +55,13 @@ fun cleanCache(context: Context) = CoroutineScope(Dispatchers.IO).launch {
|
||||
while (cacheSize.invoke() > limit/2) {
|
||||
val caches = cacheFolder.list() ?: return@withLock
|
||||
|
||||
(histories.toList().firstOrNull {
|
||||
synchronized(histories) {
|
||||
(histories.firstOrNull {
|
||||
caches.contains(it.toString()) && !downloadManager.isDownloading(it)
|
||||
} ?: return@withLock).let {
|
||||
Cache.delete(context, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,13 @@ var translations: Map<String, String> = run {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
fun updateTranslations() = CoroutineScope(Dispatchers.IO).launch {
|
||||
translations = emptyMap()
|
||||
kotlin.runCatching {
|
||||
translations = Json.decodeFromString<Map<String, String>>(client.newCall(
|
||||
Request.Builder()
|
||||
.url(contentURL + "${Preferences["tag_language", ""]}.json")
|
||||
.build()
|
||||
).execute().also { if (it.code() != 200) return@launch }.body()?.use { it.string() } ?: return@launch).filterValues { it.isNotEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
fun getAvailableLanguages(): List<String> {
|
||||
|
||||
@@ -212,8 +212,8 @@
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/divider"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="parent" />
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/galleryblock_favorite"
|
||||
|
||||
@@ -154,4 +154,5 @@
|
||||
<string name="settings_cache_unlimited">制限なし</string>
|
||||
<string name="settings_tag_language">タグ言語</string>
|
||||
<string name="settings_tag_language_message">Githubにて翻訳に参加できます</string>
|
||||
<string name="settings_concurrent_download">並列ダウンロード</string>
|
||||
</resources>
|
||||
@@ -154,4 +154,5 @@
|
||||
<string name="settings_cache_unlimited">무제한</string>
|
||||
<string name="settings_tag_language">태그 언어</string>
|
||||
<string name="settings_tag_language_message">Github에서 번역에 참여하세요</string>
|
||||
<string name="settings_concurrent_download">병렬 다운로드</string>
|
||||
</resources>
|
||||
@@ -176,6 +176,7 @@
|
||||
|
||||
<string name="settings_miscellaneous_title">Miscellaneous</string>
|
||||
<string name="settings_tag_language">Tag Language</string>
|
||||
<string name="settings_concurrent_download">Concurrent Download</string>
|
||||
<string name="settings_tag_language_message">Participate in translation on Github</string>
|
||||
<string name="settings_mirror_summary">Load images from mirrors</string>
|
||||
<string name="settings_proxy_title">Proxy</string>
|
||||
|
||||
@@ -6,7 +6,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
|
||||
@@ -15,6 +15,7 @@ org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
|
||||
org.gradle.parallel=true
|
||||
org.gradle.daemon=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.caching=true
|
||||
kotlin.code.style=official
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Thu Oct 01 20:54:37 KST 2020
|
||||
#Tue Oct 13 22:37:11 KST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
|
||||
Reference in New Issue
Block a user