diff --git a/app/build.gradle b/app/build.gradle index 3e89689a..3fef32d8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -29,6 +29,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1' implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.11.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8a646c94..766a3ca7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,7 +25,8 @@ + android:parentActivityName=".MainActivity" + android:configChanges="keyboardHidden|orientation|screenSize"/> diff --git a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt index 6e9f18f7..951ff28a 100644 --- a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt @@ -218,7 +218,9 @@ class MainActivity : AppCompatActivity() { private fun setupRecyclerView() { with(main_recyclerview) { - adapter = GalleryBlockAdapter(galleries) + adapter = GalleryBlockAdapter(galleries).apply { + + } addOnScrollListener( object: RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { @@ -235,8 +237,7 @@ class MainActivity : AppCompatActivity() { ItemClickSupport.addTo(this).setOnItemClickListener { _, position, _ -> val intent = Intent(this@MainActivity, ReaderActivity::class.java) val gallery = galleries[position].first - intent.putExtra("GALLERY_ID", gallery.id) - intent.putExtra("GALLERY_TITLE", gallery.title) + intent.putExtra("galleryblock", Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), gallery)) //TODO: Maybe sprinke some transitions will be nice :D startActivity(intent) diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index bf5d8b3b..8e1184dd 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -1,21 +1,40 @@ package xyz.quaver.pupil -import android.content.Intent -import android.os.Process +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.os.Build +import android.preference.PreferenceManager +import android.util.SparseArray import com.finotes.android.finotescore.Fn import com.finotes.android.finotescore.ObservableApplication import com.finotes.android.finotescore.Severity +import kotlinx.coroutines.Job class Pupil : ObservableApplication() { override fun onCreate() { + val preference = PreferenceManager.getDefaultSharedPreferences(this) + super.onCreate() Fn.init(this) Fn.enableFrameDetection() - Thread.setDefaultUncaughtExceptionHandler { t, e -> - Fn.reportException(t, Exception(e), Severity.FATAL) + if (!preference.getBoolean("channel_created", false)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val channel = NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_LOW).apply { + description = getString(R.string.channel_download_description) + enableLights(false) + enableVibration(false) + lockscreenVisibility = Notification.VISIBILITY_SECRET + } + manager.createNotificationChannel(channel) + } + + preference.edit().putBoolean("channel_created", true).apply() } } diff --git a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt index 91e54659..039be0dc 100644 --- a/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ReaderActivity.kt @@ -1,7 +1,7 @@ package xyz.quaver.pupil +import android.graphics.drawable.Drawable import android.os.Bundle -import android.util.Log import android.view.* import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity @@ -10,37 +10,33 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.PagerSnapHelper import androidx.recyclerview.widget.RecyclerView +import androidx.vectordrawable.graphics.drawable.Animatable2Compat +import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.android.synthetic.main.activity_reader.view.* import kotlinx.android.synthetic.main.dialog_numberpicker.view.* -import kotlinx.coroutines.* -import kotlinx.io.IOException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration -import kotlinx.serialization.list -import xyz.quaver.hitomi.Reader -import xyz.quaver.hitomi.ReaderItem -import xyz.quaver.hitomi.getReader -import xyz.quaver.hitomi.getReferer +import xyz.quaver.hitomi.GalleryBlock import xyz.quaver.pupil.adapters.ReaderAdapter +import xyz.quaver.pupil.util.GalleryDownloader import xyz.quaver.pupil.util.ItemClickSupport -import java.io.File -import java.io.FileOutputStream -import java.net.URL -import javax.net.ssl.HttpsURLConnection class ReaderActivity : AppCompatActivity() { private val images = ArrayList() - private var galleryID = 0 - private var gallerySize: Int = 0 - private var currentPage: Int = 0 - private lateinit var reader: Deferred - private var loadJob: Job? = null + private lateinit var galleryBlock: GalleryBlock + private var gallerySize = 0 + private var currentPage = 0 private var isScroll = true private var isFullscreen = false + private lateinit var downloader: GalleryDownloader + private val snapHelper = PagerSnapHelper() private var menu: Menu? = null @@ -54,54 +50,20 @@ class ReaderActivity : AppCompatActivity() { setContentView(R.layout.activity_reader) - supportActionBar?.title = intent.getStringExtra("GALLERY_TITLE") + galleryBlock = Json(JsonConfiguration.Stable).parse( + GalleryBlock.serializer(), + intent.getStringExtra("galleryblock") + ) - galleryID = intent.getIntExtra("GALLERY_ID", 0) - reader = CoroutineScope(Dispatchers.IO).async { - val json = Json(JsonConfiguration.Stable) - val serializer = ReaderItem.serializer().list - val preference = PreferenceManager.getDefaultSharedPreferences(this@ReaderActivity) - val isHiyobi = preference.getBoolean("use_hiyobi", false) + supportActionBar?.title = galleryBlock.title + supportActionBar?.setDisplayHomeAsUpEnabled(false) - val cache = when { - isHiyobi -> File(cacheDir, "imageCache/$galleryID/reader-hiyobi.json") - else -> File(cacheDir, "imageCache/$galleryID/reader.json") - } - - if (cache.exists()) { - val cached = json.parse(serializer, cache.readText()) - - if (cached.isNotEmpty()) - return@async cached - } - - val reader = when { - isHiyobi -> { - xyz.quaver.hiyobi.getReader(galleryID).let { - when { - it.isEmpty() -> getReader(galleryID) - else -> it - } - } - } - else -> { - getReader(galleryID) - } - } - - if (reader.isEmpty()) - finish() - - if (!cache.parentFile.exists()) - cache.parentFile.mkdirs() - - cache.writeText(json.stringify(serializer, reader)) - - reader - } + initDownloader() initView() - loadImages() + + if (!downloader.notify) + downloader.start() } override fun onResume() { @@ -149,6 +111,9 @@ class ReaderActivity : AppCompatActivity() { override fun onDestroy() { super.onDestroy() + + if (!downloader.notify) + downloader.cancel() } override fun onBackPressed() { @@ -166,6 +131,85 @@ class ReaderActivity : AppCompatActivity() { } } + private fun initDownloader() { + var d: GalleryDownloader? = GalleryDownloader.get(galleryBlock.id) + + if (d == null) { + d = GalleryDownloader(this, galleryBlock) + } + + downloader = d.apply { + onReaderLoadedHandler = { + CoroutineScope(Dispatchers.Main).launch { + with(reader_progressbar) { + max = it.size + progress = 0 + + visibility = View.VISIBLE + } + + gallerySize = it.size + menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/${it.size}" + } + } + onProgressHandler = { + CoroutineScope(Dispatchers.Main).launch { + reader_progressbar.progress = it + } + } + onDownloadedHandler = { + CoroutineScope(Dispatchers.Main).launch { + if (images.isEmpty()) { + images.addAll(it) + reader_recyclerview.adapter?.notifyDataSetChanged() + } else { + images.add(it.last()) + reader_recyclerview.adapter?.notifyItemInserted(images.size-1) + } + } + } + onErrorHandler = { + downloader.notify = false + } + onCompleteHandler = { + CoroutineScope(Dispatchers.Main).launch { + reader_progressbar.visibility = View.GONE + } + } + onNotifyChangedHandler = { notify -> + val fab = reader_fab_download + + if (notify) { + val icon = AnimatedVectorDrawableCompat.create(this, R.drawable.ic_downloading) + icon?.registerAnimationCallback(object: Animatable2Compat.AnimationCallback() { + override fun onAnimationEnd(drawable: Drawable?) { + if (downloader.notify) + fab.post { + icon.start() + fab.labelText = getString(R.string.reader_fab_download_cancel) + } + else + fab.post { + fab.setImageResource(R.drawable.ic_download) + fab.labelText = getString(R.string.reader_fab_download) + } + } + }) + + fab.setImageDrawable(icon) + icon?.start() + } else { + fab.setImageResource(R.drawable.ic_download) + } + } + } + + if (downloader.notify) { + downloader.invokeOnReaderLoaded() + downloader.invokeOnNotifyChanged() + } + } + private fun initView() { with(reader_recyclerview) { adapter = ReaderAdapter(images) @@ -208,6 +252,13 @@ class ReaderActivity : AppCompatActivity() { reader_fab.close(true) } + + reader_fab_download.setOnClickListener { + downloader.notify = !downloader.notify + + if (!downloader.notify) + downloader.clearNotification() + } } private fun fullscreen(isFullscreen: Boolean) { @@ -237,68 +288,4 @@ class ReaderActivity : AppCompatActivity() { (reader_recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(currentPage-1, 0) } - - private fun loadImages() { - fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp" - - loadJob = CoroutineScope(Dispatchers.Default).launch { - val reader = reader.await() - - launch(Dispatchers.Main) { - with(reader_progressbar) { - max = reader.size - progress = 0 - - visibility = View.VISIBLE - } - - gallerySize = reader.size - menu?.findItem(R.id.reader_menu_page_indicator)?.title = "$currentPage/$gallerySize" - } - - reader.chunked(4).forEach { chunked -> - chunked.map { - async(Dispatchers.IO) { - val url = if (it.galleryInfo?.haswebp == 1) webpUrlFromUrl(it.url) else it.url - - val fileName: String - - with(url) { - fileName = substring(lastIndexOf('/')+1) - } - - val cache = File(cacheDir, "/imageCache/$galleryID/$fileName") - - if (!cache.exists()) - try { - with(URL(url).openConnection() as HttpsURLConnection) { - setRequestProperty("Referer", getReferer(galleryID)) - - if (!cache.parentFile.exists()) - cache.parentFile.mkdirs() - - inputStream.copyTo(FileOutputStream(cache)) - } - } catch (e: Exception) { - cache.delete() - } - - cache.absolutePath - } - }.forEach { - val cache = it.await() - - launch(Dispatchers.Main) { - images.add(cache) - reader_recyclerview.adapter?.notifyItemInserted(images.size - 1) - reader_progressbar.progress++ - } - } - } - - launch(Dispatchers.Main) { - reader_progressbar.visibility = View.GONE - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt index c7c4f67e..54166f8e 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt @@ -1,6 +1,7 @@ package xyz.quaver.pupil.adapters import android.graphics.BitmapFactory +import android.util.SparseArray import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -14,9 +15,17 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonConfiguration +import kotlinx.serialization.list import xyz.quaver.hitomi.GalleryBlock +import xyz.quaver.hitomi.ReaderItem import xyz.quaver.pupil.R import xyz.quaver.pupil.types.Tag +import java.io.File +import java.util.* +import kotlin.collections.ArrayList +import kotlin.concurrent.schedule class GalleryBlockAdapter(private val galleries: List>>) : RecyclerView.Adapter() { @@ -35,9 +44,12 @@ class GalleryBlockAdapter(private val galleries: List() - class ViewHolder(val view: CardView) : RecyclerView.ViewHolder(view) - class ProgressViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view) + private var onChipClickedHandler = ArrayList<((Tag) -> Unit)>() + + class ViewHolder(val view: CardView, var galleryID: Int? = null) : RecyclerView.ViewHolder(view) + class ProgressViewHolder(val view: LinearLayout) : RecyclerView.ViewHolder(view) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { when(viewType) { @@ -71,16 +83,62 @@ class GalleryBlockAdapter(private val galleries: List View.GONE + false -> View.VISIBLE + } + } } - override fun getItemCount() = if (galleries.isEmpty()) 0 else galleries.size+(if (noMore) 0 else 1) + override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { + super.onViewDetachedFromWindow(holder) + + if (holder is ViewHolder) { + val galleryID = holder.galleryID ?: return + val task = refreshTasks.get(galleryID) ?: return + + refreshTasks.remove(galleryID) + task.cancel() + } + } + + override fun getItemCount() = if (galleries.isEmpty()) 0 else galleries.size+1 override fun getItemViewType(position: Int): Int { return when { diff --git a/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt new file mode 100644 index 00000000..ef36b282 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt @@ -0,0 +1,232 @@ +package xyz.quaver.pupil.util + +import android.app.PendingIntent +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.util.SparseArray +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.core.app.TaskStackBuilder +import androidx.preference.PreferenceManager +import kotlinx.coroutines.* +import kotlinx.io.IOException +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonConfiguration +import kotlinx.serialization.list +import xyz.quaver.hitomi.* +import xyz.quaver.pupil.R +import xyz.quaver.pupil.ReaderActivity +import java.io.File +import java.io.FileOutputStream +import java.net.URL +import javax.net.ssl.HttpsURLConnection + +class GalleryDownloader( + base: Context, + private val galleryBlock: GalleryBlock +) : ContextWrapper(base) { + + var notify: Boolean = false + set(value) { + if (value) { + field = true + notificationManager.notify(galleryBlock.id, notificationBuilder.build()) + + if (downloadJob?.isActive != true) + field = false + } else { + field = false + } + + onNotifyChangedHandler?.invoke(value) + } + + private val reader: Deferred + private var downloadJob: Job? = null + + private lateinit var notificationBuilder: NotificationCompat.Builder + private lateinit var notificationManager: NotificationManagerCompat + + var onReaderLoadedHandler: ((Reader) -> Unit)? = null + var onProgressHandler: ((Int) -> Unit)? = null + var onDownloadedHandler: ((List) -> Unit)? = null + var onErrorHandler: (() -> Unit)? = null + var onCompleteHandler: (() -> Unit)? = null + var onNotifyChangedHandler: ((Boolean) -> Unit)? = null + + companion object : SparseArray() + + init { + put(galleryBlock.id, this) + + initNotification() + + reader = CoroutineScope(Dispatchers.IO).async { + val json = Json(JsonConfiguration.Stable) + val serializer = ReaderItem.serializer().list + val preference = PreferenceManager.getDefaultSharedPreferences(this@GalleryDownloader) + val useHiyobi = preference.getBoolean("use_hiyobi", false) + + //Check cache + val cache = File(cacheDir, "imageCache/${galleryBlock.id}/reader.json") + + if (cache.exists()) { + val cached = json.parse(serializer, cache.readText()) + + if (cached.isNotEmpty()) + return@async cached + } + + //Cache doesn't exist. Load from internet + val reader = when { + useHiyobi -> { + xyz.quaver.hiyobi.getReader(galleryBlock.id).let { + when { + it.isEmpty() -> getReader(galleryBlock.id) + else -> it + } + } + } + else -> { + getReader(galleryBlock.id) + } + } + + //Could not retrieve reader + if (reader.isEmpty()) + throw IOException("Can't retrieve Reader") + + //Save cache + if (!cache.parentFile.exists()) + cache.parentFile.mkdirs() + + cache.writeText(json.stringify(serializer, reader)) + + reader + } + } + + private fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp" + + fun start() { + downloadJob = CoroutineScope(Dispatchers.Default).launch { + val reader = reader.await() + + val list = ArrayList() + + onReaderLoadedHandler?.invoke(reader) + + notificationBuilder + .setProgress(reader.size, 0, false) + .setContentText("0/${reader.size}") + + reader.chunked(4).forEachIndexed { chunkIndex, chunked -> + chunked.mapIndexed { i, it -> + val index = chunkIndex*4+i + + onProgressHandler?.invoke(index) + + notificationBuilder + .setProgress(reader.size, index, false) + .setContentText("$index/${reader.size}") + + if (notify) + notificationManager.notify(galleryBlock.id, notificationBuilder.build()) + + async(Dispatchers.IO) { + val url = if (it.galleryInfo?.haswebp == 1) webpUrlFromUrl(it.url) else it.url + + val name = "$index".padStart(4, '0') + val ext = url.split('.').last() + + val cache = File(cacheDir, "/imageCache/${galleryBlock.id}/images/$name.$ext") + + if (!cache.exists()) + try { + with(URL(url).openConnection() as HttpsURLConnection) { + setRequestProperty("Referer", getReferer(galleryBlock.id)) + + if (!cache.parentFile.exists()) + cache.parentFile.mkdirs() + + inputStream.copyTo(FileOutputStream(cache)) + } + } catch (e: Exception) { + cache.delete() + + onErrorHandler?.invoke() + + notificationBuilder + .setContentTitle(galleryBlock.title) + .setContentText(getString(R.string.reader_notification_error)) + .setProgress(0, 0, false) + + notificationManager.notify(galleryBlock.id, notificationBuilder.build()) + } + + cache.absolutePath + } + }.forEach { + list.add(it.await()) + onDownloadedHandler?.invoke(list) + } + } + + onCompleteHandler?.invoke() + + notificationBuilder + .setContentTitle(galleryBlock.title) + .setContentText(getString(R.string.reader_notification_complete)) + .setProgress(0, 0, false) + + if (notify) + notificationManager.notify(galleryBlock.id, notificationBuilder.build()) + + notify = false + + remove(galleryBlock.id) + } + } + + fun cancel() { + downloadJob?.cancel() + + remove(galleryBlock.id) + } + + fun invokeOnReaderLoaded() { + CoroutineScope(Dispatchers.Default).launch { + onReaderLoadedHandler?.invoke(reader.await()) + } + } + + fun clearNotification() { + notificationManager.cancel(galleryBlock.id) + } + + fun invokeOnNotifyChanged() { + onNotifyChangedHandler?.invoke(notify) + } + + private fun initNotification() { + val intent = Intent(this, ReaderActivity::class.java).apply { + putExtra("galleryblock", Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), galleryBlock)) + } + val pendingIntent = TaskStackBuilder.create(this).run { + addNextIntentWithParentStack(intent) + getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) + } + + notificationBuilder = NotificationCompat.Builder(this, "download").apply { + setContentTitle(galleryBlock.title) + setContentText(getString(R.string.reader_notification_text)) + setSmallIcon(R.drawable.ic_download) + setContentIntent(pendingIntent) + setProgress(0, 0, true) + priority = NotificationCompat.PRIORITY_LOW + } + notificationManager = NotificationManagerCompat.from(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/history.kt b/app/src/main/java/xyz/quaver/pupil/util/history.kt index b0ad4395..a7fdce46 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/history.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/history.kt @@ -1,6 +1,5 @@ package xyz.quaver.pupil.util -import kotlinx.io.IOException import kotlinx.serialization.ImplicitReflectionSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration @@ -8,7 +7,6 @@ import kotlinx.serialization.parseList import kotlinx.serialization.stringify import java.io.File - class Histories(private val file: File) : ArrayList() { init { diff --git a/app/src/main/java/xyz/quaver/pupil/util/progress.kt b/app/src/main/java/xyz/quaver/pupil/util/progress.kt deleted file mode 100644 index 554cfe05..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/progress.kt +++ /dev/null @@ -1,2 +0,0 @@ -package xyz.quaver.pupil.util - diff --git a/app/src/main/res/drawable-anydpi/ic_downloading.xml b/app/src/main/res/drawable-anydpi/ic_downloading.xml new file mode 100644 index 00000000..9188c5f3 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_downloading.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml new file mode 100644 index 00000000..c95797c1 --- /dev/null +++ b/app/src/main/res/drawable/ic_download.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 0e0c6bd7..59ff93c1 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -41,6 +41,15 @@ android:layout_gravity="bottom|end" app:menu_colorNormal="@color/colorAccent"> + + - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_galleryblock.xml b/app/src/main/res/layout/item_galleryblock.xml index 69883a53..594363a9 100644 --- a/app/src/main/res/layout/item_galleryblock.xml +++ b/app/src/main/res/layout/item_galleryblock.xml @@ -18,6 +18,14 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + - - - \ No newline at end of file + app:chipCornerRadius="100dp"/> \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a0018929..eff3b9be 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -44,4 +44,11 @@ 準備中 準備中です。 フルスクリーン + ダウンロード + ダウンロードの進行を通知 + バックグラウンドダウンロード + ダウンロード中… + ダウンロード完了 + ダウンロードエラー + バックグラウンドダウンロード中止 \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index ed39440d..40800583 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -44,4 +44,11 @@ 준비 중 준비중입니다. 전체 화면 + 다운로드 + 다운로드 상태 알림 + 백그라운드 다운로드 + 다운로드 중… + 다운로드 완료 + 다운로드 오류 + 백그라운드 다운로드 취소 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e004b06b..b137f139 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - - Pupil + + Pupil https://api.github.com/repos/tom5079/Pupil-issue/releases Pupil-v(\\d+\\.)+\\d+\\.apk @@ -22,6 +22,9 @@ Denying any permission can deactivate some functions + Download + Shows download status + Search No result @@ -49,6 +52,11 @@ Go to page Fullscreen + Background download + Cancel background download + Downloading… + Download complete + Download error Settings Search Settings diff --git a/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt b/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt index fec18cac..c4a08536 100644 --- a/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt +++ b/app/src/test/java/xyz/quaver/pupil/ExampleUnitTest.kt @@ -12,7 +12,6 @@ import org.junit.Test class ExampleUnitTest { @Test - @ImplicitReflectionSerializer fun test() { } diff --git a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt index b573e193..e85582af 100644 --- a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt +++ b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt @@ -7,9 +7,7 @@ import java.net.URL class UnitTest { @Test fun test() { - val f = File("C:/Users/tom50/Workspace/Pupil/nodir/nodir/asdf.txt") - - f.delete() + print(File("C:\\asdf").list()?.size ?: 0) } @Test