From 4975787afabdcea80ff3906f60a4647f15323ed0 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Thu, 6 Oct 2016 21:51:51 +0200 Subject: [PATCH] Added code to prevent OutOfMemory error. Made notification optional. Can now save image on long press. Bug fixes --- .../data/download/DownloadManager.kt | 14 ++++- .../data/download/DownloadNotifier.kt | 52 +++++++++++-------- .../tachiyomi/data/download/ImageNotifier.kt | 26 +++------- .../data/preference/PreferenceKeys.kt | 4 ++ .../data/preference/PreferencesHelper.kt | 4 ++ .../tachiyomi/ui/reader/ReaderActivity.kt | 18 ++++++- .../tachiyomi/ui/reader/ReaderPresenter.kt | 25 ++++++++- .../ui/reader/viewer/pager/PagerReader.kt | 5 ++ .../ui/reader/viewer/webtoon/WebtoonReader.kt | 5 ++ .../kanade/tachiyomi/util/FileExtensions.kt | 40 ++++++++++++++ app/src/main/res/values/arrays.xml | 12 +++++ app/src/main/res/values/keys.xml | 3 +- app/src/main/res/values/strings.xml | 5 ++ app/src/main/res/xml/pref_downloads.xml | 15 ++++++ 14 files changed, 180 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index 115e10bd63..5e85b17bf6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -47,6 +47,8 @@ class DownloadManager( private val threadsSubject = BehaviorSubject.create() private var threadsSubscription: Subscription? = null + private var notificationSubscription: Subscription? = null + val queue = DownloadQueue() val imageFilenameRegex = "[^\\sa-zA-Z0-9.-]".toRegex() @@ -66,6 +68,12 @@ class DownloadManager( downloadNotifier.multipleDownloadThreads = it > 1 } + notificationSubscription = preferences.showMangaDownloadNotification().asObservable() + .subscribe { + downloadNotifier.onClear() + downloadNotifier.showNotification = it + } + downloadsSubscription = downloadsQueueSubject.flatMap { Observable.from(it) } .lift(DynamicConcurrentMergeOperator({ downloadChapter(it) }, threadsSubject)) .onBackpressureBuffer() @@ -107,6 +115,10 @@ class DownloadManager( threadsSubscription?.unsubscribe() } + if (notificationSubscription != null) { + notificationSubscription?.unsubscribe() + } + } // Create a download object for every chapter and add them to the downloads queue @@ -188,7 +200,7 @@ class DownloadManager( DiskUtils.createDirectory(download.directory) val pageListObservable: Observable> = if (download.pages == null) - // Pull page list from network and add them to download object + // Pull page list from network and add them to download object download.source.fetchPageListFromNetwork(download.chapter) .doOnNext { pages -> download.pages = pages diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt index 498a08883f..06eae3dca3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.DownloadQueue import eu.kanade.tachiyomi.util.notificationManager +import eu.kanade.tachiyomi.util.toast /** * DownloadNotifier is used to show notifications when downloading one or multiple chapters. @@ -40,6 +41,11 @@ class DownloadNotifier(private val context: Context) { */ internal var multipleDownloadThreads = false + /** + * Value determining if notification should be shown + */ + internal var showNotification = true + /** * Called when download progress changes. * Note: Only accepted when multi download active. @@ -47,9 +53,8 @@ class DownloadNotifier(private val context: Context) { * @param queue the queue containing downloads. */ internal fun onProgressChange(queue: DownloadQueue) { - if (multipleDownloadThreads) { + if (multipleDownloadThreads && showNotification) doOnProgressChange(null, queue) - } } /** @@ -60,9 +65,8 @@ class DownloadNotifier(private val context: Context) { * @param queue the queue containing downloads */ internal fun onProgressChange(download: Download, queue: DownloadQueue) { - if (!multipleDownloadThreads) { + if (!multipleDownloadThreads && showNotification) doOnProgressChange(download, queue) - } } /** @@ -86,7 +90,7 @@ class DownloadNotifier(private val context: Context) { } // Create notification - with (notificationBuilder) { + with(notificationBuilder) { // Check if icon needs refresh if (!isDownloading) { setSmallIcon(android.R.drawable.stat_sys_download) @@ -127,17 +131,18 @@ class DownloadNotifier(private val context: Context) { * @param download download object containing download information */ private fun onComplete(download: Download?) { - // Create notification. - with(notificationBuilder) { - setContentTitle(download?.chapter?.name ?: context.getString(R.string.app_name)) - setContentText(context.getString(R.string.update_check_notification_download_complete)) - setSmallIcon(android.R.drawable.stat_sys_download_done) - setProgress(0, 0, false) + if (showNotification) { + // Create notification. + with(notificationBuilder) { + setContentTitle(download?.chapter?.name ?: context.getString(R.string.app_name)) + setContentText(context.getString(R.string.update_check_notification_download_complete)) + setSmallIcon(android.R.drawable.stat_sys_download_done) + setProgress(0, 0, false) + } + + // Show notification. + context.notificationManager.notify(notificationId, notificationBuilder.build()) } - - // Show notification. - context.notificationManager.notify(notificationId, notificationBuilder.build()) - // Reset initial values isDownloading = false initialQueueSize = 0 @@ -158,14 +163,17 @@ class DownloadNotifier(private val context: Context) { */ internal fun onError(error: String? = null, chapter: String? = null) { // Create notification - with(notificationBuilder) { - setContentTitle(chapter ?: context.getString(R.string.download_notifier_title_error)) - setContentText(error ?: context.getString(R.string.download_notifier_unkown_error)) - setSmallIcon(android.R.drawable.stat_sys_warning) - setProgress(0, 0, false) + if (showNotification) { + with(notificationBuilder) { + setContentTitle(chapter ?: context.getString(R.string.download_notifier_title_error)) + setContentText(error ?: context.getString(R.string.download_notifier_unkown_error)) + setSmallIcon(android.R.drawable.stat_sys_warning) + setProgress(0, 0, false) + } + context.notificationManager.notify(Constants.NOTIFICATION_DOWNLOAD_CHAPTER_ERROR_ID, notificationBuilder.build()) + } else { + context.toast(error ?: context.getString(R.string.download_notifier_unkown_error)) } - context.notificationManager.notify(Constants.NOTIFICATION_DOWNLOAD_CHAPTER_ERROR_ID, notificationBuilder.build()) - // Reset download information onClear() isDownloading = false diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt index dbd4a5cecf..990c5a1874 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt @@ -1,11 +1,10 @@ package eu.kanade.tachiyomi.data.download import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.support.v4.app.NotificationCompat import eu.kanade.tachiyomi.Constants import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.util.decodeSampledBitmap import eu.kanade.tachiyomi.util.notificationManager import java.io.File @@ -52,9 +51,9 @@ class ImageNotifier(private val context: Context) { /** * Called when image download is complete - * @param bitmap image file containing downloaded page image + * @param file image file containing downloaded page image */ - fun onComplete(bitmap: Bitmap, file: File) { + fun onComplete(file: File) { with(notificationBuilder) { if (isDownloading) { setProgress(0, 0, false) @@ -62,8 +61,8 @@ class ImageNotifier(private val context: Context) { } setContentTitle(context.getString(R.string.picture_saved)) setSmallIcon(R.drawable.ic_insert_photo_black_24dp) - setLargeIcon(bitmap) - setStyle(NotificationCompat.BigPictureStyle().bigPicture(bitmap)) + setLargeIcon(file.decodeSampledBitmap(100, 100)) + setStyle(NotificationCompat.BigPictureStyle().bigPicture(file.decodeSampledBitmap(1024, 1024))) setAutoCancel(true) // Clear old actions if they exist @@ -84,10 +83,6 @@ class ImageNotifier(private val context: Context) { context.notificationManager.notify(notificationId, notificationBuilder.build()) } - fun onComplete(file: File) { - onComplete(convertToBitmap(file), file) - } - /** * Clears the notification message */ @@ -112,13 +107,4 @@ class ImageNotifier(private val context: Context) { isDownloading = false } - /** - * Converts file to bitmap - */ - fun convertToBitmap(image: File): Bitmap { - val options = BitmapFactory.Options() - options.inPreferredConfig = Bitmap.Config.ARGB_8888 - return BitmapFactory.decodeFile(image.absolutePath, options) - } - -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 46b07458fe..fe9c092efa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -72,6 +72,10 @@ class PreferenceKeys(context: Context) { val removeAfterMarkedAsRead = context.getString(R.string.pref_remove_after_marked_as_read_key) + val showMangaDownloadNotification = context.getString(R.string.pref_notifications_manga_download_key) + + val showSavePageNotification = context.getString(R.string.pref_notifications_single_page_key) + val libraryUpdateInterval = context.getString(R.string.pref_library_update_interval_key) val libraryUpdateRestriction = context.getString(R.string.pref_library_update_restriction_key) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index c18c1cd0a0..6e4ade899d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -122,6 +122,10 @@ class PreferencesHelper(context: Context) { fun removeAfterMarkedAsRead() = prefs.getBoolean(keys.removeAfterMarkedAsRead, false) + fun showMangaDownloadNotification() = rxPrefs.getBoolean(keys.showMangaDownloadNotification, true) + + fun showSavePageNotification() = prefs.getBoolean(keys.showSavePageNotification, false) + fun libraryUpdateInterval() = rxPrefs.getInteger(keys.libraryUpdateInterval, 0) fun libraryUpdateRestriction() = prefs.getStringSet(keys.libraryUpdateRestriction, emptySet()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 4c1c64a780..69c4ab3d8b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -145,8 +145,6 @@ class ReaderActivity : BaseRxActivity() { when (item.itemId) { R.id.action_settings -> ReaderSettingsDialog().show(supportFragmentManager, "settings") R.id.action_custom_filter -> ReaderCustomFilterDialog().show(supportFragmentManager, "filter") - R.id.action_save_page -> presenter.savePage() - R.id.action_set_as_cover -> presenter.setCover() else -> return super.onOptionsItemSelected(item) } return true @@ -230,6 +228,22 @@ class ReaderActivity : BaseRxActivity() { // Ignore } + fun onLongPress() { + MaterialDialog.Builder(this).apply { + title = "Choose" + items(R.array.reader_image_options) + .itemsIds(R.array.reader_image_options_values) + itemsCallback { materialDialog, view, i, charSequence -> + when (i) { + 0 -> presenter.setCover() + 1 -> presenter.shareImage() + 2 -> presenter.savePage() + } + + }.show() + } + } + /** * Called from the presenter at startup, allowing to prepare the selected reader. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 6451a36847..bd440bb5f3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.ui.reader +import android.content.Intent +import android.net.Uri import android.os.Bundle import android.os.Environment import eu.kanade.tachiyomi.R @@ -576,6 +578,19 @@ class ReaderPresenter : BasePresenter() { return false } + fun shareImage() { + chapter.pages?.get(chapter.last_page_read)?.let { page -> + val shareIntent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_STREAM, Uri.parse(page.imagePath)) + flags = Intent.FLAG_ACTIVITY_NEW_TASK + type = "image/jpeg" + } + context.startActivity(Intent.createChooser(shareIntent, context.resources.getText(R.string.action_share)) + .apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK }) + } + } + /** * Save page to local storage * @throws IOException @@ -595,7 +610,10 @@ class ReaderPresenter : BasePresenter() { //Check if file doesn't already exist if (destFile.exists()) { - imageNotifier.onComplete(destFile) + if (prefs.showSavePageNotification()) + imageNotifier.onComplete(destFile) + else + context.toast(context.getString(R.string.page_downloaded, destFile.path)) } else { if (inputFile.exists()) { // Copy file @@ -606,7 +624,10 @@ class ReaderPresenter : BasePresenter() { { imageNotifier.onComplete(it) }, { error -> Timber.e(error.message) - imageNotifier.onError(error.message) + if (prefs.showSavePageNotification()) + imageNotifier.onError(error.message) + else + context.toast(error.message) }) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt index 6d9a4bb63d..4220ece003 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt @@ -185,6 +185,11 @@ abstract class PagerReader : BaseReader() { } return true } + + override fun onLongPress(e: MotionEvent?) { + super.onLongPress(e) + readerActivity.onLongPress() + } }) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt index f08eecd551..3041b17914 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt @@ -140,6 +140,11 @@ class WebtoonReader : BaseReader() { } return true } + + override fun onLongPress(e: MotionEvent?) { + super.onLongPress(e) + readerActivity.onLongPress() + } }) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt new file mode 100644 index 0000000000..44ba46f1e1 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt @@ -0,0 +1,40 @@ +package eu.kanade.tachiyomi.util + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import java.io.File + +fun File.decodeSampledBitmap(reqWidth: Int, reqHeight: Int): Bitmap { + // First decode with inJustDecodeBounds=true to check dimensions + val options = BitmapFactory.Options() + options.inJustDecodeBounds = true + BitmapFactory.decodeFile(this.absolutePath, options) + + // Calculate inSampleSize + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight) + + // Decode bitmap with inSampleSize set + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(this.absolutePath, options) +} + +fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { + // Raw height and width of image + val height = options.outHeight + val width = options.outWidth + var inSampleSize = 1 + + if (height > reqHeight || width > reqWidth) { + + val halfHeight = height / 2 + val halfWidth = width / 2 + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { + inSampleSize *= 2 + } + } + + return inSampleSize +} \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 1b61924f6e..52405f3a4b 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -174,4 +174,16 @@ 3 + + @string/set_as_cover + @string/share_image + @string/save_image + + + + 0 + 1 + 2 + + \ No newline at end of file diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index ad8de7baab..0fafb4123f 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -48,7 +48,8 @@ pref_download_only_over_wifi_key pref_remove_after_marked_as_read_key pref_category_remove_after_read_key - + notifications_single_page + notifications_manga_download last_used_category pref_source_languages diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 642b4c9028..169672072e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -281,6 +281,11 @@ Custom filter + Set as cover + Share image + Save image + Cover updated + Page copied to %1$s Downloading… Downloaded %1$d%% Page: %1$d diff --git a/app/src/main/res/xml/pref_downloads.xml b/app/src/main/res/xml/pref_downloads.xml index 8eff6f5bac..d21305ac80 100644 --- a/app/src/main/res/xml/pref_downloads.xml +++ b/app/src/main/res/xml/pref_downloads.xml @@ -40,6 +40,21 @@ android:summary="%s" android:title="@string/pref_remove_after_read" /> + + + + + + + \ No newline at end of file