aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPavelBARABANOV <pavelbarabanov94@gmail.com>2026-02-01 22:03:35 +0100
committercrueter <crueter@eden-emu.dev>2026-02-01 22:03:35 +0100
commitffdaf7369a5bc964b05a1803cd796aadfea13f4b (patch)
tree8f58b1278047f2823436c41cc2327eabfa2aade7 /src
parent5113f503d140c1edd8670d03d44bcb79fb1a9518 (diff)
[android] add qlaunch button (#3439)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3439 Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: Maufeat <sahyno1996@gmail.com> Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com> Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt61
-rw-r--r--src/android/app/src/main/jni/android_settings.h4
-rw-r--r--src/android/app/src/main/res/layout-land/fragment_games.xml17
-rw-r--r--src/android/app/src/main/res/layout/fragment_games.xml17
-rw-r--r--src/android/app/src/main/res/values/strings.xml6
8 files changed, 133 insertions, 1 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
index 40e75acff7..2059177621 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
@@ -36,6 +36,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"),
+ ENABLE_FOLDER_BUTTON("enable_folder_button"),
+ ENABLE_QLAUNCH_BUTTON("enable_qlaunch_button"),
+
ENABLE_UPDATE_CHECKS("enable_update_checks"),
JOYSTICK_REL_CENTER("joystick_rel_center"),
DPAD_SLIDE("dpad_slide"),
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index afa76362ff..870eec1a1b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -60,6 +60,11 @@ abstract class SettingsItem(
return NativeInput.getStyleIndex(0) != NpadStyleIndex.Handheld
}
+ // Can't edit enable_qlaunch_button if firmware is not available
+ if (setting.key == BooleanSetting.ENABLE_QLAUNCH_BUTTON.key) {
+ return NativeLibrary.isFirmwareAvailable()
+ }
+
// Can't edit settings that aren't saveable in per-game config even if they are switchable
if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) {
return false
@@ -795,6 +800,20 @@ abstract class SettingsItem(
)
)
put(
+ SwitchSetting(
+ BooleanSetting.ENABLE_FOLDER_BUTTON,
+ titleId = R.string.enable_folder_button,
+ descriptionId = R.string.enable_folder_button_description,
+ )
+ )
+ put(
+ SwitchSetting(
+ BooleanSetting.ENABLE_QLAUNCH_BUTTON,
+ titleId = R.string.enable_qlaunch_button,
+ descriptionId = R.string.enable_qlaunch_button_description,
+ )
+ )
+ put(
SingleChoiceSetting(
IntSetting.APP_LANGUAGE,
titleId = R.string.app_language,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index b6cb7acf1e..490f2a97a5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -1191,6 +1191,13 @@ class SettingsFragmentPresenter(
descriptionId = R.string.use_black_backgrounds_description
)
)
+
+ add(HeaderSetting(R.string.buttons))
+ add(BooleanSetting.ENABLE_FOLDER_BUTTON.key)
+ add(BooleanSetting.ENABLE_QLAUNCH_BUTTON.key)
+ if (!NativeLibrary.isFirmwareAvailable()) {
+ BooleanSetting.ENABLE_QLAUNCH_BUTTON.setBoolean(false)
+ }
}
}
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..6931a1f9d5 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
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.ui
@@ -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
@@ -27,10 +28,14 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import org.yuzu.yuzu_emu.HomeNavigationDirections
+import org.yuzu.yuzu_emu.NativeLibrary
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.features.settings.model.BooleanSetting
+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
@@ -173,10 +178,16 @@ class GamesFragment : Fragment() {
setupTopView()
+ updateButtonsVisibility()
+
binding.addDirectory.setOnClickListener {
getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
}
+ binding.launchQlaunch?.setOnClickListener {
+ launchQLaunch()
+ }
+
setInsets()
}
@@ -445,6 +456,47 @@ 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 updateButtonsVisibility() {
+ val showQLaunch = BooleanSetting.ENABLE_QLAUNCH_BUTTON.getBoolean()
+ val showFolder = BooleanSetting.ENABLE_FOLDER_BUTTON.getBoolean()
+ val isFirmwareAvailable = NativeLibrary.isFirmwareAvailable()
+
+ val shouldShowQLaunch = showQLaunch && isFirmwareAvailable
+ binding.launchQlaunch.visibility = if (shouldShowQLaunch) View.VISIBLE else View.GONE
+
+ binding.addDirectory.visibility = if (showFolder) View.VISIBLE else View.GONE
+ }
+
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -498,6 +550,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/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h
index f8260e183a..b6fd37c9dd 100644
--- a/src/android/app/src/main/jni/android_settings.h
+++ b/src/android/app/src/main/jni/android_settings.h
@@ -65,6 +65,10 @@ namespace AndroidSettings {
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
Settings::Category::Android};
+ Settings::Setting<bool> enable_folder_button{linkage, true, "enable_folder_button",
+ Settings::Category::Android};
+ Settings::Setting<bool> enable_qlaunch_button{linkage, false, "enable_qlaunch_button",
+ Settings::Category::Android};
// Input/performance overlay settings
std::vector<OverlayControlData> overlay_control_data;
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..da778eab69 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
@@ -220,6 +220,23 @@
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:iconTint="?attr/colorOnPrimary"
+ app:rippleColor="#99FFFFFF"
+ />
+
+ <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
+ android:id="@+id/launch_qlaunch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:contentDescription="Launch QLaunch"
+ android:text="@string/qlaunch_applet"
+ app:icon="@drawable/ic_home"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:textColor="?attr/colorOnPrimary"
+ app:backgroundTint="?attr/colorPrimary"
+ app:iconTint="?attr/colorOnPrimary"
+ app:rippleColor="#99FFFFFF"
/>
</androidx.constraintlayout.widget.ConstraintLayout> \ 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..921625e42b 100644
--- a/src/android/app/src/main/res/layout/fragment_games.xml
+++ b/src/android/app/src/main/res/layout/fragment_games.xml
@@ -215,6 +215,22 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
+ android:id="@+id/launch_qlaunch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:contentDescription="Launch QLaunch"
+ android:text="@string/qlaunch_applet"
+ app:icon="@drawable/ic_home"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:textColor="?attr/colorOnPrimary"
+ app:backgroundTint="?attr/colorPrimary"
+ app:iconTint="?attr/colorOnPrimary"
+ app:rippleColor="#99FFFFFF"
+ />
+
+ <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/add_directory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -227,6 +243,7 @@
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:iconTint="?attr/colorOnPrimary"
+ app:rippleColor="#99FFFFFF"
/>
</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 3740a54639..1e49450b95 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -1163,6 +1163,12 @@
<string name="use_black_backgrounds">Black backgrounds</string>
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
+ <!-- Buttons -->
+ <string name="enable_folder_button">Folder</string>
+ <string name="enable_folder_button_description">Show the button to add game folders</string>
+ <string name="enable_qlaunch_button">QLaunch</string>
+ <string name="enable_qlaunch_button_description">Show the button to launch QLaunch</string>
+
<!-- App Language -->
<string name="app_language">App Language</string>
<string name="app_language_description">Change the language of the app interface</string>