From 2991906a85caf46b8a0a02ecbe50978747252516 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Tue, 27 Sep 2016 00:15:21 +0200 Subject: [PATCH 01/11] Added option to download page or set page as cover --- app/src/main/AndroidManifest.xml | 6 +- .../java/eu/kanade/tachiyomi/Constants.kt | 1 + .../data/download/DownloadManager.kt | 2 +- .../download/ImageNotificationReceiver.kt | 90 +++++++++++++ .../tachiyomi/data/download/ImageNotifier.kt | 124 +++++++++++++++++ .../ui/manga/info/MangaInfoFragment.kt | 3 +- .../tachiyomi/ui/reader/ReaderActivity.kt | 10 +- .../tachiyomi/ui/reader/ReaderPresenter.kt | 127 +++++++++++++++++- .../drawable/ic_insert_photo_black_24dp.xml | 9 ++ app/src/main/res/values/strings.xml | 9 +- 10 files changed, 367 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotificationReceiver.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt create mode 100644 app/src/main/res/drawable/ic_insert_photo_black_24dp.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ca07c95dfa..c9aaa32fd1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -86,9 +86,9 @@ - - + + + { + shareImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION)) + context.notificationManager.cancel(intent.getIntExtra(NOTIFICATION_ID, 5)) + } + ACTION_SHOW_IMAGE -> + showImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION)) + ACTION_DELETE_IMAGE -> { + deleteImage(intent.getStringExtra(EXTRA_FILE_LOCATION)) + context.notificationManager.cancel(intent.getIntExtra(NOTIFICATION_ID, 5)) + } + } + } + + fun deleteImage(path: String) { + val file = File(path) + if (file.exists()) file.delete() + } + + fun shareImage(context: Context, path: String) { + val shareIntent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_STREAM, Uri.parse(path)) + 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 }) + } + + fun showImage(context: Context, path: String) { + val intent = Intent().apply { + action = Intent.ACTION_VIEW + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK + setDataAndType(Uri.parse("file://" + path), "image/*") + } + context.startActivity(intent) + } + + companion object { + const val ACTION_SHARE_IMAGE = "eu.kanade.SHARE_IMAGE" + + const val ACTION_SHOW_IMAGE = "eu.kanade.SHOW_IMAGE" + + const val ACTION_DELETE_IMAGE = "eu.kanade.DELETE_IMAGE" + + const val EXTRA_FILE_LOCATION = "file_location" + + const val NOTIFICATION_ID = "notification_id" + + fun shareImageIntent(context: Context, path: String, notificationId: Int): PendingIntent { + val intent = Intent(context, ImageNotificationReceiver::class.java).apply { + action = ACTION_SHARE_IMAGE + putExtra(EXTRA_FILE_LOCATION, path) + putExtra(NOTIFICATION_ID, notificationId) + } + return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + fun showImageIntent(context: Context, path: String): PendingIntent { + val intent = Intent(context, ImageNotificationReceiver::class.java).apply { + action = ACTION_SHOW_IMAGE + putExtra(EXTRA_FILE_LOCATION, path) + } + return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + fun deleteImageIntent(context: Context, path: String, notificationId: Int): PendingIntent { + val intent = Intent(context, ImageNotificationReceiver::class.java).apply { + action = ACTION_DELETE_IMAGE + putExtra(EXTRA_FILE_LOCATION, path) + putExtra(NOTIFICATION_ID, notificationId) + } + return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + } +} 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 new file mode 100644 index 0000000000..dbd4a5cecf --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt @@ -0,0 +1,124 @@ +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.notificationManager +import java.io.File + + +class ImageNotifier(private val context: Context) { + /** + * Notification builder. + */ + private val notificationBuilder = NotificationCompat.Builder(context) + + /** + * Id of the notification. + */ + private val notificationId: Int + get() = Constants.NOTIFICATION_DOWNLOAD_IMAGE_ID + + /** + * Status of download. Used for correct notification icon. + */ + private var isDownloading = false + + /** + * Called when download progress changes. + * @param progress progress value in range [0,100] + */ + fun onProgressChange(progress: Int) { + with(notificationBuilder) { + if (!isDownloading) { + setContentTitle(context.getString(R.string.saving_picture)) + setSmallIcon(android.R.drawable.stat_sys_download) + setLargeIcon(null) + setStyle(null) + // Clear old actions if they exist + if (!mActions.isEmpty()) + mActions.clear() + isDownloading = true + } + + setProgress(100, progress, false) + } + // Displays the progress bar on notification + context.notificationManager.notify(notificationId, notificationBuilder.build()) + } + + /** + * Called when image download is complete + * @param bitmap image file containing downloaded page image + */ + fun onComplete(bitmap: Bitmap, file: File) { + with(notificationBuilder) { + if (isDownloading) { + setProgress(0, 0, false) + isDownloading = false + } + setContentTitle(context.getString(R.string.picture_saved)) + setSmallIcon(R.drawable.ic_insert_photo_black_24dp) + setLargeIcon(bitmap) + setStyle(NotificationCompat.BigPictureStyle().bigPicture(bitmap)) + setAutoCancel(true) + + // Clear old actions if they exist + if (!mActions.isEmpty()) + mActions.clear() + + setContentIntent(ImageNotificationReceiver.showImageIntent(context, file.absolutePath)) + // Share action + addAction(R.drawable.ic_share_white_24dp, + context.getString(R.string.action_share), + ImageNotificationReceiver.shareImageIntent(context, file.absolutePath, notificationId)) + // Delete action + addAction(R.drawable.ic_delete_white_24dp, + context.getString(R.string.action_delete), + ImageNotificationReceiver.deleteImageIntent(context, file.absolutePath, notificationId)) + } + // Displays the progress bar on notification + context.notificationManager.notify(notificationId, notificationBuilder.build()) + } + + fun onComplete(file: File) { + onComplete(convertToBitmap(file), file) + } + + /** + * Clears the notification message + */ + internal fun onClear() { + context.notificationManager.cancel(notificationId) + } + + + /** + * Called on error while downloading image + * @param error string containing error information + */ + internal fun onError(error: String?) { + // Create notification + with(notificationBuilder) { + setContentTitle(context.getString(R.string.download_notifier_title_error)) + setContentText(error ?: context.getString(R.string.download_notifier_unkown_error)) + setSmallIcon(android.R.drawable.ic_menu_report_image) + setProgress(0, 0, false) + } + context.notificationManager.notify(notificationId, notificationBuilder.build()) + 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/ui/manga/info/MangaInfoFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt index 2f67fd5fb9..9cf1221982 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt @@ -184,10 +184,9 @@ class MangaInfoFragment : BaseRxFragment() { val url = source.mangaDetailsRequest(presenter.manga).url().toString() val sharingIntent = Intent(Intent.ACTION_SEND).apply { type = "text/plain" - putExtra(android.content.Intent.EXTRA_SUBJECT, presenter.manga.title) putExtra(android.content.Intent.EXTRA_TEXT, resources.getString(R.string.share_text, presenter.manga.title, url)) } - startActivity(Intent.createChooser(sharingIntent, resources.getText(R.string.share_subject))) + startActivity(Intent.createChooser(sharingIntent, resources.getText(R.string.action_share))) } catch (e: Exception) { context.toast(e.message) } 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 0b935c8735..4c1c64a780 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,6 +145,8 @@ 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 @@ -393,16 +395,16 @@ class ReaderActivity : BaseRxActivity() { private fun setRotation(rotation: Int) { when (rotation) { - // Rotation free + // Rotation free 1 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - // Lock in current rotation + // Lock in current rotation 2 -> { val currentOrientation = resources.configuration.orientation setRotation(if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) 3 else 4) } - // Lock in portrait + // Lock in portrait 3 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - // Lock in landscape + // Lock in landscape 4 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE } } 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 69cd6dff15..448e1fc0c5 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,15 +1,23 @@ package eu.kanade.tachiyomi.ui.reader import android.os.Bundle +import android.os.Environment +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.ChapterCache +import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaSync import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.data.download.ImageNotifier import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager import eu.kanade.tachiyomi.data.mangasync.UpdateMangaSyncService +import eu.kanade.tachiyomi.data.network.GET +import eu.kanade.tachiyomi.data.network.NetworkHelper +import eu.kanade.tachiyomi.data.network.ProgressListener +import eu.kanade.tachiyomi.data.network.newCallWithProgress import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.source.SourceManager import eu.kanade.tachiyomi.data.source.model.Page @@ -17,6 +25,8 @@ import eu.kanade.tachiyomi.data.source.online.OnlineSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.RetryWithDelay import eu.kanade.tachiyomi.util.SharedData +import eu.kanade.tachiyomi.util.saveTo +import eu.kanade.tachiyomi.util.toast import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -24,6 +34,8 @@ import rx.schedulers.Schedulers import timber.log.Timber import uy.kohesive.injekt.injectLazy import java.io.File +import java.io.IOException +import java.io.InputStream import java.util.* /** @@ -31,6 +43,11 @@ import java.util.* */ class ReaderPresenter : BasePresenter() { + /** + * Network helper + */ + private val network: NetworkHelper by injectLazy() + /** * Preferences. */ @@ -61,6 +78,11 @@ class ReaderPresenter : BasePresenter() { */ val chapterCache: ChapterCache by injectLazy() + /** + * Cover cache. + */ + val coverCache: CoverCache by injectLazy() + /** * Manga being read. */ @@ -88,6 +110,20 @@ class ReaderPresenter : BasePresenter() { */ private val source by lazy { sourceManager.get(manga.source)!! } + /** + * + */ + val imageNotifier by lazy { ImageNotifier(context) } + + /** + * Directory of pictures + */ + private val pictureDirectory: String by lazy { + Environment.getExternalStorageDirectory().absolutePath + File.separator + + Environment.DIRECTORY_PICTURES + File.separator + + context.getString(R.string.app_name) + File.separator + } + /** * Chapter list for the active manga. It's retrieved lazily and should be accessed for the first * time in a background thread to avoid blocking the UI. @@ -365,7 +401,9 @@ class ReaderPresenter : BasePresenter() { val removeAfterReadSlots = prefs.removeAfterReadSlots() when (removeAfterReadSlots) { // Setting disabled - -1 -> { /**Empty function**/ } + -1 -> { + /**Empty function**/ + } // Remove current read chapter 0 -> deleteChapter(chapter, manga) // Remove previous chapter specified by user in settings. @@ -384,8 +422,8 @@ class ReaderPresenter : BasePresenter() { Timber.e(error) } } - .subscribeOn(Schedulers.io()) - .subscribe() + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -508,4 +546,87 @@ class ReaderPresenter : BasePresenter() { db.insertManga(manga).executeAsBlocking() } + /** + * Update cover with page file. + */ + internal fun setCover() { + chapter.pages?.get(chapter.last_page_read)?.let { + // Update cover to selected file, show error if something went wrong + try { + if (editCoverWithStream(File(it.imagePath).inputStream(), manga)) { + context.toast(R.string.cover_updated) + } else { + throw Exception("Stream copy failed") + } + } catch(e: Exception) { + context.toast(R.string.notification_manga_update_failed) + Timber.e(e.message) + } + } + } + + /** + * Called to copy image to cache + * @param inputStream the new cover. + * @param manga the manga edited. + * @return true if the cover is updated, false otherwise + */ + @Throws(IOException::class) + private fun editCoverWithStream(inputStream: InputStream, manga: Manga): Boolean { + if (manga.thumbnail_url != null && manga.favorite) { + coverCache.copyToCache(manga.thumbnail_url!!, inputStream) + return true + } + return false + } + + /** + * Save page to local storage + * @throws IOException + */ + @Throws(IOException::class) + internal fun savePage() { + chapter.pages?.get(chapter.last_page_read)?.let { page -> + // File where the image will be saved + val destFile = File(pictureDirectory, manga.title + " - " + chapter.name + + " - " + downloadManager.getImageFilename(page)) + + if (destFile.exists()) { + imageNotifier.onComplete(destFile) + } else { + // Progress of the download + var savedProgress = 0 + + val progressListener = object : ProgressListener { + override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { + val progress = (100 * bytesRead / contentLength).toInt() + if (progress > savedProgress) { + savedProgress = progress + imageNotifier.onProgressChange(progress) + } + } + } + + // Download and save the image. + Observable.fromCallable { -> + network.client.newCallWithProgress(GET(page.imageUrl!!), progressListener).execute() + }.map { + response -> + if (response.isSuccessful) { + response.body().source().saveTo(destFile) + imageNotifier.onComplete(destFile) + } else { + response.close() + throw Exception("Unsuccessful response") + } + } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .subscribe({}, { error -> + Timber.e(error.message) + imageNotifier.onError(error.message) + }) + } + } + } } diff --git a/app/src/main/res/drawable/ic_insert_photo_black_24dp.xml b/app/src/main/res/drawable/ic_insert_photo_black_24dp.xml new file mode 100644 index 0000000000..7c62bb3073 --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_photo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 91b4af0914..642b4c9028 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -223,7 +223,6 @@ Status Source Genres - Share… Check out %1$s! at %2$s Circular icon Rounded icon @@ -267,10 +266,18 @@ Status Chapters + + Custom filter + Download page + Set as cover + Cover updated This will remove the read date of this chapter. Are you sure? Reset all chapters for this manga + + Picture saved + Saving picture Custom filter From 2a4527a8d6b941af481cf142b51757992c6822e8 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Sat, 1 Oct 2016 16:32:52 +0200 Subject: [PATCH 02/11] Removed network call now copies from page image --- .../tachiyomi/ui/reader/ReaderPresenter.kt | 44 ++++++------------- 1 file changed, 13 insertions(+), 31 deletions(-) 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 448e1fc0c5..2c1a2952d7 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 @@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.util.RetryWithDelay import eu.kanade.tachiyomi.util.SharedData import eu.kanade.tachiyomi.util.saveTo import eu.kanade.tachiyomi.util.toast +import okio.BufferedSource import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -34,6 +35,7 @@ import rx.schedulers.Schedulers import timber.log.Timber import uy.kohesive.injekt.injectLazy import java.io.File +import java.io.FileInputStream import java.io.IOException import java.io.InputStream import java.util.* @@ -587,6 +589,8 @@ class ReaderPresenter : BasePresenter() { @Throws(IOException::class) internal fun savePage() { chapter.pages?.get(chapter.last_page_read)?.let { page -> + val inputFile = File(page.imagePath) + // File where the image will be saved val destFile = File(pictureDirectory, manga.title + " - " + chapter.name + " - " + downloadManager.getImageFilename(page)) @@ -594,38 +598,16 @@ class ReaderPresenter : BasePresenter() { if (destFile.exists()) { imageNotifier.onComplete(destFile) } else { - // Progress of the download - var savedProgress = 0 - - val progressListener = object : ProgressListener { - override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { - val progress = (100 * bytesRead / contentLength).toInt() - if (progress > savedProgress) { - savedProgress = progress - imageNotifier.onProgressChange(progress) - } - } + if (inputFile.exists()) { + Observable.fromCallable { inputFile.copyTo(destFile) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .subscribe( + { imageNotifier.onComplete(it) }, { error -> + Timber.e(error.message) + imageNotifier.onError(error.message) + }) } - - // Download and save the image. - Observable.fromCallable { -> - network.client.newCallWithProgress(GET(page.imageUrl!!), progressListener).execute() - }.map { - response -> - if (response.isSuccessful) { - response.body().source().saveTo(destFile) - imageNotifier.onComplete(destFile) - } else { - response.close() - throw Exception("Unsuccessful response") - } - } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe({}, { error -> - Timber.e(error.message) - imageNotifier.onError(error.message) - }) } } } From 1210691fddcf71102fb1a45a0cb4d72c89492bc6 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Sat, 1 Oct 2016 16:43:52 +0200 Subject: [PATCH 03/11] Format fix + notification feedback --- .../tachiyomi/ui/reader/ReaderPresenter.kt | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) 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 2c1a2952d7..6451a36847 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 @@ -14,10 +14,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.ImageNotifier import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager import eu.kanade.tachiyomi.data.mangasync.UpdateMangaSyncService -import eu.kanade.tachiyomi.data.network.GET import eu.kanade.tachiyomi.data.network.NetworkHelper -import eu.kanade.tachiyomi.data.network.ProgressListener -import eu.kanade.tachiyomi.data.network.newCallWithProgress import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.source.SourceManager import eu.kanade.tachiyomi.data.source.model.Page @@ -25,9 +22,7 @@ import eu.kanade.tachiyomi.data.source.online.OnlineSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.RetryWithDelay import eu.kanade.tachiyomi.util.SharedData -import eu.kanade.tachiyomi.util.saveTo import eu.kanade.tachiyomi.util.toast -import okio.BufferedSource import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -35,7 +30,6 @@ import rx.schedulers.Schedulers import timber.log.Timber import uy.kohesive.injekt.injectLazy import java.io.File -import java.io.FileInputStream import java.io.IOException import java.io.InputStream import java.util.* @@ -589,24 +583,31 @@ class ReaderPresenter : BasePresenter() { @Throws(IOException::class) internal fun savePage() { chapter.pages?.get(chapter.last_page_read)?.let { page -> + // Location of image file. val inputFile = File(page.imagePath) - // File where the image will be saved + // File where the image will be saved. val destFile = File(pictureDirectory, manga.title + " - " + chapter.name + " - " + downloadManager.getImageFilename(page)) + //Remove the notification if already exist (user feedback) + imageNotifier.onClear() + + //Check if file doesn't already exist if (destFile.exists()) { imageNotifier.onComplete(destFile) } else { if (inputFile.exists()) { + // Copy file Observable.fromCallable { inputFile.copyTo(destFile) } .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe( - { imageNotifier.onComplete(it) }, { error -> - Timber.e(error.message) - imageNotifier.onError(error.message) - }) + { imageNotifier.onComplete(it) }, + { error -> + Timber.e(error.message) + imageNotifier.onError(error.message) + }) } } } 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 04/11] 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 From 414b8c9f21d2b6700a3194e7646dca4ec0bafcfe Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Tue, 11 Oct 2016 17:04:47 +0200 Subject: [PATCH 05/11] Now uses glide for notification --- .../data/download/DownloadManager.kt | 12 ------ .../tachiyomi/data/download/ImageNotifier.kt | 28 +++++++++++-- .../data/preference/PreferenceKeys.kt | 4 -- .../data/preference/PreferencesHelper.kt | 4 -- .../tachiyomi/ui/reader/ReaderPresenter.kt | 6 --- .../kanade/tachiyomi/util/FileExtensions.kt | 40 ------------------- app/src/main/res/values/arrays.xml | 4 +- app/src/main/res/values/strings.xml | 3 +- app/src/main/res/xml/pref_downloads.xml | 15 ------- build.gradle | 2 +- 10 files changed, 29 insertions(+), 89 deletions(-) delete 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 5e85b17bf6..d41450035e 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,8 +47,6 @@ 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() @@ -68,12 +66,6 @@ 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() @@ -115,10 +107,6 @@ class DownloadManager( threadsSubscription?.unsubscribe() } - if (notificationSubscription != null) { - notificationSubscription?.unsubscribe() - } - } // Create a download object for every chapter and add them to the downloads queue 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 990c5a1874..1f413c5cbb 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,10 +1,13 @@ package eu.kanade.tachiyomi.data.download import android.content.Context +import android.graphics.Bitmap import android.support.v4.app.NotificationCompat +import com.bumptech.glide.Glide +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget 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 @@ -61,8 +64,27 @@ class ImageNotifier(private val context: Context) { } setContentTitle(context.getString(R.string.picture_saved)) setSmallIcon(R.drawable.ic_insert_photo_black_24dp) - setLargeIcon(file.decodeSampledBitmap(100, 100)) - setStyle(NotificationCompat.BigPictureStyle().bigPicture(file.decodeSampledBitmap(1024, 1024))) + Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(100, 100) { + /** + * The method that will be called when the resource load has finished. + * @param resource the loaded resource. + */ + override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { + setLargeIcon(resource) + context.notificationManager.notify(notificationId, notificationBuilder.build()) + } + }) + Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(512, 384) { + /** + * The method that will be called when the resource load has finished. + * @param resource the loaded resource. + */ + override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { + setStyle(NotificationCompat.BigPictureStyle().bigPicture(resource)) + context.notificationManager.notify(notificationId, notificationBuilder.build()) + } + }) + setAutoCancel(true) // Clear old actions if they exist 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 fe9c092efa..46b07458fe 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,10 +72,6 @@ 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 6e4ade899d..c18c1cd0a0 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,10 +122,6 @@ 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/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index bd440bb5f3..073888a9c5 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 @@ -610,10 +610,7 @@ class ReaderPresenter : BasePresenter() { //Check if file doesn't already exist if (destFile.exists()) { - if (prefs.showSavePageNotification()) imageNotifier.onComplete(destFile) - else - context.toast(context.getString(R.string.page_downloaded, destFile.path)) } else { if (inputFile.exists()) { // Copy file @@ -624,10 +621,7 @@ class ReaderPresenter : BasePresenter() { { imageNotifier.onComplete(it) }, { error -> Timber.e(error.message) - if (prefs.showSavePageNotification()) imageNotifier.onError(error.message) - else - context.toast(error.message) }) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt deleted file mode 100644 index 44ba46f1e1..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt +++ /dev/null @@ -1,40 +0,0 @@ -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 52405f3a4b..b491208c3e 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -176,8 +176,8 @@ @string/set_as_cover - @string/share_image - @string/save_image + @string/action_share + @string/action_save diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 169672072e..52d5ac8d3d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,6 +59,7 @@ Sort Install Share + Save Deleting… @@ -282,8 +283,6 @@ Custom filter Set as cover - Share image - Save image Cover updated Page copied to %1$s Downloading… diff --git a/app/src/main/res/xml/pref_downloads.xml b/app/src/main/res/xml/pref_downloads.xml index d21305ac80..8eff6f5bac 100644 --- a/app/src/main/res/xml/pref_downloads.xml +++ b/app/src/main/res/xml/pref_downloads.xml @@ -40,21 +40,6 @@ android:summary="%s" android:title="@string/pref_remove_after_read" /> - - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5995e49e83..319ddb2e7d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,4 +18,4 @@ allprojects { jcenter() maven { url "https://jitpack.io" } } -} \ No newline at end of file +} From 8ff8ab4f27f49b5bdd0310906788a8a65752b691 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Thu, 13 Oct 2016 15:16:10 +0200 Subject: [PATCH 06/11] Fixed webtoon page --- .../tachiyomi/data/download/ImageNotifier.kt | 4 +- .../tachiyomi/ui/reader/ReaderActivity.kt | 8 +-- .../tachiyomi/ui/reader/ReaderPresenter.kt | 58 +++++++++---------- .../ui/reader/viewer/pager/PagerReader.kt | 2 +- .../ui/reader/viewer/webtoon/WebtoonReader.kt | 6 +- 5 files changed, 37 insertions(+), 41 deletions(-) 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 1f413c5cbb..f2da096aae 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 @@ -64,7 +64,7 @@ class ImageNotifier(private val context: Context) { } setContentTitle(context.getString(R.string.picture_saved)) setSmallIcon(R.drawable.ic_insert_photo_black_24dp) - Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(100, 100) { + Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(96, 96) { /** * The method that will be called when the resource load has finished. * @param resource the loaded resource. @@ -74,7 +74,7 @@ class ImageNotifier(private val context: Context) { context.notificationManager.notify(notificationId, notificationBuilder.build()) } }) - Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(512, 384) { + Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(720, 1280) { /** * The method that will be called when the resource load has finished. * @param resource the loaded resource. 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 69c4ab3d8b..ef1a8820b4 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 @@ -228,16 +228,16 @@ class ReaderActivity : BaseRxActivity() { // Ignore } - fun onLongPress() { + fun onLongPress(page: Page) { 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() + 0 -> presenter.setCover(page) + 1 -> presenter.shareImage(page) + 2 -> presenter.savePage(page) } }.show() 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 073888a9c5..fde3321b21 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 @@ -547,11 +547,10 @@ class ReaderPresenter : BasePresenter() { /** * Update cover with page file. */ - internal fun setCover() { - chapter.pages?.get(chapter.last_page_read)?.let { + internal fun setCover(page: Page) { // Update cover to selected file, show error if something went wrong try { - if (editCoverWithStream(File(it.imagePath).inputStream(), manga)) { + if (editCoverWithStream(File(page.imagePath).inputStream(), manga)) { context.toast(R.string.cover_updated) } else { throw Exception("Stream copy failed") @@ -560,7 +559,6 @@ class ReaderPresenter : BasePresenter() { context.toast(R.string.notification_manga_update_failed) Timber.e(e.message) } - } } /** @@ -578,8 +576,7 @@ class ReaderPresenter : BasePresenter() { return false } - fun shareImage() { - chapter.pages?.get(chapter.last_page_read)?.let { page -> + fun shareImage(page: Page) { val shareIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_STREAM, Uri.parse(page.imagePath)) @@ -588,7 +585,6 @@ class ReaderPresenter : BasePresenter() { } 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 }) - } } /** @@ -596,34 +592,32 @@ class ReaderPresenter : BasePresenter() { * @throws IOException */ @Throws(IOException::class) - internal fun savePage() { - chapter.pages?.get(chapter.last_page_read)?.let { page -> - // Location of image file. - val inputFile = File(page.imagePath) + internal fun savePage(page: Page) { + // Location of image file. + val inputFile = File(page.imagePath) - // File where the image will be saved. - val destFile = File(pictureDirectory, manga.title + " - " + chapter.name + - " - " + downloadManager.getImageFilename(page)) + // File where the image will be saved. + val destFile = File(pictureDirectory, manga.title + " - " + chapter.name + + " - " + downloadManager.getImageFilename(page)) - //Remove the notification if already exist (user feedback) - imageNotifier.onClear() + //Remove the notification if already exist (user feedback) + imageNotifier.onClear() - //Check if file doesn't already exist - if (destFile.exists()) { - imageNotifier.onComplete(destFile) - } else { - if (inputFile.exists()) { - // Copy file - Observable.fromCallable { inputFile.copyTo(destFile) } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - { imageNotifier.onComplete(it) }, - { error -> - Timber.e(error.message) - imageNotifier.onError(error.message) - }) - } + //Check if file doesn't already exist + if (destFile.exists()) { + imageNotifier.onComplete(destFile) + } else { + if (inputFile.exists()) { + // Copy file + Observable.fromCallable { inputFile.copyTo(destFile) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .subscribe( + { imageNotifier.onComplete(it) }, + { error -> + Timber.e(error.message) + imageNotifier.onError(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 4220ece003..b7d56bbeca 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 @@ -188,7 +188,7 @@ abstract class PagerReader : BaseReader() { override fun onLongPress(e: MotionEvent?) { super.onLongPress(e) - readerActivity.onLongPress() + readerActivity.onLongPress(adapter.pages!![pager.currentItem]) } }) } 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 3041b17914..8dd7bf8d96 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 @@ -141,9 +141,11 @@ class WebtoonReader : BaseReader() { return true } - override fun onLongPress(e: MotionEvent?) { + override fun onLongPress(e: MotionEvent) { super.onLongPress(e) - readerActivity.onLongPress() + val a = recycler.findChildViewUnder(e.rawX, e.rawY) + val i = recycler.getChildAdapterPosition(a) + readerActivity.onLongPress(adapter.getItem(i)) } }) } From c2b113ac0a56a72628a9402f772e72c5265ae81e Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Thu, 13 Oct 2016 17:54:07 +0200 Subject: [PATCH 07/11] Fixes + API 16 support --- app/src/main/AndroidManifest.xml | 2 +- .../data/download/DownloadNotifier.kt | 46 +++--- .../tachiyomi/data/download/ImageNotifier.kt | 132 ------------------ .../tachiyomi/ui/reader/ReaderActivity.kt | 36 +++-- .../tachiyomi/ui/reader/ReaderPresenter.kt | 99 ++++--------- .../ImageNotificationReceiver.kt | 43 ++++-- .../ui/reader/notification/ImageNotifier.kt | 93 ++++++++++++ .../ui/reader/viewer/pager/PagerReader.kt | 10 +- .../ui/reader/viewer/webtoon/WebtoonReader.kt | 18 ++- .../res/drawable-hdpi/ic_delete_grey_24dp.png | Bin 0 -> 485 bytes .../ic_insert_photo_white_24dp.png | Bin 0 -> 247 bytes .../res/drawable-hdpi/ic_share_grey_24dp.png | Bin 0 -> 928 bytes .../res/drawable-mdpi/ic_delete_grey_24dp.png | Bin 0 -> 367 bytes .../ic_insert_photo_white_24dp.png | Bin 0 -> 185 bytes .../res/drawable-mdpi/ic_share_grey_24dp.png | Bin 0 -> 554 bytes .../drawable-xhdpi/ic_delete_grey_24dp.png | Bin 0 -> 594 bytes .../ic_insert_photo_white_24dp.png | Bin 0 -> 304 bytes .../res/drawable-xhdpi/ic_share_grey_24dp.png | Bin 0 -> 1222 bytes .../drawable-xxhdpi/ic_delete_grey_24dp.png | Bin 0 -> 695 bytes .../ic_insert_photo_white_24dp.png | Bin 0 -> 450 bytes .../drawable-xxhdpi/ic_share_grey_24dp.png | Bin 0 -> 1823 bytes .../drawable-xxxhdpi/ic_delete_grey_24dp.png | Bin 0 -> 1076 bytes .../ic_insert_photo_white_24dp.png | Bin 0 -> 570 bytes .../drawable-xxxhdpi/ic_share_grey_24dp.png | Bin 0 -> 2776 bytes .../drawable/ic_insert_photo_black_24dp.xml | 9 -- .../drawable/ic_insert_photo_white_24dp.png | Bin 0 -> 185 bytes app/src/main/res/values/keys.xml | 2 - app/src/main/res/values/strings.xml | 7 +- 28 files changed, 219 insertions(+), 278 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotifier.kt rename app/src/main/java/eu/kanade/tachiyomi/{data/download => ui/reader/notification}/ImageNotificationReceiver.kt (68%) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt create mode 100644 app/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_insert_photo_white_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_share_grey_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_delete_grey_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_insert_photo_white_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_share_grey_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_delete_grey_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_insert_photo_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_share_grey_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_delete_grey_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_insert_photo_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_share_grey_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_delete_grey_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_insert_photo_white_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_share_grey_24dp.png delete mode 100644 app/src/main/res/drawable/ic_insert_photo_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_insert_photo_white_24dp.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c9aaa32fd1..379f290acb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -88,7 +88,7 @@ - + (96, 96) { - /** - * The method that will be called when the resource load has finished. - * @param resource the loaded resource. - */ - override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { - setLargeIcon(resource) - context.notificationManager.notify(notificationId, notificationBuilder.build()) - } - }) - Glide.with(context).load(file).asBitmap().into(object : SimpleTarget(720, 1280) { - /** - * The method that will be called when the resource load has finished. - * @param resource the loaded resource. - */ - override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { - setStyle(NotificationCompat.BigPictureStyle().bigPicture(resource)) - context.notificationManager.notify(notificationId, notificationBuilder.build()) - } - }) - - setAutoCancel(true) - - // Clear old actions if they exist - if (!mActions.isEmpty()) - mActions.clear() - - setContentIntent(ImageNotificationReceiver.showImageIntent(context, file.absolutePath)) - // Share action - addAction(R.drawable.ic_share_white_24dp, - context.getString(R.string.action_share), - ImageNotificationReceiver.shareImageIntent(context, file.absolutePath, notificationId)) - // Delete action - addAction(R.drawable.ic_delete_white_24dp, - context.getString(R.string.action_delete), - ImageNotificationReceiver.deleteImageIntent(context, file.absolutePath, notificationId)) - } - // Displays the progress bar on notification - context.notificationManager.notify(notificationId, notificationBuilder.build()) - } - - /** - * Clears the notification message - */ - internal fun onClear() { - context.notificationManager.cancel(notificationId) - } - - - /** - * Called on error while downloading image - * @param error string containing error information - */ - internal fun onError(error: String?) { - // Create notification - with(notificationBuilder) { - setContentTitle(context.getString(R.string.download_notifier_title_error)) - setContentText(error ?: context.getString(R.string.download_notifier_unkown_error)) - setSmallIcon(android.R.drawable.ic_menu_report_image) - setProgress(0, 0, false) - } - context.notificationManager.notify(notificationId, notificationBuilder.build()) - isDownloading = false - } - -} 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 ef1a8820b4..fe3104f701 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 @@ -5,6 +5,7 @@ import android.content.Intent import android.content.pm.ActivityInfo import android.content.res.Configuration import android.graphics.Color +import android.net.Uri import android.os.Build import android.os.Build.VERSION_CODES.KITKAT import android.os.Bundle @@ -229,19 +230,17 @@ class ReaderActivity : BaseRxActivity() { } fun onLongPress(page: Page) { - MaterialDialog.Builder(this).apply { - title = "Choose" - items(R.array.reader_image_options) + MaterialDialog.Builder(this) + .title(getString(R.string.options)) + .items(R.array.reader_image_options) .itemsIds(R.array.reader_image_options_values) - itemsCallback { materialDialog, view, i, charSequence -> + .itemsCallback { materialDialog, view, i, charSequence -> when (i) { 0 -> presenter.setCover(page) - 1 -> presenter.shareImage(page) + 1 -> shareImage(page) 2 -> presenter.savePage(page) } - }.show() - } } /** @@ -409,16 +408,16 @@ class ReaderActivity : BaseRxActivity() { private fun setRotation(rotation: Int) { when (rotation) { - // Rotation free + // Rotation free 1 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - // Lock in current rotation + // Lock in current rotation 2 -> { val currentOrientation = resources.configuration.orientation setRotation(if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) 3 else 4) } - // Lock in portrait + // Lock in portrait 3 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - // Lock in landscape + // Lock in landscape 4 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE } } @@ -471,6 +470,21 @@ class ReaderActivity : BaseRxActivity() { } } + /** + * Start a share intent that lets user share image + * + * @param page page object containing image information. + */ + fun shareImage(page: 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" + } + startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.action_share))) + } + /** * Sets the brightness of the screen. Range is [-75, 100]. * From -75 to -1 a semi-transparent black view is shown at the top with the minimum brightness. 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 fde3321b21..aef86551d4 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,7 +1,5 @@ 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 @@ -13,15 +11,14 @@ import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaSync import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.download.ImageNotifier import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager import eu.kanade.tachiyomi.data.mangasync.UpdateMangaSyncService -import eu.kanade.tachiyomi.data.network.NetworkHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.source.SourceManager import eu.kanade.tachiyomi.data.source.model.Page import eu.kanade.tachiyomi.data.source.online.OnlineSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter +import eu.kanade.tachiyomi.ui.reader.notification.ImageNotifier import eu.kanade.tachiyomi.util.RetryWithDelay import eu.kanade.tachiyomi.util.SharedData import eu.kanade.tachiyomi.util.toast @@ -33,19 +30,12 @@ import timber.log.Timber import uy.kohesive.injekt.injectLazy import java.io.File import java.io.IOException -import java.io.InputStream import java.util.* /** * Presenter of [ReaderActivity]. */ class ReaderPresenter : BasePresenter() { - - /** - * Network helper - */ - private val network: NetworkHelper by injectLazy() - /** * Preferences. */ @@ -108,11 +98,6 @@ class ReaderPresenter : BasePresenter() { */ private val source by lazy { sourceManager.get(manga.source)!! } - /** - * - */ - val imageNotifier by lazy { ImageNotifier(context) } - /** * Directory of pictures */ @@ -398,13 +383,13 @@ class ReaderPresenter : BasePresenter() { if (chapter.read) { val removeAfterReadSlots = prefs.removeAfterReadSlots() when (removeAfterReadSlots) { - // Setting disabled + // Setting disabled -1 -> { /**Empty function**/ } - // Remove current read chapter + // Remove current read chapter 0 -> deleteChapter(chapter, manga) - // Remove previous chapter specified by user in settings. + // Remove previous chapter specified by user in settings. else -> getAdjacentChaptersStrategy(chapter, removeAfterReadSlots) .first?.let { deleteChapter(it, manga) } } @@ -548,43 +533,21 @@ class ReaderPresenter : BasePresenter() { * Update cover with page file. */ internal fun setCover(page: Page) { - // Update cover to selected file, show error if something went wrong - try { - if (editCoverWithStream(File(page.imagePath).inputStream(), manga)) { + try { + if (manga.favorite) { + if (manga.thumbnail_url != null) { + coverCache.copyToCache(manga.thumbnail_url!!, File(page.imagePath).inputStream()) context.toast(R.string.cover_updated) } else { - throw Exception("Stream copy failed") + throw Exception("Image url not found") } - } catch(e: Exception) { - context.toast(R.string.notification_manga_update_failed) - Timber.e(e.message) + } else { + context.toast(R.string.notification_first_add_to_library) } - } - - /** - * Called to copy image to cache - * @param inputStream the new cover. - * @param manga the manga edited. - * @return true if the cover is updated, false otherwise - */ - @Throws(IOException::class) - private fun editCoverWithStream(inputStream: InputStream, manga: Manga): Boolean { - if (manga.thumbnail_url != null && manga.favorite) { - coverCache.copyToCache(manga.thumbnail_url!!, inputStream) - return true + } catch (error: Exception) { + context.toast(R.string.notification_cover_update_failed) + Timber.e(error) } - return false - } - - fun shareImage(page: 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 }) } /** @@ -593,6 +556,9 @@ class ReaderPresenter : BasePresenter() { */ @Throws(IOException::class) internal fun savePage(page: Page) { + // Used to show image notification + val imageNotifier = ImageNotifier(context) + // Location of image file. val inputFile = File(page.imagePath) @@ -602,23 +568,20 @@ class ReaderPresenter : BasePresenter() { //Remove the notification if already exist (user feedback) imageNotifier.onClear() - - //Check if file doesn't already exist - if (destFile.exists()) { - imageNotifier.onComplete(destFile) - } else { - if (inputFile.exists()) { - // Copy file - Observable.fromCallable { inputFile.copyTo(destFile) } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - { imageNotifier.onComplete(it) }, - { error -> - Timber.e(error.message) - imageNotifier.onError(error.message) - }) - } + if (inputFile.exists()) { + // Copy file + Observable.fromCallable { inputFile.copyTo(destFile, true) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + // Show notification + imageNotifier.onComplete(it) + }, + { error -> + Timber.e(error) + imageNotifier.onError(error.message) + }) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt similarity index 68% rename from app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotificationReceiver.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt index 13a2ff754e..fc1348ce5f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/ImageNotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.data.download +package eu.kanade.tachiyomi.ui.reader.notification import android.app.PendingIntent import android.content.BroadcastReceiver @@ -9,6 +9,10 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.notificationManager import java.io.File +/** + * The BroadcastReceiver of [ImageNotifier] + * Intent calls should be made from this class. + */ class ImageNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { @@ -25,23 +29,36 @@ class ImageNotificationReceiver : BroadcastReceiver() { } } - fun deleteImage(path: String) { + /** + * Called to delete image + * @param path path of file + */ + private fun deleteImage(path: String) { val file = File(path) if (file.exists()) file.delete() } - fun shareImage(context: Context, path: String) { + /** + * Called to start share intent to share image + * @param context context of application + * @param path path of file + */ + private fun shareImage(context: Context, path: String) { val shareIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_STREAM, Uri.parse(path)) - 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 }) } - fun showImage(context: Context, path: String) { + /** + * Called to show image in gallery application + * @param context context of application + * @param path path of file + */ + private fun showImage(context: Context, path: String) { val intent = Intent().apply { action = Intent.ACTION_VIEW flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK @@ -51,17 +68,17 @@ class ImageNotificationReceiver : BroadcastReceiver() { } companion object { - const val ACTION_SHARE_IMAGE = "eu.kanade.SHARE_IMAGE" + private const val ACTION_SHARE_IMAGE = "eu.kanade.SHARE_IMAGE" - const val ACTION_SHOW_IMAGE = "eu.kanade.SHOW_IMAGE" + private const val ACTION_SHOW_IMAGE = "eu.kanade.SHOW_IMAGE" - const val ACTION_DELETE_IMAGE = "eu.kanade.DELETE_IMAGE" + private const val ACTION_DELETE_IMAGE = "eu.kanade.DELETE_IMAGE" - const val EXTRA_FILE_LOCATION = "file_location" + private const val EXTRA_FILE_LOCATION = "file_location" - const val NOTIFICATION_ID = "notification_id" + private const val NOTIFICATION_ID = "notification_id" - fun shareImageIntent(context: Context, path: String, notificationId: Int): PendingIntent { + internal fun shareImageIntent(context: Context, path: String, notificationId: Int): PendingIntent { val intent = Intent(context, ImageNotificationReceiver::class.java).apply { action = ACTION_SHARE_IMAGE putExtra(EXTRA_FILE_LOCATION, path) @@ -70,7 +87,7 @@ class ImageNotificationReceiver : BroadcastReceiver() { return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } - fun showImageIntent(context: Context, path: String): PendingIntent { + internal fun showImageIntent(context: Context, path: String): PendingIntent { val intent = Intent(context, ImageNotificationReceiver::class.java).apply { action = ACTION_SHOW_IMAGE putExtra(EXTRA_FILE_LOCATION, path) @@ -78,7 +95,7 @@ class ImageNotificationReceiver : BroadcastReceiver() { return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } - fun deleteImageIntent(context: Context, path: String, notificationId: Int): PendingIntent { + internal fun deleteImageIntent(context: Context, path: String, notificationId: Int): PendingIntent { val intent = Intent(context, ImageNotificationReceiver::class.java).apply { action = ACTION_DELETE_IMAGE putExtra(EXTRA_FILE_LOCATION, path) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt new file mode 100644 index 0000000000..241f5b72fb --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt @@ -0,0 +1,93 @@ +package eu.kanade.tachiyomi.ui.reader.notification + +import android.content.Context +import android.graphics.Bitmap +import android.support.v4.app.NotificationCompat +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget +import eu.kanade.tachiyomi.Constants +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.util.notificationManager +import java.io.File + +/** + * Class used to show BigPictureStyle notifications + */ +class ImageNotifier(private val context: Context) { + /** + * Notification builder. + */ + private val notificationBuilder = NotificationCompat.Builder(context) + + /** + * Id of the notification. + */ + private val notificationId: Int + get() = Constants.NOTIFICATION_DOWNLOAD_IMAGE_ID + + /** + * Called when image download/copy is complete + * @param file image file containing downloaded page image + */ + fun onComplete(file: File) { + with(notificationBuilder) { + Glide.with(context).load(file).asBitmap().diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true).into(object : SimpleTarget(720, 1280) { + /** + * The method that will be called when the resource load has finished. + * @param resource the loaded resource. + */ + override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { + setContentTitle(context.getString(R.string.picture_saved)) + setSmallIcon(R.drawable.ic_insert_photo_white_24dp) + setStyle(NotificationCompat.BigPictureStyle().bigPicture(resource)) + setLargeIcon(resource) + setAutoCancel(true) + // Clear old actions if they exist + if (!mActions.isEmpty()) + mActions.clear() + + setContentIntent(ImageNotificationReceiver.showImageIntent(context, file.absolutePath)) + // Share action + addAction(R.drawable.ic_share_grey_24dp, + context.getString(R.string.action_share), + ImageNotificationReceiver.shareImageIntent(context, file.absolutePath, notificationId)) + // Delete action + addAction(R.drawable.ic_delete_grey_24dp, + context.getString(R.string.action_delete), + ImageNotificationReceiver.deleteImageIntent(context, file.absolutePath, notificationId)) + updateNotification() + } + }) + } + } + + /** + * Clears the notification message + */ + fun onClear() { + context.notificationManager.cancel(notificationId) + } + + private fun updateNotification() { + // Displays the progress bar on notification + context.notificationManager.notify(notificationId, notificationBuilder.build()) + } + + + /** + * Called on error while downloading image + * @param error string containing error information + */ + fun onError(error: String?) { + // Create notification + with(notificationBuilder) { + setContentTitle(context.getString(R.string.download_notifier_title_error)) + setContentText(error ?: context.getString(R.string.unknown_error)) + setSmallIcon(android.R.drawable.ic_menu_report_image) + } + updateNotification() + } + +} 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 b7d56bbeca..18cf1501c3 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 @@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderChapter import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.LeftToRightReader import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader +import eu.kanade.tachiyomi.util.toast import rx.subscriptions.CompositeSubscription /** @@ -187,8 +188,13 @@ abstract class PagerReader : BaseReader() { } override fun onLongPress(e: MotionEvent?) { - super.onLongPress(e) - readerActivity.onLongPress(adapter.pages!![pager.currentItem]) + if (isAdded) { + val page = adapter.pages.getOrNull(pager.currentItem) + if (page != null) + readerActivity.onLongPress(page) + else + context.toast(getString(R.string.unknown_error)) + } } }) } 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 8dd7bf8d96..41fb2ac0a9 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 @@ -6,9 +6,11 @@ import android.view.* import android.view.GestureDetector.SimpleOnGestureListener import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.source.model.Page import eu.kanade.tachiyomi.ui.reader.ReaderChapter import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader +import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.widget.PreCachingLayoutManager import rx.subscriptions.CompositeSubscription @@ -142,17 +144,21 @@ class WebtoonReader : BaseReader() { } override fun onLongPress(e: MotionEvent) { - super.onLongPress(e) - val a = recycler.findChildViewUnder(e.rawX, e.rawY) - val i = recycler.getChildAdapterPosition(a) - readerActivity.onLongPress(adapter.getItem(i)) + if (isAdded) { + val child = recycler.findChildViewUnder(e.rawX, e.rawY) + val position = recycler.getChildAdapterPosition(child) + val page = adapter.pages?.getOrNull(position) + if (page != null) + readerActivity.onLongPress(page) + else + context.toast(getString(R.string.unknown_error)) + } } }) } /** * Called when a new chapter is set in [BaseReader]. - * * @param chapter the chapter set. * @param currentPage the initial page to display. */ @@ -167,7 +173,6 @@ class WebtoonReader : BaseReader() { /** * Called when a chapter is appended in [BaseReader]. - * * @param chapter the chapter appended. */ override fun onChapterAppended(chapter: ReaderChapter) { @@ -191,7 +196,6 @@ class WebtoonReader : BaseReader() { /** * Sets the active page. - * * @param pageNumber the index of the page from [pages]. */ override fun setActivePage(pageNumber: Int) { diff --git a/app/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..13d2741f36a92e9e62e14434f7de95e83052fe4c GIT binary patch literal 485 zcmVa`j!y#$vOWH!i&Y?wFmV9^ZA?yMIs1e z%-^vLqG?*lnb6g0H9xL@F`Z7iEJ)J(jYi`yKv}Jng3uh;wtb5bx=9&Jy!Ku$m*0Z# zhXBjv(xj9=qy=D%txBcRl>!!v#lUf#kRS<+5MoxV)yG)Ce!uTVyXnxiuIurD*=#m& zT{pFZLZM*R>vg#U0T3xVbjMMhNRbjC93<^~Pk*q3B!vxXl@2D8$$(Ot+5yJcY&M(n z8VEqvBL6=i>!2we937B#l4Bi=Mx)GKWEh6Liv%F+B*y~A<8jY%oPOF#CWQ1`t=6;j zYdRbbuPCJ(gwSbz;d}I400000NkvXXu0mjf8ExUl literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_insert_photo_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..25a9576ddd920f235d3f1391477aed6697c8ca03 GIT binary patch literal 247 zcmVgF&^r)t_CE()tu|&z;WnrSDjp5yz5TC% zQZOeHYtWYejBuHDpzAy_%J>Du7wMq5lZZi;q3MZWJp(%08_hKPsRIAlvN~xtJNu<^q5D}VZDdmqtLqpH>1gKOh zA1I}28^z5%=RCA+JGE`V+}vEh5MoLxmEB^c|8yMZK-U1RHCC(Dmk}`=hT-ujisTl6 zvg0_z9RrN;{QUe;MD&U1*(i!Ij^nFZYabDx1Aw;xU>^Ydf{3;C_4S30T~scY4>HD1 zYpvf^N@a*>6#zcBEUReS_I1zm*ucQRegij{z{gqCq-$BHD7=};9aco@jH2{?A_4;?7=f&+RtpO;P%da5fCq(p^@v^ZS=X@Oz zZzV}`P$^}Eu9$R;jg1*V$D;x8eSawkg4fJ-tK}GDrg*L+Vv&eGb6t0>W92(9HUPz9 z@ir0d-OSGbFf=|sUg=i&o;8@Bp1utLdp8piLX6~cxl&Jnsi~<;jIlR1iy)Os{UL-X zMNzb1+qQ8}SEG@lLZR>y0DKAnkGFjN9{{W%;vp$zEQI(Wj^onE$jHTR2=~~uzrX(& z5k0{eyQ#Il5(L4GR4R1>06wxT>#z{QbjokzIQCapS1)&L({?kOoSfXx82bFIxED1iVA_I|@rjaL$)p*L}Swz~bT}UtV4=AfgQbyu~QDIOp%Xu6v;;K+~Q{lAH#B6GW6@ zjQvbRALsM=OWSf$J3DWD-g5-)fV+Tp8QS?@sQ&>BqNFzW>>X180000X1^@s6IQ*`u0003tNkl5>et@nDRh@6fsL;Pw&v3SBZKk!)YF zAZbhtIS5^HgCtJ6kJEoAAzWy9VLV(5pe)O9uZ2?T0RUczNFC|Zv~9cUy6$7|i=wFR z*G_|~s%XE_wk;TAPPCO$f)L{1pUq}2)(u&fy?LGoUDpA3)>=Ou18$|1kKB@4Yu~lj zKLf{uC5%D zQik*S{7-`(V2oh{lv4iy*zI=g41C`|&7cP`>hJnw6wvnpN5K9}U&eumX`0?OP4h)W zH;iUl3nA_oi^cb$6Nw0y%jGj7>NAiv0K6tivO+}ng0JOEVzj-6zmROnb2dbs~(^j5ic0>pDDE2 jzES4mqy6s}oc+sic8*Qfk2kwOj%4t3^>bP0l+XkKat%vT literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-mdpi/ic_share_grey_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e2814bdc98156d1ab0710b985e8a5c671727b109 GIT binary patch literal 554 zcmV+_0@eMAP)X1^@s6IQ*`u0005;NklDY-|L76rKb@Z4a^VFSy1w5wi)G1a?WW(PXoPJ2nuKkm4%A zzrgBh(c(}WJLL)m@kfFpMBLfgH?m?t5>zVAag;=v>ShyMvM9*-|D z#)be;0DwIrx>GC`U#9k8G#Wh*!|)Oj0b>jd!+23DmDW-Nf*=UvIOd25N-5AZEv#0n z=1Rb1GPy!T_viEZ`X3{IRIAl)Ed>NYkmsCx0I(s1cq6530>Bz$>?#pGky3VT+y49$ zFc=IjB4R-)wHHOvYtu9xrBqP}5ep$&*=%;FTrP(Pg${?q;U*DzM8p$ai1<}Xc`OXW z9YnlWuh%~wmR9Wd`%@vriNu&+21z11YuomInwVp+*ZZWDI{90%G)?oIWm&IM0es)T z3jkXHzyTo9`6ZXj9S491MAWQQDjyD&kUaXne;xoX1Hd!R`F<2dHC@-soO1;L-Pvq5 zc3t=TfhI1acRHQCrfDtC`E6a--w~0+7&`+1*BE0@r_$=}o2C3Wa77(#z7{<*w zj$skyOeXWtvaF4jfJKL%=OyDjwYclL{=U&@;fY0I*xNAHK5&YpJt40 s6VY|X*kdBvY&M&3Qv;Tn{SN?s0G-Ly8u8t$XaE2J07*qoM6N<$f})o5S^xk5 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-xhdpi/ic_delete_grey_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..4ca7f7c9ad1acae880b05e4d6d89514f5faf95fd GIT binary patch literal 594 zcmV-Y0BjE6vyA4q_agmb?MqUkSTLNMJd=>+Ovz)>(6jART#v_sc8Q2HGT{RoB5 z{Q#v~IG<$e!UY1ctwg8zL}HK^Vd=elzx&^Ne`F(g;tzV_`p^Qj3bYEe3K%IcnM_{v zdc98=;}fM+4Z=gqGo|#uiOH=2q-lCwmV_}rS}vC#q?9l3D}H;Q z5OU?Z?uAn7XW3do5M127zXp&bi7HDfiURUHH`&lljO)7KI8JGN7=~*#*SDM>AGzK`X>kw)zcvH5 z0H)LF008tDZOwU|v);@HfaB3oEZte<7s+_nOQ zkil>`Gy{-QT34Xc>C^+T-GuuGV7muuDX>^9toJ~-+cob24Pd(m_6H!2<9?p!)_uV9 zyaA=u%m* ztH)3&m6#(q@3lEra+D1^8~2pw2##6Q08_bH{nD*-s?E+OQsD2h{rkY@ox zIF55Jr99`HFDn6bz<4}<1pptFQtuH$uXlj>i!uI|W!V?b`Mt^fc4 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_insert_photo_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2642b9e09ec00be308649f62d9323f22ae2b6c6c GIT binary patch literal 304 zcmV-00nh%4P)0++mR7nD4pd~x$TQLGba6~{cu-M!3I>jYZG8L#~C$dSzGCa?>% zii{qBH_l~3H}Ow_R&mWIA6&_uY{DqeDkOK@%2_vI7ibl>$R-Q|t-=u5gh8NHSX1ob zZ91p^`0a>6o%RQ$Cqo6Qpk>-nPOXnuLHxL2AA)bf8YiVe5h%F;00003Y(x$KKLXu%PLH$Ocd8)D@kwubPpp!Nt#mH zCXEs1&`n=d)Qzz{%oi2Gfs@e(VVh{tIasz4>4Y}Py}x^o{9+<)?f)d~B|iv(o7{6g zzwf!f?>QIYE-$>x`JoBWRG_IqQ-OvkkWQyt48!P=QoaQMy8%EF(XT>?kLTy-v%z4n zP&L4Y0A#b-1I(OqUAL8pfSEx`sXue3X^t)|ETpRtbqC01vwNBOi(;|(;7T@cSr!?F zk?Qa759;3=0dTZXD7?E?kFhLkW?*1Im!|#z>2&&2*L7dfvLj+y{^j3NN;eP)SPcP~ znwmPPl6B6)R!Y6*x~|{zJpG^%GoMGqct=OagwO!k%UP1^kP4hMY+$5qW9LE7IHvs5l$8_>=IIJPIyvhnpPfs84JTK)qPU}jM zG)M(XXTPZBo}ZsT7mLOIC9PqV0aB^dOtDzpwT^lGjEJFyg@v!{k$A}|7#kbA0|49B zvCk8>Z6B;*vn$?OR$z2=^bR6!TPwJf@)O&(`x*j}OeQZ?28UJS8-{UNN*SG-n>*Wx z66`0U_Ym=c)ykmBd_EsbDK9Z|BA?Hnss~891o{{%r4A9%QAE6V8N^LyzJZ8ORwoB4VpnM2}deX`TmwM0FG7t_dMNVCMUXsE>%s?uv*d!!W)o6bj);ByxR;5p7hi zmHwweT3T9OWaeSrdUY<#vdY$7>6ZV^gr;d~rG7!gHwFg>zb}K;l6>*K$z-zI^SlTm z>UV;c)ofk&70a?R!C-Kpt^ie-cs!m2fbd!yGfneyC=}Y!5P9}|HGn>^xFfkMp%?$hv`WFN*y5Qnn z*ly{A13!kXnW-6zgBmz4=zcZz-m7{Gd#B)zKkAP64?=+3L2*DFASxguL==z=7YE1^ z5(|g}L;=Zgaeyo#u>jeDEXy8sI-QRIa9**OYw!Itt@WphxIeCw2;_PG_;@^iI2;b= z&N)y@f%m@j?|#339YxVAt@Zo5Bnk=Sd47Qv^xofd&TZ>9e@nL4>je@crPL4Xom%U! zf8Qx2u-olCRxF(F_xl^gsZY1ty>ShD27|#rmkLqa?UvpZ)=iD`;czGfYUtJ+q>=+w z(xhto)V)6%jmnKsbDFhZ319v8dmz05B~a!wfz$y4F3SGjAt-??%Y5CLZ30)6{gnu8 zHXF~m(Btv=q{yfP>-C!TLrn;X1H_0TkI-thVof13fiOaxDKwc(XeksNAWi`ZE(Dg# zCF>3};sECkOs7-Y4g?2CLreq<0datPgcgehYYH{81Dq)|o6Tq`6dWK<0SPVy(llk= zfkqtQ+<`cbX*&=cAPq4QECj>>?h%^L=d3Bz$PRF(P?99H6bcRyr+@?(0@hmA9caV> z&K)qu(00ID`x5}pNP}D-d})k1`7aFU*X!2W*8uRMeh(z%8)MANQx#AGX_`KC&V2!Z z`=nN?gRi0}dJ@O+HxhvWw$_dTApHC<5?4y8I7yOs7;n^p+XB|w2LSNgd;e4^b=J~i zUjo2q0C;PR`HnRo&Px+0Q;g$|5a3X~(w|wm8^qo(BZMi`_PIFFw!&C_aR5`O?Q?OU dZH2M=zW^S?_<8q8m|@f&vEk zXhJXy z)&q8Jdy{=h?m>-(r*@dK*d3epCi{|HgU+qz4*BYtIwp6bB0wo2#+nm8I>3B8iEGdk zTNzJQxB%cRn_*v)JJ1{dbN|paSFGhz>`QV3I>zMAKdKnfM6N&`Di|k|EDy3@h4PVK zk{o2e3gsieq-8-3jN^&)U)Wy&nw9O-LW-|?GEfU&#WGOH2p`=L$UkuoJ#eZRDaa7g sq|daVQ|=KHU?d>_qaXz-NI@l=ck_!~>**H-(*OVf07*qoM6N<$f*#evGXMYp literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_share_grey_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..9ed5b4d43206a8ca290e29b0bb645c76ee07ca26 GIT binary patch literal 1823 zcmV+)2jKXLP)39sV&C+;DUL02RiRsVFj=NwTKNYr9r`YGQsY z%V^W4n~L+tP*G43oeKW8>U1iI;ID~JWKMLyl$gA}yxb$Vv?Yy6*Y}e3Rmg)-NY1_Q z`#I;_^Ul4m2>=IZEb;B0WdT)v|wap1dFt~Ka%jm$sz;a2FB85WX zV#6?)jkFnk$N|98U@$m5V*q`9eP_wC`~VT%G%_-x2;pVo_jAs7Gscz^QFFD03jlu- z(e0|L?wqk!VsLOU4gjiQ7+{)arED4YcswiDuV0^y#bT#RlJqtJEUI8AJbq&+6#8RE znmLi@obz_WFcw$Jb42{CSS)s_s`?%xPV^A{{rydaLg75l`DuvQ$~pg&bN-92>)&gd zR?!1>E2Bh&>2!LrEXxm@rnzFgt1R=_&xkmf&1Ujsd?WS-@muQm(=tMoQQ zp-{+cRp8O=D*_A-4$k46cQD4TLBulv;3NPzf{4Fy&Ob5?C^T>#)s&UtS>pZ`+RG=4NeR)7Bwz~;@H=eynRS4`6!&EL|hAto2yprR-_ zA_^knTGKQy6N^+_CE__E{zyc~ubb5{bm+ zMD(6j0I|LEcsw5?VwczJ{m|<8TJ0y5(Re)m1QFeeqJU3v$W*@2#i5hSyu~uQz9X|;m5{aBF%d$9+Y_VF6guMU}4>-nHx7X{9&-jB(P;c6_X<@Ngd@rPrV{dQoKGDoIH#c_zz+FT%zf^#Th=_(P%R5ce?DqTpUmuHz)UBP4Mx#$7 z;w@rdP?~;Y=b3`-F`v(OmmM!pHKuL=LUH$+XfKoBhX!H&M5UF)`d0Gh&S(bMZQHRgx`=mUrG)2!LKh`gnHkg=l_)#vkVsswRN z0mKa>k;nyzC@R(s03er&5FpLX&HDl1HO83ehR>;V2q0h;Mfo(F&93b3?mj#zs`bdj z>C6#}#jYhH5s~xD_ZwoDCyrgFddV^N#Q)Va%_U+xJATh&9)WVWNF;JIV{AJSxvV}c z$12+94I4HD9Rm#uA!dy1xMIWgCaN1!w!kx1l0M7(!8 zDOhUL($ccQ@AvmP4vq}3z9bE(CUfi~An{x2r!6%7m zP1U9i@&4}a?uW{ozgYn=E;<|zUy6uV0>C9ibdop?C!!A-WAAL-xbYiDnmG%(ZOe34 zMZgY01Hg{g>N%znfqHt=&RmTM*zsCD$21~PPjA|ps}TV^UaRMre*qxDpLv_nR?Ywb N002ovPDHLkV1iT^WM%*W literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_delete_grey_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a1b86d06e88c02bc7f265596e330996c9ba6ff37 GIT binary patch literal 1076 zcmV-41k3x0P)g%)ddC79QcklDQcNbr5&N6=SjPIWj08&84 z2~Y}TTmV!ADFrA6GERU}Amaj{E-ae9aG^{?;74xroZ7NwLogCMARo>z(^V9T<83n9AO+uMt_ZU2hH z=bn#P0W2>sA0HkbR-2!9UH2U4oJlEJ9G|9XeiK4G=A5_63u zTN3T7)#_jhsMqWNMGZJi3cO0q4 zJ3Fc90%!_Q0CdY6vOXyQs|b<;vYZ0VW^=^%{Z!lw6bc2LF5tRuD!PCWV$`UNj_VAKGW z0+18XZ9@vcOo6n_1W{^0nr4D%0CeX!WPLRgL<6AXzrLtxhgJmBG!sNq07QbiZBSDn zsvLFLtC=8*0@5-OA_b5FklLV10o?@-vOa1JfCQl11_eO9UQf+aV#Q(+uM6ltUC8>R z01O4JuC88nUH3WXTh+4o;imt4zT=aea31e*cmAC|7n?i`O z+1c6mkQl)LmX?;zgkiWSrMv@itjmUT{?ssx`MJ5dPmmbE0Mz@yg+k$Wzu&Jh#!f?= zYq0s8%jFha*L~(VP9L&97=UtCtJO|QDep7J#u#JAAPXF!%}>TyM?KQNu(0qQx^5%@ ze<7TbQr?wP+MM$f2`Pwb^9|qk*B!_C0o}Z^iwr=0$#ERZG|jVyVU!tTm!*^!B2?)( z-zomUIe#05;d&4R9|w88ejor*2q)c^03`i{u;U{IU=vQde^NlwPY63cQUEsLr28iY uB>jZ2<0A!N6HdB+Qb5vA2s^&aE8q`BL3Ql%jz0bX0000Ea5IfQowI9-hvuwR$tP^fy(>8sSO2|8{wRtGpvc@#B$n~B~Rwm&yIIB)&jy;7gW zTKL?7mzK@v|L<(N|7b3=;GHmT*|XKxR_ zisKEuaTo73N#D@a7GnOhx@e+huI&M-u%#?A#q8EMMfY92V!WoXj#HDtTEZ^x>C~Zf8IWQby>8Ib0dT5wN0yQ*dG`x>m;y#Wc*hW`8x0OY*zD)2SPUjd28<` z%OxHB?A^isVY&9DKSD{2WgAXtCo%nb*|kec?7;kW6+k(LjH+Fa;+@JJK3|^tKI_OAXssMiVIA01S&2t%?+TE1u8C3 zae--$K*a^7xdBwNKqy^+h_JP_wR+a9SzkiLC5U(~0DO^%W&yx^MD!1>^^30S{&w!% zxqVBQE>+nqJ#+v(`|PuFU|`^UBD$G~uJnCBs+0n)^^lB+2vW+SA0fos0PwKmINKT; z8un)bA#?yd@W2CCBH}vF^G;JrNg^5&I@7-lf?*g3Ow-)zIL`W5EVg$%2%!R?r>Ey) zrPTB3boy8pB$x1`K`~7;ZJK8Lo;`bP+qToAK?n^1n>TMhg@}IXIL?B}WG>S*9Vz8^ z>+0%W4jlltZ5uT;HEYu8bOHdPg=&8MbCzXsOt`SFuI}In2%)e5*1qriTYcZZXfoO# zc}EBVkx1lwb#-;y!Un)%&+{G$f?$3z0Pwq(Wj()Q#fob~1wdzK=QRuf0L-4O`H#FO zgm^z5kDneY06IE4ZuEWs(PD+?_t^~^8X69}ekfuYj#+FN#`QrEEOA|TsOl@h`VasXB@&7LvIU^KyL*uk;-(-7u24$V`o52a zns=V(JVdNZBodrW4zIEag0^i(Yiep%5z#F{5X|;{-zfz^miRcXg`1Ro6;2XAWAIkQDBMv}USJy3wc!%%%Cj~(e$r0Th0C?IkjJvCySHDCX}|4nS8|*SSK7Yqi!lc%E0oex79oEI0r>X&A=#cs%}5 zF@hEPZe9Rv+ZHFDc;aaQaGnrizEWzwlyZ=WK2%D*d+^}F->+J=>f`Yr?Ck73$uNvt zl~Pv+L9oE{JR?VR-=($QB7}G@nM}T0=;2H8TuuNsZroUFS=Nu0QkN4^mDZa5%mM%< zgy6!$H4LLa2!gi#`}aS=!G`^E@7}#v3nA|IeScvP1Qs*4IfQ>rDV40Ms`^(UK3fW* z^VR_zWsg7p_-{!mA9P(eUzBE+#S=n2#y^~Il~Qc(hpFmuhi0GV;PinIBAG}eI7c6~ zHNgT{gMEE{-yx#bbUJ-1pR9mlgF#>}-U)(W2B)~zu9!JFI=gpho5+1bgp_&c1c3NiaU-It4q`-tcs$8nx2H^D~`8v{Ul zd;5K^>o$}?c&^=_;sz&M4L)g=mH5Rm0BqW{=?|{!o>zkY`(s4BDVa>ZP~!8Je7i9K zY}l~DC8DAFyhspqG#XuY`|Y=HDfx*@yx|xCT3T8-KSxUNjnD${IskmF1OR*-iA0vg z27vqTzyA#1_e;`@ z7>40TB9VOnuy)_ReOp731{uue=H^Ec@dr#Ul)w_WMAnf=@eCrKS%PdZluh_&#*7(zcyLKdxwWRI<}YPi3J=pv-v)p-09g1bRmIw! zk?kGRG{H2@_Ym;~*L5E*haxE>AHeOfWm#Vb0KSkse36&~44;TL1He{9Tmb+#W_y+? zF4Ht!(=>aPQY&Mz*h`-hyLnNG}ZVObX6)%_|6f`ky_pJhXcj6N_^Vv$JXR4FA7Bl4iq zDFDEf*iJ;`p~OFCqQus%TUTos#*c_-2>>vqW@G|_N7*dP`ZoYPuC?A4i^bk4sfzP# zmX{MO_Ao6iEng*~tBB}_h&U%xVCA6&!!QEFF#e8+FFKC%SW{Ee?qa`P$oo?c03U*B z@n|&4Ks57MYqspdZZSO0##V4|ZEfu@raD_35dcPOB9%%lL&Q6YXl}N?V|bd2=lZrg zjfoPOK3Ip$1QoV9v;d#g;-G?~N+g1}Fw)9#uzYnYG7d#7;30pP2#R4R3vlyVtg zjUgh(m5kjd$A@S%%Dmx2zVB~~$KxN22-V!&Jd3SL2yqr7o(%vTu%kkVKCSgmDdn5# zbozJsQtc53U_^y{IXXBvcrGH|KtxLcU}m;#!ERv~#@kx!CqMb*lb_C>J^NHdtS6#N zwALq&Fj%7|!I+>uAcXjvl=7+m{(dgSGg{D517Jj0+qU^`k2}!yM06GaWaJ{*Elkt= zpJ|#OYOS^Bd8aF-hHi$lt>NIxo$1C%B+{Jee(|USFmm`*Ds?O(-lny#L&W2VDC14i zNNJtpDt&@GMWfLHzNi@(7NpU`3p#Y$*t?m3E z2p-W|b5Bv!vMg&;V`F1HQ~eb9tm3JYONx+_-9<#r{pWWbw zNdoY$l=8CiQz@ab02Z1XC(|@v8NR;DNU>!Ahr6X+M0DF-cir{Mc#a@c0I+b(HS*{z z05EmWL~XwHKC?>;7A)AFiCqdE04!}wOUucg=UpX);2W&7vjje#N!rdt>%xT#|D26l z3nc&y0>^~iyLTUJnkKWV5*P}%f1y02#cns>YNn|m?~t$vTwx#!lJ3E eI_I>vfd2!>QSHB`6gf2j0000 - - diff --git a/app/src/main/res/drawable/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable/ic_insert_photo_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d474bd577d00d2aa045685f38b1729e4b2c314e2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+i22U5q5R22v2@-1_)Iaz?{r|_t z@c(}UO&^5wG3f`I3NX5v2Dl$y{{P_r{X*9Y*v@e=cBuVzj-6zmROnb2dbs~(^j5ic0>pDDE2 jzES4mqy6s}oc+sic8*Qfk2kwOj%4t3^>bP0l+XkKat%vT literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index 0fafb4123f..f3694dc7ad 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -48,8 +48,6 @@ 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 52d5ac8d3d..7815e3f951 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -267,11 +267,6 @@ Status Chapters - - Custom filter - Download page - Set as cover - Cover updated This will remove the read date of this chapter. Are you sure? Reset all chapters for this manga @@ -279,6 +274,7 @@ Picture saved Saving picture + Options Custom filter @@ -315,6 +311,7 @@ No new chapters found New chapters found for: Failed to update manga: + Failed to update cover Please add the manga to your library before doing this Sync canceled Not connected to AC power From 93f90b5a6276bebc84c861cce08045fd0808390e Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Tue, 25 Oct 2016 16:08:33 +0200 Subject: [PATCH 08/11] fixes --- .../data/download/DownloadManager.kt | 2 +- .../tachiyomi/ui/reader/ReaderPresenter.kt | 4 +- .../ui/reader/notification/ImageNotifier.kt | 63 +++++++++++-------- 3 files changed, 39 insertions(+), 30 deletions(-) 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 d41450035e..115e10bd63 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 @@ -188,7 +188,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/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index aef86551d4..1dd62da5f7 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 @@ -384,9 +384,7 @@ class ReaderPresenter : BasePresenter() { val removeAfterReadSlots = prefs.removeAfterReadSlots() when (removeAfterReadSlots) { // Setting disabled - -1 -> { - /**Empty function**/ - } + -1 -> { /**Empty function**/ } // Remove current read chapter 0 -> deleteChapter(chapter, manga) // Remove previous chapter specified by user in settings. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt index 241f5b72fb..a4edfcb52e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotifier.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.notification import android.content.Context import android.graphics.Bitmap +import android.media.Image import android.support.v4.app.NotificationCompat import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy @@ -32,34 +33,44 @@ class ImageNotifier(private val context: Context) { * @param file image file containing downloaded page image */ fun onComplete(file: File) { - with(notificationBuilder) { - Glide.with(context).load(file).asBitmap().diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true).into(object : SimpleTarget(720, 1280) { - /** - * The method that will be called when the resource load has finished. - * @param resource the loaded resource. - */ - override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { - setContentTitle(context.getString(R.string.picture_saved)) - setSmallIcon(R.drawable.ic_insert_photo_white_24dp) - setStyle(NotificationCompat.BigPictureStyle().bigPicture(resource)) - setLargeIcon(resource) - setAutoCancel(true) - // Clear old actions if they exist - if (!mActions.isEmpty()) - mActions.clear() - setContentIntent(ImageNotificationReceiver.showImageIntent(context, file.absolutePath)) - // Share action - addAction(R.drawable.ic_share_grey_24dp, - context.getString(R.string.action_share), - ImageNotificationReceiver.shareImageIntent(context, file.absolutePath, notificationId)) - // Delete action - addAction(R.drawable.ic_delete_grey_24dp, - context.getString(R.string.action_delete), - ImageNotificationReceiver.deleteImageIntent(context, file.absolutePath, notificationId)) - updateNotification() + Glide.with(context).load(file).asBitmap().diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true).into(object : SimpleTarget(720, 1280) { + /** + * The method that will be called when the resource load has finished. + * @param resource the loaded resource. + */ + override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { + if (resource!= null){ + showCompleteNotification(file, resource) + }else{ + onError(null) } - }) + } + }) + } + + private fun showCompleteNotification(file: File, image: Bitmap) { + with(notificationBuilder) { + setContentTitle(context.getString(R.string.picture_saved)) + setSmallIcon(R.drawable.ic_insert_photo_white_24dp) + setStyle(NotificationCompat.BigPictureStyle().bigPicture(image)) + setLargeIcon(image) + setAutoCancel(true) + // Clear old actions if they exist + if (!mActions.isEmpty()) + mActions.clear() + + setContentIntent(ImageNotificationReceiver.showImageIntent(context, file.absolutePath)) + // Share action + addAction(R.drawable.ic_share_grey_24dp, + context.getString(R.string.action_share), + ImageNotificationReceiver.shareImageIntent(context, file.absolutePath, notificationId)) + // Delete action + addAction(R.drawable.ic_delete_grey_24dp, + context.getString(R.string.action_delete), + ImageNotificationReceiver.deleteImageIntent(context, file.absolutePath, notificationId)) + updateNotification() + } } From 7d3d0999f3510dbf54a8a6f0f37c98058138c86a Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Tue, 25 Oct 2016 17:34:49 +0200 Subject: [PATCH 09/11] Fixed API 24 FileProvider error --- app/src/main/AndroidManifest.xml | 10 ++++++++++ .../reader/notification/ImageNotificationReceiver.kt | 6 ++++-- app/src/main/res/xml/provider_paths.xml | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/xml/provider_paths.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 379f290acb..b7d73c3e06 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -54,6 +54,16 @@ android:theme="@style/FilePickerTheme"> + + + + diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt index fc1348ce5f..2c2a83d4e3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/notification/ImageNotificationReceiver.kt @@ -5,6 +5,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.net.Uri +import android.support.v4.content.FileProvider import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.notificationManager import java.io.File @@ -61,8 +62,9 @@ class ImageNotificationReceiver : BroadcastReceiver() { private fun showImage(context: Context, path: String) { val intent = Intent().apply { action = Intent.ACTION_VIEW - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK - setDataAndType(Uri.parse("file://" + path), "image/*") + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + val uri = FileProvider.getUriForFile(context,"eu.kanade.tachiyomi.provider",File(path)) + setDataAndType(uri, "image/*") } context.startActivity(intent) } diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000000..5817df3bcb --- /dev/null +++ b/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 13954ffe0100c50d691127aef659816a53636b21 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Sun, 13 Nov 2016 14:07:20 +0100 Subject: [PATCH 10/11] Added page.ready check --- .../tachiyomi/ui/reader/ReaderActivity.kt | 39 ++++++++++--------- .../tachiyomi/ui/reader/ReaderPresenter.kt | 16 ++++++-- 2 files changed, 33 insertions(+), 22 deletions(-) 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 fe3104f701..488669a1f6 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 @@ -225,22 +225,22 @@ class ReaderActivity : BaseRxActivity() { toast(error.message) } - fun onChapterAppendError() { - // Ignore - } - fun onLongPress(page: Page) { MaterialDialog.Builder(this) - .title(getString(R.string.options)) - .items(R.array.reader_image_options) - .itemsIds(R.array.reader_image_options_values) - .itemsCallback { materialDialog, view, i, charSequence -> - when (i) { - 0 -> presenter.setCover(page) - 1 -> shareImage(page) - 2 -> presenter.savePage(page) - } - }.show() + .title(getString(R.string.options)) + .items(R.array.reader_image_options) + .itemsIds(R.array.reader_image_options_values) + .itemsCallback { materialDialog, view, i, charSequence -> + when (i) { + 0 -> presenter.setCover(page) + 1 -> shareImage(page) + 2 -> presenter.savePage(page) + } + }.show() + } + + fun onChapterAppendError() { + // Ignore } /** @@ -408,16 +408,16 @@ class ReaderActivity : BaseRxActivity() { private fun setRotation(rotation: Int) { when (rotation) { - // Rotation free + // Rotation free 1 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - // Lock in current rotation + // Lock in current rotation 2 -> { val currentOrientation = resources.configuration.orientation setRotation(if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) 3 else 4) } - // Lock in portrait + // Lock in portrait 3 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - // Lock in landscape + // Lock in landscape 4 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE } } @@ -476,6 +476,9 @@ class ReaderActivity : BaseRxActivity() { * @param page page object containing image information. */ fun shareImage(page: Page) { + if (page.status != Page.READY) + return + val shareIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_STREAM, Uri.parse(page.imagePath)) 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 1dd62da5f7..cddcf0e23e 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 @@ -383,11 +383,13 @@ class ReaderPresenter : BasePresenter() { if (chapter.read) { val removeAfterReadSlots = prefs.removeAfterReadSlots() when (removeAfterReadSlots) { - // Setting disabled - -1 -> { /**Empty function**/ } - // Remove current read chapter + // Setting disabled + -1 -> { + /**Empty function**/ + } + // Remove current read chapter 0 -> deleteChapter(chapter, manga) - // Remove previous chapter specified by user in settings. + // Remove previous chapter specified by user in settings. else -> getAdjacentChaptersStrategy(chapter, removeAfterReadSlots) .first?.let { deleteChapter(it, manga) } } @@ -531,6 +533,9 @@ class ReaderPresenter : BasePresenter() { * Update cover with page file. */ internal fun setCover(page: Page) { + if (page.status != Page.READY) + return + try { if (manga.favorite) { if (manga.thumbnail_url != null) { @@ -554,6 +559,9 @@ class ReaderPresenter : BasePresenter() { */ @Throws(IOException::class) internal fun savePage(page: Page) { + if (page.status != Page.READY) + return + // Used to show image notification val imageNotifier = ImageNotifier(context) From 4dc5f3e7d99335c987e9f601b89dd373fb4eff56 Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Sun, 13 Nov 2016 14:09:32 +0100 Subject: [PATCH 11/11] Indention --- .../eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt | 8 ++++---- .../eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) 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 488669a1f6..4f8634b871 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 @@ -408,16 +408,16 @@ class ReaderActivity : BaseRxActivity() { private fun setRotation(rotation: Int) { when (rotation) { - // Rotation free + // Rotation free 1 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - // Lock in current rotation + // Lock in current rotation 2 -> { val currentOrientation = resources.configuration.orientation setRotation(if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) 3 else 4) } - // Lock in portrait + // Lock in portrait 3 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - // Lock in landscape + // Lock in landscape 4 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE } } 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 cddcf0e23e..3f94a3f629 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 @@ -383,13 +383,11 @@ class ReaderPresenter : BasePresenter() { if (chapter.read) { val removeAfterReadSlots = prefs.removeAfterReadSlots() when (removeAfterReadSlots) { - // Setting disabled - -1 -> { - /**Empty function**/ - } - // Remove current read chapter + // Setting disabled + -1 -> { /**Empty function**/ } + // Remove current read chapter 0 -> deleteChapter(chapter, manga) - // Remove previous chapter specified by user in settings. + // Remove previous chapter specified by user in settings. else -> getAdjacentChaptersStrategy(chapter, removeAfterReadSlots) .first?.let { deleteChapter(it, manga) } }