Compare commits
29 Commits
4.2-beta2-
...
4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
|
||||||
apply plugin: 'io.fabric'
|
if (file("google-services.json").exists()) {
|
||||||
apply plugin: 'com.google.firebase.firebase-perf'
|
logger.lifecycle("Firebase Enabled")
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
apply plugin: 'io.fabric'
|
||||||
|
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"
|
||||||
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 {
|
||||||
@@ -55,12 +61,12 @@ dependencies {
|
|||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.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-alpha03'
|
||||||
implementation 'com.google.firebase:firebase-core:17.2.1'
|
implementation 'com.google.firebase:firebase-core:17.2.1'
|
||||||
implementation 'com.google.firebase:firebase-perf:19.0.3'
|
implementation 'com.google.firebase:firebase-perf:19.0.4'
|
||||||
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'
|
||||||
|
|||||||
@@ -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":31,"versionName":"4.2","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,10 +4,8 @@
|
|||||||
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"
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
android:maxSdkVersion="28"/>
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".Pupil"
|
android:name=".Pupil"
|
||||||
@@ -28,11 +26,11 @@
|
|||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/file_paths"/>
|
android:resource="@xml/file_paths" />
|
||||||
|
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<activity android:name=".ui.LockActivity"/>
|
<activity android:name=".ui.LockActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ReaderActivity"
|
android:name=".ui.ReaderActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
@@ -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,19 +62,15 @@ 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 {
|
description = getString(R.string.channel_download_description)
|
||||||
description = getString(R.string.channel_download_description)
|
enableLights(false)
|
||||||
enableLights(false)
|
enableVibration(false)
|
||||||
enableVibration(false)
|
lockscreenVisibility = Notification.VISIBILITY_SECRET
|
||||||
lockscreenVisibility = Notification.VISIBILITY_SECRET
|
|
||||||
}
|
|
||||||
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)) {
|
||||||
|
|||||||
@@ -18,17 +18,11 @@
|
|||||||
|
|
||||||
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
|
||||||
@@ -42,7 +36,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
|
||||||
@@ -60,11 +53,8 @@ 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(
|
||||||
@@ -613,7 +483,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()
|
||||||
|
|||||||
@@ -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,7 +94,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
handleIntent(intent)
|
handleIntent(intent)
|
||||||
|
|
||||||
Crashlytics.setInt("GalleryID", galleryID)
|
if (Fabric.isInitialized())
|
||||||
|
Crashlytics.setInt("GalleryID", galleryID)
|
||||||
|
|
||||||
if (galleryID == 0) {
|
if (galleryID == 0) {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -44,9 +44,8 @@ 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.types.Tags
|
||||||
import xyz.quaver.pupil.util.Lock
|
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialog
|
||||||
import xyz.quaver.pupil.util.LockManager
|
import xyz.quaver.pupil.util.*
|
||||||
import xyz.quaver.pupil.util.getDownloadDirectory
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -85,14 +84,6 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat() {
|
class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
private val suffix = listOf(
|
|
||||||
"B",
|
|
||||||
"kB",
|
|
||||||
"MB",
|
|
||||||
"GB",
|
|
||||||
"TB" //really?
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
@@ -112,15 +103,9 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getDirSize(dir: File) : String {
|
private fun getDirSize(dir: File) : String {
|
||||||
var size = dir.walk().map { it.length() }.sum()
|
val size = dir.walk().map { it.length() }.sum()
|
||||||
var suffixIndex = 0
|
|
||||||
|
|
||||||
while (size >= 1024) {
|
return getString(R.string.settings_clear_summary, byteToString(size))
|
||||||
size /= 1024
|
|
||||||
suffixIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
return getString(R.string.settings_clear_summary, size, suffix[suffixIndex])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
@@ -132,7 +117,13 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
val manager = context.packageManager
|
val manager = context.packageManager
|
||||||
val info = manager.getPackageInfo(context.packageName, 0)
|
val info = manager.getPackageInfo(context.packageName, 0)
|
||||||
|
|
||||||
summary = info.versionName
|
summary = context.getString(R.string.settings_app_version_description, info.versionName)
|
||||||
|
|
||||||
|
setOnPreferenceClickListener {
|
||||||
|
checkUpdate(activity as SettingsActivity, true)
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(findPreference<Preference>("delete_cache")) {
|
with(findPreference<Preference>("delete_cache")) {
|
||||||
@@ -208,6 +199,25 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with(findPreference<Preference>("dl_location")) {
|
||||||
|
this!!
|
||||||
|
|
||||||
|
summary = getDownloadDirectory(context).absolutePath
|
||||||
|
|
||||||
|
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
DownloadLocationDialog(context).apply {
|
||||||
|
onDownloadLocationChangedListener = { value ->
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).edit()
|
||||||
|
.putInt(key, value)
|
||||||
|
.apply()
|
||||||
|
summary = getDownloadDirectory(context).absolutePath
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
with(findPreference<Preference>("default_query")) {
|
with(findPreference<Preference>("default_query")) {
|
||||||
this!!
|
this!!
|
||||||
|
|
||||||
|
|||||||
@@ -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) }
|
||||||
}
|
}
|
||||||
@@ -163,8 +163,6 @@ 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
|
||||||
|
|||||||
@@ -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,45 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import android.content.Context
|
import java.util.*
|
||||||
import android.content.pm.PackageManager
|
import kotlin.collections.ArrayList
|
||||||
import androidx.core.content.ContextCompat
|
import kotlin.math.round
|
||||||
|
|
||||||
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>()
|
||||||
|
|
||||||
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(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//https://discuss.kotlinlang.org/t/how-do-you-round-a-number-to-n-decimal-places/8843(fvasco)
|
||||||
|
fun Double.round(decimals: Int): Double {
|
||||||
|
var multiplier = 1.0
|
||||||
|
repeat(decimals) { multiplier *= 10 }
|
||||||
|
return round(this * multiplier) / multiplier
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "${size.round(precision)} ${suffix[suffixIndex]}"
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,15 +18,31 @@
|
|||||||
|
|
||||||
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.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 +54,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 +73,128 @@ 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
|
}
|
||||||
else
|
}
|
||||||
Pair(it.jsonObject["browser_download_url"]?.content, it.jsonObject["name"]?.content)
|
|
||||||
|
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) {
|
||||||
|
Locale.KOREAN -> "한국어"
|
||||||
|
Locale.JAPANESE -> "日本語"
|
||||||
|
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 {
|
||||||
|
val target = File(getDownloadDirectory(context), "Pupil.apk")
|
||||||
|
|
||||||
|
URL(url).download(target) { progress, fileSize ->
|
||||||
|
builder.setProgress(fileSize.toInt(), progress.toInt(), false)
|
||||||
|
notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
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().getExtensionFromMimeType(".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
|
||||||
|
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"/>
|
||||||
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>
|
||||||
@@ -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>
|
||||||
@@ -110,4 +110,12 @@
|
|||||||
<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>
|
||||||
</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>
|
||||||
@@ -110,4 +110,12 @@
|
|||||||
<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>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -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,43 @@
|
|||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
|
<!-- 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 +164,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 +177,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>
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
app:title="@string/settings_app_version_title"
|
app:title="@string/settings_app_version_title"
|
||||||
app:key="app_version"/>
|
app:key="app_version"/>
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:title="@string/settings_beta"
|
||||||
|
app:key="beta"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
app:title="@string/settings_search_title">
|
app:title="@string/settings_search_title">
|
||||||
|
|
||||||
@@ -39,6 +43,10 @@
|
|||||||
app:title="@string/settings_clear_history"
|
app:title="@string/settings_clear_history"
|
||||||
app:key="clear_history"/>
|
app:key="clear_history"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
app:title="@string/settings_dl_location"
|
||||||
|
app:key="dl_location"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
@@ -53,23 +61,23 @@
|
|||||||
<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'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user