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 ea3a073d7..53b3be48d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.data.notification import android.app.PendingIntent import android.content.BroadcastReceiver -import android.content.ClipData import android.content.Context import android.content.Intent import android.net.Uri @@ -25,6 +24,7 @@ import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.system.notificationManager +import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -130,16 +130,8 @@ class NotificationReceiver : BroadcastReceiver() { * @param notificationId id of notification */ private fun shareImage(context: Context, path: String, notificationId: Int) { - val intent = Intent(Intent.ACTION_SEND).apply { - val uri = File(path).getUriCompat(context) - putExtra(Intent.EXTRA_STREAM, uri) - clipData = ClipData.newRawUri(null, uri) - type = "image/*" - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION - } dismissNotification(context, notificationId) - // Launch share activity - context.startActivity(intent) + context.startActivity(File(path).getUriCompat(context).toShareIntent()) } /** @@ -150,16 +142,8 @@ class NotificationReceiver : BroadcastReceiver() { * @param notificationId id of notification */ private fun shareFile(context: Context, uri: Uri, fileMimeType: String, notificationId: Int) { - val sendIntent = Intent(Intent.ACTION_SEND).apply { - putExtra(Intent.EXTRA_STREAM, uri) - clipData = ClipData.newRawUri(null, uri) - type = fileMimeType - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION - } - // Dismiss notification dismissNotification(context, notificationId) - // Launch share activity - context.startActivity(sendIntent) + context.startActivity(uri.toShareIntent()) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt index 581b6eee2..ecc5da8a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt @@ -9,7 +9,6 @@ import android.widget.ArrayAdapter import androidx.core.content.ContextCompat import androidx.core.os.bundleOf import androidx.core.view.children -import androidx.core.view.isVisible import coil.loadAny import coil.transform.RoundedCornersTransformation import com.afollestad.materialdialogs.MaterialDialog @@ -27,7 +26,6 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.system.getResourceColor -import eu.kanade.tachiyomi.util.system.toast import exh.util.dropBlank import exh.util.trimOrNull import kotlinx.coroutines.flow.launchIn @@ -76,10 +74,7 @@ class EditMangaDialog : DialogController { } fun onViewCreated() { - val radius = context.resources.getDimension(R.dimen.card_radius) - binding.mangaCover.loadAny(manga) { - transformations(RoundedCornersTransformation(radius)) - } + loadCover() val isLocal = manga.source == LocalSource.ID @@ -159,14 +154,6 @@ class EditMangaDialog : DialogController { binding.resetTags.clicks() .onEach { resetTags() } .launchIn(infoController.viewScope) - binding.resetCover.isVisible = !isLocal - binding.resetCover.clicks() - .onEach { - context.toast(R.string.cover_reset_toast) - customCoverUri = null - willResetCover = true - } - .launchIn(infoController.viewScope) } private fun resetTags() { @@ -177,6 +164,13 @@ class EditMangaDialog : DialogController { } } + fun loadCover() { + val radius = context.resources.getDimension(R.dimen.card_radius) + binding.mangaCover.loadAny(manga) { + transformations(RoundedCornersTransformation(radius)) + } + } + fun updateCover(uri: Uri) { willResetCover = false val radius = context.resources.getDimension(R.dimen.card_radius) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 3f49cd5c0..950698d91 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -5,7 +5,6 @@ import android.animation.AnimatorListenerAdapter import android.animation.AnimatorSet import android.animation.ObjectAnimator import android.app.Activity -import android.content.ClipData import android.content.Intent import android.graphics.Color import android.graphics.Point @@ -99,6 +98,7 @@ import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.getCoordinates import eu.kanade.tachiyomi.util.view.shrinkOnScroll @@ -123,7 +123,6 @@ import timber.log.Timber import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy -import java.io.IOException import java.util.ArrayDeque import kotlin.math.min @@ -239,8 +238,6 @@ class MangaController : private var editMergedSettingsDialog: EditMergedSettingsDialog? = null private var currentAnimator: Animator? = null - - private var isExpanded: Boolean = false // EXH <-- init { @@ -510,16 +507,6 @@ class MangaController : menu.findItem(R.id.action_recommend).isVisible = preferences.recommendsInOverflow().get() menu.findItem(R.id.action_merged).isVisible = presenter.manga.source == MERGED_SOURCE_ID menu.findItem(R.id.action_toggle_dedupe).isVisible = false // presenter.manga.source == MERGED_SOURCE_ID - val shareCoverItem = menu.findItem(R.id.action_share_cover) - val saveCoverItem = menu.findItem(R.id.action_save) - if (isExpanded) { - menu.forEach { - it.isVisible = it == shareCoverItem || it == saveCoverItem - } - } else { - shareCoverItem.isVisible = false - saveCoverItem.isVisible = false - } // SY <-- } @@ -530,6 +517,10 @@ class MangaController : R.id.download_custom, R.id.download_unread, R.id.download_all -> downloadChapters(item.itemId) + R.id.action_share_cover -> shareCover() + R.id.action_save_cover -> saveCover() + // SY --> R.id.action_edit_cover -> changeCover() // SY <-- + // SY --> R.id.action_edit -> { editMangaDialog = EditMangaDialog( @@ -556,34 +547,7 @@ class MangaController : // SY <-- R.id.action_edit_categories -> onCategoriesClick() - // SY --> R.id.action_edit_cover -> handleChangeCover() // SY <-- R.id.action_migrate -> migrateManga() - // SY --> - R.id.action_save -> { - try { - presenter.saveCover(activity!!) - activity?.toast(R.string.cover_saved) - } catch (e: Exception) { - e.message?.let { activity?.toast(it) } ?: activity?.toast(R.string.error_saving_cover) - } - } - R.id.action_share_cover -> { - try { - val activity = activity!! - val cover = presenter.shareCover(activity) - val stream = cover.getUriCompat(activity) - 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, activity.getString(R.string.action_share))) - } catch (e: Exception) { - e.message?.let { activity?.toast(it) } ?: activity?.toast(R.string.error_sharing_cover) - } - } - // SY <-- } return super.onOptionsItemSelected(item) } @@ -769,22 +733,6 @@ class MangaController : } // SY --> - fun changeCover() { - if (manga?.favorite == true || source?.id == LocalSource.ID) { - val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.type = "image/*" - startActivityForResult( - Intent.createChooser( - intent, - resources?.getString(R.string.action_edit_cover) - ), - REQUEST_EDIT_MANGA_COVER - ) - } else { - activity?.toast(R.string.notification_first_add_to_library) - } - } - fun setRefreshing() { isRefreshingInfo = true updateRefreshing() @@ -931,8 +879,6 @@ class MangaController : binding.expandedImage.pivotX = 0f binding.expandedImage.pivotY = 0f - isExpanded = true - activity?.invalidateOptionsMenu() currentAnimator = AnimatorSet().apply { play( @@ -965,8 +911,6 @@ class MangaController : binding.expandedImage.clicks() .onEach { - isExpanded = false - activity?.invalidateOptionsMenu() currentAnimator?.cancel() currentAnimator = AnimatorSet().apply { @@ -1051,20 +995,35 @@ class MangaController : } } - private fun handleChangeCover() { - val manga = manga ?: return - if (manga.hasCustomCover(coverCache)) { - showEditCoverDialog(manga) - } else { - openMangaCoverPicker(manga) + private fun shareCover() { + try { + val activity = activity!! + val cover = presenter.shareCover(activity) + val uri = cover.getUriCompat(activity) + startActivity(Intent.createChooser(uri.toShareIntent(), activity.getString(R.string.action_share))) + } catch (e: Exception) { + Timber.e(e) + activity?.toast(R.string.error_sharing_cover) } } - /** - * Edit custom cover for selected manga. - */ - private fun showEditCoverDialog(manga: Manga) { - ChangeMangaCoverDialog(this, manga).showDialog(router) + private fun saveCover() { + try { + presenter.saveCover(activity!!) + activity?.toast(R.string.cover_saved) + } catch (e: Exception) { + Timber.e(e) + activity?.toast(R.string.error_saving_cover) + } + } + + fun changeCover() { + val manga = manga ?: return + if (manga.hasCustomCover(coverCache)) { + ChangeMangaCoverDialog(this, manga).showDialog(router) + } else { + openMangaCoverPicker(manga) + } } override fun openMangaCoverPicker(manga: Manga) { @@ -1097,27 +1056,16 @@ class MangaController : val dataUri = data?.data if (dataUri == null || resultCode != Activity.RESULT_OK) return val activity = activity ?: return - presenter.editCover(manga!!, activity, dataUri) + // SY --> + if (editMangaDialog != null) { + editMangaDialog?.updateCover(dataUri) + } else presenter.editCover(manga!!, activity, dataUri) + // SY <-- } - // SY --> - if (requestCode == REQUEST_EDIT_MANGA_COVER) { - if (data == null || resultCode != Activity.RESULT_OK) return - val activity = activity ?: return - try { - val uri = data.data ?: return - if (editMangaDialog != null) editMangaDialog?.updateCover(uri) - else { - presenter.editCoverWithStream(activity, uri) - } - } catch (error: IOException) { - activity.toast(R.string.notification_cover_update_failed) - Timber.e(error) - } - } - // SY <-- } fun onSetCoverSuccess() { + editMangaDialog?.loadCover() mangaInfoAdapter?.notifyDataSetChanged() activity?.toast(R.string.cover_updated) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 1a64d2e32..52549b99b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -3,9 +3,7 @@ package eu.kanade.tachiyomi.ui.manga import android.content.Context import android.net.Uri import android.os.Bundle -import android.os.Environment import com.jakewharton.rxrelay.PublishRelay -import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category @@ -42,6 +40,8 @@ import eu.kanade.tachiyomi.util.prepUpdateCover import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.util.shouldDownloadNewChapters import eu.kanade.tachiyomi.util.storage.DiskUtil +import eu.kanade.tachiyomi.util.storage.getPicturesDir +import eu.kanade.tachiyomi.util.storage.getTempShareDir import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.updateCoverLastModified @@ -357,7 +357,7 @@ class MangaPresenter( } if (uri != null) { - editCoverWithStream(context, uri) + editCover(manga, context, uri) } else if (resetCover) { coverCache.deleteCustomCover(manga) manga.updateCoverLastModified(db) @@ -385,25 +385,6 @@ class MangaPresenter( } } - fun editCoverWithStream(context: Context, uri: Uri): Boolean { - val inputStream = context.contentResolver.openInputStream(uri) ?: return false - if (manga.source == LocalSource.ID) { - val cover = LocalSource.updateCover(context, manga, inputStream) - if (manga.thumbnail_url.isNullOrBlank() && cover != null) { - manga.thumbnail_url = cover.absolutePath - db.updateMangaThumbnail(manga).executeAsBlocking() - } - return true - } - - if (manga.favorite) { - coverCache.setCustomCoverToCache(manga, inputStream) - manga.updateCoverLastModified(db) - return true - } - return false - } - suspend fun smartSearchMerge(manga: Manga, originalMangaId: Long): Manga { val originalManga = db.getManga(originalMangaId).executeAsBlocking() ?: throw IllegalArgumentException("Unknown manga ID: $originalMangaId") if (originalManga.source == MERGED_SOURCE_ID) { @@ -545,41 +526,6 @@ class MangaPresenter( fun toggleDedupe() { // I cant find any way to call the chapter list subscription to get the chapters again } - - fun shareCover(context: Context): File { - val destDir = File(context.cacheDir, "shared_image") - return saveCover(destDir) - } - - fun saveCover(context: Context) { - val directory = File( - Environment.getExternalStorageDirectory().absolutePath + - File.separator + Environment.DIRECTORY_PICTURES + - File.separator + context.getString(R.string.app_name) - ) - saveCover(directory) - } - - private fun saveCover(directory: File): File { - val cover = coverCache.getCoverFile(manga) ?: throw Exception("Cover url was null") - if (!cover.exists()) throw Exception("Cover not in cache") - val type = ImageUtil.findImageType(cover.inputStream()) - ?: throw Exception("Not an image") - - directory.mkdirs() - - // Build destination file. - val filename = DiskUtil.buildValidFilename("${manga.title}.${type.extension}") - - val destFile = File(directory, filename) - cover.inputStream().use { input -> - destFile.outputStream().use { output -> - input.copyTo(output) - } - } - return destFile - } - // SY <-- /** @@ -661,6 +607,33 @@ class MangaPresenter( moveMangaToCategories(manga, listOfNotNull(category)) } + fun shareCover(context: Context): File { + return saveCover(getTempShareDir(context)) + } + + fun saveCover(context: Context) { + saveCover(getPicturesDir(context)) + } + + private fun saveCover(directory: File): File { + val cover = coverCache.getCoverFile(manga) ?: throw Exception("Cover url was null") + if (!cover.exists()) throw Exception("Cover not in cache") + val type = ImageUtil.findImageType(cover.inputStream()) + ?: throw Exception("Not an image") + + directory.mkdirs() + + val filename = DiskUtil.buildValidFilename("${manga.title}.${type.extension}") + + val destFile = File(directory, filename) + cover.inputStream().use { input -> + destFile.outputStream().use { output -> + input.copyTo(output) + } + } + return destFile + } + /** * Update cover with local file. * 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 e1cf15657..5d5b58247 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 @@ -4,7 +4,6 @@ import android.app.Application import android.content.Context import android.graphics.BitmapFactory import android.os.Bundle -import android.os.Environment import androidx.annotation.ColorInt import com.jakewharton.rxrelay.BehaviorRelay import eu.kanade.tachiyomi.R @@ -36,6 +35,8 @@ import eu.kanade.tachiyomi.util.lang.byteSize import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.takeBytes import eu.kanade.tachiyomi.util.storage.DiskUtil +import eu.kanade.tachiyomi.util.storage.getPicturesDir +import eu.kanade.tachiyomi.util.storage.getTempShareDir import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.updateCoverLastModified import exh.md.utils.FollowStatus @@ -704,9 +705,7 @@ class ReaderPresenter( notifier.onClear() // Pictures directory. - val baseDir = Environment.getExternalStorageDirectory().absolutePath + - File.separator + Environment.DIRECTORY_PICTURES + - File.separator + context.getString(R.string.app_name) + val baseDir = getPicturesDir(context).absolutePath val destDir = if (preferences.folderPerManga()) { File(baseDir + File.separator + manga.title) } else { @@ -739,11 +738,7 @@ class ReaderPresenter( notifier.onClear() // Pictures directory. - val destDir = File( - Environment.getExternalStorageDirectory().absolutePath + - File.separator + Environment.DIRECTORY_PICTURES + - File.separator + context.getString(R.string.app_name) - ) + val destDir = getPicturesDir(context) // Copy file in background. Observable.fromCallable { saveImages(firstPage, secondPage, isLTR, bg, destDir, manga) } @@ -804,7 +799,7 @@ class ReaderPresenter( val manga = manga ?: return val context = Injekt.get() - val destDir = File(context.cacheDir, "shared_image") + val destDir = getTempShareDir(context) Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file .map { saveImage(page, destDir, manga) } @@ -823,7 +818,7 @@ class ReaderPresenter( val manga = manga ?: return val context = Injekt.get() - val destDir = File(context.cacheDir, "shared_image") + val destDir = getTempShareDir(context) Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file .map { saveImages(firstPage, secondPage, isLTR, bg, destDir, manga) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt index 6c7265773..ae26a5fd9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt @@ -3,11 +3,21 @@ package eu.kanade.tachiyomi.util.storage import android.content.Context import android.net.Uri import android.os.Build +import android.os.Environment import androidx.core.content.FileProvider import androidx.core.net.toUri import eu.kanade.tachiyomi.BuildConfig +import eu.kanade.tachiyomi.R import java.io.File +fun getTempShareDir(context: Context) = File(context.cacheDir, "shared_image") + +fun getPicturesDir(context: Context) = File( + Environment.getExternalStorageDirectory().absolutePath + + File.separator + Environment.DIRECTORY_PICTURES + + File.separator + context.getString(R.string.app_name) +) + /** * Returns the uri of a file * diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/IntentExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/IntentExtensions.kt new file mode 100644 index 000000000..f5a3abf8f --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/IntentExtensions.kt @@ -0,0 +1,15 @@ +package eu.kanade.tachiyomi.util.system + +import android.content.ClipData +import android.content.Intent +import android.net.Uri + +fun Uri.toShareIntent(): Intent { + val uri = this + return Intent(Intent.ACTION_SEND).apply { + putExtra(Intent.EXTRA_STREAM, uri) + clipData = ClipData.newRawUri(null, uri) + type = "image/*" + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + } +} diff --git a/app/src/main/res/layout/edit_manga_dialog.xml b/app/src/main/res/layout/edit_manga_dialog.xml index 615098733..e3dc0ac31 100644 --- a/app/src/main/res/layout/edit_manga_dialog.xml +++ b/app/src/main/res/layout/edit_manga_dialog.xml @@ -29,19 +29,9 @@ android:orientation="horizontal" android:gravity="center"> -