From 1eb75acb400c75ddbb6a5b9f72ffa20b42cf4b6f Mon Sep 17 00:00:00 2001 From: tom5079 Date: Sun, 7 Jul 2019 15:21:56 +0900 Subject: [PATCH] UI update Added sort by popularity functionality Added auto update --- .idea/codeStyles/Project.xml | 112 ++++++ .idea/misc.xml | 2 +- app/build.gradle | 5 +- app/release/output.json | 2 +- app/src/main/AndroidManifest.xml | 5 +- app/src/main/java/xyz/quaver/pupil/Pupil.kt | 3 + .../quaver/pupil/types/SelectorSuggestion.kt | 31 -- .../java/xyz/quaver/pupil/ui/MainActivity.kt | 379 ++++++++++-------- .../xyz/quaver/pupil/ui/ReaderActivity.kt | 21 +- .../quaver/pupil/util/GalleryDownloader.kt | 84 ++-- .../main/java/xyz/quaver/pupil/util/update.kt | 32 +- app/src/main/res/drawable/ic_download.xml | 2 +- app/src/main/res/drawable/ic_numeric.xml | 8 - .../res/drawable/image_broken_variant.xml | 8 + app/src/main/res/drawable/numeric.xml | 2 +- app/src/main/res/drawable/sort_variant.xml | 8 + .../main/res/layout/activity_main_content.xml | 24 ++ app/src/main/res/layout/activity_reader.xml | 3 +- .../res/layout/item_selector_suggestion.xml | 34 -- app/src/main/res/menu/main.xml | 22 +- app/src/main/res/values-ja/strings.xml | 3 + app/src/main/res/values-ko/strings.xml | 5 +- app/src/main/res/values/strings.xml | 6 +- .../java/xyz/quaver/pupil/ExampleUnitTest.kt | 3 + build.gradle | 2 +- .../main/java/xyz/quaver/hitomi/results.kt | 49 ++- .../src/main/java/xyz/quaver/hitomi/search.kt | 5 +- .../test/java/xyz/quaver/hitomi/UnitTest.kt | 9 +- 28 files changed, 506 insertions(+), 363 deletions(-) delete mode 100644 app/src/main/java/xyz/quaver/pupil/types/SelectorSuggestion.kt delete mode 100644 app/src/main/res/drawable/ic_numeric.xml create mode 100644 app/src/main/res/drawable/image_broken_variant.xml create mode 100644 app/src/main/res/drawable/sort_variant.xml delete mode 100644 app/src/main/res/layout/item_selector_suggestion.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1bec35e5..cb22ebb7 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,8 +1,120 @@ + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml index 7bfef59d..37a75096 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/build.gradle b/app/build.gradle index db1cf65d..ef3a25cf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/release/output.json b/app/release/output.json index de58b687..e36241c5 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -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":{}}] \ No newline at end of file +[{"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":{}}] \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 89e70b1e..08cc55a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,9 @@ package="xyz.quaver.pupil"> - + + + . - */ - -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 "" - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt index d5e7bd78..c4708b98 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -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>>() @@ -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(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(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 { diff --git a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt index 71c5638b..3d3270ac 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt @@ -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) diff --git a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt index c9188220..d78a565f 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt @@ -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() diff --git a/app/src/main/java/xyz/quaver/pupil/util/update.kt b/app/src/main/java/xyz/quaver/pupil/util/update.kt index 1a3998bc..fec736d6 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt @@ -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? { + 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 } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml index c95797c1..aa88433b 100644 --- a/app/src/main/res/drawable/ic_download.xml +++ b/app/src/main/res/drawable/ic_download.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/drawable/ic_numeric.xml b/app/src/main/res/drawable/ic_numeric.xml deleted file mode 100644 index fc54c34a..00000000 --- a/app/src/main/res/drawable/ic_numeric.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/image_broken_variant.xml b/app/src/main/res/drawable/image_broken_variant.xml new file mode 100644 index 00000000..c4aa1d54 --- /dev/null +++ b/app/src/main/res/drawable/image_broken_variant.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/numeric.xml b/app/src/main/res/drawable/numeric.xml index fc54c34a..db07bdc4 100644 --- a/app/src/main/res/drawable/numeric.xml +++ b/app/src/main/res/drawable/numeric.xml @@ -4,5 +4,5 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/sort_variant.xml b/app/src/main/res/drawable/sort_variant.xml new file mode 100644 index 00000000..fdea2e49 --- /dev/null +++ b/app/src/main/res/drawable/sort_variant.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml index bde8ddf4..38049787 100644 --- a/app/src/main/res/layout/activity_main_content.xml +++ b/app/src/main/res/layout/activity_main_content.xml @@ -56,6 +56,30 @@ android:scrollbars="vertical" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/> + + + + + + + + @@ -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"/> diff --git a/app/src/main/res/layout/item_selector_suggestion.xml b/app/src/main/res/layout/item_selector_suggestion.xml deleted file mode 100644 index 144792cb..00000000 --- a/app/src/main/res/layout/item_selector_suggestion.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - -