Преглед на файлове

Added code to prevent OutOfMemory error. Made notification optional. Can now save image on long press. Bug fixes

Bram van de Kerkhof преди 10 години
родител
ревизия
4975787afa

+ 13 - 1
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt

@@ -47,6 +47,8 @@ class DownloadManager(
     private val threadsSubject = BehaviorSubject.create<Int>()
     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<Download, Download>({ 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<List<Page>> = 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

+ 30 - 22
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)
-        }
-
-        // Show notification.
-        context.notificationManager.notify(notificationId, notificationBuilder.build())
+        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())
+        }
         // 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

+ 6 - 20
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)
-    }
-
-}
+}

+ 4 - 0
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)

+ 4 - 0
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())

+ 16 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt

@@ -145,8 +145,6 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
         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<ReaderPresenter>() {
         // 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.
      */

+ 23 - 2
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<ReaderActivity>() {
         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<ReaderActivity>() {
 
             //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<ReaderActivity>() {
                                     { imageNotifier.onComplete(it) },
                                     { error ->
                                         Timber.e(error.message)
-                                        imageNotifier.onError(error.message)
+                                        if (prefs.showSavePageNotification())
+                                            imageNotifier.onError(error.message)
+                                        else
+                                            context.toast(error.message)
                                     })
                 }
             }

+ 5 - 0
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()
+            }
         })
     }
 

+ 5 - 0
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()
+            }
         })
     }
 

+ 40 - 0
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
+}

+ 12 - 0
app/src/main/res/values/arrays.xml

@@ -174,4 +174,16 @@
         <item>3</item>
     </string-array>
 
+    <string-array name="reader_image_options">
+        <item>@string/set_as_cover</item>
+        <item>@string/share_image</item>
+        <item>@string/save_image</item>
+    </string-array>
+
+    <string-array name="reader_image_options_values">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
 </resources>

+ 2 - 1
app/src/main/res/values/keys.xml

@@ -48,7 +48,8 @@
     <string name="pref_download_only_over_wifi_key">pref_download_only_over_wifi_key</string>
     <string name="pref_remove_after_marked_as_read_key">pref_remove_after_marked_as_read_key</string>
     <string name="pref_category_remove_after_read_key">pref_category_remove_after_read_key</string>
-
+    <string name="pref_notifications_single_page_key">notifications_single_page</string>
+    <string name="pref_notifications_manga_download_key">notifications_manga_download</string>
     <string name="pref_last_used_category_key">last_used_category</string>
 
     <string name="pref_source_languages">pref_source_languages</string>

+ 5 - 0
app/src/main/res/values/strings.xml

@@ -281,6 +281,11 @@
 
     <!-- Reader activity -->
     <string name="custom_filter">Custom filter</string>
+    <string name="set_as_cover">Set as cover</string>
+    <string name="share_image">Share image</string>
+    <string name="save_image">Save image</string>
+    <string name="cover_updated">Cover updated</string>
+    <string name="page_downloaded">Page copied to %1$s</string>
     <string name="downloading">Downloading…</string>
     <string name="download_progress">Downloaded %1$d%%</string>
     <string name="chapter_progress">Page: %1$d</string>

+ 15 - 0
app/src/main/res/xml/pref_downloads.xml

@@ -40,6 +40,21 @@
             android:summary="%s"
             android:title="@string/pref_remove_after_read" />
 
+        <PreferenceCategory
+            android:persistent="false"
+            android:title="@string/pref_notifications" />
+
+        <SwitchPreference
+            android:defaultValue="true"
+            android:key="@string/pref_notifications_manga_download_key"
+            android:title="@string/pref_notifications_manga_download" />
+
+        <SwitchPreference
+            android:defaultValue="false"
+            android:key="@string/pref_notifications_single_page_key"
+            android:title="@string/pref_notifications_single_page" />
+
+
     </PreferenceScreen>
 
 </PreferenceScreen>