From e7995b4bd921915d881a981969ede41ae3696b3a Mon Sep 17 00:00:00 2001
From: Bnyro <82752168+Bnyro@users.noreply.github.com>
Date: Mon, 10 Apr 2023 12:44:41 +0200
Subject: [PATCH] In-built browser intent chooser (#3511)
Co-authored-by: Isira Seneviratne <31027858+Isira-Seneviratne@users.noreply.github.com>
---
app/src/main/AndroidManifest.xml | 11 ++---
.../github/libretube/helpers/IntentHelper.kt | 39 ++++++++++++----
.../libretube/ui/activities/AboutActivity.kt | 4 +-
.../libretube/ui/activities/HelpActivity.kt | 2 +-
.../ui/adapters/IntentChooserAdapter.kt | 44 +++++++++++++++++++
.../libretube/ui/fragments/PlayerFragment.kt | 2 +-
.../libretube/ui/sheets/IntentChooserSheet.kt | 37 ++++++++++++++++
.../ui/sheets/VideoOptionsBottomSheet.kt | 2 -
.../ui/viewholders/IntentChooserViewHolder.kt | 8 ++++
.../main/res/layout/intent_chooser_item.xml | 30 +++++++++++++
10 files changed, 160 insertions(+), 19 deletions(-)
create mode 100644 app/src/main/java/com/github/libretube/ui/adapters/IntentChooserAdapter.kt
create mode 100644 app/src/main/java/com/github/libretube/ui/sheets/IntentChooserSheet.kt
create mode 100644 app/src/main/java/com/github/libretube/ui/viewholders/IntentChooserViewHolder.kt
create mode 100644 app/src/main/res/layout/intent_chooser_item.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ac3774274..7c48270b5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -338,11 +338,6 @@
android:enabled="true"
android:exported="false" />
-
-
+
+
+
+
+
+
diff --git a/app/src/main/java/com/github/libretube/helpers/IntentHelper.kt b/app/src/main/java/com/github/libretube/helpers/IntentHelper.kt
index bc0836bb1..05a57eb68 100644
--- a/app/src/main/java/com/github/libretube/helpers/IntentHelper.kt
+++ b/app/src/main/java/com/github/libretube/helpers/IntentHelper.kt
@@ -2,18 +2,41 @@ package com.github.libretube.helpers
import android.content.Context
import android.content.Intent
-import android.net.Uri
+import android.content.pm.PackageManager
+import android.os.Build
+import androidx.core.net.toUri
+import androidx.fragment.app.FragmentManager
import com.github.libretube.R
import com.github.libretube.extensions.toastFromMainThread
+import com.github.libretube.ui.sheets.IntentChooserSheet
object IntentHelper {
- fun openLinkFromHref(context: Context, link: String) {
- val uri = Uri.parse(link)
- val launchIntent = Intent(Intent.ACTION_VIEW).setData(uri)
- try {
- context.startActivity(launchIntent)
- } catch (e: Exception) {
- context.toastFromMainThread(R.string.unknown_error)
+ fun openLinkFromHref(context: Context, fragmentManager: FragmentManager, link: String) {
+ val intent = Intent(Intent.ACTION_VIEW)
+ .setData(link.toUri())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ @Suppress("DEPRECATION")
+ val resolveInfoList = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ context.packageManager
+ .queryIntentActivities(
+ intent,
+ PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong())
+ )
+ } else {
+ context.packageManager
+ .queryIntentActivities(intent, PackageManager.MATCH_ALL)
+ }
+
+ if (resolveInfoList.isEmpty()) {
+ try {
+ context.startActivity(intent)
+ } catch (e: Exception) {
+ context.toastFromMainThread(R.string.error)
+ }
+ } else {
+ IntentChooserSheet(resolveInfoList, link)
+ .show(fragmentManager)
}
}
}
diff --git a/app/src/main/java/com/github/libretube/ui/activities/AboutActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/AboutActivity.kt
index 719a99fff..ada5df55c 100644
--- a/app/src/main/java/com/github/libretube/ui/activities/AboutActivity.kt
+++ b/app/src/main/java/com/github/libretube/ui/activities/AboutActivity.kt
@@ -59,7 +59,7 @@ class AboutActivity : BaseActivity() {
private fun setupCard(card: MaterialCardView, link: String) {
card.setOnClickListener {
- IntentHelper.openLinkFromHref(this, link)
+ IntentHelper.openLinkFromHref(this, supportFragmentManager, link)
}
card.setOnLongClickListener {
onLongClick(link)
@@ -77,7 +77,7 @@ class AboutActivity : BaseActivity() {
Snackbar.LENGTH_LONG
)
.setAction(R.string.open_copied) {
- IntentHelper.openLinkFromHref(this, href)
+ IntentHelper.openLinkFromHref(this, supportFragmentManager, href)
}
.setAnimationMode(Snackbar.ANIMATION_MODE_FADE)
.show()
diff --git a/app/src/main/java/com/github/libretube/ui/activities/HelpActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/HelpActivity.kt
index bff219596..ea2ccf86a 100644
--- a/app/src/main/java/com/github/libretube/ui/activities/HelpActivity.kt
+++ b/app/src/main/java/com/github/libretube/ui/activities/HelpActivity.kt
@@ -35,7 +35,7 @@ class HelpActivity : BaseActivity() {
private fun setupCard(card: MaterialCardView, link: String) {
card.setOnClickListener {
- IntentHelper.openLinkFromHref(this, link)
+ IntentHelper.openLinkFromHref(this, supportFragmentManager, link)
}
}
}
diff --git a/app/src/main/java/com/github/libretube/ui/adapters/IntentChooserAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/IntentChooserAdapter.kt
new file mode 100644
index 000000000..11073fb7f
--- /dev/null
+++ b/app/src/main/java/com/github/libretube/ui/adapters/IntentChooserAdapter.kt
@@ -0,0 +1,44 @@
+package com.github.libretube.ui.adapters
+
+import android.content.Intent
+import android.content.pm.ResolveInfo
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.net.toUri
+import androidx.recyclerview.widget.RecyclerView
+import com.github.libretube.databinding.IntentChooserItemBinding
+import com.github.libretube.ui.viewholders.IntentChooserViewHolder
+
+/**
+ * An adapter for opening an intent chooser inside the app, example-wise for urls
+ * @param packages A list of resolved packages found by a package query
+ */
+class IntentChooserAdapter(
+ private val packages: List,
+ private val queryUrl: String
+) : RecyclerView.Adapter() {
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IntentChooserViewHolder {
+ val layoutInflater = LayoutInflater.from(parent.context)
+ val binding = IntentChooserItemBinding.inflate(layoutInflater, parent, false)
+ return IntentChooserViewHolder(binding)
+ }
+
+ override fun getItemCount() = packages.size
+
+ override fun onBindViewHolder(holder: IntentChooserViewHolder, position: Int) {
+ val currentPackage = packages[position]
+ holder.binding.apply {
+ val drawable = currentPackage.loadIcon(root.context.packageManager)
+ appIconIV.setImageDrawable(drawable)
+ val appLabel = currentPackage.loadLabel(root.context.packageManager)
+ appNameTV.text = appLabel
+ root.setOnClickListener {
+ runCatching {
+ val intent = Intent(Intent.ACTION_VIEW, queryUrl.toUri())
+ .setPackage(currentPackage.activityInfo.packageName)
+ root.context.startActivity(intent)
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt
index 8c2190ba7..4da860ef3 100644
--- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt
+++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt
@@ -184,7 +184,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
private val handler = Handler(Looper.getMainLooper())
private val mainActivity get() = activity as MainActivity
- private val windowInsetsControllerCompat get() = WindowCompat
+ private val windowInsetsControllerCompat get() = WindowCompat
.getInsetsController(mainActivity.window, mainActivity.window.decorView)
/**
diff --git a/app/src/main/java/com/github/libretube/ui/sheets/IntentChooserSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/IntentChooserSheet.kt
new file mode 100644
index 000000000..4065aa064
--- /dev/null
+++ b/app/src/main/java/com/github/libretube/ui/sheets/IntentChooserSheet.kt
@@ -0,0 +1,37 @@
+package com.github.libretube.ui.sheets
+
+import android.content.pm.ResolveInfo
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.GridLayoutManager
+import com.github.libretube.databinding.BottomSheetBinding
+import com.github.libretube.ui.adapters.IntentChooserAdapter
+
+class IntentChooserSheet(
+ private val packages: List,
+ private val url: String
+) : BaseBottomSheet() {
+ private var _binding: BottomSheetBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = BottomSheetBinding.inflate(inflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.optionsRecycler.layoutManager = GridLayoutManager(context, 3)
+ binding.optionsRecycler.adapter = IntentChooserAdapter(packages, url)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt
index 55c29c819..8fcbb498c 100644
--- a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt
+++ b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt
@@ -18,9 +18,7 @@ import com.github.libretube.ui.dialogs.DownloadDialog
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.fragments.SubscriptionsFragment
import com.github.libretube.util.PlayingQueue
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
diff --git a/app/src/main/java/com/github/libretube/ui/viewholders/IntentChooserViewHolder.kt b/app/src/main/java/com/github/libretube/ui/viewholders/IntentChooserViewHolder.kt
new file mode 100644
index 000000000..f9dfb13fe
--- /dev/null
+++ b/app/src/main/java/com/github/libretube/ui/viewholders/IntentChooserViewHolder.kt
@@ -0,0 +1,8 @@
+package com.github.libretube.ui.viewholders
+
+import androidx.recyclerview.widget.RecyclerView
+import com.github.libretube.databinding.IntentChooserItemBinding
+
+class IntentChooserViewHolder(
+ val binding: IntentChooserItemBinding
+) : RecyclerView.ViewHolder(binding.root)
diff --git a/app/src/main/res/layout/intent_chooser_item.xml b/app/src/main/res/layout/intent_chooser_item.xml
new file mode 100644
index 000000000..4449bb3fc
--- /dev/null
+++ b/app/src/main/res/layout/intent_chooser_item.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file