Compare commits
48 Commits
4.2-beta2-
...
4.3-hotfix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20bc5423cf | ||
|
|
b84cddffdc | ||
|
|
e46d1123df | ||
|
|
2c9c8e223c | ||
|
|
e81b5a4e3a | ||
|
|
0b87c57fbf | ||
|
|
5fd985ba39 | ||
|
|
8c64548513 | ||
|
|
a6de64ceb9 | ||
|
|
16ebb437a3 | ||
|
|
683118a3f4 | ||
|
|
08e38ed45c | ||
|
|
7abf08f1fb | ||
|
|
f3019e9b84 | ||
|
|
c468764234 | ||
|
|
31c3178430 | ||
|
|
e81c189afc | ||
|
|
e0ccac13c1 | ||
|
|
93228459d7 | ||
|
|
63e07f56e0 | ||
|
|
ee87122bb2 | ||
|
|
290dda9018 | ||
|
|
1d3d78b936 | ||
|
|
a947bc6415 | ||
|
|
9ca891b2f5 | ||
|
|
48e0ebc8ae | ||
|
|
b323353006 | ||
|
|
c85d3ebe81 | ||
|
|
ce843abec8 | ||
|
|
6b43faa70e | ||
|
|
2d0c997b2e | ||
|
|
1db5118377 | ||
|
|
26b53ed7ac | ||
|
|
2c85ea6443 | ||
|
|
cbc2b30f47 | ||
|
|
0b58deb92c | ||
|
|
ed1cf23c91 | ||
|
|
6fbb644e4b | ||
|
|
774867502d | ||
|
|
c8b1439aeb | ||
|
|
38c16adffe | ||
|
|
18aede2701 | ||
|
|
c59d08a0a1 | ||
|
|
66ae29eb5b | ||
|
|
7d9cb3e150 | ||
|
|
3159c343c1 | ||
|
|
678a8f0914 | ||
|
|
f2a2656837 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,4 +16,4 @@
|
|||||||
/gh-pages
|
/gh-pages
|
||||||
|
|
||||||
#Private files
|
#Private files
|
||||||
/app/google-services.json
|
**/google-services.json
|
||||||
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@@ -2,5 +2,6 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/gh-pages" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -3,9 +3,15 @@ apply plugin: 'kotlin-android'
|
|||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
apply plugin: 'kotlinx-serialization'
|
apply plugin: 'kotlinx-serialization'
|
||||||
|
|
||||||
|
if (file("google-services.json").exists()) {
|
||||||
|
logger.lifecycle("Firebase Enabled")
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
apply plugin: 'io.fabric'
|
apply plugin: 'io.fabric'
|
||||||
apply plugin: 'com.google.firebase.firebase-perf'
|
apply plugin: 'com.google.firebase.firebase-perf'
|
||||||
|
} else {
|
||||||
|
logger.lifecycle("Firebase Disabled")
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
@@ -13,8 +19,8 @@ android {
|
|||||||
applicationId "xyz.quaver.pupil"
|
applicationId "xyz.quaver.pupil"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 31
|
versionCode 32
|
||||||
versionName "4.2-beta2-hotfix1"
|
versionName "4.3-hotfix1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
@@ -25,7 +31,6 @@ android {
|
|||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
buildTypes.each {
|
buildTypes.each {
|
||||||
it.buildConfigField('boolean', 'PRERELEASE', 'true')
|
|
||||||
it.buildConfigField('boolean', 'CENSOR', 'false')
|
it.buildConfigField('boolean', 'CENSOR', 'false')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +41,7 @@ android {
|
|||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
buildToolsVersion = '29.0.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -44,34 +50,34 @@ dependencies {
|
|||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0"
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
implementation 'androidx.preference:preference:1.1.0'
|
implementation 'androidx.preference:preference:1.1.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation "androidx.biometric:biometric:1.0.0"
|
implementation "androidx.biometric:biometric:1.0.1"
|
||||||
implementation 'com.android.support:multidex:1.0.3'
|
implementation 'com.android.support:multidex:1.0.3'
|
||||||
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.2.0-alpha02'
|
implementation 'com.google.android.material:material:1.2.0-alpha04'
|
||||||
implementation 'com.google.firebase:firebase-core:17.2.1'
|
implementation 'com.google.firebase:firebase-core:17.2.2'
|
||||||
implementation 'com.google.firebase:firebase-perf:19.0.3'
|
implementation 'com.google.firebase:firebase-perf:19.0.5'
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
||||||
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
|
||||||
implementation 'com.github.clans:fab:1.6.4'
|
implementation 'com.github.clans:fab:1.6.4'
|
||||||
implementation 'com.github.bumptech.glide:glide:4.9.0'
|
implementation 'com.github.bumptech.glide:glide:4.10.0'
|
||||||
implementation ("com.github.bumptech.glide:recyclerview-integration:4.9.0") {
|
implementation ("com.github.bumptech.glide:recyclerview-integration:4.10.0") {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
|
||||||
implementation "ru.noties.markwon:core:${markwonVersion}"
|
implementation "ru.noties.markwon:core:${markwonVersion}"
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.9.0'
|
kapt 'com.github.bumptech.glide:compiler:4.10.0'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.13'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":31,"versionName":"4.2-beta2-hotfix1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":32,"versionName":"4.3-hotfix1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil
|
package xyz.quaver.pupil
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.rule.ActivityTestRule
|
import androidx.test.rule.ActivityTestRule
|
||||||
@@ -64,7 +64,9 @@ class ExampleInstrumentedTest {
|
|||||||
val activityTestRule = ActivityTestRule(LockActivity::class.java)
|
val activityTestRule = ActivityTestRule(LockActivity::class.java)
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
|
||||||
activityTestRule.launchActivity(Intent())
|
ContextCompat.getExternalFilesDirs(appContext, null).forEachIndexed { index, file ->
|
||||||
|
Log.i("PUPILD", "$index: ${file?.absolutePath}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
package="xyz.quaver.pupil">
|
package="xyz.quaver.pupil">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
|
||||||
android:maxSdkVersion="28"/>
|
|
||||||
<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" />
|
||||||
|
|
||||||
@@ -55,18 +53,7 @@
|
|||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data
|
<data
|
||||||
android:host="히요비.asia"
|
android:host="hiyobi.me"
|
||||||
android:pathPrefix="/reader"
|
|
||||||
android:scheme="https" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:host="xn--9w3b15m8vo.asia"
|
|
||||||
android:pathPrefix="/reader"
|
android:pathPrefix="/reader"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@@ -99,20 +86,9 @@
|
|||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data
|
<data
|
||||||
android:host="히요비.asia"
|
android:host="hiyobi.me"
|
||||||
android:pathPrefix="/reader"
|
android:scheme="http"
|
||||||
android:scheme="http" />
|
android:pathPrefix="/reader" />
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:host="xn--9w3b15m8vo.asia"
|
|
||||||
android:pathPrefix="/reader"
|
|
||||||
android:scheme="http" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ class Pupil : MultiDexApplication() {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!preference.getBoolean("channel_created", false)) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
val channel = NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_LOW).apply {
|
val channel = NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_LOW).apply {
|
||||||
@@ -74,9 +73,6 @@ class Pupil : MultiDexApplication() {
|
|||||||
manager.createNotificationChannel(channel)
|
manager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
preference.edit().putBoolean("channel_created", true).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
AppCompatDelegate.setDefaultNightMode(when (preference.getBoolean("dark_mode", false)) {
|
AppCompatDelegate.setDefaultNightMode(when (preference.getBoolean("dark_mode", false)) {
|
||||||
true -> AppCompatDelegate.MODE_NIGHT_YES
|
true -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
false -> AppCompatDelegate.MODE_NIGHT_NO
|
false -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
text = tag.tag.wordCapitalize()
|
text = tag.tag.wordCapitalize()
|
||||||
|
setEnsureMinTouchTargetSize(false)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
for (callback in onChipClickedHandler)
|
for (callback in onChipClickedHandler)
|
||||||
callback.invoke(tag)
|
callback.invoke(tag)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import kotlinx.android.synthetic.main.activity_lock.*
|
import kotlinx.android.synthetic.main.activity_lock.*
|
||||||
import kotlinx.android.synthetic.main.fragment_pattern_lock.*
|
import kotlinx.android.synthetic.main.fragment_pattern_lock.*
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.ui.fragment.PatternLockFragment
|
||||||
import xyz.quaver.pupil.util.Lock
|
import xyz.quaver.pupil.util.Lock
|
||||||
import xyz.quaver.pupil.util.LockManager
|
import xyz.quaver.pupil.util.LockManager
|
||||||
|
|
||||||
|
|||||||
@@ -18,23 +18,18 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui
|
package xyz.quaver.pupil.ui
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.DownloadManager
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.text.*
|
import android.text.*
|
||||||
import android.text.style.AlignmentSpan
|
import android.text.style.AlignmentSpan
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
@@ -42,7 +37,6 @@ import android.widget.TextView
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
@@ -53,18 +47,14 @@ import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
|||||||
import com.arlib.floatingsearchview.util.view.SearchInputView
|
import com.arlib.floatingsearchview.util.view.SearchInputView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.activity_main_content.*
|
import kotlinx.android.synthetic.main.activity_main_content.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
import kotlinx.serialization.json.content
|
|
||||||
import kotlinx.serialization.list
|
import kotlinx.serialization.list
|
||||||
import kotlinx.serialization.stringify
|
import kotlinx.serialization.stringify
|
||||||
import ru.noties.markwon.Markwon
|
|
||||||
import xyz.quaver.hitomi.*
|
import xyz.quaver.hitomi.*
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
@@ -72,6 +62,7 @@ import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
|||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.types.TagSuggestion
|
import xyz.quaver.pupil.types.TagSuggestion
|
||||||
import xyz.quaver.pupil.types.Tags
|
import xyz.quaver.pupil.types.Tags
|
||||||
|
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
||||||
import xyz.quaver.pupil.util.*
|
import xyz.quaver.pupil.util.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
@@ -143,8 +134,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (lockManager.isNotEmpty())
|
if (lockManager.isNotEmpty())
|
||||||
startActivityForResult(Intent(this, LockActivity::class.java), REQUEST_LOCK)
|
startActivityForResult(Intent(this, LockActivity::class.java), REQUEST_LOCK)
|
||||||
|
|
||||||
checkPermissions()
|
|
||||||
|
|
||||||
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
if (Locale.getDefault().language == "ko") {
|
if (Locale.getDefault().language == "ko") {
|
||||||
@@ -167,7 +156,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
checkUpdate()
|
checkUpdate(this)
|
||||||
|
|
||||||
initView()
|
initView()
|
||||||
}
|
}
|
||||||
@@ -256,125 +245,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkUpdate() {
|
|
||||||
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
val ignoreUpdateUntil = preferences.getLong("ignore_update_until", 0)
|
|
||||||
|
|
||||||
if (ignoreUpdateUntil > System.currentTimeMillis())
|
|
||||||
return
|
|
||||||
|
|
||||||
fun extractReleaseNote(update: JsonObject, locale: String) : String {
|
|
||||||
val markdown = update["body"]!!.content
|
|
||||||
|
|
||||||
val target = when(locale) {
|
|
||||||
"ko" -> "한국어"
|
|
||||||
"ja" -> "日本語"
|
|
||||||
else -> "English"
|
|
||||||
}
|
|
||||||
|
|
||||||
val releaseNote = Regex("^# Release Note.+$")
|
|
||||||
val language = Regex("^## $target$")
|
|
||||||
val end = Regex("^#.+$")
|
|
||||||
|
|
||||||
var releaseNoteFlag = false
|
|
||||||
var languageFlag = false
|
|
||||||
|
|
||||||
val result = StringBuilder()
|
|
||||||
|
|
||||||
for(line in markdown.lines()) {
|
|
||||||
if (releaseNote.matches(line)) {
|
|
||||||
releaseNoteFlag = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (releaseNoteFlag) {
|
|
||||||
if (language.matches(line)) {
|
|
||||||
languageFlag = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (languageFlag) {
|
|
||||||
if (end.matches(line))
|
|
||||||
break
|
|
||||||
|
|
||||||
result.append(line+"\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getString(R.string.update_release_note, update["tag_name"]?.content, result.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
|
||||||
val update =
|
|
||||||
checkUpdate(getString(R.string.release_url)) ?: return@launch
|
|
||||||
|
|
||||||
val (url, fileName) = getApkUrl(update) ?: return@launch
|
|
||||||
fileName ?: return@launch
|
|
||||||
|
|
||||||
val dialog = AlertDialog.Builder(this@MainActivity).apply {
|
|
||||||
setTitle(R.string.update_title)
|
|
||||||
val msg = extractReleaseNote(update, Locale.getDefault().language)
|
|
||||||
setMessage(Markwon.create(context).toMarkdown(msg))
|
|
||||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
|
||||||
if (!this@MainActivity.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
|
||||||
AlertDialog.Builder(this@MainActivity).apply {
|
|
||||||
setTitle(R.string.warning)
|
|
||||||
setMessage(R.string.update_no_permission)
|
|
||||||
setPositiveButton(android.R.string.ok) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
return@setPositiveButton
|
|
||||||
}
|
|
||||||
|
|
||||||
val request = DownloadManager.Request(Uri.parse(url)).apply {
|
|
||||||
setDescription(getString(R.string.update_notification_description))
|
|
||||||
setTitle(getString(R.string.app_name))
|
|
||||||
setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
|
||||||
val id = manager.enqueue(request)
|
|
||||||
|
|
||||||
registerReceiver(object: BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
|
||||||
try {
|
|
||||||
val install = Intent(Intent.ACTION_VIEW).apply {
|
|
||||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
||||||
setDataAndType(manager.getUriForDownloadedFile(id), manager.getMimeTypeForDownloadedFile(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
startActivity(install)
|
|
||||||
unregisterReceiver(this)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
AlertDialog.Builder(this@MainActivity).apply {
|
|
||||||
setTitle(R.string.update_failed)
|
|
||||||
setMessage(R.string.update_failed_message)
|
|
||||||
setPositiveButton(android.R.string.ok) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
|
||||||
}
|
|
||||||
setNegativeButton(R.string.ignore_update) { _, _ ->
|
|
||||||
preferences.edit()
|
|
||||||
.putLong("ignore_update_until", System.currentTimeMillis() + 604800000)
|
|
||||||
.apply()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
dialog.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkPermissions() {
|
|
||||||
if (!hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE))
|
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 13489)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
var prevP1 = 0
|
var prevP1 = 0
|
||||||
main_appbar_layout.addOnOffsetChangedListener(
|
main_appbar_layout.addOnOffsetChangedListener(
|
||||||
@@ -495,21 +365,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setTitle(R.string.main_open_gallery_by_id)
|
setTitle(R.string.main_open_gallery_by_id)
|
||||||
|
|
||||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
val galleryID = editText.text.toString().toInt()
|
||||||
try {
|
val intent = Intent(this@MainActivity, ReaderActivity::class.java).apply {
|
||||||
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
putExtra("galleryID", galleryID)
|
||||||
val gallery =
|
}
|
||||||
getGalleryBlock(editText.text.toString().toInt()) ?: throw Exception()
|
|
||||||
intent.putExtra("galleryID", gallery.id)
|
|
||||||
|
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
|
|
||||||
histories.add(gallery.id)
|
histories.add(galleryID)
|
||||||
} catch (e: Exception) {
|
|
||||||
Snackbar.make(main_layout,
|
|
||||||
R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
@@ -613,7 +476,10 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val galleryID = galleries[position].first.id
|
val galleryID = galleries[position].first.id
|
||||||
|
|
||||||
GalleryDialog(this@MainActivity, galleryID).apply {
|
GalleryDialog(
|
||||||
|
this@MainActivity,
|
||||||
|
galleryID
|
||||||
|
).apply {
|
||||||
onChipClickedHandler.add {
|
onChipClickedHandler.add {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
query = it.toQuery()
|
query = it.toQuery()
|
||||||
@@ -856,6 +722,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
s.replace(0, s.length, s.toString().toLowerCase(Locale.getDefault()))
|
s.replace(0, s.length, s.toString().toLowerCase(Locale.getDefault()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
||||||
|
|
||||||
with(main_searchview as FloatingSearchView) {
|
with(main_searchview as FloatingSearchView) {
|
||||||
val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json")
|
val favoritesFile = File(ContextCompat.getDataDir(context), "favorites_tags.json")
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.ui
|
package xyz.quaver.pupil.ui
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@@ -36,6 +35,7 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
|||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import io.fabric.sdk.android.Fabric
|
||||||
import kotlinx.android.synthetic.main.activity_reader.*
|
import kotlinx.android.synthetic.main.activity_reader.*
|
||||||
import kotlinx.android.synthetic.main.activity_reader.view.*
|
import kotlinx.android.synthetic.main.activity_reader.view.*
|
||||||
import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
||||||
@@ -49,7 +49,6 @@ import xyz.quaver.pupil.adapters.ReaderAdapter
|
|||||||
import xyz.quaver.pupil.util.GalleryDownloader
|
import xyz.quaver.pupil.util.GalleryDownloader
|
||||||
import xyz.quaver.pupil.util.Histories
|
import xyz.quaver.pupil.util.Histories
|
||||||
import xyz.quaver.pupil.util.ItemClickSupport
|
import xyz.quaver.pupil.util.ItemClickSupport
|
||||||
import xyz.quaver.pupil.util.hasPermission
|
|
||||||
|
|
||||||
class ReaderActivity : AppCompatActivity() {
|
class ReaderActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@@ -95,6 +94,7 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
handleIntent(intent)
|
handleIntent(intent)
|
||||||
|
|
||||||
|
if (Fabric.isInitialized())
|
||||||
Crashlytics.setInt("GalleryID", galleryID)
|
Crashlytics.setInt("GalleryID", galleryID)
|
||||||
|
|
||||||
if (galleryID == 0) {
|
if (galleryID == 0) {
|
||||||
@@ -371,17 +371,6 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
with(reader_fab_download) {
|
with(reader_fab_download) {
|
||||||
setImageResource(R.drawable.ic_download)
|
setImageResource(R.drawable.ic_download)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
|
|
||||||
if (!this@ReaderActivity.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
|
||||||
AlertDialog.Builder(this@ReaderActivity).apply {
|
|
||||||
setTitle(R.string.warning)
|
|
||||||
setMessage(R.string.update_no_permission)
|
|
||||||
setPositiveButton(android.R.string.ok) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
return@setOnClickListener
|
|
||||||
}
|
|
||||||
|
|
||||||
downloader.download = !downloader.download
|
downloader.download = !downloader.download
|
||||||
|
|
||||||
if (!downloader.download)
|
if (!downloader.download)
|
||||||
|
|||||||
@@ -21,35 +21,19 @@ package xyz.quaver.pupil.ui
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.dialog_default_query.view.*
|
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.parseList
|
import kotlinx.serialization.parseList
|
||||||
import xyz.quaver.pupil.Pupil
|
import xyz.quaver.pupil.Pupil
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.types.Tags
|
import xyz.quaver.pupil.ui.fragment.LockFragment
|
||||||
import xyz.quaver.pupil.util.Lock
|
import xyz.quaver.pupil.ui.fragment.SettingsFragment
|
||||||
import xyz.quaver.pupil.util.LockManager
|
|
||||||
import xyz.quaver.pupil.util.getDownloadDirectory
|
|
||||||
import java.io.File
|
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class SettingsActivity : AppCompatActivity() {
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@@ -83,369 +67,6 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat() {
|
|
||||||
|
|
||||||
private val suffix = listOf(
|
|
||||||
"B",
|
|
||||||
"kB",
|
|
||||||
"MB",
|
|
||||||
"GB",
|
|
||||||
"TB" //really?
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
val lockManager = LockManager(context!!)
|
|
||||||
|
|
||||||
findPreference<Preference>("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) {
|
|
||||||
getString(R.string.settings_lock_none)
|
|
||||||
} else {
|
|
||||||
lockManager.locks?.joinToString(", ") {
|
|
||||||
when(it.type) {
|
|
||||||
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
|
||||||
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
|
||||||
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDirSize(dir: File) : String {
|
|
||||||
var size = dir.walk().map { it.length() }.sum()
|
|
||||||
var suffixIndex = 0
|
|
||||||
|
|
||||||
while (size >= 1024) {
|
|
||||||
size /= 1024
|
|
||||||
suffixIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
return getString(R.string.settings_clear_summary, size, suffix[suffixIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
|
||||||
|
|
||||||
with(findPreference<Preference>("app_version")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
val manager = context.packageManager
|
|
||||||
val info = manager.getPackageInfo(context.packageName, 0)
|
|
||||||
|
|
||||||
summary = info.versionName
|
|
||||||
}
|
|
||||||
|
|
||||||
with(findPreference<Preference>("delete_cache")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
val dir = File(context.cacheDir, "imageCache")
|
|
||||||
|
|
||||||
summary = getDirSize(dir)
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
AlertDialog.Builder(context).apply {
|
|
||||||
setTitle(R.string.warning)
|
|
||||||
setMessage(R.string.settings_clear_cache_alert_message)
|
|
||||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
|
||||||
if (dir.exists())
|
|
||||||
dir.deleteRecursively()
|
|
||||||
|
|
||||||
summary = getDirSize(dir)
|
|
||||||
}
|
|
||||||
setNegativeButton(android.R.string.no) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(findPreference<Preference>("delete_downloads")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
val dir = getDownloadDirectory(context)
|
|
||||||
|
|
||||||
summary = getDirSize(dir)
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
AlertDialog.Builder(context).apply {
|
|
||||||
setTitle(R.string.warning)
|
|
||||||
setMessage(R.string.settings_clear_downloads_alert_message)
|
|
||||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
|
||||||
if (dir.exists())
|
|
||||||
dir.deleteRecursively()
|
|
||||||
|
|
||||||
val downloads = (activity!!.application as Pupil).downloads
|
|
||||||
|
|
||||||
downloads.clear()
|
|
||||||
|
|
||||||
summary = getDirSize(dir)
|
|
||||||
}
|
|
||||||
setNegativeButton(android.R.string.no) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with(findPreference<Preference>("clear_history")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
val histories = (activity!!.application as Pupil).histories
|
|
||||||
|
|
||||||
summary = getString(R.string.settings_clear_history_summary, histories.size)
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
AlertDialog.Builder(context).apply {
|
|
||||||
setTitle(R.string.warning)
|
|
||||||
setMessage(R.string.settings_clear_history_alert_message)
|
|
||||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
|
||||||
histories.clear()
|
|
||||||
summary = getString(R.string.settings_clear_history_summary, histories.size)
|
|
||||||
}
|
|
||||||
setNegativeButton(android.R.string.no) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(findPreference<Preference>("default_query")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
|
||||||
|
|
||||||
summary = preferences.getString("default_query", "") ?: ""
|
|
||||||
|
|
||||||
val languages = resources.getStringArray(R.array.languages).map {
|
|
||||||
it.split("|").let { split ->
|
|
||||||
Pair(split[0], split[1])
|
|
||||||
}
|
|
||||||
}.toMap()
|
|
||||||
val reverseLanguages = languages.entries.associate { (k, v) -> v to k }
|
|
||||||
|
|
||||||
val excludeBL = "-male:yaoi"
|
|
||||||
val excludeGuro = listOf("-female:guro", "-male:guro")
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
val dialogView = LayoutInflater.from(context).inflate(
|
|
||||||
R.layout.dialog_default_query,
|
|
||||||
LinearLayout(context),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
val tags = Tags.parse(
|
|
||||||
preferences.getString("default_query", "") ?: ""
|
|
||||||
)
|
|
||||||
|
|
||||||
summary = tags.toString()
|
|
||||||
|
|
||||||
with(dialogView.default_query_dialog_language_selector) {
|
|
||||||
adapter =
|
|
||||||
ArrayAdapter(
|
|
||||||
context,
|
|
||||||
android.R.layout.simple_spinner_dropdown_item,
|
|
||||||
arrayListOf(
|
|
||||||
getString(R.string.default_query_dialog_language_selector_none)
|
|
||||||
).apply {
|
|
||||||
addAll(languages.values)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (tags.any { it.area == "language" && !it.isNegative }) {
|
|
||||||
val tag = languages[tags.first { it.area == "language" }.tag]
|
|
||||||
if (tag != null) {
|
|
||||||
setSelection(
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
(adapter as ArrayAdapter<String>).getPosition(tag)
|
|
||||||
)
|
|
||||||
tags.removeByArea("language", false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(dialogView.default_query_dialog_BL_checkbox) {
|
|
||||||
isChecked = tags.contains(excludeBL)
|
|
||||||
if (tags.contains(excludeBL))
|
|
||||||
tags.remove(excludeBL)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(dialogView.default_query_dialog_guro_checkbox) {
|
|
||||||
isChecked = excludeGuro.all { tags.contains(it) }
|
|
||||||
if (excludeGuro.all { tags.contains(it) })
|
|
||||||
excludeGuro.forEach {
|
|
||||||
tags.remove(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(dialogView.default_query_dialog_edittext) {
|
|
||||||
setText(tags.toString(), TextView.BufferType.EDITABLE)
|
|
||||||
addTextChangedListener(object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
|
||||||
|
|
||||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable?) {
|
|
||||||
s ?: return
|
|
||||||
|
|
||||||
if (s.any { it.isUpperCase() })
|
|
||||||
s.replace(0, s.length, s.toString().toLowerCase(Locale.getDefault()))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
val dialog = AlertDialog.Builder(context!!).apply {
|
|
||||||
setView(dialogView)
|
|
||||||
}.create()
|
|
||||||
|
|
||||||
dialogView.default_query_dialog_ok.setOnClickListener {
|
|
||||||
val newTags = Tags.parse(dialogView.default_query_dialog_edittext.text.toString())
|
|
||||||
|
|
||||||
with(dialogView.default_query_dialog_language_selector) {
|
|
||||||
if (selectedItemPosition != 0)
|
|
||||||
newTags.add("language:${reverseLanguages[selectedItem]}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dialogView.default_query_dialog_BL_checkbox.isChecked)
|
|
||||||
newTags.add(excludeBL)
|
|
||||||
|
|
||||||
if (dialogView.default_query_dialog_guro_checkbox.isChecked)
|
|
||||||
excludeGuro.forEach { tag ->
|
|
||||||
newTags.add(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
preferenceManager.sharedPreferences.edit().putString("default_query", newTags.toString()).apply()
|
|
||||||
summary = preferences.getString("default_query", "") ?: ""
|
|
||||||
tags.clear()
|
|
||||||
tags.addAll(newTags)
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with(findPreference<Preference>("app_lock")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
val lockManager = LockManager(context)
|
|
||||||
|
|
||||||
summary = if (lockManager.locks.isNullOrEmpty()) {
|
|
||||||
getString(R.string.settings_lock_none)
|
|
||||||
} else {
|
|
||||||
lockManager.locks?.joinToString(", ") {
|
|
||||||
when(it.type) {
|
|
||||||
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
|
||||||
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
|
||||||
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
val intent = Intent(context, LockActivity::class.java)
|
|
||||||
activity?.startActivityForResult(intent, (activity as SettingsActivity).REQUEST_LOCK)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(findPreference<Preference>("dark_mode")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
|
||||||
AppCompatDelegate.setDefaultNightMode(when (newValue as Boolean) {
|
|
||||||
true -> AppCompatDelegate.MODE_NIGHT_YES
|
|
||||||
false -> AppCompatDelegate.MODE_NIGHT_NO
|
|
||||||
})
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(findPreference<Preference>("backup")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
File(ContextCompat.getDataDir(context), "favorites.json").copyTo(
|
|
||||||
File(getDownloadDirectory(context), "favorites.json"),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
Snackbar.make(this@SettingsFragment.listView, R.string.settings_backup_snackbar, Snackbar.LENGTH_LONG)
|
|
||||||
.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(findPreference<Preference>("restore")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
type = "*/*"
|
|
||||||
}
|
|
||||||
|
|
||||||
activity?.startActivityForResult(intent, (activity as SettingsActivity).REQUEST_RESTORE)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LockFragment : PreferenceFragmentCompat() {
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
val lockManager = LockManager(context!!)
|
|
||||||
|
|
||||||
findPreference<Preference>("lock_pattern")?.summary =
|
|
||||||
if (lockManager.contains(Lock.Type.PATTERN))
|
|
||||||
getString(R.string.settings_lock_enabled)
|
|
||||||
else
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.lock_preferences, rootKey)
|
|
||||||
|
|
||||||
with(findPreference<Preference>("lock_pattern")) {
|
|
||||||
this!!
|
|
||||||
|
|
||||||
if (LockManager(context!!).contains(Lock.Type.PATTERN))
|
|
||||||
summary = getString(R.string.settings_lock_enabled)
|
|
||||||
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
val lockManager = LockManager(context!!)
|
|
||||||
|
|
||||||
if (lockManager.contains(Lock.Type.PATTERN)) {
|
|
||||||
AlertDialog.Builder(context).apply {
|
|
||||||
setTitle(R.string.warning)
|
|
||||||
setMessage(R.string.settings_lock_remove_message)
|
|
||||||
|
|
||||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
|
||||||
lockManager.remove(Lock.Type.PATTERN)
|
|
||||||
onResume()
|
|
||||||
}
|
|
||||||
setNegativeButton(android.R.string.no) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
} else {
|
|
||||||
val intent = Intent(context, LockActivity::class.java).apply {
|
|
||||||
putExtra("mode", "add_lock")
|
|
||||||
putExtra("type", "pattern")
|
|
||||||
}
|
|
||||||
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||||
when (item?.itemId) {
|
when (item?.itemId) {
|
||||||
android.R.id.home -> onBackPressed()
|
android.R.id.home -> onBackPressed()
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Pupil, Hitomi.la viewer for Android
|
||||||
|
* Copyright (C) 2020 tom5079
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import kotlinx.android.synthetic.main.dialog_default_query.view.*
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.types.Tags
|
||||||
|
|
||||||
|
class DefaultQueryDialog(context : Context) : AlertDialog(context) {
|
||||||
|
|
||||||
|
private val languages = context.resources.getStringArray(R.array.languages).map {
|
||||||
|
it.split("|").let { split ->
|
||||||
|
Pair(split[0], split[1])
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
|
private val reverseLanguages = languages.entries.associate { (k, v) -> v to k }
|
||||||
|
|
||||||
|
private val excludeBL = "-male:yaoi"
|
||||||
|
private val excludeGuro = listOf("-female:guro", "-male:guro")
|
||||||
|
|
||||||
|
private lateinit var dialogView : View
|
||||||
|
|
||||||
|
var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_default_query, null)
|
||||||
|
|
||||||
|
initView()
|
||||||
|
|
||||||
|
setContentView(dialogView)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val tags = Tags.parse(
|
||||||
|
preferences.getString("default_query", "") ?: ""
|
||||||
|
)
|
||||||
|
|
||||||
|
with(dialogView.default_query_dialog_language_selector) {
|
||||||
|
adapter =
|
||||||
|
ArrayAdapter(
|
||||||
|
context,
|
||||||
|
android.R.layout.simple_spinner_dropdown_item,
|
||||||
|
arrayListOf(
|
||||||
|
context.getString(R.string.default_query_dialog_language_selector_none)
|
||||||
|
).apply {
|
||||||
|
addAll(languages.values)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (tags.any { it.area == "language" && !it.isNegative }) {
|
||||||
|
val tag = languages[tags.first { it.area == "language" }.tag]
|
||||||
|
if (tag != null) {
|
||||||
|
setSelection(
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
(adapter as ArrayAdapter<String>).getPosition(tag)
|
||||||
|
)
|
||||||
|
tags.removeByArea("language", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(dialogView.default_query_dialog_BL_checkbox) {
|
||||||
|
isChecked = tags.contains(excludeBL)
|
||||||
|
if (tags.contains(excludeBL))
|
||||||
|
tags.remove(excludeBL)
|
||||||
|
}
|
||||||
|
|
||||||
|
with(dialogView.default_query_dialog_guro_checkbox) {
|
||||||
|
isChecked = excludeGuro.all { tags.contains(it) }
|
||||||
|
if (excludeGuro.all { tags.contains(it) })
|
||||||
|
excludeGuro.forEach {
|
||||||
|
tags.remove(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(dialogView.default_query_dialog_edittext) {
|
||||||
|
setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE)
|
||||||
|
addTextChangedListener(object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||||
|
|
||||||
|
override fun afterTextChanged(s: Editable?) {
|
||||||
|
s ?: return
|
||||||
|
|
||||||
|
if (s.any { it.isUpperCase() })
|
||||||
|
s.replace(0, s.length, s.toString().toLowerCase(java.util.Locale.getDefault()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.default_query_dialog_ok.setOnClickListener {
|
||||||
|
val newTags = Tags.parse(dialogView.default_query_dialog_edittext.text.toString())
|
||||||
|
|
||||||
|
with(dialogView.default_query_dialog_language_selector) {
|
||||||
|
if (selectedItemPosition != 0)
|
||||||
|
newTags.add("language:${reverseLanguages[selectedItem]}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogView.default_query_dialog_BL_checkbox.isChecked)
|
||||||
|
newTags.add(excludeBL)
|
||||||
|
|
||||||
|
if (dialogView.default_query_dialog_guro_checkbox.isChecked)
|
||||||
|
excludeGuro.forEach { tag ->
|
||||||
|
newTags.add(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositiveButtonClickListener?.invoke(newTags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Pupil, Hitomi.la viewer for Android
|
||||||
|
* Copyright (C) 2020 tom5079
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import kotlinx.android.synthetic.main.item_dl_location.view.*
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.util.byteToString
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
class DownloadLocationDialog(context: Context) : AlertDialog(context) {
|
||||||
|
|
||||||
|
private val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
private val buttons = mutableListOf<RadioButton>()
|
||||||
|
var onDownloadLocationChangedListener : ((Int) -> (Unit))? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
val view = layoutInflater.inflate(R.layout.dialog_dl_location, null) as LinearLayout
|
||||||
|
|
||||||
|
ContextCompat.getExternalFilesDirs(context, null).forEachIndexed { index, dir ->
|
||||||
|
|
||||||
|
dir ?: return@forEachIndexed
|
||||||
|
|
||||||
|
view.addView(layoutInflater.inflate(R.layout.item_dl_location, view, false).apply {
|
||||||
|
location_type.text = context.getString(when (index) {
|
||||||
|
0 -> R.string.settings_dl_location_internal
|
||||||
|
else -> R.string.settings_dl_location_removable
|
||||||
|
})
|
||||||
|
location_available.text = context.getString(
|
||||||
|
R.string.settings_dl_location_available,
|
||||||
|
byteToString(dir.freeSpace)
|
||||||
|
)
|
||||||
|
setOnClickListener {
|
||||||
|
buttons.forEach { button ->
|
||||||
|
button.isChecked = false
|
||||||
|
}
|
||||||
|
button.performClick()
|
||||||
|
onDownloadLocationChangedListener?.invoke(index)
|
||||||
|
}
|
||||||
|
buttons.add(button)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons[preference.getInt("dl_location", 0)].isChecked = true
|
||||||
|
|
||||||
|
setTitle(R.string.settings_dl_location)
|
||||||
|
|
||||||
|
setView(view)
|
||||||
|
|
||||||
|
setButton(Dialog.BUTTON_POSITIVE, context.getText(android.R.string.ok)) { _, _ ->
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Pupil, Hitomi.la viewer for Android
|
* Pupil, Hitomi.la viewer for Android
|
||||||
* Copyright (C) 2019 tom5079
|
* Copyright (C) 2020 tom5079
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package xyz.quaver.pupil.ui
|
package xyz.quaver.pupil.ui.dialog
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -46,6 +46,7 @@ import xyz.quaver.pupil.R
|
|||||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||||
import xyz.quaver.pupil.adapters.ThumbnailAdapter
|
import xyz.quaver.pupil.adapters.ThumbnailAdapter
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
|
import xyz.quaver.pupil.ui.ReaderActivity
|
||||||
import xyz.quaver.pupil.util.ItemClickSupport
|
import xyz.quaver.pupil.util.ItemClickSupport
|
||||||
import xyz.quaver.pupil.util.wordCapitalize
|
import xyz.quaver.pupil.util.wordCapitalize
|
||||||
|
|
||||||
@@ -256,7 +257,10 @@ class GalleryDialog(context: Context, private val galleryID: Int) : Dialog(conte
|
|||||||
(context.applicationContext as Pupil).histories.add(galleries[position].first.id)
|
(context.applicationContext as Pupil).histories.add(galleries[position].first.id)
|
||||||
}
|
}
|
||||||
.setOnItemLongClickListener { _, position, _ ->
|
.setOnItemLongClickListener { _, position, _ ->
|
||||||
GalleryDialog(context, galleries[position].first.id).apply {
|
GalleryDialog(
|
||||||
|
context,
|
||||||
|
galleries[position].first.id
|
||||||
|
).apply {
|
||||||
onChipClickedHandler.add { tag ->
|
onChipClickedHandler.add { tag ->
|
||||||
this@GalleryDialog.onChipClickedHandler.forEach { it.invoke(tag) }
|
this@GalleryDialog.onChipClickedHandler.forEach { it.invoke(tag) }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.fragment
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.ui.LockActivity
|
||||||
|
import xyz.quaver.pupil.util.Lock
|
||||||
|
import xyz.quaver.pupil.util.LockManager
|
||||||
|
|
||||||
|
class LockFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
val lockManager = LockManager(context!!)
|
||||||
|
|
||||||
|
findPreference<Preference>("lock_pattern")?.summary =
|
||||||
|
if (lockManager.contains(Lock.Type.PATTERN))
|
||||||
|
getString(R.string.settings_lock_enabled)
|
||||||
|
else
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.lock_preferences, rootKey)
|
||||||
|
|
||||||
|
with(findPreference<Preference>("lock_pattern")) {
|
||||||
|
this!!
|
||||||
|
|
||||||
|
if (LockManager(context!!).contains(Lock.Type.PATTERN))
|
||||||
|
summary = getString(R.string.settings_lock_enabled)
|
||||||
|
|
||||||
|
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
val lockManager = LockManager(context!!)
|
||||||
|
|
||||||
|
if (lockManager.contains(Lock.Type.PATTERN)) {
|
||||||
|
AlertDialog.Builder(context).apply {
|
||||||
|
setTitle(R.string.warning)
|
||||||
|
setMessage(R.string.settings_lock_remove_message)
|
||||||
|
|
||||||
|
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
|
lockManager.remove(Lock.Type.PATTERN)
|
||||||
|
onResume()
|
||||||
|
}
|
||||||
|
setNegativeButton(android.R.string.no) { _, _ -> }
|
||||||
|
}.show()
|
||||||
|
} else {
|
||||||
|
val intent = Intent(context, LockActivity::class.java).apply {
|
||||||
|
putExtra("mode", "add_lock")
|
||||||
|
putExtra("type", "pattern")
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package xyz.quaver.pupil.ui
|
package xyz.quaver.pupil.ui.fragment
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* 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.fragment
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceCategory
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import xyz.quaver.pupil.Pupil
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.ui.LockActivity
|
||||||
|
import xyz.quaver.pupil.ui.SettingsActivity
|
||||||
|
import xyz.quaver.pupil.ui.dialog.DefaultQueryDialog
|
||||||
|
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialog
|
||||||
|
import xyz.quaver.pupil.util.*
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsFragment :
|
||||||
|
PreferenceFragmentCompat(),
|
||||||
|
Preference.OnPreferenceClickListener,
|
||||||
|
Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
val lockManager = LockManager(context!!)
|
||||||
|
|
||||||
|
findPreference<Preference>("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) {
|
||||||
|
getString(R.string.settings_lock_none)
|
||||||
|
} else {
|
||||||
|
lockManager.locks?.joinToString(", ") {
|
||||||
|
when(it.type) {
|
||||||
|
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
||||||
|
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
||||||
|
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDirSize(dir: File) : String {
|
||||||
|
val size = dir.walk().map { it.length() }.sum()
|
||||||
|
|
||||||
|
return getString(R.string.settings_clear_summary, byteToString(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceClick(preference: Preference?): Boolean {
|
||||||
|
with (preference) {
|
||||||
|
this ?: return false
|
||||||
|
|
||||||
|
when (key) {
|
||||||
|
"app_version" -> {
|
||||||
|
checkUpdate(activity as SettingsActivity, true)
|
||||||
|
}
|
||||||
|
"delete_cache" -> {
|
||||||
|
val dir = File(context.cacheDir, "imageCache")
|
||||||
|
|
||||||
|
AlertDialog.Builder(context).apply {
|
||||||
|
setTitle(R.string.warning)
|
||||||
|
setMessage(R.string.settings_clear_cache_alert_message)
|
||||||
|
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
|
if (dir.exists())
|
||||||
|
dir.deleteRecursively()
|
||||||
|
|
||||||
|
summary = getDirSize(dir)
|
||||||
|
}
|
||||||
|
setNegativeButton(android.R.string.no) { _, _ -> }
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
"delete_downloads" -> {
|
||||||
|
val dir = getDownloadDirectory(context)
|
||||||
|
|
||||||
|
AlertDialog.Builder(context).apply {
|
||||||
|
setTitle(R.string.warning)
|
||||||
|
setMessage(R.string.settings_clear_downloads_alert_message)
|
||||||
|
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
|
if (dir.exists())
|
||||||
|
dir.deleteRecursively()
|
||||||
|
|
||||||
|
val downloads = (activity!!.application as Pupil).downloads
|
||||||
|
|
||||||
|
downloads.clear()
|
||||||
|
|
||||||
|
summary = getDirSize(dir)
|
||||||
|
}
|
||||||
|
setNegativeButton(android.R.string.no) { _, _ -> }
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
"clear_history" -> {
|
||||||
|
val histories = (context.applicationContext as Pupil).histories
|
||||||
|
|
||||||
|
AlertDialog.Builder(context).apply {
|
||||||
|
setTitle(R.string.warning)
|
||||||
|
setMessage(R.string.settings_clear_history_alert_message)
|
||||||
|
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
|
histories.clear()
|
||||||
|
summary = getString(R.string.settings_clear_history_summary, histories.size)
|
||||||
|
}
|
||||||
|
setNegativeButton(android.R.string.no) { _, _ -> }
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
"dl_location" -> {
|
||||||
|
DownloadLocationDialog(context).apply {
|
||||||
|
onDownloadLocationChangedListener = { value ->
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
||||||
|
.putInt(key, value)
|
||||||
|
.apply()
|
||||||
|
summary = getDownloadDirectory(context).absolutePath
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
"default_query" -> {
|
||||||
|
DefaultQueryDialog(context).apply {
|
||||||
|
onPositiveButtonClickListener = { newTags ->
|
||||||
|
sharedPreferences.edit().putString("default_query", newTags.toString()).apply()
|
||||||
|
summary = newTags.toString()
|
||||||
|
dismiss() //This sucks
|
||||||
|
// TODO: make dialog dissmiss itself :P
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
"app_lock" -> {
|
||||||
|
val intent = Intent(context, LockActivity::class.java)
|
||||||
|
activity?.startActivityForResult(intent, (activity as SettingsActivity).REQUEST_LOCK)
|
||||||
|
}
|
||||||
|
"backup" -> {
|
||||||
|
File(ContextCompat.getDataDir(context), "favorites.json").copyTo(
|
||||||
|
File(getDownloadDirectory(context), "favorites.json"),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
Snackbar.make(this@SettingsFragment.listView, R.string.settings_backup_snackbar, Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
"restore" -> {
|
||||||
|
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "*/*"
|
||||||
|
}
|
||||||
|
|
||||||
|
activity?.startActivityForResult(intent, (activity as SettingsActivity).REQUEST_RESTORE)
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
|
||||||
|
with (preference) {
|
||||||
|
this ?: return false
|
||||||
|
|
||||||
|
when (key) {
|
||||||
|
"dark_mode" -> {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(when (newValue as Boolean) {
|
||||||
|
true -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
false -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||||
|
|
||||||
|
initPreferences()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initPreferences() {
|
||||||
|
for (i in 0 until preferenceScreen.preferenceCount) {
|
||||||
|
|
||||||
|
preferenceScreen.getPreference(i).run {
|
||||||
|
if (this is PreferenceCategory)
|
||||||
|
(0 until preferenceCount).map { getPreference(it) }
|
||||||
|
else
|
||||||
|
listOf(this)
|
||||||
|
}.forEach { preference ->
|
||||||
|
with (preference) {
|
||||||
|
|
||||||
|
when (key) {
|
||||||
|
"app_version" -> {
|
||||||
|
val manager = context.packageManager
|
||||||
|
val info = manager.getPackageInfo(context.packageName, 0)
|
||||||
|
summary = context.getString(R.string.settings_app_version_description, info.versionName)
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"delete_cache" -> {
|
||||||
|
val dir = File(context.cacheDir, "imageCache")
|
||||||
|
summary = getDirSize(dir)
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"delete_downloads" -> {
|
||||||
|
val dir = getDownloadDirectory(context)
|
||||||
|
summary = getDirSize(dir)
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"clear_history" -> {
|
||||||
|
val histories = (activity!!.application as Pupil).histories
|
||||||
|
summary = getString(R.string.settings_clear_history_summary, histories.size)
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"dl_location" -> {
|
||||||
|
summary = getDownloadDirectory(context).absolutePath
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"default_query" -> {
|
||||||
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
summary = preferences.getString("default_query", "") ?: ""
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"app_lock" -> {
|
||||||
|
val lockManager = LockManager(context)
|
||||||
|
summary =
|
||||||
|
if (lockManager.locks.isNullOrEmpty()) {
|
||||||
|
getString(R.string.settings_lock_none)
|
||||||
|
} else {
|
||||||
|
lockManager.locks?.joinToString(", ") {
|
||||||
|
when (it.type) {
|
||||||
|
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
||||||
|
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
||||||
|
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"dark_mode" -> {
|
||||||
|
onPreferenceChangeListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"backup" -> {
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
"restore" -> {
|
||||||
|
onPreferenceClickListener = this@SettingsFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -163,11 +163,11 @@ class GalleryDownloader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp"
|
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
downloadJob = CoroutineScope(Dispatchers.Default).launch {
|
downloadJob = CoroutineScope(Dispatchers.Default).launch {
|
||||||
val reader = reader!!.await() ?: return@launch
|
val reader = reader!!.await() ?: return@launch
|
||||||
|
val lowQuality = PreferenceManager.getDefaultSharedPreferences(this@GalleryDownloader)
|
||||||
|
.getBoolean("low_quality", false)
|
||||||
|
|
||||||
notificationBuilder.setContentTitle(reader.title)
|
notificationBuilder.setContentTitle(reader.title)
|
||||||
|
|
||||||
@@ -179,15 +179,15 @@ class GalleryDownloader(
|
|||||||
.setProgress(reader.galleryInfo.size, 0, false)
|
.setProgress(reader.galleryInfo.size, 0, false)
|
||||||
.setContentText("0/${reader.galleryInfo.size}")
|
.setContentText("0/${reader.galleryInfo.size}")
|
||||||
|
|
||||||
reader.galleryInfo.chunked(4).forEachIndexed { chunkIndex, chunked ->
|
reader.galleryInfo.chunked(4).forEachIndexed { chunkIndex, chunk ->
|
||||||
chunked.mapIndexed { i, galleryInfo ->
|
chunk.mapIndexed { i, galleryInfo ->
|
||||||
val index = chunkIndex*4+i
|
val index = chunkIndex*4+i
|
||||||
|
|
||||||
async(Dispatchers.IO) {
|
async(Dispatchers.IO) {
|
||||||
val url = when(useHiyobi) {
|
val url = when(useHiyobi) {
|
||||||
true -> createImgList(galleryID, reader)[index].path
|
true -> createImgList(galleryID, reader, lowQuality)[index].path
|
||||||
false -> when {
|
false -> when {
|
||||||
(!galleryInfo.hash.isNullOrBlank()) and (galleryInfo.haswebp == 1) ->
|
(!galleryInfo.hash.isNullOrBlank()) && (galleryInfo.haswebp == 1) && lowQuality ->
|
||||||
urlFromUrlFromHash(galleryID, galleryInfo, "webp")
|
urlFromUrlFromHash(galleryID, galleryInfo, "webp")
|
||||||
else ->
|
else ->
|
||||||
urlFromUrlFromHash(galleryID, galleryInfo)
|
urlFromUrlFromHash(galleryID, galleryInfo)
|
||||||
|
|||||||
@@ -19,9 +19,10 @@
|
|||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import androidx.core.content.ContextCompat
|
||||||
import android.os.Environment
|
import androidx.preference.PreferenceManager
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
fun getCachedGallery(context: Context, galleryID: Int): File {
|
fun getCachedGallery(context: Context, galleryID: Int): File {
|
||||||
return File(getDownloadDirectory(context), galleryID.toString()).let {
|
return File(getDownloadDirectory(context), galleryID.toString()).let {
|
||||||
@@ -32,10 +33,32 @@ fun getCachedGallery(context: Context, galleryID: Int): File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
fun getDownloadDirectory(context: Context): File {
|
fun getDownloadDirectory(context: Context): File {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
val dlLocation = PreferenceManager.getDefaultSharedPreferences(context).getInt("dl_location", 0)
|
||||||
context.getExternalFilesDir("Pupil")!!
|
|
||||||
else
|
return ContextCompat.getExternalFilesDirs(context, null)[dlLocation]
|
||||||
File(Environment.getExternalStorageDirectory(), "Pupil")
|
}
|
||||||
|
|
||||||
|
fun URL.download(to: File, onDownloadProgress: ((Long, Long) -> Unit)? = null) {
|
||||||
|
to.outputStream().use { out ->
|
||||||
|
|
||||||
|
with(openConnection()) {
|
||||||
|
val fileSize = contentLength.toLong()
|
||||||
|
|
||||||
|
getInputStream().use {
|
||||||
|
|
||||||
|
var bytesCopied: Long = 0
|
||||||
|
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||||
|
var bytes = it.read(buffer)
|
||||||
|
while (bytes >= 0) {
|
||||||
|
out.write(buffer, 0, bytes)
|
||||||
|
bytesCopied += bytes
|
||||||
|
onDownloadProgress?.invoke(bytesCopied, fileSize)
|
||||||
|
bytes = it.read(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,18 +18,37 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager
|
import java.util.*
|
||||||
import androidx.core.content.ContextCompat
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
fun Context.hasPermission(permission: String) =
|
|
||||||
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
|
|
||||||
|
|
||||||
|
@UseExperimental(ExperimentalStdlibApi::class)
|
||||||
fun String.wordCapitalize() : String {
|
fun String.wordCapitalize() : String {
|
||||||
val result = ArrayList<String>()
|
val result = ArrayList<String>()
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
for (word in this.split(" "))
|
for (word in this.split(" "))
|
||||||
result.add(word.capitalize())
|
result.add(word.capitalize(Locale.US))
|
||||||
|
|
||||||
return result.joinToString(" ")
|
return result.joinToString(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun byteToString(byte: Long, precision : Int = 1) : String {
|
||||||
|
|
||||||
|
val suffix = listOf(
|
||||||
|
"B",
|
||||||
|
"kB",
|
||||||
|
"MB",
|
||||||
|
"GB",
|
||||||
|
"TB" //really?
|
||||||
|
)
|
||||||
|
var size = byte.toDouble(); var suffixIndex = 0
|
||||||
|
|
||||||
|
while (size >= 1024) {
|
||||||
|
size /= 1024
|
||||||
|
suffixIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
return "%.${precision}f ${suffix[suffixIndex]}".format(size)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,15 +18,32 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.webkit.MimeTypeMap
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.InternalSerializationApi
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
import kotlinx.serialization.internal.EnumSerializer
|
import kotlinx.serialization.internal.EnumSerializer
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
|
import ru.noties.markwon.Markwon
|
||||||
import xyz.quaver.availableInHiyobi
|
import xyz.quaver.availableInHiyobi
|
||||||
import xyz.quaver.hitomi.Reader
|
import xyz.quaver.hitomi.Reader
|
||||||
import xyz.quaver.pupil.BuildConfig
|
import xyz.quaver.pupil.BuildConfig
|
||||||
|
import xyz.quaver.pupil.R
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
fun getReleases(url: String) : JsonArray {
|
fun getReleases(url: String) : JsonArray {
|
||||||
return try {
|
return try {
|
||||||
@@ -38,18 +55,17 @@ fun getReleases(url: String) : JsonArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkUpdate(url: String) : JsonObject? {
|
fun checkUpdate(context: Context, url: String) : JsonObject? {
|
||||||
val releases = getReleases(url)
|
val releases = getReleases(url)
|
||||||
|
|
||||||
if (releases.isEmpty())
|
if (releases.isEmpty())
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return releases.firstOrNull {
|
return releases.firstOrNull {
|
||||||
if (BuildConfig.PRERELEASE) {
|
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("beta", false))
|
||||||
true
|
true
|
||||||
} else {
|
else
|
||||||
it.jsonObject["prerelease"]?.boolean == false
|
it.jsonObject["prerelease"]?.boolean == false
|
||||||
}
|
|
||||||
}?.let {
|
}?.let {
|
||||||
if (it.jsonObject["tag_name"]?.content == BuildConfig.VERSION_NAME)
|
if (it.jsonObject["tag_name"]?.content == BuildConfig.VERSION_NAME)
|
||||||
null
|
null
|
||||||
@@ -58,14 +74,145 @@ fun checkUpdate(url: String) : JsonObject? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getApkUrl(releases: JsonObject) : Pair<String?, String?>? {
|
fun getApkUrl(releases: JsonObject) : String? {
|
||||||
return releases["assets"]?.jsonArray?.firstOrNull {
|
return releases["assets"]?.jsonArray?.firstOrNull {
|
||||||
Regex("Pupil-v.+\\.apk").matches(it.jsonObject["name"]?.content ?: "")
|
Regex("Pupil-v.+\\.apk").matches(it.jsonObject["name"]?.content ?: "")
|
||||||
}.let {
|
}.let {
|
||||||
if (it == null)
|
it?.jsonObject?.get("browser_download_url")?.content
|
||||||
null
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const val UPDATE_NOTIFICATION_ID = 384823
|
||||||
|
fun checkUpdate(context: AppCompatActivity, force: Boolean = false) {
|
||||||
|
|
||||||
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val ignoreUpdateUntil = preferences.getLong("ignore_update_until", 0)
|
||||||
|
|
||||||
|
if (!force && ignoreUpdateUntil > System.currentTimeMillis())
|
||||||
|
return
|
||||||
|
|
||||||
|
fun extractReleaseNote(update: JsonObject, locale: Locale) : String {
|
||||||
|
val markdown = update["body"]!!.content
|
||||||
|
|
||||||
|
val target = when(locale.language) {
|
||||||
|
"ko" -> "한국어"
|
||||||
|
"ja" -> "日本語"
|
||||||
|
else -> "English"
|
||||||
|
}
|
||||||
|
|
||||||
|
val releaseNote = Regex("^# Release Note.+$")
|
||||||
|
val language = Regex("^## $target$")
|
||||||
|
val end = Regex("^#.+$")
|
||||||
|
|
||||||
|
var releaseNoteFlag = false
|
||||||
|
var languageFlag = false
|
||||||
|
|
||||||
|
val result = StringBuilder()
|
||||||
|
|
||||||
|
for(line in markdown.lines()) {
|
||||||
|
if (releaseNote.matches(line)) {
|
||||||
|
releaseNoteFlag = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (releaseNoteFlag) {
|
||||||
|
if (language.matches(line)) {
|
||||||
|
languageFlag = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (languageFlag) {
|
||||||
|
if (end.matches(line))
|
||||||
|
break
|
||||||
|
|
||||||
|
result.append(line+"\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.getString(R.string.update_release_note, update["tag_name"]?.content, result.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
val update =
|
||||||
|
checkUpdate(context, context.getString(R.string.release_url)) ?: return@launch
|
||||||
|
|
||||||
|
val url = getApkUrl(update) ?: return@launch
|
||||||
|
|
||||||
|
val dialog = AlertDialog.Builder(context).apply {
|
||||||
|
setTitle(R.string.update_title)
|
||||||
|
val msg = extractReleaseNote(update, Locale.getDefault())
|
||||||
|
setMessage(Markwon.create(context).toMarkdown(msg))
|
||||||
|
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
|
|
||||||
|
val notificationManager = NotificationManagerCompat.from(context)
|
||||||
|
val builder = NotificationCompat.Builder(context, "download").apply {
|
||||||
|
setContentTitle(context.getString(R.string.update_notification_description))
|
||||||
|
setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
|
priority = NotificationCompat.PRIORITY_LOW
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch io@{
|
||||||
|
val target = File(getDownloadDirectory(context), "Pupil.apk")
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL(url).download(target) { progress, fileSize ->
|
||||||
|
builder.setProgress(fileSize.toInt(), progress.toInt(), false)
|
||||||
|
notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
builder.apply {
|
||||||
|
setContentText(context.getString(R.string.update_failed))
|
||||||
|
setMessage(context.getString(R.string.update_failed_message))
|
||||||
|
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationManager.cancel(UPDATE_NOTIFICATION_ID)
|
||||||
|
notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
|
|
||||||
|
return@io
|
||||||
|
}
|
||||||
|
|
||||||
|
val install = Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
setDataAndType(FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
context.applicationContext.packageName + ".fileprovider",
|
||||||
|
target
|
||||||
|
), MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk"))
|
||||||
|
|
||||||
|
if (resolveActivity(context.packageManager) == null)
|
||||||
|
setDataAndType(Uri.fromFile(target),
|
||||||
|
MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk"))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.apply {
|
||||||
|
setContentIntent(PendingIntent.getActivity(context, 0, install, 0))
|
||||||
|
setProgress(0, 0, false)
|
||||||
|
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||||
|
setContentTitle(context.getString(R.string.update_download_completed))
|
||||||
|
setContentText(context.getString(R.string.update_download_completed_description))
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationManager.cancel(UPDATE_NOTIFICATION_ID)
|
||||||
|
|
||||||
|
if (context.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED))
|
||||||
|
context.startActivity(install)
|
||||||
else
|
else
|
||||||
Pair(it.jsonObject["browser_download_url"]?.content, it.jsonObject["name"]?.content)
|
notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setNegativeButton(if (force) android.R.string.no else R.string.ignore_update) { _, _ ->
|
||||||
|
if (!force)
|
||||||
|
preferences.edit()
|
||||||
|
.putLong("ignore_update_until", System.currentTimeMillis() + 604800000)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
app/src/main/res/layout/dialog_dl_location.xml
Normal file
25
app/src/main/res/layout/dialog_dl_location.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"/>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
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"
|
||||||
tools:context=".ui.PatternLockFragment">
|
tools:context=".ui.fragment.PatternLockFragment">
|
||||||
|
|
||||||
<com.andrognito.patternlockview.PatternLockView
|
<com.andrognito.patternlockview.PatternLockView
|
||||||
android:id="@+id/lock_pattern_view"
|
android:id="@+id/lock_pattern_view"
|
||||||
|
|||||||
51
app/src/main/res/layout/item_dl_location.xml
Normal file
51
app/src/main/res/layout/item_dl_location.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="horizontal" android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/button"
|
||||||
|
android:clickable="false"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/location_type"
|
||||||
|
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/location_available"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.github.chrisbanes.photoview.PhotoView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:contentDescription="@string/reader_imageview_description"
|
android:contentDescription="@string/reader_imageview_description"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
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"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/nav_header_height"
|
android:layout_height="@dimen/nav_header_height"
|
||||||
android:background="@drawable/side_nav_bar"
|
android:background="@drawable/side_nav_bar"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<string name="search_hint_with_page">ギャラリー検索</string>
|
<string name="search_hint_with_page">ギャラリー検索</string>
|
||||||
<string name="settings_clear_cache">キャッシュクリア</string>
|
<string name="settings_clear_cache">キャッシュクリア</string>
|
||||||
<string name="settings_clear_cache_alert_message">キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?</string>
|
<string name="settings_clear_cache_alert_message">キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか?</string>
|
||||||
<string name="settings_clear_summary">サイズ: %1$d%2$s</string>
|
<string name="settings_clear_summary">サイズ: %s</string>
|
||||||
<string name="settings_default_query">デフォルトキーワード</string>
|
<string name="settings_default_query">デフォルトキーワード</string>
|
||||||
<string name="settings_galleries_per_page">一回にロードするギャラリー数</string>
|
<string name="settings_galleries_per_page">一回にロードするギャラリー数</string>
|
||||||
<string name="settings_search_title">検索設定</string>
|
<string name="settings_search_title">検索設定</string>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
<string name="main_drawer_grouop_contact_discord">ディスコード</string>
|
<string name="main_drawer_grouop_contact_discord">ディスコード</string>
|
||||||
<string name="settings_app_lock">アプリロック</string>
|
<string name="settings_app_lock">アプリロック</string>
|
||||||
<string name="settings_app_lock_type">アップロックの種類</string>
|
<string name="settings_app_lock_type">アップロックの種類</string>
|
||||||
<string name="settings_app_version_title">バージョン</string>
|
<string name="settings_app_version_title">バージョン(アップデート確認)</string>
|
||||||
<string name="settings_lock_biometrics">生体認識</string>
|
<string name="settings_lock_biometrics">生体認識</string>
|
||||||
<string name="settings_lock_confirm">ロック確認のためもう一回入力してください。</string>
|
<string name="settings_lock_confirm">ロック確認のためもう一回入力してください。</string>
|
||||||
<string name="settings_lock_enabled">有効</string>
|
<string name="settings_lock_enabled">有効</string>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<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="update_failed">アップデートに失敗しました</string>
|
<string name="update_failed">アップデートに失敗しました</string>
|
||||||
<string name="update_failed_message">マニュアルインストールが必要です。APKファイルは</string>
|
<string name="update_failed_message">アップデート中エラーが発生しました</string>
|
||||||
<string name="ignore_update">無視</string>
|
<string name="ignore_update">無視</string>
|
||||||
<string name="lock_corrupted">ロックファイルが破損されています。Pupilを再再インストールしてください。</string>
|
<string name="lock_corrupted">ロックファイルが破損されています。Pupilを再再インストールしてください。</string>
|
||||||
<string name="update_no_permission">権限がないため自動アップデートを行えません。ホームページで直接ダウンロードしてください。</string>
|
<string name="update_no_permission">権限がないため自動アップデートを行えません。ホームページで直接ダウンロードしてください。</string>
|
||||||
@@ -110,4 +110,14 @@
|
|||||||
<string name="settings_backup_checkout">確認</string>
|
<string name="settings_backup_checkout">確認</string>
|
||||||
<string name="settings_restore_failed">復元に失敗しました</string>
|
<string name="settings_restore_failed">復元に失敗しました</string>
|
||||||
<string name="settings_restore_successful">%1$d項目を復元しました</string>
|
<string name="settings_restore_successful">%1$d項目を復元しました</string>
|
||||||
|
<string name="settings_dl_location">ダウンロード場所</string>
|
||||||
|
<string name="settings_dl_location_internal">内部ストレージ</string>
|
||||||
|
<string name="settings_dl_location_removable">外部SDカード</string>
|
||||||
|
<string name="settings_dl_location_available">%s 使用可能</string>
|
||||||
|
<string name="update_download_completed">ダウンロードが完了しました</string>
|
||||||
|
<string name="update_download_completed_description">ここをクリックしてアップデートを行えます</string>
|
||||||
|
<string name="settings_beta">ベータチャンネルでアップデートを受信</string>
|
||||||
|
<string name="settings_app_version_description">v%s</string>
|
||||||
|
<string name="settings_low_quality">低解像度イメージ</string>
|
||||||
|
<string name="settings_low_quality_summary">ロード速度とデータ使用料を改善するため低解像度イメージをロード</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<string name="settings_default_query">기본 검색어</string>
|
<string name="settings_default_query">기본 검색어</string>
|
||||||
<string name="settings_clear_cache">캐시 정리하기</string>
|
<string name="settings_clear_cache">캐시 정리하기</string>
|
||||||
<string name="settings_clear_cache_alert_message">캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?</string>
|
<string name="settings_clear_cache_alert_message">캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까?</string>
|
||||||
<string name="settings_clear_summary">사용량: %1$d%2$s</string>
|
<string name="settings_clear_summary">사용량: %s</string>
|
||||||
<string name="settings_galleries_per_page">한 번에 로드할 갤러리 수</string>
|
<string name="settings_galleries_per_page">한 번에 로드할 갤러리 수</string>
|
||||||
<string name="settings_search_title">검색 설정</string>
|
<string name="settings_search_title">검색 설정</string>
|
||||||
<string name="settings_title">설정</string>
|
<string name="settings_title">설정</string>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
<string name="main_drawer_grouop_contact_discord">디스코드</string>
|
<string name="main_drawer_grouop_contact_discord">디스코드</string>
|
||||||
<string name="settings_app_lock">앱 잠금</string>
|
<string name="settings_app_lock">앱 잠금</string>
|
||||||
<string name="settings_app_lock_type">앱 잠금 종류</string>
|
<string name="settings_app_lock_type">앱 잠금 종류</string>
|
||||||
<string name="settings_app_version_title">앱 버전</string>
|
<string name="settings_app_version_title">앱 버전(업데이트 확인)</string>
|
||||||
<string name="settings_lock_biometrics">생체 인식</string>
|
<string name="settings_lock_biometrics">생체 인식</string>
|
||||||
<string name="settings_lock_confirm">잠금 확인을 위해 한번 더 입력해주세요</string>
|
<string name="settings_lock_confirm">잠금 확인을 위해 한번 더 입력해주세요</string>
|
||||||
<string name="settings_lock_enabled">사용 중</string>
|
<string name="settings_lock_enabled">사용 중</string>
|
||||||
@@ -83,8 +83,8 @@
|
|||||||
<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="update_failed">"업데이트 "</string>
|
<string name="update_failed">"업데이트 에러</string>
|
||||||
<string name="update_failed_message">수동 업데이트가 필요합니다. APK 파일은 다운로드 폴더에 있습니다.</string>
|
<string name="update_failed_message">업데이트 중 에러가 발생했습니다</string>
|
||||||
<string name="ignore_update">무시</string>
|
<string name="ignore_update">무시</string>
|
||||||
<string name="lock_corrupted">잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.</string>
|
<string name="lock_corrupted">잠금 파일이 손상되었습니다! 앱을 재설치 해 주시기 바랍니다.</string>
|
||||||
<string name="update_no_permission">권한이 부여되어 있지 않아 자동 업데이트를 진행할 수 없습니다. 홈페이지에서 직접 다운로드 받으시기 바랍니다.</string>
|
<string name="update_no_permission">권한이 부여되어 있지 않아 자동 업데이트를 진행할 수 없습니다. 홈페이지에서 직접 다운로드 받으시기 바랍니다.</string>
|
||||||
@@ -110,4 +110,14 @@
|
|||||||
<string name="settings_backup_checkout">확인</string>
|
<string name="settings_backup_checkout">확인</string>
|
||||||
<string name="settings_restore_failed">복원에 실패했습니다</string>
|
<string name="settings_restore_failed">복원에 실패했습니다</string>
|
||||||
<string name="settings_restore_successful">%1$d개 항목을 복원했습니다</string>
|
<string name="settings_restore_successful">%1$d개 항목을 복원했습니다</string>
|
||||||
|
<string name="settings_dl_location">다운로드 위치</string>
|
||||||
|
<string name="settings_dl_location_internal">내부 저장공간</string>
|
||||||
|
<string name="settings_dl_location_removable">외부 SD카드</string>
|
||||||
|
<string name="settings_dl_location_available">%s 사용 가능</string>
|
||||||
|
<string name="update_download_completed">다운로드가 완료되었습니다</string>
|
||||||
|
<string name="update_download_completed_description">여기를 클릭해서 업데이트를 진행할 수 있습니다</string>
|
||||||
|
<string name="settings_beta">베타 채널에서 업데이트</string>
|
||||||
|
<string name="settings_app_version_description">v%s</string>
|
||||||
|
<string name="settings_low_quality">저해상도 이미지</string>
|
||||||
|
<string name="settings_low_quality_summary">로드 속도와 데이터 사용량을 줄이기 위해 저해상도 이미지를 로드</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<string name="https_block_alert">(Korean only)</string>
|
<string name="https_block_alert">(Korean only)</string>
|
||||||
|
|
||||||
<string name="update_failed">Update failed</string>
|
<string name="update_failed">Update failed</string>
|
||||||
<string name="update_failed_message">Please install manually. APK file is in the Downloads folder.</string>
|
<string name="update_failed_message">Please install manually by visiting github release page :{ (or try again!)</string>
|
||||||
<string name="update_no_permission">Cannot auto update because permission is denied. Please download manually from the webpage.</string>
|
<string name="update_no_permission">Cannot auto update because permission is denied. Please download manually from the webpage.</string>
|
||||||
<string name="ignore_update">Ignore</string>
|
<string name="ignore_update">Ignore</string>
|
||||||
|
|
||||||
@@ -76,7 +76,9 @@
|
|||||||
|
|
||||||
<string name="update_title">Update available</string>
|
<string name="update_title">Update available</string>
|
||||||
<string name="update_download_started">Download started</string>
|
<string name="update_download_started">Download started</string>
|
||||||
<string name="update_notification_description">Downloading apk…</string>
|
<string name="update_download_completed">Download Completed</string>
|
||||||
|
<string name="update_download_completed_description">Click here to update</string>
|
||||||
|
<string name="update_notification_description">Downloading update…</string>
|
||||||
<string name="update_release_note"># Release Note(v%1$s)\n%2$s</string>
|
<string name="update_release_note"># Release Note(v%1$s)\n%2$s</string>
|
||||||
|
|
||||||
<string name="search_hint">Search galleries</string>
|
<string name="search_hint">Search galleries</string>
|
||||||
@@ -96,6 +98,8 @@
|
|||||||
<string name="galleryblock_type">Type: %1$s</string>
|
<string name="galleryblock_type">Type: %1$s</string>
|
||||||
<string name="galleryblock_language">Language: %1$s</string>
|
<string name="galleryblock_language">Language: %1$s</string>
|
||||||
|
|
||||||
|
<!-- READER -->
|
||||||
|
|
||||||
<string name="reader_loading">Loading</string>
|
<string name="reader_loading">Loading</string>
|
||||||
<string name="reader_go_to_page">Go to page</string>
|
<string name="reader_go_to_page">Go to page</string>
|
||||||
<string name="reader_fab_fullscreen">Fullscreen</string>
|
<string name="reader_fab_fullscreen">Fullscreen</string>
|
||||||
@@ -107,22 +111,45 @@
|
|||||||
|
|
||||||
<string name="reader_help">Help</string>
|
<string name="reader_help">Help</string>
|
||||||
|
|
||||||
|
<!-- SETTINGS -->
|
||||||
|
|
||||||
<string name="settings_title">Settings</string>
|
<string name="settings_title">Settings</string>
|
||||||
<string name="settings_app_version_title">App version</string>
|
|
||||||
|
<string name="settings_app_version_title">App version(Click to check update)</string>
|
||||||
|
<string name="settings_app_version_description">v%s</string>
|
||||||
|
<string name="settings_beta">Update from beta channel</string>
|
||||||
|
|
||||||
|
<!-- SEARCH -->
|
||||||
|
|
||||||
<string name="settings_search_title">Search Settings</string>
|
<string name="settings_search_title">Search Settings</string>
|
||||||
<string name="settings_galleries_per_page">Galleries per page</string>
|
<string name="settings_galleries_per_page">Galleries per page</string>
|
||||||
<string name="settings_default_query">Default query</string>
|
<string name="settings_default_query">Default query</string>
|
||||||
|
|
||||||
|
<!-- SETTINGS/STORAGE -->
|
||||||
|
|
||||||
<string name="settings_storage">Storage</string>
|
<string name="settings_storage">Storage</string>
|
||||||
<string name="settings_clear_cache">Clear cache</string>
|
<string name="settings_clear_cache">Clear cache</string>
|
||||||
<string name="settings_clear_cache_alert_message">Deleting cache can affect image loading speed. Do you want to continue?</string>
|
<string name="settings_clear_cache_alert_message">Deleting cache can affect image loading speed. Do you want to continue?</string>
|
||||||
<string name="settings_clear_summary">Currently using %1$d%2$s</string>
|
<string name="settings_clear_summary">Currently using %s</string>
|
||||||
<string name="settings_clear_downloads">Clear downloads</string>
|
<string name="settings_clear_downloads">Clear downloads</string>
|
||||||
<string name="settings_clear_downloads_alert_message">Delete all downloaded galleries.\nDo you want to continue?</string>
|
<string name="settings_clear_downloads_alert_message">Delete all downloaded galleries.\nDo you want to continue?</string>
|
||||||
<string name="settings_clear_history">Clear history</string>
|
<string name="settings_clear_history">Clear history</string>
|
||||||
<string name="settings_clear_history_alert_message">Do you want to clear histories?</string>
|
<string name="settings_clear_history_alert_message">Do you want to clear histories?</string>
|
||||||
<string name="settings_clear_history_summary">%1$d histories saved</string>
|
<string name="settings_clear_history_summary">%1$d histories saved</string>
|
||||||
|
<string name="settings_dl_location">Download directory</string>
|
||||||
|
<string name="settings_dl_location_removable">Removable Storage</string>
|
||||||
|
<string name="settings_dl_location_internal">Internal Storage</string>
|
||||||
|
<string name="settings_dl_location_available">%s available</string>
|
||||||
|
<string name="settings_low_quality">Low quality images</string>
|
||||||
|
<string name="settings_low_quality_summary">Load low quality images to improve load speed and data usage</string>
|
||||||
|
|
||||||
|
<!-- SETTINGS/APP LOCK -->
|
||||||
|
|
||||||
<string name="settings_app_lock">App lock</string>
|
<string name="settings_app_lock">App lock</string>
|
||||||
<string name="settings_app_lock_type">App lock type</string>
|
<string name="settings_app_lock_type">App lock type</string>
|
||||||
|
|
||||||
|
<!-- SETTINGS/MISCELLANEOUS -->
|
||||||
|
|
||||||
<string name="settings_miscellaneous_title">Miscellaneous</string>
|
<string name="settings_miscellaneous_title">Miscellaneous</string>
|
||||||
<string name="settings_use_hiyobi_title">Use hiyobi.me</string>
|
<string name="settings_use_hiyobi_title">Use hiyobi.me</string>
|
||||||
<string name="settings_use_hiyobi_summary">Load images from hiyobi.me to improve loading speed (if available)</string>
|
<string name="settings_use_hiyobi_summary">Load images from hiyobi.me to improve loading speed (if available)</string>
|
||||||
@@ -139,6 +166,8 @@
|
|||||||
<string name="settings_restore_failed">Restore failed</string>
|
<string name="settings_restore_failed">Restore failed</string>
|
||||||
<string name="settings_restore_successful">%1$d entries restored</string>
|
<string name="settings_restore_successful">%1$d entries restored</string>
|
||||||
|
|
||||||
|
<!-- SETTINGS/APP LOCK ACTIVITY -->
|
||||||
|
|
||||||
<string name="settings_lock_none">None</string>
|
<string name="settings_lock_none">None</string>
|
||||||
<string name="settings_lock_pattern">Pattern</string>
|
<string name="settings_lock_pattern">Pattern</string>
|
||||||
<string name="settings_lock_pin" translatable="false">PIN</string>
|
<string name="settings_lock_pin" translatable="false">PIN</string>
|
||||||
@@ -150,6 +179,8 @@
|
|||||||
<string name="settings_lock_remove_message">Do you want to remove lock?</string>
|
<string name="settings_lock_remove_message">Do you want to remove lock?</string>
|
||||||
<string name="settings_lock_wrong_confirm">Lock is different from last one. Please try again.</string>
|
<string name="settings_lock_wrong_confirm">Lock is different from last one. Please try again.</string>
|
||||||
|
|
||||||
|
<!-- SETTINGS/DEFAULT QUERY DIALOG -->
|
||||||
|
|
||||||
<string name="default_query_dialog_title">Set default query</string>
|
<string name="default_query_dialog_title">Set default query</string>
|
||||||
<string name="default_query_dialog_language">Language: </string>
|
<string name="default_query_dialog_language">Language: </string>
|
||||||
<string name="default_query_dialog_filter_BL">Filter BL</string>
|
<string name="default_query_dialog_filter_BL">Filter BL</string>
|
||||||
|
|||||||
@@ -3,8 +3,12 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:title="@string/settings_app_version_title"
|
app:key="app_version"
|
||||||
app:key="app_version"/>
|
app:title="@string/settings_app_version_title"/>
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:key="beta"
|
||||||
|
app:title="@string/settings_beta"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
app:title="@string/settings_search_title">
|
app:title="@string/settings_search_title">
|
||||||
@@ -28,16 +32,25 @@
|
|||||||
app:title="@string/settings_storage">
|
app:title="@string/settings_storage">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:title="@string/settings_clear_cache"
|
app:key="delete_cache"
|
||||||
app:key="delete_cache"/>
|
app:title="@string/settings_clear_cache"/>
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:title="@string/settings_clear_downloads"
|
app:key="delete_downloads"
|
||||||
app:key="delete_downloads"/>
|
app:title="@string/settings_clear_downloads"/>
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:title="@string/settings_clear_history"
|
app:key="clear_history"
|
||||||
app:key="clear_history"/>
|
app:title="@string/settings_clear_history"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
app:key="dl_location"
|
||||||
|
app:title="@string/settings_dl_location"/>
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:key="dl_low_quality"
|
||||||
|
app:title="@string/settings_low_quality"
|
||||||
|
app:summary="@string/settings_low_quality_summary"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
@@ -45,31 +58,31 @@
|
|||||||
app:title="@string/settings_app_lock">
|
app:title="@string/settings_app_lock">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:title="@string/settings_app_lock_type"
|
app:key="app_lock"
|
||||||
app:key="app_lock"/>
|
app:title="@string/settings_app_lock_type"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
app:title="@string/settings_miscellaneous_title">
|
app:title="@string/settings_miscellaneous_title">
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreferenceCompat
|
||||||
app:key="use_hiyobi"
|
app:key="use_hiyobi"
|
||||||
app:title="@string/settings_use_hiyobi_title"
|
app:title="@string/settings_use_hiyobi_title"
|
||||||
app:summary="@string/settings_use_hiyobi_summary"/>
|
app:summary="@string/settings_use_hiyobi_summary"/>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreferenceCompat
|
||||||
app:key="security_mode"
|
app:key="security_mode"
|
||||||
app:title="@string/settings_security_mode_title"
|
app:title="@string/settings_security_mode_title"
|
||||||
app:summary="@string/settings_security_mode_summary"
|
app:summary="@string/settings_security_mode_summary"
|
||||||
app:defaultValue="true"/>
|
app:defaultValue="true"/>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreferenceCompat
|
||||||
app:key="dark_mode"
|
app:key="dark_mode"
|
||||||
app:title="@string/settings_dark_mode_title"
|
app:title="@string/settings_dark_mode_title"
|
||||||
app:summary="@string/settings_dark_mode_summary"/>
|
app:summary="@string/settings_dark_mode_summary"/>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreferenceCompat
|
||||||
app:key="nomedia"
|
app:key="nomedia"
|
||||||
app:title="@string/settings_nomedia_title"
|
app:title="@string/settings_nomedia_title"
|
||||||
app:summary="@string/settings_nomedia_title"/>
|
app:summary="@string/settings_nomedia_title"/>
|
||||||
|
|||||||
@@ -27,12 +27,19 @@ package xyz.quaver.pupil
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import xyz.quaver.pupil.util.download
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
class ExampleUnitTest {
|
class ExampleUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test() {
|
fun test() {
|
||||||
|
URL("https://github.om/tom5079/Pupil/releases/download/4.2-beta2-hotfix2/Pupil-v4.2-beta2-hotfix2.apk").download(
|
||||||
|
File(System.getenv("USERPROFILE"), "Pupil.apk")
|
||||||
|
) { downloaded, fileSize ->
|
||||||
|
println("%.1f%%".format(downloaded*100.0/fileSize))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0"
|
||||||
implementation 'org.jsoup:jsoup:1.11.3'
|
implementation 'org.jsoup:jsoup:1.12.1'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,20 +17,19 @@
|
|||||||
package xyz.quaver.hitomi
|
package xyz.quaver.hitomi
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
|
||||||
import kotlinx.serialization.list
|
import kotlinx.serialization.list
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
const val protocol = "https:"
|
const val protocol = "https:"
|
||||||
|
|
||||||
fun getGalleryInfo(galleryID: Int): List<GalleryInfo> {
|
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||||
return Json(JsonConfiguration.Stable).parse(
|
fun getGalleryInfo(galleryID: Int) =
|
||||||
|
Json.nonstrict.parse(
|
||||||
GalleryInfo.serializer().list,
|
GalleryInfo.serializer().list,
|
||||||
Regex("""\[.+]""").find(
|
Regex("""\[.+]""").find(
|
||||||
URL("$protocol//$domain/galleries/$galleryID.js").readText()
|
URL("$protocol//$domain/galleries/$galleryID.js").readText()
|
||||||
)?.value ?: "[]"
|
)?.value ?: "[]"
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
//common.js
|
//common.js
|
||||||
var adapose = false
|
var adapose = false
|
||||||
@@ -54,17 +53,9 @@ fun subdomainFromURL(url: String, base: String? = null) : String {
|
|||||||
if (!base.isNullOrBlank())
|
if (!base.isNullOrBlank())
|
||||||
retval = base
|
retval = base
|
||||||
|
|
||||||
val r = Regex("""/galleries/\d*(\d)/""")
|
val b = 16
|
||||||
var m = r.find(url)
|
val r = Regex("""/[0-9a-f]/([0-9a-f]{2})/""")
|
||||||
var b = 10
|
val m = r.find(url) ?: return retval
|
||||||
|
|
||||||
if (m == null) {
|
|
||||||
b = 16
|
|
||||||
val r2 = Regex("""/[0-9a-f]/([0-9a-f]{2})/""")
|
|
||||||
m = r2.find(url)
|
|
||||||
if (m == null)
|
|
||||||
return retval
|
|
||||||
}
|
|
||||||
|
|
||||||
val g = m.groupValues[1].toIntOrNull(b) ?: return retval
|
val g = m.groupValues[1].toIntOrNull(b) ?: return retval
|
||||||
|
|
||||||
@@ -84,15 +75,12 @@ fun fullPathFromHash(hash: String?) : String? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun urlFromHash(galleryID: Int, image: GalleryInfo, webp: String? = null) : String {
|
@Suppress("NAME_SHADOWING", "UNUSED_PARAMETER")
|
||||||
val ext = webp ?: image.name.split('.').last()
|
fun urlFromHash(galleryID: Int, image: GalleryInfo, dir: String? = null, ext: String? = null) : String {
|
||||||
return when {
|
val ext = ext ?: dir ?: image.name.split('.').last()
|
||||||
image.hash.isNullOrBlank() ->
|
val dir = dir ?: "images"
|
||||||
"$protocol//a.hitomi.la/galleries/$galleryID/${image.name}"
|
return "$protocol//a.hitomi.la/$dir/${fullPathFromHash(image.hash)}.$ext"
|
||||||
else ->
|
|
||||||
"$protocol//a.hitomi.la/${webp?:"images"}/${fullPathFromHash(image.hash)}.$ext"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun urlFromUrlFromHash(galleryID: Int, image: GalleryInfo, webp: String? = null) =
|
fun urlFromUrlFromHash(galleryID: Int, image: GalleryInfo, dir: String? = null, ext: String? = null, base: String? = null) =
|
||||||
urlFromURL(urlFromHash(galleryID, image, webp))
|
urlFromURL(urlFromHash(galleryID, image, dir, ext), base)
|
||||||
@@ -68,8 +68,8 @@ fun getGallery(galleryID: Int) : Gallery {
|
|||||||
href.slice(5 until href.indexOf('-'))
|
href.slice(5 until href.indexOf('-'))
|
||||||
}
|
}
|
||||||
|
|
||||||
val thumbnails = getGalleryInfo(galleryID).map {
|
val thumbnails = getGalleryInfo(galleryID).map { galleryInfo ->
|
||||||
"$protocol//tn.hitomi.la/smalltn/$galleryID/${it.name}.jpg"
|
urlFromUrlFromHash(galleryID, galleryInfo, "smalltn", "jpg", "tn")
|
||||||
}
|
}
|
||||||
|
|
||||||
return Gallery(related, langList, cover, title, artists, groups, type, language, series, characters, tags, thumbnails)
|
return Gallery(related, langList, cover, title, artists, groups, type, language, series, characters, tags, thumbnails)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import kotlinx.serialization.Serializable
|
|||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
fun getReferer(galleryID: Int) = "https://hitomi.la/reader/$galleryID.html"
|
fun getReferer(galleryID: Int) = "https://hitomi.la/reader/$galleryID.html"
|
||||||
fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp"
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GalleryInfo(
|
data class GalleryInfo(
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package xyz.quaver.hiyobi
|
package xyz.quaver.hiyobi
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonConfiguration
|
|
||||||
import kotlinx.serialization.list
|
import kotlinx.serialization.list
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import xyz.quaver.hitomi.GalleryInfo
|
import xyz.quaver.hitomi.GalleryInfo
|
||||||
@@ -64,7 +63,8 @@ fun getReader(galleryID: Int) : Reader {
|
|||||||
|
|
||||||
val title = Jsoup.connect(reader).get().title()
|
val title = Jsoup.connect(reader).get().title()
|
||||||
|
|
||||||
val galleryInfo = Json(JsonConfiguration.Stable).parse(
|
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||||
|
val galleryInfo = Json.parse(
|
||||||
GalleryInfo.serializer().list,
|
GalleryInfo.serializer().list,
|
||||||
with(URL(url).openConnection() as HttpsURLConnection) {
|
with(URL(url).openConnection() as HttpsURLConnection) {
|
||||||
setRequestProperty("User-Agent", user_agent)
|
setRequestProperty("User-Agent", user_agent)
|
||||||
@@ -79,5 +79,11 @@ fun getReader(galleryID: Int) : Reader {
|
|||||||
return Reader(Reader.Code.HIYOBI, title, galleryInfo)
|
return Reader(Reader.Code.HIYOBI, title, galleryInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createImgList(galleryID: Int, reader: Reader) =
|
fun createImgList(galleryID: Int, reader: Reader, lowQuality: Boolean = false) =
|
||||||
|
if (lowQuality)
|
||||||
|
reader.galleryInfo.map {
|
||||||
|
val name = it.name.replace(Regex("/.[^/.]+$"), "") + ".jpg"
|
||||||
|
Images("$protocol//$hiyobi/data/$galleryID/$name.jpg", galleryID, it.name)
|
||||||
|
}
|
||||||
|
else
|
||||||
reader.galleryInfo.map { Images("$protocol//$hiyobi/data/$galleryID/${it.name}", galleryID, it.name) }
|
reader.galleryInfo.map { Images("$protocol//$hiyobi/data/$galleryID/${it.name}", galleryID, it.name) }
|
||||||
@@ -68,7 +68,7 @@ class UnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_getGallery() {
|
fun test_getGallery() {
|
||||||
val gallery = getGallery(1510566)
|
val gallery = getGallery(1552751)
|
||||||
|
|
||||||
print(gallery)
|
print(gallery)
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,9 @@ class UnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_hiyobi() {
|
fun test_hiyobi() {
|
||||||
xyz.quaver.hiyobi.getReader(1510567)
|
val reader = xyz.quaver.hiyobi.getReader(10000062)
|
||||||
|
|
||||||
|
print(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user