diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt index 9a32e39c4d..61aa18c7f8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt @@ -30,6 +30,7 @@ import androidx.appcompat.view.ActionMode import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.SearchView import androidx.core.graphics.ColorUtils +import androidx.core.view.iterator import androidx.palette.graphics.Palette import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -177,6 +178,7 @@ class MangaDetailsController : private var currentAnimator: Animator? = null var headerHeight = 0 + var fullCoverActive = false override fun getTitle(): String? { return null @@ -190,6 +192,7 @@ class MangaDetailsController : override fun onViewCreated(view: View) { super.onViewCreated(view) coverColor = null + fullCoverActive = false setRecycler(view) setPaletteColor() @@ -756,6 +759,19 @@ class MangaDetailsController : searchView.clearFocus() } + val menuItems = menu.iterator() + while (menuItems.hasNext()) { + menuItems.next().isVisible = !fullCoverActive + } + val saveItem = menu.findItem(R.id.save) + val shareItem = menu.findItem(R.id.share) + saveItem.isVisible = fullCoverActive + shareItem.isVisible = fullCoverActive + if (fullCoverActive) { + saveItem.icon.setTint(Color.WHITE) + shareItem.icon.setTint(Color.WHITE) + } + setOnQueryTextChangeListener(searchView) { query = it ?: "" if (query.isNotEmpty()) getHeader()?.collapse() @@ -798,6 +814,28 @@ class MangaDetailsController : R.id.download_next, R.id.download_next_5, R.id.download_custom, R.id.download_unread, R.id.download_all -> downloadChapters( item.itemId ) + R.id.save -> { + if (presenter.saveCover()) { + activity?.toast(R.string.cover_saved) + } else { + activity?.toast(R.string.error_saving_cover) + } + } + R.id.share -> { + val cover = presenter.shareCover() + if (cover != null) { + 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.share))) + } else { + activity?.toast(R.string.error_sharing_cover) + } + } else -> return super.onOptionsItemSelected(item) } return true @@ -1324,6 +1362,24 @@ class MangaDetailsController : } expandedImageView.requestLayout() + val activity = activity as? MainActivity ?: return + val currTheme = activity.appbar.context.theme + val currColor = activity.drawerArrow?.color + if (!activity.isInNightMode()) { + activity.appbar.context.setTheme(R.style.ThemeOverlay_AppCompat_Dark_ActionBar) + + val iconPrimary = Color.WHITE + activity.toolbar.setTitleTextColor(iconPrimary) + activity.drawerArrow?.color = iconPrimary + activity.toolbar.overflowIcon?.setTint(iconPrimary) + activity.window.decorView.systemUiVisibility = + activity.window.decorView.systemUiVisibility.rem( + View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + ) + } + fullCoverActive = true + activity.invalidateOptionsMenu() + expandedImageView.post { val defMargin = 16.dpToPx expandedImageView.updateLayoutParams { @@ -1374,6 +1430,8 @@ class MangaDetailsController : expandedImageView.setOnClickListener { currentAnimator?.cancel() + fullCoverActive = false + activity.invalidateOptionsMenu() val rect2 = Rect() thumbView.getGlobalVisibleRect(rect2) expandedImageView.updateLayoutParams { @@ -1399,6 +1457,21 @@ class MangaDetailsController : play(ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f)) duration = shortAnimationDuration.toLong() interpolator = DecelerateInterpolator() + + if (!activity.isInNightMode()) { + activity.appbar.context.setTheme( + ThemeUtil.theme(presenter.preferences.theme()) + ) + + val iconPrimary = currColor ?: Color.WHITE + activity.toolbar.setTitleTextColor(iconPrimary) + activity.drawerArrow?.color = iconPrimary + activity.toolbar.overflowIcon?.setTint(iconPrimary) + activity.window.decorView.systemUiVisibility = + activity.window.decorView.systemUiVisibility.or( + View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + ) + } addListener( object : AnimatorListenerAdapter() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt index 4da74f6c84..cb6c3c2b94 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.manga import android.app.Application import android.graphics.Bitmap import android.net.Uri +import android.os.Environment import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper @@ -35,6 +36,7 @@ import eu.kanade.tachiyomi.util.chapter.ChapterUtil import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.lang.trimOrNull import eu.kanade.tachiyomi.util.storage.DiskUtil +import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.executeOnIO import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -694,6 +696,49 @@ class MangaDetailsPresenter( return false } + fun shareCover(): File? { + return try { + val destDir = File(coverCache.context.cacheDir, "shared_image") + val file = saveCover(destDir) + file + } catch (e: Exception) { + null + } + } + + fun saveCover(): Boolean { + return try { + val directory = File( + Environment.getExternalStorageDirectory().absolutePath + + File.separator + Environment.DIRECTORY_PICTURES + + File.separator + "Tachiyomi" + ) + saveCover(directory) + true + } catch (e: Exception) { + false + } + } + + private fun saveCover(directory: File): File { + val cover = coverCache.getCoverFile(manga) + 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 + } + fun isTracked(): Boolean = loggedServices.any { service -> tracks.any { it.sync_id == service.id } } diff --git a/app/src/main/res/menu/manga_details.xml b/app/src/main/res/menu/manga_details.xml index e526908064..582d7cce19 100644 --- a/app/src/main/res/menu/manga_details.xml +++ b/app/src/main/res/menu/manga_details.xml @@ -78,4 +78,17 @@ android:title="@string/migrate" app:showAsAction="never" /> + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e4ea7b555..659823bfb4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -394,6 +394,9 @@ Manga must be in your library to edit Remember this choice Source not installed + Cover saved + Error saving cover + Error sharing cover A chapter has been removed from the source:\n%2$s\nDelete its download?