diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index d5110055a3..c97a94acad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.notification import android.app.Notification import android.app.PendingIntent import android.content.BroadcastReceiver +import android.content.ClipData import android.content.Context import android.content.Intent import android.os.Handler @@ -86,12 +87,16 @@ class NotificationReceiver : BroadcastReceiver() { val uri = File(path).getUriCompat(context) putExtra(Intent.EXTRA_STREAM, uri) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + clipData = ClipData.newRawUri(null, uri) type = "image/*" } - // Dismiss notification - dismissNotification(context, notificationId) + // Close Navigation Shade + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) // Launch share activity - context.startActivity(intent) + val shareIntent = Intent.createChooser(intent, context.getString(R.string + .action_share)) + shareIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + context.startActivity(shareIntent) } /** @@ -106,8 +111,7 @@ class NotificationReceiver : BroadcastReceiver() { val db = DatabaseHelper(context) val manga = db.getManga(mangaId).executeAsBlocking() val chapter = db.getChapter(chapterId).executeAsBlocking() - val it = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - context.sendBroadcast(it) + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) if (manga != null && chapter != null) { val intent = ReaderActivity.newIntent(context, manga, chapter).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt index 7ebb33c770..aa17339f45 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt @@ -20,6 +20,7 @@ import android.widget.Toast import com.afollestad.materialdialogs.MaterialDialog import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.transition.Transition import com.jakewharton.rxbinding.support.v4.widget.refreshes @@ -46,6 +47,7 @@ import jp.wasabeef.glide.transformations.CropSquareTransformation import jp.wasabeef.glide.transformations.MaskTransformation import kotlinx.android.synthetic.main.manga_info_controller.* import uy.kohesive.injekt.injectLazy +import java.io.File import java.text.DateFormat import java.text.DecimalFormat import java.util.Date @@ -161,7 +163,7 @@ class MangaInfoController : NucleusController(), when (item.itemId) { R.id.action_open_in_browser -> openInBrowser() R.id.action_open_in_web_view -> openInWebView() - R.id.action_share -> shareManga() + R.id.action_share -> prepareToShareManga() R.id.action_add_to_home_screen -> addToHomeScreen() else -> return super.onOptionsItemSelected(item) } @@ -325,15 +327,40 @@ class MangaInfoController : NucleusController(), /** * Called to run Intent with [Intent.ACTION_SEND], which show share dialog. */ - private fun shareManga() { + private fun prepareToShareManga() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + GlideApp.with(activity!!).asBitmap().load(presenter.manga).into(object : + CustomTarget() { + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + presenter.shareManga(resource) + } + override fun onLoadCleared(placeholder: Drawable?) {} + + override fun onLoadFailed(errorDrawable: Drawable?) { + shareManga() + } + }) + else shareManga() + } + + /** + * Called to run Intent with [Intent.ACTION_SEND], which show share dialog. + */ + fun shareManga(cover: File? = null) { val context = view?.context ?: return val source = presenter.source as? HttpSource ?: return + val stream = cover?.getUriCompat(context) try { val url = source.mangaDetailsRequest(presenter.manga).url.toString() val intent = Intent(Intent.ACTION_SEND).apply { - type = "text/plain" + type = "text/*" putExtra(Intent.EXTRA_TEXT, url) + putExtra(Intent.EXTRA_TITLE, presenter.manga.title) + flags = Intent.FLAG_GRANT_READ_URI_PERMISSION + if (stream != null) { + clipData = ClipData.newRawUri(null, stream) + } } startActivity(Intent.createChooser(intent, context.getString(R.string.action_share))) } catch (e: Exception) { @@ -523,11 +550,13 @@ class MangaInfoController : NucleusController(), 3 -> centerCrop().transform(MaskTransformation(R.drawable.mask_star)) } } - .into(object : SimpleTarget(96, 96) { + .into(object : CustomTarget(96, 96) { override fun onResourceReady(resource: Bitmap, transition: Transition?) { createShortcut(resource) } + override fun onLoadCleared(placeholder: Drawable?) { } + override fun onLoadFailed(errorDrawable: Drawable?) { activity?.toast(R.string.icon_creation_fail) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt index 5e389d2e31..572d152a9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.ui.manga.info +import android.app.Application +import android.graphics.Bitmap import android.os.Bundle import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.PublishRelay @@ -11,6 +13,8 @@ import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter +import eu.kanade.tachiyomi.util.DiskUtil +import eu.kanade.tachiyomi.util.ImageUtil import eu.kanade.tachiyomi.util.isNullOrUnsubscribed import rx.Observable import rx.Subscription @@ -18,6 +22,11 @@ import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.InputStream +import java.io.OutputStream import java.util.* /** @@ -116,6 +125,35 @@ class MangaInfoPresenter( toggleFavorite() } + fun shareManga(cover:Bitmap) { + val context = Injekt.get() + + val destDir = File(context.cacheDir, "shared_image") + + Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file + .map { saveImage(cover, destDir, manga) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, file -> view.shareManga(file) }, + { view, error -> view.shareManga() } + ) + } + + private fun saveImage(cover:Bitmap, directory: File, manga: Manga): File? { + directory.mkdirs() + + // Build destination file. + val filename = DiskUtil.buildValidFilename("${manga.title} - Cover.jpg") + + val destFile = File(directory, filename) + val stream: OutputStream = FileOutputStream(destFile) + cover.compress(Bitmap.CompressFormat.JPEG,75,stream) + stream.flush() + stream.close() + return destFile + } + /** * Get the default, and user categories. * 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 f7711fc6a7..cf1ef64ba8 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 @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader import android.annotation.SuppressLint import android.app.ProgressDialog +import android.content.ClipData import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo @@ -156,17 +157,6 @@ class ReaderActivity : BaseRxActivity(), config = ReaderConfig() initializeMenu() - val container: ViewGroup = findViewById(R.id.reader_container) - val readerBHeight = reader_menu_bottom.layoutParams.height - container.doOnApplyWindowInsets { _, insets, padding -> - val bottomInset = if (Build.VERSION.SDK_INT >= 29) - (insets.mandatorySystemGestureInsets.bottom - insets.systemWindowInsetBottom) - else 0 - reader_menu_bottom.updateLayoutParams { - height = readerBHeight + bottomInset - } - reader_menu_bottom.updatePaddingRelative(bottom = padding.bottom + bottomInset) - } } /** @@ -312,6 +302,9 @@ class ReaderActivity : BaseRxActivity(), systemUi?.show() reader_menu.visibility = View.VISIBLE reader_menu_bottom.visibility = View.VISIBLE + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + window.navigationBarColor = getResourceColor(R.attr.colorPrimaryDark) + } if (animate) { if (!menuStickyVisible) { val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top) @@ -513,6 +506,7 @@ class ReaderActivity : BaseRxActivity(), val intent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_STREAM, stream) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + clipData = ClipData.newRawUri(null, stream) type = "image/*" } startActivity(Intent.createChooser(intent, getString(R.string.action_share))) @@ -570,6 +564,9 @@ class ReaderActivity : BaseRxActivity(), setMenuVisibility(false) menuStickyVisible = false } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + window.navigationBarColor = getColor(android.R.color.transparent) + } reader_menu_bottom.visibility = View.GONE reader_menu.visibility = View.VISIBLE val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top) @@ -579,9 +576,6 @@ class ReaderActivity : BaseRxActivity(), } }) toolbar.startAnimation(toolbarAnimation) - /*val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim - .enter_from_bottom) - reader_menu_bottom.startAnimation(bottomAnimation)*/ } } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSeekBar.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSeekBar.kt index 255367d3c4..48aeb56d32 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSeekBar.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSeekBar.kt @@ -20,6 +20,8 @@ class ReaderSeekBar @JvmOverloads constructor( * Whether the seekbar should draw from right to left. */ var isRTL = false + private val boundingBox: Rect = Rect() + private val exclusions = listOf(boundingBox) /** * Draws the seekbar, translating the canvas if using a right to left reader. @@ -43,4 +45,14 @@ class ReaderSeekBar @JvmOverloads constructor( } return super.onTouchEvent(event) } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + if (Build.VERSION.SDK_INT >= 29) { + if (changed) { + boundingBox.set(left, top, right, bottom) + systemGestureExclusionRects = exclusions + } + } + } }