diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
index 280631fa4e..89b397b5eb 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
@@ -13,6 +13,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.PopupMenu
+import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
@@ -31,9 +32,12 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
+import org.yuzu.yuzu_emu.HomeNavigationDirections
+import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
+import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
@@ -75,6 +79,36 @@ class GamesFragment : Fragment() {
}
}
+ private fun launchQLaunch() {
+ try {
+ val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.QLaunch.entryId)
+ if (appletPath.isEmpty()) {
+ Toast.makeText(
+ requireContext(),
+ R.string.applets_error_applet,
+ Toast.LENGTH_SHORT
+ ).show()
+ return
+ }
+
+ NativeLibrary.setCurrentAppletId(AppletInfo.QLaunch.appletId)
+
+ val qlaunchGame = Game(
+ title = getString(R.string.qlaunch_applet),
+ path = appletPath
+ )
+
+ val action = HomeNavigationDirections.actionGlobalEmulationActivity(qlaunchGame)
+ findNavController().navigate(action)
+ } catch (e: Exception) {
+ Toast.makeText(
+ requireContext(),
+ "Failed to launch QLaunch: ${e.message}",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+
private fun getCurrentViewType(): Int {
val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val key = if (isLandscape) CarouselRecyclerView.CAROUSEL_VIEW_TYPE_LANDSCAPE else CarouselRecyclerView.CAROUSEL_VIEW_TYPE_PORTRAIT
@@ -177,6 +211,10 @@ class GamesFragment : Fragment() {
getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
}
+ binding.launchQlaunch?.setOnClickListener {
+ launchQLaunch()
+ }
+
setInsets()
}
@@ -498,6 +536,13 @@ class GamesFragment : Fragment() {
mlpFab.rightMargin = rightInset + fabPadding
binding.addDirectory.layoutParams = mlpFab
+ binding.launchQlaunch?.let { qlaunchButton ->
+ val mlpQLaunch = qlaunchButton.layoutParams as ViewGroup.MarginLayoutParams
+ mlpQLaunch.leftMargin = leftInset + fabPadding
+ mlpQLaunch.bottomMargin = barInsets.bottom + fabPadding
+ qlaunchButton.layoutParams = mlpQLaunch
+ }
+
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
val gestureInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
val bottomInset = maxOf(navInsets.bottom, gestureInsets.bottom, cutoutInsets.bottom)
diff --git a/src/android/app/src/main/res/layout-land/fragment_games.xml b/src/android/app/src/main/res/layout-land/fragment_games.xml
index d264f58baf..eee367e78b 100644
--- a/src/android/app/src/main/res/layout-land/fragment_games.xml
+++ b/src/android/app/src/main/res/layout-land/fragment_games.xml
@@ -222,4 +222,19 @@
app:iconTint="?attr/colorOnPrimary"
/>
+
+
\ No newline at end of file
diff --git a/src/android/app/src/main/res/layout/fragment_games.xml b/src/android/app/src/main/res/layout/fragment_games.xml
index 1f151955d9..2cfb7aa0ef 100644
--- a/src/android/app/src/main/res/layout/fragment_games.xml
+++ b/src/android/app/src/main/res/layout/fragment_games.xml
@@ -214,6 +214,21 @@
+
+