mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-12 20:19:05 +01:00
Notification Improvements (#594)
* Download notifier improvements * Notification improvements Added a Notification Service. Added a Notification Activity Handler. * Removed service. Everything is now managed by single broadcast * Fixed some flags * Fixed ReaderActivity call * Code review * Added Handler. Removed dismiss onDestroy
This commit is contained in:
committed by
inorichi
parent
52c50398b8
commit
c445ea90ba
@@ -2,15 +2,17 @@ package eu.kanade.tachiyomi.ui.download
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.view.*
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.fragment_download_queue.*
|
||||
import kotlinx.android.synthetic.main.toolbar.*
|
||||
import nucleus.factory.RequiresPresenter
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
@@ -20,19 +22,18 @@ import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Fragment that shows the currently active downloads.
|
||||
* Activity that shows the currently active downloads.
|
||||
* Uses R.layout.fragment_download_queue.
|
||||
*/
|
||||
@RequiresPresenter(DownloadPresenter::class)
|
||||
class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
|
||||
class DownloadActivity : BaseRxActivity<DownloadPresenter>() {
|
||||
/**
|
||||
* Adapter containing the active downloads.
|
||||
*/
|
||||
private lateinit var adapter: DownloadAdapter
|
||||
|
||||
/**
|
||||
* Subscription list to be cleared during [onDestroyView].
|
||||
* Subscription list to be cleared during [onDestroy].
|
||||
*/
|
||||
private val subscriptions by lazy { CompositeSubscription() }
|
||||
|
||||
@@ -46,38 +47,22 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
*/
|
||||
private var isRunning: Boolean = false
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Creates a new instance of this fragment.
|
||||
*
|
||||
* @return a new instance of [DownloadFragment].
|
||||
*/
|
||||
fun newInstance(): DownloadFragment {
|
||||
return DownloadFragment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
setAppTheme()
|
||||
super.onCreate(savedState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View {
|
||||
return inflater.inflate(R.layout.fragment_download_queue, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
setContentView(R.layout.activity_download_manager)
|
||||
setupToolbar(toolbar)
|
||||
setToolbarTitle(R.string.label_download_queue)
|
||||
|
||||
// Check if download queue is empty and update information accordingly.
|
||||
setInformationView()
|
||||
|
||||
// Initialize adapter.
|
||||
adapter = DownloadAdapter(activity)
|
||||
adapter = DownloadAdapter(this)
|
||||
recycler.adapter = adapter
|
||||
|
||||
// Set the layout manager for the recycler and fixed size.
|
||||
recycler.layoutManager = LinearLayoutManager(activity)
|
||||
recycler.layoutManager = LinearLayoutManager(this)
|
||||
recycler.setHasFixedSize(true)
|
||||
|
||||
// Suscribe to changes
|
||||
@@ -94,20 +79,21 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
.subscribe { onUpdateDownloadedPages(it) }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
override fun onDestroy() {
|
||||
for (subscription in progressSubscriptions.values) {
|
||||
subscription.unsubscribe()
|
||||
}
|
||||
progressSubscriptions.clear()
|
||||
subscriptions.clear()
|
||||
super.onDestroyView()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.download_queue, menu)
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.download_queue, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
// Set start button visibility.
|
||||
menu.findItem(R.id.start_queue).isVisible = !isRunning && !presenter.downloadQueue.isEmpty()
|
||||
|
||||
@@ -116,14 +102,18 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
|
||||
// Set clear button visibility.
|
||||
menu.findItem(R.id.clear_queue).isVisible = !presenter.downloadQueue.isEmpty()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.start_queue -> DownloadService.start(activity)
|
||||
R.id.pause_queue -> DownloadService.stop(activity)
|
||||
R.id.start_queue -> DownloadService.start(this)
|
||||
R.id.pause_queue -> {
|
||||
DownloadService.stop(this)
|
||||
presenter.pauseDownloads()
|
||||
}
|
||||
R.id.clear_queue -> {
|
||||
DownloadService.stop(activity)
|
||||
DownloadService.stop(this)
|
||||
presenter.clearQueue()
|
||||
}
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
@@ -198,7 +188,7 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
*/
|
||||
private fun onQueueStatusChange(running: Boolean) {
|
||||
isRunning = running
|
||||
activity.supportInvalidateOptionsMenu()
|
||||
supportInvalidateOptionsMenu()
|
||||
|
||||
// Check if download queue is empty and update information accordingly.
|
||||
setInformationView()
|
||||
@@ -210,7 +200,7 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
* @param downloads the downloads from the queue.
|
||||
*/
|
||||
fun onNextDownloads(downloads: List<Download>) {
|
||||
activity.supportInvalidateOptionsMenu()
|
||||
supportInvalidateOptionsMenu()
|
||||
setInformationView()
|
||||
adapter.setItems(downloads)
|
||||
}
|
||||
@@ -247,8 +237,11 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
|
||||
* Set information view when queue is empty
|
||||
*/
|
||||
private fun setInformationView() {
|
||||
(activity as MainActivity).updateEmptyView(presenter.downloadQueue.isEmpty(),
|
||||
updateEmptyView(presenter.downloadQueue.isEmpty(),
|
||||
R.string.information_no_downloads, R.drawable.ic_file_download_black_128dp)
|
||||
}
|
||||
|
||||
fun updateEmptyView(show: Boolean, textResource: Int, drawable: Int) {
|
||||
if (show) empty_view.show(drawable, textResource) else empty_view.hide()
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,9 @@ import uy.kohesive.injekt.injectLazy
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Presenter of [DownloadFragment].
|
||||
* Presenter of [DownloadActivity].
|
||||
*/
|
||||
class DownloadPresenter : BasePresenter<DownloadFragment>() {
|
||||
class DownloadPresenter : BasePresenter<DownloadActivity>() {
|
||||
|
||||
/**
|
||||
* Download manager.
|
||||
@@ -33,7 +33,7 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
|
||||
downloadQueue.getUpdatedObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { ArrayList(it) }
|
||||
.subscribeLatestCache(DownloadFragment::onNextDownloads, { view, error ->
|
||||
.subscribeLatestCache(DownloadActivity::onNextDownloads, { view, error ->
|
||||
Timber.e(error)
|
||||
})
|
||||
}
|
||||
@@ -48,6 +48,13 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
|
||||
.onBackpressureBuffer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the download queue.
|
||||
*/
|
||||
fun pauseDownloads() {
|
||||
downloadManager.pauseDownloads()
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the download queue.
|
||||
*/
|
||||
@@ -55,4 +62,4 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
|
||||
downloadManager.clearQueue()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.backup.BackupFragment
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment
|
||||
import eu.kanade.tachiyomi.ui.download.DownloadFragment
|
||||
import eu.kanade.tachiyomi.ui.download.DownloadActivity
|
||||
import eu.kanade.tachiyomi.ui.latest_updates.LatestUpdatesFragment
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryFragment
|
||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment
|
||||
@@ -63,7 +63,7 @@ class MainActivity : BaseActivity() {
|
||||
R.id.nav_drawer_recently_read -> setFragment(RecentlyReadFragment.newInstance(), id)
|
||||
R.id.nav_drawer_catalogues -> setFragment(CatalogueFragment.newInstance(), id)
|
||||
R.id.nav_drawer_latest_updates -> setFragment(LatestUpdatesFragment.newInstance(), id)
|
||||
R.id.nav_drawer_downloads -> setFragment(DownloadFragment.newInstance(), id)
|
||||
R.id.nav_drawer_downloads -> startActivity(Intent(this, DownloadActivity::class.java))
|
||||
R.id.nav_drawer_settings -> {
|
||||
val intent = Intent(this, SettingsActivity::class.java)
|
||||
startActivityForResult(intent, REQUEST_OPEN_SETTINGS)
|
||||
|
||||
@@ -19,7 +19,7 @@ import eu.kanade.tachiyomi.data.source.online.OnlineSource
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackUpdateService
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.reader.notification.ImageNotifier
|
||||
import eu.kanade.tachiyomi.ui.reader.SaveImageNotifier
|
||||
import eu.kanade.tachiyomi.util.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.RetryWithDelay
|
||||
import eu.kanade.tachiyomi.util.SharedData
|
||||
@@ -562,7 +562,7 @@ class ReaderPresenter : BasePresenter<ReaderActivity>() {
|
||||
return
|
||||
|
||||
// Used to show image notification.
|
||||
val imageNotifier = ImageNotifier(context)
|
||||
val imageNotifier = SaveImageNotifier(context)
|
||||
|
||||
// Remove the notification if it already exists (user feedback).
|
||||
imageNotifier.onClear()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.notification
|
||||
package eu.kanade.tachiyomi.ui.reader
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
@@ -7,13 +7,15 @@ import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import eu.kanade.tachiyomi.Constants
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Class used to show BigPictureStyle notifications
|
||||
*/
|
||||
class ImageNotifier(private val context: Context) {
|
||||
class SaveImageNotifier(private val context: Context) {
|
||||
/**
|
||||
* Notification builder.
|
||||
*/
|
||||
@@ -58,15 +60,15 @@ class ImageNotifier(private val context: Context) {
|
||||
if (!mActions.isEmpty())
|
||||
mActions.clear()
|
||||
|
||||
setContentIntent(ImageNotificationReceiver.showImageIntent(context, file))
|
||||
setContentIntent(NotificationHandler.openImagePendingActivity(context, file))
|
||||
// Share action
|
||||
addAction(R.drawable.ic_share_grey_24dp,
|
||||
context.getString(R.string.action_share),
|
||||
ImageNotificationReceiver.shareImageIntent(context, file))
|
||||
context.getString(R.string.action_share),
|
||||
NotificationReceiver.shareImagePendingBroadcast(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))
|
||||
NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId))
|
||||
updateNotification()
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.notification
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.support.v4.content.FileProvider
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import java.io.File
|
||||
import eu.kanade.tachiyomi.Constants.NOTIFICATION_DOWNLOAD_IMAGE_ID as defaultNotification
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
ACTION_DELETE_IMAGE -> {
|
||||
deleteImage(intent.getStringExtra(EXTRA_FILE_LOCATION))
|
||||
context.notificationManager.cancel(intent.getIntExtra(NOTIFICATION_ID, defaultNotification))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to delete image
|
||||
*
|
||||
* @param path path of file
|
||||
*/
|
||||
private fun deleteImage(path: String) {
|
||||
val file = File(path)
|
||||
if (file.exists()) file.delete()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ACTION_DELETE_IMAGE = "eu.kanade.DELETE_IMAGE"
|
||||
|
||||
private const val EXTRA_FILE_LOCATION = "file_location"
|
||||
|
||||
private const val NOTIFICATION_ID = "notification_id"
|
||||
|
||||
/**
|
||||
* Called to start share intent to share image
|
||||
*
|
||||
* @param context context of application
|
||||
* @param file file that contains image
|
||||
*/
|
||||
internal fun shareImageIntent(context: Context, file: File): PendingIntent {
|
||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||
val uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file)
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = "image/*"
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to show image in gallery application
|
||||
*
|
||||
* @param context context of application
|
||||
* @param file file that contains image
|
||||
*/
|
||||
internal fun showImageIntent(context: Context, file: File): PendingIntent {
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
val uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file)
|
||||
setDataAndType(uri, "image/*")
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
return PendingIntent.getActivity(context, 0, intent, 0)
|
||||
}
|
||||
|
||||
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)
|
||||
putExtra(NOTIFICATION_ID, notificationId)
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user