Improve manga link sharing

This commit is contained in:
Koitharu
2025-03-11 08:33:11 +02:00
parent b3028258ca
commit f689bf0cf7
6 changed files with 79 additions and 21 deletions

View File

@@ -6,6 +6,7 @@ import android.text.SpannableStringBuilder
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.collection.MutableObjectIntMap
import androidx.core.net.toUri
import androidx.core.os.LocaleListCompat
import androidx.core.text.buildSpannedString
import androidx.core.text.strikeThrough
@@ -125,7 +126,8 @@ val Manga.isBroken: Boolean
get() = source == UnknownMangaSource
val Manga.appUrl: Uri
get() = Uri.parse("https://kotatsu.app/manga").buildUpon()
get() = "https://kotatsu.app/manga".toUri()
.buildUpon()
.appendQueryParameter("source", source.name)
.appendQueryParameter("name", title)
.appendQueryParameter("url", url)

View File

@@ -12,6 +12,8 @@ import android.provider.Settings
import android.view.View
import androidx.annotation.CheckResult
import androidx.annotation.UiContext
import androidx.core.app.ShareCompat
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
@@ -29,7 +31,10 @@ import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.model.MangaSourceInfo
import org.koitharu.kotatsu.core.model.appUrl
import org.koitharu.kotatsu.core.model.getTitle
import org.koitharu.kotatsu.core.model.isBroken
import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaListFilter
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaPage
@@ -43,6 +48,8 @@ import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog
import org.koitharu.kotatsu.core.util.ext.connectivityManager
import org.koitharu.kotatsu.core.util.ext.findActivity
import org.koitharu.kotatsu.core.util.ext.getThemeDrawable
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.details.ui.DetailsActivity
@@ -72,6 +79,7 @@ import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.ellipsize
import org.koitharu.kotatsu.parsers.util.isNullOrEmpty
import org.koitharu.kotatsu.parsers.util.mapToArray
import org.koitharu.kotatsu.reader.ui.colorfilter.ColorFilterConfigActivity
@@ -96,6 +104,8 @@ import org.koitharu.kotatsu.stats.ui.StatsActivity
import org.koitharu.kotatsu.stats.ui.sheet.MangaStatsSheet
import org.koitharu.kotatsu.suggestions.ui.SuggestionsActivity
import org.koitharu.kotatsu.tracker.ui.updates.UpdatesActivity
import java.io.File
import com.google.android.material.R as materialR
class AppRouter private constructor(
private val activity: FragmentActivity?,
@@ -391,6 +401,37 @@ class AppRouter private constructor(
}.show()
}
fun showShareDialog(manga: Manga) {
if (manga.isBroken) {
return
}
if (manga.isLocal) {
manga.url.toUri().toFileOrNull()?.let {
shareFile(it)
}
return
}
buildAlertDialog(contextOrNull() ?: return) {
setIcon(context.getThemeDrawable(materialR.attr.actionModeShareDrawable))
setTitle(R.string.share)
setItems(
arrayOf(
context.getString(R.string.link_to_manga_in_app),
context.getString(R.string.link_to_manga_on_s, manga.source.getTitle(context)),
),
) { _, which ->
val link = when (which) {
0 -> manga.appUrl.toString()
1 -> manga.publicUrl
else -> return@setItems
}
shareLink(link, manga.title)
}
setNegativeButton(android.R.string.cancel, null)
setCancelable(true)
}.show()
}
fun showErrorDialog(error: Throwable, url: String? = null) {
ErrorDetailsDialog().withArgs(2) {
putSerializable(KEY_ERROR, error)
@@ -565,6 +606,25 @@ class AppRouter private constructor(
return fragment?.childFragmentManager ?: activity?.supportFragmentManager
}
private fun shareLink(link: String, title: String) {
val context = contextOrNull() ?: return
ShareCompat.IntentBuilder(context)
.setText(link)
.setType(TYPE_TEXT)
.setChooserTitle(context.getString(R.string.share_s, title.ellipsize(12)))
.startChooser()
}
private fun shareFile(file: File) { // TODO directory sharing support
val context = contextOrNull() ?: return
val intentBuilder = ShareCompat.IntentBuilder(context)
.setType(TYPE_CBZ)
val uri = FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.files", file)
intentBuilder.addStream(uri)
intentBuilder.setChooserTitle(context.getString(R.string.share_s, file.name))
intentBuilder.startChooser()
}
@UiContext
private fun contextOrNull(): Context? = activity ?: fragment?.context
@@ -726,6 +786,10 @@ class AppRouter private constructor(
private const val ACTION_ACCOUNT_SYNC_SETTINGS = "android.settings.ACCOUNT_SYNC_SETTINGS"
private const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
private const val TYPE_TEXT = "text/plain"
private const val TYPE_IMAGE = "image/*"
private const val TYPE_CBZ = "application/x-cbz"
private fun Class<out Fragment>.fragmentTag() = name // TODO
private inline fun <reified F : Fragment> fragmentTag() = F::class.java.fragmentTag()

View File

@@ -15,6 +15,7 @@ private const val TYPE_TEXT = "text/plain"
private const val TYPE_IMAGE = "image/*"
private const val TYPE_CBZ = "application/x-cbz"
@Deprecated("")
class ShareHelper(private val context: Context) {
fun shareMangaLink(manga: Manga) {

View File

@@ -5,20 +5,16 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.net.toFile
import androidx.core.net.toUri
import androidx.core.view.MenuProvider
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.LocalMangaSource
import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.util.ShareHelper
import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog
class DetailsMenuProvider(
private val activity: FragmentActivity,
@@ -47,23 +43,16 @@ class DetailsMenuProvider(
val manga = viewModel.getMangaOrNull() ?: return false
when (menuItem.itemId) {
R.id.action_share -> {
val shareHelper = ShareHelper(activity)
if (manga.isLocal) {
shareHelper.shareCbz(listOf(manga.url.toUri().toFile()))
} else {
shareHelper.shareMangaLink(manga)
}
activity.router.showShareDialog(manga)
}
R.id.action_delete -> {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.delete_manga)
.setMessage(activity.getString(R.string.text_delete_local_manga, manga.title))
.setPositiveButton(R.string.delete) { _, _ ->
viewModel.deleteLocal()
}
.setNegativeButton(android.R.string.cancel, null)
.show()
buildAlertDialog(activity) {
setTitle(R.string.delete_manga)
setMessage(activity.getString(R.string.text_delete_local_manga, manga.title))
setPositiveButton(R.string.delete) { _, _ -> viewModel.deleteLocal() }
setNegativeButton(android.R.string.cancel, null)
}.show()
}
R.id.action_save -> {

View File

@@ -814,4 +814,6 @@
<string name="error_disclaimer_manga">Try to open manga in a web browser to ensure it is available on its source.</string>
<string name="error_disclaimer_app_outdated">It looks like your version of Kotatsu is out of date. Please install the latest version to get all available fixes.</string>
<string name="error_disclaimer_report">You can submit a bug report to the developers. This will help us investigate and fix the issue.</string>
<string name="link_to_manga_on_s">Link to manga on %s</string>
<string name="link_to_manga_in_app">Link to manga in Kotatsu</string>
</resources>

View File

@@ -31,7 +31,7 @@ material = "1.13.0-alpha11"
moshi = "1.15.2"
okhttp = "4.12.0"
okio = "3.10.2"
parsers = "d5a4cf68c6"
parsers = "e83636edc0"
preference = "1.2.1"
recyclerview = "1.4.0"
room = "2.6.1"