Add share and save cover actions (closes #3011)

(cherry picked from commit 281a3911f69b96050bae4b232af94ca3671b92ae)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt
This commit is contained in:
arkon 2021-06-01 18:36:06 -04:00 committed by Jobobby04
parent 6d7e8cdcb9
commit 88102b9705
13 changed files with 132 additions and 235 deletions

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.data.notification
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.ClipData
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri 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.DiskUtil
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import eu.kanade.tachiyomi.util.system.toShareIntent
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -130,16 +130,8 @@ class NotificationReceiver : BroadcastReceiver() {
* @param notificationId id of notification * @param notificationId id of notification
*/ */
private fun shareImage(context: Context, path: String, notificationId: Int) { 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) dismissNotification(context, notificationId)
// Launch share activity context.startActivity(File(path).getUriCompat(context).toShareIntent())
context.startActivity(intent)
} }
/** /**
@ -150,16 +142,8 @@ class NotificationReceiver : BroadcastReceiver() {
* @param notificationId id of notification * @param notificationId id of notification
*/ */
private fun shareFile(context: Context, uri: Uri, fileMimeType: String, notificationId: Int) { 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) dismissNotification(context, notificationId)
// Launch share activity context.startActivity(uri.toShareIntent())
context.startActivity(sendIntent)
} }
/** /**

View File

@ -9,7 +9,6 @@ import android.widget.ArrayAdapter
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.isVisible
import coil.loadAny import coil.loadAny
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import com.afollestad.materialdialogs.MaterialDialog 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.ui.base.controller.DialogController
import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.toast
import exh.util.dropBlank import exh.util.dropBlank
import exh.util.trimOrNull import exh.util.trimOrNull
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -76,10 +74,7 @@ class EditMangaDialog : DialogController {
} }
fun onViewCreated() { fun onViewCreated() {
val radius = context.resources.getDimension(R.dimen.card_radius) loadCover()
binding.mangaCover.loadAny(manga) {
transformations(RoundedCornersTransformation(radius))
}
val isLocal = manga.source == LocalSource.ID val isLocal = manga.source == LocalSource.ID
@ -159,14 +154,6 @@ class EditMangaDialog : DialogController {
binding.resetTags.clicks() binding.resetTags.clicks()
.onEach { resetTags() } .onEach { resetTags() }
.launchIn(infoController.viewScope) .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() { 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) { fun updateCover(uri: Uri) {
willResetCover = false willResetCover = false
val radius = context.resources.getDimension(R.dimen.card_radius) val radius = context.resources.getDimension(R.dimen.card_radius)

View File

@ -5,7 +5,6 @@ import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet import android.animation.AnimatorSet
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.app.Activity import android.app.Activity
import android.content.ClipData
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.graphics.Point 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.lang.launchUI
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.getResourceColor 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.system.toast
import eu.kanade.tachiyomi.util.view.getCoordinates import eu.kanade.tachiyomi.util.view.getCoordinates
import eu.kanade.tachiyomi.util.view.shrinkOnScroll import eu.kanade.tachiyomi.util.view.shrinkOnScroll
@ -123,7 +123,6 @@ import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.util.ArrayDeque import java.util.ArrayDeque
import kotlin.math.min import kotlin.math.min
@ -239,8 +238,6 @@ class MangaController :
private var editMergedSettingsDialog: EditMergedSettingsDialog? = null private var editMergedSettingsDialog: EditMergedSettingsDialog? = null
private var currentAnimator: Animator? = null private var currentAnimator: Animator? = null
private var isExpanded: Boolean = false
// EXH <-- // EXH <--
init { init {
@ -510,16 +507,6 @@ class MangaController :
menu.findItem(R.id.action_recommend).isVisible = preferences.recommendsInOverflow().get() 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_merged).isVisible = presenter.manga.source == MERGED_SOURCE_ID
menu.findItem(R.id.action_toggle_dedupe).isVisible = false // 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 <-- // SY <--
} }
@ -530,6 +517,10 @@ class MangaController :
R.id.download_custom, R.id.download_unread, R.id.download_all R.id.download_custom, R.id.download_unread, R.id.download_all
-> downloadChapters(item.itemId) -> downloadChapters(item.itemId)
R.id.action_share_cover -> shareCover()
R.id.action_save_cover -> saveCover()
// SY --> R.id.action_edit_cover -> changeCover() // SY <--
// SY --> // SY -->
R.id.action_edit -> { R.id.action_edit -> {
editMangaDialog = EditMangaDialog( editMangaDialog = EditMangaDialog(
@ -556,34 +547,7 @@ class MangaController :
// SY <-- // SY <--
R.id.action_edit_categories -> onCategoriesClick() R.id.action_edit_categories -> onCategoriesClick()
// SY --> R.id.action_edit_cover -> handleChangeCover() // SY <--
R.id.action_migrate -> migrateManga() 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) return super.onOptionsItemSelected(item)
} }
@ -769,22 +733,6 @@ class MangaController :
} }
// SY --> // 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() { fun setRefreshing() {
isRefreshingInfo = true isRefreshingInfo = true
updateRefreshing() updateRefreshing()
@ -931,8 +879,6 @@ class MangaController :
binding.expandedImage.pivotX = 0f binding.expandedImage.pivotX = 0f
binding.expandedImage.pivotY = 0f binding.expandedImage.pivotY = 0f
isExpanded = true
activity?.invalidateOptionsMenu()
currentAnimator = AnimatorSet().apply { currentAnimator = AnimatorSet().apply {
play( play(
@ -965,8 +911,6 @@ class MangaController :
binding.expandedImage.clicks() binding.expandedImage.clicks()
.onEach { .onEach {
isExpanded = false
activity?.invalidateOptionsMenu()
currentAnimator?.cancel() currentAnimator?.cancel()
currentAnimator = AnimatorSet().apply { currentAnimator = AnimatorSet().apply {
@ -1051,20 +995,35 @@ class MangaController :
} }
} }
private fun handleChangeCover() { private fun shareCover() {
val manga = manga ?: return try {
if (manga.hasCustomCover(coverCache)) { val activity = activity!!
showEditCoverDialog(manga) val cover = presenter.shareCover(activity)
} else { val uri = cover.getUriCompat(activity)
openMangaCoverPicker(manga) startActivity(Intent.createChooser(uri.toShareIntent(), activity.getString(R.string.action_share)))
} catch (e: Exception) {
Timber.e(e)
activity?.toast(R.string.error_sharing_cover)
} }
} }
/** private fun saveCover() {
* Edit custom cover for selected manga. try {
*/ presenter.saveCover(activity!!)
private fun showEditCoverDialog(manga: Manga) { 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) ChangeMangaCoverDialog(this, manga).showDialog(router)
} else {
openMangaCoverPicker(manga)
}
} }
override fun openMangaCoverPicker(manga: Manga) { override fun openMangaCoverPicker(manga: Manga) {
@ -1097,27 +1056,16 @@ class MangaController :
val dataUri = data?.data val dataUri = data?.data
if (dataUri == null || resultCode != Activity.RESULT_OK) return if (dataUri == null || resultCode != Activity.RESULT_OK) return
val activity = activity ?: return val activity = activity ?: return
presenter.editCover(manga!!, activity, dataUri)
}
// SY --> // SY -->
if (requestCode == REQUEST_EDIT_MANGA_COVER) { if (editMangaDialog != null) {
if (data == null || resultCode != Activity.RESULT_OK) return editMangaDialog?.updateCover(dataUri)
val activity = activity ?: return } else presenter.editCover(manga!!, activity, dataUri)
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 <-- // SY <--
} }
}
fun onSetCoverSuccess() { fun onSetCoverSuccess() {
editMangaDialog?.loadCover()
mangaInfoAdapter?.notifyDataSetChanged() mangaInfoAdapter?.notifyDataSetChanged()
activity?.toast(R.string.cover_updated) activity?.toast(R.string.cover_updated)
} }

View File

@ -3,9 +3,7 @@ package eu.kanade.tachiyomi.ui.manga
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import com.jakewharton.rxrelay.PublishRelay import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category 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.removeCovers
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
import eu.kanade.tachiyomi.util.storage.DiskUtil 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.ImageUtil
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.updateCoverLastModified import eu.kanade.tachiyomi.util.updateCoverLastModified
@ -357,7 +357,7 @@ class MangaPresenter(
} }
if (uri != null) { if (uri != null) {
editCoverWithStream(context, uri) editCover(manga, context, uri)
} else if (resetCover) { } else if (resetCover) {
coverCache.deleteCustomCover(manga) coverCache.deleteCustomCover(manga)
manga.updateCoverLastModified(db) 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 { suspend fun smartSearchMerge(manga: Manga, originalMangaId: Long): Manga {
val originalManga = db.getManga(originalMangaId).executeAsBlocking() ?: throw IllegalArgumentException("Unknown manga ID: $originalMangaId") val originalManga = db.getManga(originalMangaId).executeAsBlocking() ?: throw IllegalArgumentException("Unknown manga ID: $originalMangaId")
if (originalManga.source == MERGED_SOURCE_ID) { if (originalManga.source == MERGED_SOURCE_ID) {
@ -545,41 +526,6 @@ class MangaPresenter(
fun toggleDedupe() { fun toggleDedupe() {
// I cant find any way to call the chapter list subscription to get the chapters again // 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 <-- // SY <--
/** /**
@ -661,6 +607,33 @@ class MangaPresenter(
moveMangaToCategories(manga, listOfNotNull(category)) 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. * Update cover with local file.
* *

View File

@ -4,7 +4,6 @@ import android.app.Application
import android.content.Context import android.content.Context
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.tachiyomi.R 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.launchIO
import eu.kanade.tachiyomi.util.lang.takeBytes import eu.kanade.tachiyomi.util.lang.takeBytes
import eu.kanade.tachiyomi.util.storage.DiskUtil 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.ImageUtil
import eu.kanade.tachiyomi.util.updateCoverLastModified import eu.kanade.tachiyomi.util.updateCoverLastModified
import exh.md.utils.FollowStatus import exh.md.utils.FollowStatus
@ -704,9 +705,7 @@ class ReaderPresenter(
notifier.onClear() notifier.onClear()
// Pictures directory. // Pictures directory.
val baseDir = Environment.getExternalStorageDirectory().absolutePath + val baseDir = getPicturesDir(context).absolutePath
File.separator + Environment.DIRECTORY_PICTURES +
File.separator + context.getString(R.string.app_name)
val destDir = if (preferences.folderPerManga()) { val destDir = if (preferences.folderPerManga()) {
File(baseDir + File.separator + manga.title) File(baseDir + File.separator + manga.title)
} else { } else {
@ -739,11 +738,7 @@ class ReaderPresenter(
notifier.onClear() notifier.onClear()
// Pictures directory. // Pictures directory.
val destDir = File( val destDir = getPicturesDir(context)
Environment.getExternalStorageDirectory().absolutePath +
File.separator + Environment.DIRECTORY_PICTURES +
File.separator + context.getString(R.string.app_name)
)
// Copy file in background. // Copy file in background.
Observable.fromCallable { saveImages(firstPage, secondPage, isLTR, bg, destDir, manga) } Observable.fromCallable { saveImages(firstPage, secondPage, isLTR, bg, destDir, manga) }
@ -804,7 +799,7 @@ class ReaderPresenter(
val manga = manga ?: return val manga = manga ?: return
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
val destDir = File(context.cacheDir, "shared_image") val destDir = getTempShareDir(context)
Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file
.map { saveImage(page, destDir, manga) } .map { saveImage(page, destDir, manga) }
@ -823,7 +818,7 @@ class ReaderPresenter(
val manga = manga ?: return val manga = manga ?: return
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
val destDir = File(context.cacheDir, "shared_image") val destDir = getTempShareDir(context)
Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file
.map { saveImages(firstPage, secondPage, isLTR, bg, destDir, manga) } .map { saveImages(firstPage, secondPage, isLTR, bg, destDir, manga) }

View File

@ -3,11 +3,21 @@ package eu.kanade.tachiyomi.util.storage
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.net.toUri import androidx.core.net.toUri
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import java.io.File 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 * Returns the uri of a file
* *

View File

@ -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
}
}

View File

@ -29,19 +29,9 @@
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center"> android:gravity="center">
<Button <androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/reset_cover"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Theme.Widget.Button.FilledAccent"
android:textAllCaps="false"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/reset_cover" />
<Spinner
android:id="@+id/status" android:id="@+id/status"
android:minHeight="48dp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" /> android:layout_height="match_parent" />

View File

@ -38,13 +38,25 @@
</item> </item>
<item <item
android:id="@+id/action_edit_categories" android:id="@+id/cover_group"
android:title="@string/action_edit_categories" android:title="@string/manga_cover"
app:showAsAction="never" /> app:showAsAction="never">
<menu>
<item
android:id="@+id/action_share_cover"
android:title="@string/action_share" />
<item
android:id="@+id/action_save_cover"
android:title="@string/action_save" />
<item <item
android:id="@+id/action_edit_cover" android:id="@+id/action_edit_cover"
android:title="@string/action_edit_cover" android:title="@string/action_edit" />
</menu>
</item>
<item
android:id="@+id/action_edit_categories"
android:title="@string/action_edit_categories"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
@ -80,20 +92,4 @@
android:title="@string/toggle_dedupe" android:title="@string/toggle_dedupe"
android:visible="false" android:visible="false"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_save"
android:icon="@drawable/ic_save_black_24dp"
android:title="@string/action_save"
android:visible="false"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_share_cover"
android:icon="@drawable/ic_share_24dp"
android:title="@string/share_cover"
android:visible="false"
app:iconTint="?attr/colorOnPrimary"
app:showAsAction="ifRoom" />
</menu> </menu>

View File

@ -255,10 +255,6 @@
<string name="az_recommends">Voir les recommandations</string> <string name="az_recommends">Voir les recommandations</string>
<string name="merge">Fusionner</string> <string name="merge">Fusionner</string>
<string name="merge_with_another_source">Fusionner avec une autre</string> <string name="merge_with_another_source">Fusionner avec une autre</string>
<string name="cover_saved">Couverture sauvegardée</string>
<string name="share_cover">Partage de la couverture</string>
<string name="error_saving_cover">Erreurs sauvegarde de la couverture</string>
<string name="error_sharing_cover">Erreurs du partage de la couverture</string>
<!-- Manga info fragment --> <!-- Manga info fragment -->
<string name="hiatus">Hiatus</string> <string name="hiatus">Hiatus</string>

View File

@ -304,10 +304,6 @@
<string name="az_recommends">Смотреть Рекомендации</string> <string name="az_recommends">Смотреть Рекомендации</string>
<string name="merge">Миграция</string> <string name="merge">Миграция</string>
<string name="merge_with_another_source">Слиться С Другим</string> <string name="merge_with_another_source">Слиться С Другим</string>
<string name="cover_saved">Обложка сохранена </string>
<string name="share_cover">Поделиться обложкой </string>
<string name="error_saving_cover">Ошибка при сохранении обложки</string>
<string name="error_sharing_cover">Ошибка при публикации обложки</string>
<!-- Manga info fragment --> <!-- Manga info fragment -->
<string name="hiatus">Перерыв</string> <string name="hiatus">Перерыв</string>

View File

@ -559,6 +559,10 @@
<string name="download_custom">Custom</string> <string name="download_custom">Custom</string>
<string name="download_all">All</string> <string name="download_all">All</string>
<string name="download_unread">Unread</string> <string name="download_unread">Unread</string>
<string name="manga_cover">Cover</string>
<string name="cover_saved">Cover saved</string>
<string name="error_saving_cover">Error saving cover</string>
<string name="error_sharing_cover">Error sharing cover</string>
<string name="confirm_delete_chapters">Are you sure you want to delete the selected chapters?</string> <string name="confirm_delete_chapters">Are you sure you want to delete the selected chapters?</string>
<string name="invalid_download_dir">Invalid download location</string> <string name="invalid_download_dir">Invalid download location</string>
<string name="chapter_settings">Chapter settings</string> <string name="chapter_settings">Chapter settings</string>

View File

@ -315,10 +315,6 @@
<string name="az_recommends">See Recommendations</string> <string name="az_recommends">See Recommendations</string>
<string name="merge">Merge</string> <string name="merge">Merge</string>
<string name="merge_with_another_source">Merge With Another</string> <string name="merge_with_another_source">Merge With Another</string>
<string name="cover_saved">Cover saved</string>
<string name="share_cover">Share cover</string>
<string name="error_saving_cover">Error saving cover</string>
<string name="error_sharing_cover">Error sharing cover</string>
<!-- Manga info fragment --> <!-- Manga info fragment -->
<string name="hiatus">Hiatus</string> <string name="hiatus">Hiatus</string>