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