UI update
Added sort by popularity functionality Added auto update
This commit is contained in:
@@ -13,7 +13,7 @@ android {
|
||||
applicationId "xyz.quaver.pupil"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
versionCode 20
|
||||
versionCode 21
|
||||
versionName "2.12"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
@@ -24,6 +24,9 @@ android {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
buildTypes.each {
|
||||
it.buildConfigField('boolean', 'PRERELEASE', 'true')
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental'
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":20,"versionName":"2.11.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":21,"versionName":"2.12","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
|
||||
@@ -3,7 +3,9 @@
|
||||
package="xyz.quaver.pupil">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||
|
||||
<application
|
||||
android:name=".Pupil"
|
||||
@@ -14,6 +16,7 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity android:name=".ui.LockActivity"/>
|
||||
<activity
|
||||
android:name=".ui.ReaderActivity"
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
package xyz.quaver.pupil
|
||||
|
||||
import android.app.DownloadManager
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2019 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.types
|
||||
|
||||
import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import xyz.quaver.hitomi.Suggestion
|
||||
|
||||
@Parcelize
|
||||
class SelectorSuggestion : SearchSuggestion {
|
||||
|
||||
override fun getBody(): String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,16 @@ package xyz.quaver.pupil.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.app.DownloadManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.text.*
|
||||
import android.text.style.AlignmentSpan
|
||||
import android.view.*
|
||||
@@ -35,9 +40,9 @@ import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
@@ -60,11 +65,9 @@ import kotlinx.serialization.list
|
||||
import kotlinx.serialization.stringify
|
||||
import ru.noties.markwon.Markwon
|
||||
import xyz.quaver.hitomi.*
|
||||
import xyz.quaver.pupil.BuildConfig
|
||||
import xyz.quaver.pupil.Pupil
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
|
||||
import xyz.quaver.pupil.types.SelectorSuggestion
|
||||
import xyz.quaver.pupil.types.Tag
|
||||
import xyz.quaver.pupil.types.TagSuggestion
|
||||
import xyz.quaver.pupil.types.Tags
|
||||
@@ -88,6 +91,11 @@ class MainActivity : AppCompatActivity() {
|
||||
DOWNLOAD,
|
||||
FAVORITE
|
||||
}
|
||||
|
||||
enum class SortMode {
|
||||
NEWEST,
|
||||
POPULAR
|
||||
}
|
||||
|
||||
private val galleries = ArrayList<Pair<GalleryBlock, Deferred<String>>>()
|
||||
|
||||
@@ -101,6 +109,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private var mode = Mode.SEARCH
|
||||
private var sortMode = SortMode.NEWEST
|
||||
|
||||
private val REQUEST_SETTINGS = 45162
|
||||
private val REQUEST_LOCK = 561
|
||||
@@ -156,7 +165,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
else -> super.onBackPressed()
|
||||
@@ -189,7 +198,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
@@ -203,7 +212,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
@@ -221,7 +230,7 @@ class MainActivity : AppCompatActivity() {
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
@@ -278,14 +287,36 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
val update =
|
||||
checkUpdate(getString(R.string.release_url), BuildConfig.VERSION_NAME) ?: return@launch
|
||||
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) { _, _ ->
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.update))))
|
||||
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?) {
|
||||
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)
|
||||
}
|
||||
}, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
||||
}
|
||||
setNegativeButton(android.R.string.no) { _, _ ->}
|
||||
}
|
||||
@@ -308,6 +339,13 @@ class MainActivity : AppCompatActivity() {
|
||||
main_searchview.translationY = p1.toFloat()
|
||||
main_recyclerview.scrollBy(0, prevP1 - p1)
|
||||
|
||||
with(main_fab) {
|
||||
if (prevP1 > p1)
|
||||
hideMenuButton(true)
|
||||
else if (prevP1 < p1)
|
||||
showMenuButton(true)
|
||||
}
|
||||
|
||||
prevP1 = p1
|
||||
}
|
||||
)
|
||||
@@ -324,7 +362,7 @@ class MainActivity : AppCompatActivity() {
|
||||
currentPage = 0
|
||||
query = ""
|
||||
mode = Mode.SEARCH
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
R.id.main_drawer_history -> {
|
||||
@@ -333,7 +371,7 @@ class MainActivity : AppCompatActivity() {
|
||||
currentPage = 0
|
||||
query = ""
|
||||
mode = Mode.HISTORY
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
R.id.main_drawer_downloads -> {
|
||||
@@ -342,7 +380,7 @@ class MainActivity : AppCompatActivity() {
|
||||
currentPage = 0
|
||||
query = ""
|
||||
mode = Mode.DOWNLOAD
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
R.id.main_drawer_favorite -> {
|
||||
@@ -351,7 +389,7 @@ class MainActivity : AppCompatActivity() {
|
||||
currentPage = 0
|
||||
query = ""
|
||||
mode = Mode.FAVORITE
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
R.id.main_drawer_help -> {
|
||||
@@ -375,9 +413,67 @@ class MainActivity : AppCompatActivity() {
|
||||
true
|
||||
}
|
||||
|
||||
with(main_fab_jump) {
|
||||
setImageResource(R.drawable.ic_jump)
|
||||
setOnClickListener {
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val perPage = preference.getString("per_page", "25")!!.toInt()
|
||||
val editText = EditText(context)
|
||||
|
||||
AlertDialog.Builder(context).apply {
|
||||
setView(editText)
|
||||
setTitle(R.string.main_jump_title)
|
||||
setMessage(getString(
|
||||
R.string.main_jump_message,
|
||||
currentPage+1,
|
||||
ceil(totalItems / perPage.toDouble()).roundToInt()
|
||||
))
|
||||
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
currentPage = (editText.text.toString().toIntOrNull() ?: return@setPositiveButton)-1
|
||||
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
with(main_fab_id) {
|
||||
setImageResource(R.drawable.numeric)
|
||||
setOnClickListener {
|
||||
val editText = EditText(context)
|
||||
|
||||
AlertDialog.Builder(context).apply {
|
||||
setView(editText)
|
||||
setTitle(R.string.main_open_gallery_by_id)
|
||||
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
try {
|
||||
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
||||
val gallery =
|
||||
getGalleryBlock(editText.text.toString().toInt()) ?: throw Exception()
|
||||
intent.putExtra("galleryID", gallery.id)
|
||||
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Snackbar.make(main_layout,
|
||||
R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
setupSearchBar()
|
||||
setupRecyclerView()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
|
||||
@@ -391,7 +487,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
@@ -459,7 +555,7 @@ class MainActivity : AppCompatActivity() {
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
@@ -527,7 +623,6 @@ class MainActivity : AppCompatActivity() {
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
loadBlocks()
|
||||
}
|
||||
|
||||
@@ -714,55 +809,31 @@ class MainActivity : AppCompatActivity() {
|
||||
setOnMenuItemClickListener {
|
||||
when(it.itemId) {
|
||||
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS)
|
||||
R.id.main_menu_jump -> {
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val perPage = preference.getString("per_page", "25")!!.toInt()
|
||||
val editText = EditText(context)
|
||||
R.id.main_menu_sort_newest -> {
|
||||
sortMode = SortMode.NEWEST
|
||||
it.isChecked = true
|
||||
|
||||
AlertDialog.Builder(context).apply {
|
||||
setView(editText)
|
||||
setTitle(R.string.main_jump_title)
|
||||
setMessage(getString(
|
||||
R.string.main_jump_message,
|
||||
currentPage+1,
|
||||
ceil(totalItems / perPage.toDouble()).roundToInt()
|
||||
))
|
||||
runOnUiThread {
|
||||
currentPage = 0
|
||||
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
currentPage = (editText.text.toString().toIntOrNull() ?: return@setPositiveButton)-1
|
||||
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
R.id.main_menu_id -> {
|
||||
val editText = EditText(context)
|
||||
R.id.main_menu_sort_popular -> {
|
||||
sortMode = SortMode.POPULAR
|
||||
it.isChecked = true
|
||||
|
||||
AlertDialog.Builder(context).apply {
|
||||
setView(editText)
|
||||
setTitle(R.string.main_open_gallery_by_id)
|
||||
runOnUiThread {
|
||||
currentPage = 0
|
||||
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
try {
|
||||
val intent = Intent(this@MainActivity, ReaderActivity::class.java)
|
||||
val gallery =
|
||||
getGalleryBlock(editText.text.toString().toInt()) ?: throw Exception()
|
||||
intent.putExtra("galleryID", gallery.id)
|
||||
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Snackbar.make(main_layout,
|
||||
R.string.main_open_gallery_by_id_error, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -770,20 +841,20 @@ class MainActivity : AppCompatActivity() {
|
||||
setOnQueryChangeListener { _, query ->
|
||||
this@MainActivity.query = query
|
||||
|
||||
suggestionJob?.cancel()
|
||||
|
||||
clearSuggestions()
|
||||
|
||||
if (query.isEmpty() or query.endsWith(' ')) {
|
||||
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
|
||||
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
|
||||
} + SelectorSuggestion())
|
||||
})
|
||||
|
||||
return@setOnQueryChangeListener
|
||||
}
|
||||
|
||||
val currentQuery = query.split(" ").last().replace('_', ' ')
|
||||
|
||||
suggestionJob?.cancel()
|
||||
|
||||
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
val suggestions = ArrayList(getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) })
|
||||
|
||||
@@ -802,103 +873,72 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
setOnBindSuggestionCallback { suggestionView, leftIcon, textView, item, _ ->
|
||||
if (item is SelectorSuggestion) {
|
||||
var hasSelector = false
|
||||
item as TagSuggestion
|
||||
|
||||
with(suggestionView as LinearLayout) {
|
||||
for (i in 0 until childCount) {
|
||||
val child = getChildAt(i)
|
||||
if (child is ConstraintLayout) {
|
||||
child.visibility = View.VISIBLE
|
||||
hasSelector = true
|
||||
}
|
||||
else
|
||||
child.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
||||
|
||||
if (!hasSelector) {
|
||||
val view = LayoutInflater.from(context)
|
||||
.inflate(R.layout.item_selector_suggestion, suggestionView, false)
|
||||
leftIcon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
when(item.n) {
|
||||
"female" -> R.drawable.ic_gender_female
|
||||
"male" -> R.drawable.ic_gender_male
|
||||
"language" -> R.drawable.ic_translate
|
||||
"group" -> R.drawable.ic_account_group
|
||||
"character" -> R.drawable.ic_account_star
|
||||
"series" -> R.drawable.ic_book_open
|
||||
"artist" -> R.drawable.ic_brush
|
||||
else -> R.drawable.ic_tag
|
||||
},
|
||||
null)
|
||||
)
|
||||
|
||||
suggestionView.addView(view)
|
||||
}
|
||||
} else if(item is TagSuggestion) {
|
||||
with(suggestionView as LinearLayout) {
|
||||
for (i in 0 until childCount) {
|
||||
val child = getChildAt(i)
|
||||
if (child is ConstraintLayout) {
|
||||
child.visibility = View.GONE
|
||||
}
|
||||
else
|
||||
child.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
|
||||
with(suggestionView.findViewById<ImageView>(R.id.right_icon)) {
|
||||
|
||||
leftIcon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
when(item.n) {
|
||||
"female" -> R.drawable.ic_gender_female
|
||||
"male" -> R.drawable.ic_gender_male
|
||||
"language" -> R.drawable.ic_translate
|
||||
"group" -> R.drawable.ic_account_group
|
||||
"character" -> R.drawable.ic_account_star
|
||||
"series" -> R.drawable.ic_book_open
|
||||
"artist" -> R.drawable.ic_brush
|
||||
else -> R.drawable.ic_tag
|
||||
},
|
||||
null)
|
||||
)
|
||||
if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag))
|
||||
setImageResource(R.drawable.ic_star_filled)
|
||||
else
|
||||
setImageResource(R.drawable.ic_star_empty)
|
||||
|
||||
with(suggestionView.findViewById<ImageView>(R.id.right_icon)) {
|
||||
rotation = 0f
|
||||
isEnabled = true
|
||||
|
||||
if (Tags(json.parse(serializer, favoritesFile.readText())).contains(tag))
|
||||
setImageResource(R.drawable.ic_star_filled)
|
||||
else
|
||||
setColorFilter(ContextCompat.getColor(context, R.color.material_orange_500))
|
||||
|
||||
isClickable = true
|
||||
setOnClickListener {
|
||||
val favorites = Tags(json.parse(serializer, favoritesFile.readText()))
|
||||
|
||||
if (favorites.contains(tag)) {
|
||||
setImageResource(R.drawable.ic_star_empty)
|
||||
|
||||
rotation = 0f
|
||||
isEnabled = true
|
||||
|
||||
setColorFilter(ContextCompat.getColor(context, R.color.material_orange_500))
|
||||
|
||||
isClickable = true
|
||||
setOnClickListener {
|
||||
val favorites = Tags(json.parse(serializer, favoritesFile.readText()))
|
||||
|
||||
if (favorites.contains(tag)) {
|
||||
setImageResource(R.drawable.ic_star_empty)
|
||||
favorites.remove(tag)
|
||||
}
|
||||
else {
|
||||
setImageDrawable(AnimatedVectorDrawableCompat.create(context,
|
||||
R.drawable.avd_star
|
||||
))
|
||||
(drawable as Animatable).start()
|
||||
|
||||
favorites.add(tag)
|
||||
}
|
||||
|
||||
favoritesFile.writeText(json.stringify(favorites))
|
||||
favorites.remove(tag)
|
||||
}
|
||||
else {
|
||||
setImageDrawable(AnimatedVectorDrawableCompat.create(context,
|
||||
R.drawable.avd_star
|
||||
))
|
||||
(drawable as Animatable).start()
|
||||
|
||||
favorites.add(tag)
|
||||
}
|
||||
|
||||
favoritesFile.writeText(json.stringify(favorites))
|
||||
}
|
||||
}
|
||||
|
||||
if (item.t == -1) {
|
||||
textView.text = item.s
|
||||
} else {
|
||||
val text = "${item.s}\n ${item.t}"
|
||||
if (item.t == -1) {
|
||||
textView.text = item.s
|
||||
} else {
|
||||
val text = "${item.s}\n ${item.t}"
|
||||
|
||||
val len = text.length
|
||||
val left = item.s.length
|
||||
val len = text.length
|
||||
val left = item.s.length
|
||||
|
||||
textView.text = SpannableString(text).apply {
|
||||
val s = AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE)
|
||||
setSpan(s, left, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(SetLineOverlap(true), 1, len-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(SetLineOverlap(false), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
textView.text = SpannableString(text).apply {
|
||||
val s = AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE)
|
||||
setSpan(s, left, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(SetLineOverlap(true), 1, len-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(SetLineOverlap(false), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -924,24 +964,18 @@ class MainActivity : AppCompatActivity() {
|
||||
if (query.isEmpty() or query.endsWith(' '))
|
||||
swapSuggestions(json.parse(serializer, favoritesFile.readText()).map {
|
||||
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
|
||||
} + SelectorSuggestion())
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFocusCleared() {
|
||||
suggestionJob?.cancel()
|
||||
|
||||
val query = searchInputView.text.toString()
|
||||
|
||||
if (query != this@MainActivity.query) {
|
||||
this@MainActivity.query = query
|
||||
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
currentPage = 0
|
||||
fetchGalleries(query)
|
||||
loadBlocks()
|
||||
}
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
currentPage = 0
|
||||
fetchGalleries(query, sortMode)
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -970,9 +1004,8 @@ class MainActivity : AppCompatActivity() {
|
||||
main_progressbar.show()
|
||||
}
|
||||
|
||||
private fun fetchGalleries(query: String) {
|
||||
private fun fetchGalleries(query: String, sortMode: SortMode) {
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val perPage = preference.getString("per_page", "25")?.toInt() ?: 25
|
||||
val defaultQuery = preference.getString("default_query", "")!!
|
||||
|
||||
galleryIDs = null
|
||||
@@ -985,12 +1018,14 @@ class MainActivity : AppCompatActivity() {
|
||||
Mode.SEARCH -> {
|
||||
when {
|
||||
query.isEmpty() and defaultQuery.isEmpty() -> {
|
||||
fetchNozomi(start = currentPage*perPage, count = perPage).let {
|
||||
totalItems = it.second
|
||||
it.first
|
||||
when(sortMode) {
|
||||
SortMode.POPULAR -> getGalleryIDsFromNozomi(null, "popular", "all")
|
||||
else -> getGalleryIDsFromNozomi(null, "index", "all")
|
||||
}.apply {
|
||||
totalItems = size
|
||||
}
|
||||
}
|
||||
else -> doSearch("$defaultQuery $query").apply {
|
||||
else -> doSearch("$defaultQuery $query", sortMode == SortMode.POPULAR).apply {
|
||||
totalItems = size
|
||||
}
|
||||
}
|
||||
@@ -1043,7 +1078,6 @@ class MainActivity : AppCompatActivity() {
|
||||
private fun loadBlocks() {
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val perPage = preference.getString("per_page", "25")?.toInt() ?: 25
|
||||
val defaultQuery = preference.getString("default_query", "")!!
|
||||
|
||||
loadingJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
val galleryIDs = galleryIDs?.await()
|
||||
@@ -1057,12 +1091,7 @@ class MainActivity : AppCompatActivity() {
|
||||
return@launch
|
||||
}
|
||||
|
||||
when {
|
||||
query.isEmpty() and defaultQuery.isEmpty() and (mode == Mode.SEARCH) ->
|
||||
galleryIDs
|
||||
else ->
|
||||
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size))
|
||||
}.chunked(5).let { chunks ->
|
||||
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size)).chunked(5).let { chunks ->
|
||||
for (chunk in chunks)
|
||||
chunk.map { galleryID ->
|
||||
async {
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.os.Bundle
|
||||
import android.view.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.PagerSnapHelper
|
||||
@@ -40,7 +39,6 @@ import kotlinx.android.synthetic.main.dialog_numberpicker.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.io.IOException
|
||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||
import xyz.quaver.pupil.Pupil
|
||||
import xyz.quaver.pupil.R
|
||||
@@ -222,15 +220,8 @@ class ReaderActivity : AppCompatActivity() {
|
||||
private fun initDownloader() {
|
||||
var d: GalleryDownloader? = GalleryDownloader.get(galleryID)
|
||||
|
||||
if (d == null) {
|
||||
try {
|
||||
d = GalleryDownloader(this, galleryID)
|
||||
} catch (e: IOException) {
|
||||
Snackbar.make(reader_layout, R.string.unable_to_connect, Snackbar.LENGTH_LONG).show()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
}
|
||||
if (d == null)
|
||||
d = GalleryDownloader(this, galleryID)
|
||||
|
||||
downloader = d.apply {
|
||||
onReaderLoadedHandler = {
|
||||
@@ -268,8 +259,7 @@ class ReaderActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
onErrorHandler = {
|
||||
if (it is IOException)
|
||||
Snackbar.make(reader_layout, R.string.unable_to_connect, Snackbar.LENGTH_LONG).show()
|
||||
Snackbar.make(reader_layout, it.message ?: it.javaClass.name, Snackbar.LENGTH_INDEFINITE).show()
|
||||
downloader.download = false
|
||||
}
|
||||
onCompleteHandler = {
|
||||
@@ -323,6 +313,11 @@ class ReaderActivity : AppCompatActivity() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
if (dy < 0)
|
||||
this@ReaderActivity.reader_fab.showMenuButton(true)
|
||||
else if (dy > 0)
|
||||
this@ReaderActivity.reader_fab.hideMenuButton(true)
|
||||
|
||||
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
||||
|
||||
if (layoutManager.findFirstVisibleItemPosition() == -1)
|
||||
|
||||
@@ -102,55 +102,59 @@ class GalleryDownloader(
|
||||
initNotification()
|
||||
|
||||
reader = CoroutineScope(Dispatchers.IO).async {
|
||||
download = _notify
|
||||
val json = Json(JsonConfiguration.Stable)
|
||||
val serializer = Reader.serializer()
|
||||
try {
|
||||
download = _notify
|
||||
val json = Json(JsonConfiguration.Stable)
|
||||
val serializer = Reader.serializer()
|
||||
|
||||
//Check cache
|
||||
val cache = File(getCachedGallery(this@GalleryDownloader, galleryID), "reader.json")
|
||||
//Check cache
|
||||
val cache = File(getCachedGallery(this@GalleryDownloader, galleryID), "reader.json")
|
||||
|
||||
if (cache.exists()) {
|
||||
val cached = json.parse(serializer, cache.readText())
|
||||
if (cache.exists()) {
|
||||
val cached = json.parse(serializer, cache.readText())
|
||||
|
||||
if (cached.readerItems.isNotEmpty()) {
|
||||
useHiyobi = when {
|
||||
cached.readerItems[0].url.contains("hitomi.la") -> false
|
||||
else -> true
|
||||
if (cached.readerItems.isNotEmpty()) {
|
||||
useHiyobi = when {
|
||||
cached.readerItems[0].url.contains("hitomi.la") -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
onReaderLoadedHandler?.invoke(cached)
|
||||
|
||||
return@async cached
|
||||
}
|
||||
|
||||
onReaderLoadedHandler?.invoke(cached)
|
||||
|
||||
return@async cached
|
||||
}
|
||||
}
|
||||
|
||||
//Cache doesn't exist. Load from internet
|
||||
val reader = when {
|
||||
useHiyobi -> {
|
||||
xyz.quaver.hiyobi.getReader(galleryID).let {
|
||||
when {
|
||||
it.readerItems.isEmpty() -> {
|
||||
useHiyobi = false
|
||||
getReader(galleryID)
|
||||
//Cache doesn't exist. Load from internet
|
||||
val reader = when {
|
||||
useHiyobi -> {
|
||||
xyz.quaver.hiyobi.getReader(galleryID).let {
|
||||
when {
|
||||
it.readerItems.isEmpty() -> {
|
||||
useHiyobi = false
|
||||
getReader(galleryID)
|
||||
}
|
||||
else -> it
|
||||
}
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
getReader(galleryID)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
getReader(galleryID)
|
||||
|
||||
if (reader.readerItems.isNotEmpty()) {
|
||||
//Save cache
|
||||
if (cache.parentFile?.exists() == false)
|
||||
cache.parentFile!!.mkdirs()
|
||||
|
||||
cache.writeText(json.stringify(serializer, reader))
|
||||
}
|
||||
|
||||
reader
|
||||
} catch (e: Exception) {
|
||||
Reader("", listOf())
|
||||
}
|
||||
|
||||
if (reader.readerItems.isNotEmpty()) {
|
||||
//Save cache
|
||||
if (cache.parentFile?.exists() == false)
|
||||
cache.parentFile!!.mkdirs()
|
||||
|
||||
cache.writeText(json.stringify(serializer, reader))
|
||||
}
|
||||
|
||||
reader
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +164,10 @@ class GalleryDownloader(
|
||||
downloadJob = CoroutineScope(Dispatchers.Default).launch {
|
||||
val reader = reader!!.await()
|
||||
|
||||
if (reader.readerItems.isEmpty())
|
||||
onErrorHandler?.invoke(IOException("Couldn't retrieve Reader"))
|
||||
if (reader.readerItems.isEmpty()) {
|
||||
onErrorHandler?.invoke(IOException(getString(R.string.unable_to_connect)))
|
||||
return@launch
|
||||
}
|
||||
|
||||
val list = ArrayList<String>()
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import kotlinx.serialization.json.*
|
||||
import xyz.quaver.pupil.BuildConfig
|
||||
import java.net.URL
|
||||
|
||||
fun getReleases(url: String) : JsonArray {
|
||||
@@ -31,26 +32,27 @@ fun getReleases(url: String) : JsonArray {
|
||||
}
|
||||
}
|
||||
|
||||
fun checkUpdate(url: String, currentVersion: String) : JsonObject? {
|
||||
fun checkUpdate(url: String) : JsonObject? {
|
||||
val releases = getReleases(url)
|
||||
|
||||
if (releases.isEmpty())
|
||||
return null
|
||||
|
||||
val latestVersion = releases[0].jsonObject["tag_name"]?.content
|
||||
return releases.firstOrNull {
|
||||
if (BuildConfig.PRERELEASE) {
|
||||
BuildConfig.VERSION_NAME != it.jsonObject["tag_name"]?.content
|
||||
} else {
|
||||
it.jsonObject["prerelease"]?.boolean == false &&
|
||||
BuildConfig.VERSION_NAME != (it.jsonObject["tag_name"]?.content ?: "")
|
||||
}
|
||||
}?.jsonObject
|
||||
}
|
||||
|
||||
return when {
|
||||
currentVersion.split('-').size == 1 -> {
|
||||
when {
|
||||
currentVersion != latestVersion -> releases[0].jsonObject
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
when {
|
||||
(currentVersion.split('-')[0] == latestVersion) -> releases[0].jsonObject
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
fun getApkUrl(releases: JsonObject) : Pair<String?, String?>? {
|
||||
releases["assets"]?.jsonArray?.forEach {
|
||||
if (Regex("Pupil-v(\\d+\\.)+\\d+\\.apk").matches(it.jsonObject["name"]?.content ?: ""))
|
||||
return Pair(it.jsonObject["browser_download_url"]?.content, it.jsonObject["name"]?.content)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#fff"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#ff000000" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
|
||||
<path android:fillColor="#fff" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
|
||||
</vector>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<!-- drawable/numeric.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M4,17V9H2V7H6V17H4M22,15C22,16.11 21.1,17 20,17H16V15H20V13H18V11H20V9H16V7H20A2,2 0 0,1 22,9V10.5A1.5,1.5 0 0,1 20.5,12A1.5,1.5 0 0,1 22,13.5V15M14,15V17H8V13C8,11.89 8.9,11 10,11H12V9H8V7H12A2,2 0 0,1 14,9V11C14,12.11 13.1,13 12,13H10V15H14Z" />
|
||||
</vector>
|
||||
8
app/src/main/res/drawable/image_broken_variant.xml
Normal file
8
app/src/main/res/drawable/image_broken_variant.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<!-- drawable/image_broken_variant.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M21,5V11.59L18,8.58L14,12.59L10,8.59L6,12.59L3,9.58V5A2,2 0 0,1 5,3H19A2,2 0 0,1 21,5M18,11.42L21,14.43V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V12.42L6,15.41L10,11.41L14,15.41" />
|
||||
</vector>
|
||||
@@ -4,5 +4,5 @@
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M4,17V9H2V7H6V17H4M22,15C22,16.11 21.1,17 20,17H16V15H20V13H18V11H20V9H16V7H20A2,2 0 0,1 22,9V10.5A1.5,1.5 0 0,1 20.5,12A1.5,1.5 0 0,1 22,13.5V15M14,15V17H8V13C8,11.89 8.9,11 10,11H12V9H8V7H12A2,2 0 0,1 14,9V11C14,12.11 13.1,13 12,13H10V15H14Z" />
|
||||
<path android:fillColor="#fff" android:pathData="M4,17V9H2V7H6V17H4M22,15C22,16.11 21.1,17 20,17H16V15H20V13H18V11H20V9H16V7H20A2,2 0 0,1 22,9V10.5A1.5,1.5 0 0,1 20.5,12A1.5,1.5 0 0,1 22,13.5V15M14,15V17H8V13C8,11.89 8.9,11 10,11H12V9H8V7H12A2,2 0 0,1 14,9V11C14,12.11 13.1,13 12,13H10V15H14Z" />
|
||||
</vector>
|
||||
8
app/src/main/res/drawable/sort_variant.xml
Normal file
8
app/src/main/res/drawable/sort_variant.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<!-- drawable/sort_variant.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M3,13H15V11H3M3,6V8H21V6M3,18H9V16H3V18Z" />
|
||||
</vector>
|
||||
@@ -56,6 +56,30 @@
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||
|
||||
<com.github.clans.fab.FloatingActionMenu
|
||||
android:id="@+id/main_fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
app:menu_colorNormal="@color/colorAccent">
|
||||
|
||||
<com.github.clans.fab.FloatingActionButton
|
||||
android:id="@+id/main_fab_jump"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:fab_label="@string/main_jump_title"
|
||||
app:fab_size="mini"/>
|
||||
|
||||
<com.github.clans.fab.FloatingActionButton
|
||||
android:id="@+id/main_fab_id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:fab_label="@string/main_open_gallery_by_id"
|
||||
app:fab_size="mini"/>
|
||||
|
||||
</com.github.clans.fab.FloatingActionMenu>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<com.arlib.floatingsearchview.FloatingSearchView
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:progressTint="@color/material_green_a700"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -55,7 +56,6 @@
|
||||
android:id="@+id/reader_fab_download"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_downloading"
|
||||
app:fab_label="@string/reader_fab_download"
|
||||
app:fab_size="mini"/>
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
android:id="@+id/reader_fab_fullscreen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_fullscreen"
|
||||
app:fab_label="@string/reader_fab_fullscreen"
|
||||
app:fab_size="mini"/>
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<View
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/dark_gray"
|
||||
android:layout_width="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent">
|
||||
|
||||
<Button
|
||||
style="?borderlessButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="favorite" />
|
||||
|
||||
<Button
|
||||
style="?borderlessButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="history" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -2,15 +2,19 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:id="@+id/main_menu_jump"
|
||||
android:icon="@drawable/ic_jump"
|
||||
android:title="@string/main_jump_title"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item android:id="@+id/main_menu_id"
|
||||
android:icon="@drawable/ic_numeric"
|
||||
android:title="@string/main_open_gallery_by_id"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/main_menu_sort"
|
||||
android:title="@string/main_menu_sort">
|
||||
<menu>
|
||||
<group android:checkableBehavior="single">
|
||||
<item android:id="@+id/main_menu_sort_newest"
|
||||
android:title="@string/main_menu_sort_newest"
|
||||
android:checked="true"/>
|
||||
<item android:id="@+id/main_menu_sort_popular"
|
||||
android:title="@string/main_menu_sort_popular"/>
|
||||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/main_menu_settings"
|
||||
|
||||
@@ -80,4 +80,7 @@
|
||||
<string name="settings_lock_none">なし</string>
|
||||
<string name="settings_lock_remove_message">ロックを無効にしますか?</string>
|
||||
<string name="reader_loading">ロード中</string>
|
||||
<string name="main_menu_sort">ソート</string>
|
||||
<string name="main_menu_sort_newest">投稿日時順</string>
|
||||
<string name="main_menu_sort_popular">人気順</string>
|
||||
</resources>
|
||||
@@ -54,7 +54,7 @@
|
||||
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
|
||||
<string name="main_move">%1$d 페이지로 이동</string>
|
||||
<string name="https_block_alert_title">접속 불가 현상 안내</string>
|
||||
<string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다\n이 경우 플레이스토어에서 SNIper앱을 이용하시면 정상이용이 가능합니다.</string>
|
||||
<string name="https_block_alert">최근 https 차단으로 접속이 안 되는 경우가 발생하고 있습니다 이 경우 플레이스토어에서 Intra앱을 이용하시면 정상이용이 가능합니다.</string>
|
||||
<string name="main_dialog_export">갤러리 내보내기</string>
|
||||
<string name="main_export_complete">내보내기 완료</string>
|
||||
<string name="main_export_open_folder">폴더 열기</string>
|
||||
@@ -80,4 +80,7 @@
|
||||
<string name="settings_lock_none">없음</string>
|
||||
<string name="settings_lock_remove_message">잠금을 해제할까요?</string>
|
||||
<string name="reader_loading">로딩중</string>
|
||||
<string name="main_menu_sort">정렬</string>
|
||||
<string name="main_menu_sort_popular">인기순</string>
|
||||
<string name="main_menu_sort_newest">시간순</string>
|
||||
</resources>
|
||||
@@ -1,7 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_name" translatable="false" tools:override="true">Pupil</string>
|
||||
|
||||
<string name="release_url" translatable="false">https://api.github.com/repos/tom5079/Pupil-issue/releases</string>
|
||||
<string name="release_url" translatable="false">https://api.github.com/repos/tom5079/Pupil/releases</string>
|
||||
<string name="release_name" translatable="false">Pupil-v(\\d+\\.)+\\d+\\.apk</string>
|
||||
|
||||
<string name="home_page" translatable="false">http://bit.ly/2EZDClw</string>
|
||||
@@ -45,6 +45,10 @@
|
||||
<string name="main_drawer_group_contact_email">Email me!</string>
|
||||
<string name="main_drawer_grouop_contact_kakaotalk">Kakaotalk</string>
|
||||
|
||||
<string name="main_menu_sort">Sort</string>
|
||||
<string name="main_menu_sort_newest">Newest</string>
|
||||
<string name="main_menu_sort_popular">Popular</string>
|
||||
|
||||
<string name="main_jump_title">Jump to page</string>
|
||||
<string name="main_jump_message">Current page: %1$d\nMaximum page: %2$d</string>
|
||||
<string name="main_open_gallery_by_id">Open Gallery by ID</string>
|
||||
|
||||
@@ -32,7 +32,10 @@ class ExampleUnitTest {
|
||||
|
||||
@Test
|
||||
fun test() {
|
||||
val current = "0.1"
|
||||
val latest = "0.2"
|
||||
|
||||
print(current < latest)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user