mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 00:05:47 +00:00
[frontend, web] refactor: web service frontend rewrite (#221)
- Automatic verification based on regex - Token generation button - Removed unneeded links - public lobby creation [android] Signed-off-by: crueter <swurl@swurl.xyz> Co-authored-by: Aleksandr Popovich <alekpopo@pm.me> Co-authored-by: Aleksandr Popovich <alekpopo@proton.me> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/221 Co-authored-by: crueter <swurl@swurl.xyz> Co-committed-by: crueter <swurl@swurl.xyz>
This commit is contained in:
parent
2fe728766e
commit
94c66f98bf
34 changed files with 1985 additions and 327 deletions
|
@ -4,13 +4,12 @@ HEADER="$(cat "$PWD/.ci/license/header.txt")"
|
||||||
|
|
||||||
echo "Getting branch changes"
|
echo "Getting branch changes"
|
||||||
|
|
||||||
# I created this cursed POSIX abomination only to discover a better solution
|
BRANCH=`git rev-parse --abbrev-ref HEAD`
|
||||||
#BRANCH=`git rev-parse --abbrev-ref HEAD`
|
COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"`
|
||||||
#COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"`
|
RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}"
|
||||||
#RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}"
|
FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r`
|
||||||
#FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r`
|
|
||||||
|
|
||||||
FILES=$(git diff --name-only master)
|
#FILES=$(git diff --name-only master)
|
||||||
|
|
||||||
echo "Done"
|
echo "Done"
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.dialogs
|
package org.yuzu.yuzu_emu.dialogs
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
@ -19,6 +18,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogChatBinding
|
import org.yuzu.yuzu_emu.databinding.DialogChatBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemChatMessageBinding
|
import org.yuzu.yuzu_emu.databinding.ItemChatMessageBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
import org.yuzu.yuzu_emu.network.NetPlayManager
|
import org.yuzu.yuzu_emu.network.NetPlayManager
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -82,7 +82,7 @@ class ChatDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun sendMessage(message: String) {
|
private fun sendMessage(message: String) {
|
||||||
val username = NetPlayManager.getUsername(context)
|
val username = StringSetting.WEB_USERNAME.getString()
|
||||||
NetPlayManager.netPlaySendMessage(message)
|
NetPlayManager.netPlaySendMessage(message)
|
||||||
|
|
||||||
val chatMessage = ChatMessage(
|
val chatMessage = ChatMessage(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.dialogs
|
package org.yuzu.yuzu_emu.dialogs
|
||||||
|
@ -28,6 +28,7 @@ import info.debatty.java.stringsimilarity.JaroWinkler
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogLobbyBrowserBinding
|
import org.yuzu.yuzu_emu.databinding.DialogLobbyBrowserBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemLobbyRoomBinding
|
import org.yuzu.yuzu_emu.databinding.ItemLobbyRoomBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
import org.yuzu.yuzu_emu.network.NetPlayManager
|
import org.yuzu.yuzu_emu.network.NetPlayManager
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
@ -144,7 +145,7 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun joinRoom(room: NetPlayManager.RoomInfo, password: String) {
|
private fun joinRoom(room: NetPlayManager.RoomInfo, password: String) {
|
||||||
val username = NetPlayManager.getUsername(context)
|
val username = StringSetting.WEB_USERNAME.getString()
|
||||||
|
|
||||||
Thread {
|
Thread {
|
||||||
val result = NetPlayManager.netPlayJoinRoom(room.ip, room.port, username, password)
|
val result = NetPlayManager.netPlayJoinRoom(room.ip, room.port, username, password)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.dialogs
|
package org.yuzu.yuzu_emu.dialogs
|
||||||
|
@ -24,6 +24,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogMultiplayerConnectBinding
|
import org.yuzu.yuzu_emu.databinding.DialogMultiplayerConnectBinding
|
||||||
|
@ -32,6 +33,7 @@ import org.yuzu.yuzu_emu.databinding.DialogMultiplayerRoomBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemBanListBinding
|
import org.yuzu.yuzu_emu.databinding.ItemBanListBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemButtonNetplayBinding
|
import org.yuzu.yuzu_emu.databinding.ItemButtonNetplayBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemTextNetplayBinding
|
import org.yuzu.yuzu_emu.databinding.ItemTextNetplayBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
import org.yuzu.yuzu_emu.network.NetPlayManager
|
import org.yuzu.yuzu_emu.network.NetPlayManager
|
||||||
import org.yuzu.yuzu_emu.utils.CompatUtils
|
import org.yuzu.yuzu_emu.utils.CompatUtils
|
||||||
import org.yuzu.yuzu_emu.utils.GameHelper
|
import org.yuzu.yuzu_emu.utils.GameHelper
|
||||||
|
@ -180,9 +182,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
PopupMenu(view.context, view).apply {
|
PopupMenu(view.context, view).apply {
|
||||||
menuInflater.inflate(R.menu.menu_netplay_member, menu)
|
menuInflater.inflate(R.menu.menu_netplay_member, menu)
|
||||||
menu.findItem(R.id.action_kick).isEnabled = isModerator &&
|
menu.findItem(R.id.action_kick).isEnabled = isModerator &&
|
||||||
netPlayItems.name != NetPlayManager.getUsername(context)
|
netPlayItems.name != StringSetting.WEB_USERNAME.getString()
|
||||||
menu.findItem(R.id.action_ban).isEnabled = isModerator &&
|
menu.findItem(R.id.action_ban).isEnabled = isModerator &&
|
||||||
netPlayItems.name != NetPlayManager.getUsername(context)
|
netPlayItems.name != StringSetting.WEB_USERNAME.getString()
|
||||||
setOnMenuItemClickListener { item ->
|
setOnMenuItemClickListener { item ->
|
||||||
if (item.itemId == R.id.action_kick) {
|
if (item.itemId == R.id.action_kick) {
|
||||||
NetPlayManager.netPlayKickUser(netPlayItems.name)
|
NetPlayManager.netPlayKickUser(netPlayItems.name)
|
||||||
|
@ -297,13 +299,13 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
abstract class TextValidatorWatcher(
|
abstract class TextValidatorWatcher(
|
||||||
private val btnConfirm: Button,
|
private val btnConfirm: Button,
|
||||||
private val view: EditText,
|
private val layout: TextInputLayout,
|
||||||
private val errorMessage: String
|
private val errorMessage: String
|
||||||
) : TextWatcher {
|
) : TextWatcher {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val validStates: HashMap<EditText, Boolean> = hashMapOf()
|
val validStates: HashMap<TextInputLayout, Boolean> = hashMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun validate(s: String): Boolean
|
abstract fun validate(s: String): Boolean
|
||||||
|
|
||||||
override fun beforeTextChanged(
|
override fun beforeTextChanged(
|
||||||
|
@ -325,20 +327,20 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
override fun afterTextChanged(s: Editable?) {
|
override fun afterTextChanged(s: Editable?) {
|
||||||
val input = s.toString()
|
val input = s.toString()
|
||||||
val isValid = validate(input)
|
val isValid = validate(input)
|
||||||
view.error = if (isValid) null else errorMessage
|
layout.isErrorEnabled = !isValid
|
||||||
|
layout.error = if (isValid) null else errorMessage
|
||||||
|
|
||||||
validStates.put(view, isValid)
|
validStates[layout] = isValid
|
||||||
btnConfirm.isEnabled = !validStates.containsValue(false)
|
btnConfirm.isEnabled = !validStates.containsValue(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(alekpop, crueter): Properly handle getting banned (both during and in future connects)
|
// TODO(alekpop, crueter): Properly handle getting banned (both during and in future connects)
|
||||||
private fun showNetPlayInputDialog(isCreateRoom: Boolean) {
|
private fun showNetPlayInputDialog(isCreateRoom: Boolean) {
|
||||||
|
TextValidatorWatcher.validStates.clear()
|
||||||
val activity = CompatUtils.findActivity(context)
|
val activity = CompatUtils.findActivity(context)
|
||||||
val dialog = BottomSheetDialog(activity)
|
val dialog = BottomSheetDialog(activity)
|
||||||
|
|
||||||
val validStates: HashMap<EditText, Boolean> = hashMapOf()
|
|
||||||
|
|
||||||
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
dialog.behavior.skipCollapsed =
|
dialog.behavior.skipCollapsed =
|
||||||
|
@ -347,6 +349,11 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
val binding = DialogMultiplayerRoomBinding.inflate(LayoutInflater.from(activity))
|
val binding = DialogMultiplayerRoomBinding.inflate(LayoutInflater.from(activity))
|
||||||
dialog.setContentView(binding.root)
|
dialog.setContentView(binding.root)
|
||||||
|
|
||||||
|
val visibilityList: List<String> = listOf(
|
||||||
|
context.getString(R.string.multiplayer_public_visibility),
|
||||||
|
context.getString(R.string.multiplayer_unlisted_visibility),
|
||||||
|
)
|
||||||
|
|
||||||
binding.textTitle.text = activity.getString(
|
binding.textTitle.text = activity.getString(
|
||||||
if (isCreateRoom) R.string.multiplayer_create_room
|
if (isCreateRoom) R.string.multiplayer_create_room
|
||||||
else R.string.multiplayer_join_room
|
else R.string.multiplayer_join_room
|
||||||
|
@ -355,7 +362,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
// setup listeners etc
|
// setup listeners etc
|
||||||
val roomNameWatcher = object : TextValidatorWatcher(
|
val roomNameWatcher = object : TextValidatorWatcher(
|
||||||
binding.btnConfirm, // TODO(alekpop, crueter): Figure out a better way to deal with this?
|
binding.btnConfirm, // TODO(alekpop, crueter): Figure out a better way to deal with this?
|
||||||
binding.roomName,
|
binding.layoutRoomName,
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.multiplayer_room_name_error
|
R.string.multiplayer_room_name_error
|
||||||
)
|
)
|
||||||
|
@ -367,25 +374,32 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
val preferredWatcher = object : TextValidatorWatcher(
|
val preferredWatcher = object : TextValidatorWatcher(
|
||||||
binding.btnConfirm,
|
binding.btnConfirm,
|
||||||
binding.dropdownPreferredGameName,
|
binding.preferredGameName,
|
||||||
context.getString(R.string.multiplayer_required)
|
context.getString(R.string.multiplayer_required)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return s.isNotEmpty()
|
return s.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable?) {
|
val visibilityWatcher = object : TextValidatorWatcher(
|
||||||
super.afterTextChanged(s)
|
binding.btnConfirm,
|
||||||
|
binding.lobbyVisibility,
|
||||||
|
context.getString(R.string.multiplayer_token_required)
|
||||||
|
) {
|
||||||
|
override fun validate(s: String): Boolean {
|
||||||
|
if (s != context.getString(R.string.multiplayer_public_visibility)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// special case: remove dropdown arrow
|
val token = StringSetting.WEB_TOKEN.getString()
|
||||||
val input = s.toString()
|
return token.matches(Regex("[a-z]{48}"))
|
||||||
binding.preferredGameName.isEndIconVisible = validate(input)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ipWatcher = object : TextValidatorWatcher(
|
val ipWatcher = object : TextValidatorWatcher(
|
||||||
binding.btnConfirm,
|
binding.btnConfirm,
|
||||||
binding.ipAddress,
|
binding.layoutIpAddress,
|
||||||
context.getString(R.string.multiplayer_ip_error)
|
context.getString(R.string.multiplayer_ip_error)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
|
@ -400,17 +414,17 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
val usernameWatcher = object : TextValidatorWatcher(
|
val usernameWatcher = object : TextValidatorWatcher(
|
||||||
binding.btnConfirm,
|
binding.btnConfirm,
|
||||||
binding.username,
|
binding.layoutUsername,
|
||||||
context.getString(R.string.multiplayer_username_error)
|
context.getString(R.string.multiplayer_username_error)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
return s.length >= 5
|
return s.length in 4..20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val portWatcher = object : TextValidatorWatcher(
|
val portWatcher = object : TextValidatorWatcher(
|
||||||
binding.btnConfirm,
|
binding.btnConfirm,
|
||||||
binding.ipPort,
|
binding.layoutIpPort,
|
||||||
context.getString(R.string.multiplayer_port_error)
|
context.getString(R.string.multiplayer_port_error)
|
||||||
) {
|
) {
|
||||||
override fun validate(s: String): Boolean {
|
override fun validate(s: String): Boolean {
|
||||||
|
@ -421,6 +435,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
if (isCreateRoom) {
|
if (isCreateRoom) {
|
||||||
binding.roomName.addTextChangedListener(roomNameWatcher)
|
binding.roomName.addTextChangedListener(roomNameWatcher)
|
||||||
binding.dropdownPreferredGameName.addTextChangedListener(preferredWatcher)
|
binding.dropdownPreferredGameName.addTextChangedListener(preferredWatcher)
|
||||||
|
binding.dropdownLobbyVisibility.addTextChangedListener(visibilityWatcher)
|
||||||
|
|
||||||
binding.dropdownPreferredGameName.apply {
|
binding.dropdownPreferredGameName.apply {
|
||||||
setAdapter(
|
setAdapter(
|
||||||
|
@ -431,19 +446,35 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.dropdownLobbyVisibility.setText(context.getString(R.string.multiplayer_unlisted_visibility))
|
||||||
|
|
||||||
|
binding.dropdownLobbyVisibility.apply {
|
||||||
|
setAdapter(
|
||||||
|
ArrayAdapter(
|
||||||
|
activity,
|
||||||
|
R.layout.dropdown_item,
|
||||||
|
visibilityList
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.ipAddress.addTextChangedListener(ipWatcher)
|
binding.ipAddress.addTextChangedListener(ipWatcher)
|
||||||
binding.ipPort.addTextChangedListener(portWatcher)
|
binding.ipPort.addTextChangedListener(portWatcher)
|
||||||
binding.username.addTextChangedListener(usernameWatcher)
|
binding.username.addTextChangedListener(usernameWatcher)
|
||||||
|
|
||||||
|
binding.ipAddress.setText(NetPlayManager.getRoomAddress(activity))
|
||||||
binding.ipPort.setText(NetPlayManager.getRoomPort(activity))
|
binding.ipPort.setText(NetPlayManager.getRoomPort(activity))
|
||||||
binding.username.setText(NetPlayManager.getUsername(activity))
|
binding.username.setText(StringSetting.WEB_USERNAME.getString())
|
||||||
|
|
||||||
// manually trigger text listeners
|
// manually trigger text listeners
|
||||||
if (isCreateRoom) {
|
if (isCreateRoom) {
|
||||||
roomNameWatcher.afterTextChanged(binding.roomName.text)
|
roomNameWatcher.afterTextChanged(binding.roomName.text)
|
||||||
preferredWatcher.afterTextChanged(binding.dropdownPreferredGameName.text)
|
preferredWatcher.afterTextChanged(binding.dropdownPreferredGameName.text)
|
||||||
|
|
||||||
|
// It's not needed here, the watcher is called by the initial set method
|
||||||
|
// visibilityWatcher.afterTextChanged(binding.dropdownLobbyVisibility.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
ipWatcher.afterTextChanged(binding.ipAddress.text)
|
ipWatcher.afterTextChanged(binding.ipAddress.text)
|
||||||
|
@ -451,8 +482,10 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
usernameWatcher.afterTextChanged(binding.username.text)
|
usernameWatcher.afterTextChanged(binding.username.text)
|
||||||
|
|
||||||
binding.preferredGameName.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
binding.preferredGameName.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
||||||
|
binding.lobbyVisibility.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
||||||
binding.roomName.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
binding.roomName.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
||||||
binding.maxPlayersContainer.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
binding.maxPlayersContainer.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
binding.maxPlayersLabel.text = context.getString(
|
binding.maxPlayersLabel.text = context.getString(
|
||||||
R.string.multiplayer_max_players_value,
|
R.string.multiplayer_max_players_value,
|
||||||
binding.maxPlayers.value.toInt()
|
binding.maxPlayers.value.toInt()
|
||||||
|
@ -464,7 +497,6 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(alekpop, crueter): Room descriptions
|
// TODO(alekpop, crueter): Room descriptions
|
||||||
// TODO(alekpop, crueter): Public room creation
|
|
||||||
// TODO(alekpop, crueter): Preview preferred games
|
// TODO(alekpop, crueter): Preview preferred games
|
||||||
binding.btnConfirm.setOnClickListener {
|
binding.btnConfirm.setOnClickListener {
|
||||||
binding.btnConfirm.isEnabled = false
|
binding.btnConfirm.isEnabled = false
|
||||||
|
@ -487,6 +519,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
val preferredIdx = gameNameList.indexOfFirst { it[0] == preferredGameName }
|
val preferredIdx = gameNameList.indexOfFirst { it[0] == preferredGameName }
|
||||||
val preferredGameId = if (preferredIdx == -1) 0 else gameIdList[preferredIdx][0]
|
val preferredGameId = if (preferredIdx == -1) 0 else gameIdList[preferredIdx][0]
|
||||||
|
|
||||||
|
val visibility = binding.dropdownLobbyVisibility.text.toString()
|
||||||
|
val isPublic = visibility == context.getString(R.string.multiplayer_public_visibility)
|
||||||
|
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
val result = if (isCreateRoom) {
|
val result = if (isCreateRoom) {
|
||||||
NetPlayManager.netPlayCreateRoom(
|
NetPlayManager.netPlayCreateRoom(
|
||||||
|
@ -497,23 +532,26 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
preferredGameId,
|
preferredGameId,
|
||||||
password,
|
password,
|
||||||
roomName,
|
roomName,
|
||||||
maxPlayers
|
maxPlayers,
|
||||||
|
isPublic
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
NetPlayManager.netPlayJoinRoom(ipAddress, port, username, password)
|
NetPlayManager.netPlayJoinRoom(ipAddress, port, username, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
// TODO(alekpop, crueter): These need to be moved as settings, editable in a tab
|
StringSetting.WEB_USERNAME.setString(username)
|
||||||
NetPlayManager.setUsername(activity, username)
|
|
||||||
NetPlayManager.setRoomPort(activity, portStr)
|
NetPlayManager.setRoomPort(activity, portStr)
|
||||||
|
NetPlayManager.setRoomAddress(activity, ipAddress)
|
||||||
if (!isCreateRoom) NetPlayManager.setRoomAddress(activity, ipAddress)
|
if (!isCreateRoom) NetPlayManager.setRoomAddress(activity, ipAddress)
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
YuzuApplication.appContext,
|
YuzuApplication.appContext,
|
||||||
if (isCreateRoom) R.string.multiplayer_create_room_success
|
if (isCreateRoom) R.string.multiplayer_create_room_success
|
||||||
else R.string.multiplayer_join_room_success,
|
else R.string.multiplayer_join_room_success,
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
@ -521,6 +559,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
R.string.multiplayer_could_not_connect,
|
R.string.multiplayer_could_not_connect,
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
binding.btnConfirm.isEnabled = true
|
binding.btnConfirm.isEnabled = true
|
||||||
binding.btnConfirm.text = activity.getString(R.string.ok)
|
binding.btnConfirm.text = activity.getString(R.string.ok)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -9,9 +12,8 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
|
||||||
DRIVER_PATH("driver_path"),
|
DRIVER_PATH("driver_path"),
|
||||||
DEVICE_NAME("device_name"),
|
DEVICE_NAME("device_name"),
|
||||||
|
|
||||||
// TODO(crueter, alekpop): Netplay/settings needs to be properly worked into settings
|
WEB_TOKEN("eden_token"),
|
||||||
WEB_TOKEN("yuzu_token"),
|
WEB_USERNAME("eden_username"),
|
||||||
WEB_USERNAME("yuzu_username"),
|
|
||||||
;
|
;
|
||||||
|
|
||||||
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
|
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
|
||||||
|
|
|
@ -284,11 +284,32 @@ abstract class SettingsItem(
|
||||||
descriptionId = R.string.use_custom_rtc_description
|
descriptionId = R.string.use_custom_rtc_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
put(
|
put(
|
||||||
StringInputSetting(
|
StringInputSetting(
|
||||||
StringSetting.WEB_TOKEN,
|
StringSetting.WEB_TOKEN,
|
||||||
titleId = R.string.web_token,
|
titleId = R.string.web_token,
|
||||||
descriptionId = R.string.web_token_description
|
descriptionId = R.string.web_token_description,
|
||||||
|
onGenerate = {
|
||||||
|
val chars = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
(1..48).map { chars.random() }.joinToString("")
|
||||||
|
},
|
||||||
|
validator = { s ->
|
||||||
|
s?.matches(Regex("[a-z]{48}")) == true
|
||||||
|
},
|
||||||
|
errorId = R.string.multiplayer_token_error
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
put(
|
||||||
|
StringInputSetting(
|
||||||
|
StringSetting.WEB_USERNAME,
|
||||||
|
titleId = R.string.web_username,
|
||||||
|
descriptionId = R.string.web_username_description,
|
||||||
|
validator = { s ->
|
||||||
|
s?.length in 4..20
|
||||||
|
},
|
||||||
|
errorId = R.string.multiplayer_username_error
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(DateTimeSetting(LongSetting.CUSTOM_RTC, titleId = R.string.set_custom_rtc))
|
put(DateTimeSetting(LongSetting.CUSTOM_RTC, titleId = R.string.set_custom_rtc))
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||||
|
|
||||||
|
import android.text.Editable
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
|
||||||
|
|
||||||
|
@ -11,7 +15,10 @@ class StringInputSetting(
|
||||||
@StringRes titleId: Int = 0,
|
@StringRes titleId: Int = 0,
|
||||||
titleString: String = "",
|
titleString: String = "",
|
||||||
@StringRes descriptionId: Int = 0,
|
@StringRes descriptionId: Int = 0,
|
||||||
descriptionString: String = ""
|
descriptionString: String = "",
|
||||||
|
val onGenerate: (() -> String)? = null,
|
||||||
|
val validator: ((s: String?) -> Boolean)? = null,
|
||||||
|
@StringRes val errorId: Int = 0
|
||||||
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
|
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
|
||||||
override val type = TYPE_STRING_INPUT
|
override val type = TYPE_STRING_INPUT
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -6,9 +9,13 @@ package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
@ -138,6 +145,46 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||||
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
|
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
|
||||||
val item = settingsViewModel.clickedItem as StringInputSetting
|
val item = settingsViewModel.clickedItem as StringInputSetting
|
||||||
stringInputBinding.editText.setText(item.getSelectedValue())
|
stringInputBinding.editText.setText(item.getSelectedValue())
|
||||||
|
|
||||||
|
val onGenerate = item.onGenerate
|
||||||
|
stringInputBinding.generate.isVisible = onGenerate != null
|
||||||
|
|
||||||
|
if (onGenerate != null) {
|
||||||
|
stringInputBinding.generate.setOnClickListener {
|
||||||
|
stringInputBinding.editText.setText(onGenerate())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val validator = item.validator
|
||||||
|
|
||||||
|
if (validator != null) {
|
||||||
|
val watcher = object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(
|
||||||
|
s: CharSequence?,
|
||||||
|
start: Int,
|
||||||
|
count: Int,
|
||||||
|
after: Int
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTextChanged(
|
||||||
|
s: CharSequence?,
|
||||||
|
start: Int,
|
||||||
|
before: Int,
|
||||||
|
count: Int
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterTextChanged(s: Editable?) {
|
||||||
|
stringInputBinding.editText.error =
|
||||||
|
if (validator(s.toString())) null else requireContext().getString(item.errorId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stringInputBinding.editText.addTextChangedListener(watcher)
|
||||||
|
watcher.afterTextChanged(stringInputBinding.editText.text)
|
||||||
|
}
|
||||||
|
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(item.title)
|
.setTitle(item.title)
|
||||||
.setView(stringInputBinding.root)
|
.setView(stringInputBinding.root)
|
||||||
|
|
|
@ -212,30 +212,38 @@ class SettingsFragmentPresenter(
|
||||||
add(BooleanSetting.USE_CUSTOM_RTC.key)
|
add(BooleanSetting.USE_CUSTOM_RTC.key)
|
||||||
add(LongSetting.CUSTOM_RTC.key)
|
add(LongSetting.CUSTOM_RTC.key)
|
||||||
|
|
||||||
// TODO(alekpop): Add functionality
|
add(HeaderSetting(R.string.network))
|
||||||
// add(HeaderSetting(R.string.network))
|
add(StringSetting.WEB_TOKEN.key)
|
||||||
// add(StringSetting.WEB_TOKEN.key)
|
add(StringSetting.WEB_USERNAME.key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
|
private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
|
||||||
sl.apply {
|
sl.apply {
|
||||||
// TODO(crueter): reorganize this, this is awful
|
// TODO(crueter): reorganize this, this is awful
|
||||||
|
add(HeaderSetting(R.string.backend))
|
||||||
|
|
||||||
add(IntSetting.RENDERER_ACCURACY.key)
|
add(IntSetting.RENDERER_ACCURACY.key)
|
||||||
add(IntSetting.RENDERER_RESOLUTION.key)
|
add(IntSetting.RENDERER_RESOLUTION.key)
|
||||||
add(IntSetting.RENDERER_VSYNC.key)
|
|
||||||
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
|
||||||
add(IntSetting.FSR_SHARPENING_SLIDER.key)
|
|
||||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
|
||||||
add(IntSetting.MAX_ANISOTROPY.key)
|
|
||||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
|
||||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
|
||||||
add(IntSetting.VERTICAL_ALIGNMENT.key)
|
|
||||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
|
||||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||||
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
||||||
|
|
||||||
|
add(HeaderSetting(R.string.processing))
|
||||||
|
|
||||||
|
add(IntSetting.RENDERER_VSYNC.key)
|
||||||
|
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||||
|
add(IntSetting.MAX_ANISOTROPY.key)
|
||||||
|
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
||||||
|
add(IntSetting.FSR_SHARPENING_SLIDER.key)
|
||||||
|
|
||||||
|
add(HeaderSetting(R.string.display))
|
||||||
|
|
||||||
|
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||||
|
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||||
|
add(IntSetting.VERTICAL_ALIGNMENT.key)
|
||||||
|
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.network
|
package org.yuzu.yuzu_emu.network
|
||||||
|
@ -16,6 +16,7 @@ import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.dialogs.ChatMessage
|
import org.yuzu.yuzu_emu.dialogs.ChatMessage
|
||||||
import java.net.Inet4Address
|
import java.net.Inet4Address
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
object NetPlayManager {
|
object NetPlayManager {
|
||||||
external fun netPlayCreateRoom(
|
external fun netPlayCreateRoom(
|
||||||
|
@ -26,7 +27,8 @@ object NetPlayManager {
|
||||||
preferredGameId: Long,
|
preferredGameId: Long,
|
||||||
password: String,
|
password: String,
|
||||||
roomName: String,
|
roomName: String,
|
||||||
maxPlayers: Int
|
maxPlayers: Int,
|
||||||
|
isPublic: Boolean
|
||||||
): Int
|
): Int
|
||||||
|
|
||||||
external fun netPlayJoinRoom(
|
external fun netPlayJoinRoom(
|
||||||
|
@ -125,17 +127,6 @@ object NetPlayManager {
|
||||||
adapterRefreshListener = listener
|
adapterRefreshListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUsername(activity: Context): String {
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
||||||
val name = "Eden${(Math.random() * 100).toInt()}"
|
|
||||||
return prefs.getString("NetPlayUsername", name) ?: name
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setUsername(activity: Activity, name: String) {
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
||||||
prefs.edit().putString("NetPlayUsername", name).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRoomAddress(activity: Activity): String {
|
fun getRoomAddress(activity: Activity): String {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
val address = getIpAddressByWifi(activity)
|
val address = getIpAddressByWifi(activity)
|
||||||
|
@ -144,7 +135,7 @@ object NetPlayManager {
|
||||||
|
|
||||||
fun setRoomAddress(activity: Activity, address: String) {
|
fun setRoomAddress(activity: Activity, address: String) {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
prefs.edit().putString("NetPlayRoomAddress", address).apply()
|
prefs.edit { putString("NetPlayRoomAddress", address) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRoomPort(activity: Activity): String {
|
fun getRoomPort(activity: Activity): String {
|
||||||
|
@ -154,7 +145,7 @@ object NetPlayManager {
|
||||||
|
|
||||||
fun setRoomPort(activity: Activity, port: String) {
|
fun setRoomPort(activity: Activity, port: String) {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
prefs.edit().putString("NetPlayRoomPort", port).apply()
|
prefs.edit { putString("NetPlayRoomPort", port) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val chatMessages = mutableListOf<ChatMessage>()
|
private val chatMessages = mutableListOf<ChatMessage>()
|
||||||
|
|
|
@ -975,12 +975,12 @@ Java_org_yuzu_yuzu_1emu_network_NetPlayManager_netPlayGetPublicRooms(
|
||||||
JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_network_NetPlayManager_netPlayCreateRoom(
|
JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_network_NetPlayManager_netPlayCreateRoom(
|
||||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring ipaddress, jint port,
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring ipaddress, jint port,
|
||||||
jstring username, jstring preferredGameName, jlong preferredGameId, jstring password,
|
jstring username, jstring preferredGameName, jlong preferredGameId, jstring password,
|
||||||
jstring room_name, jint max_players) {
|
jstring room_name, jint max_players, jboolean isPublic) {
|
||||||
return static_cast<jint>(
|
return static_cast<jint>(
|
||||||
multiplayer->NetPlayCreateRoom(Common::Android::GetJString(env, ipaddress), port,
|
multiplayer->NetPlayCreateRoom(Common::Android::GetJString(env, ipaddress), port,
|
||||||
Common::Android::GetJString(env, username), Common::Android::GetJString(env, preferredGameName),
|
Common::Android::GetJString(env, username), Common::Android::GetJString(env, preferredGameName),
|
||||||
preferredGameId,Common::Android::GetJString(env, password),
|
preferredGameId,Common::Android::GetJString(env, password),
|
||||||
Common::Android::GetJString(env, room_name), max_players));
|
Common::Android::GetJString(env, room_name), max_players, isPublic));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_network_NetPlayManager_netPlayJoinRoom(
|
JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_network_NetPlayManager_netPlayJoinRoom(
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
@ -20,4 +21,13 @@
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/generate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:text="@string/generate"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/edit_text_layout"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/edit_text_layout" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
android:textColor="?attr/colorOnSurface" />
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_ip_address"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/multiplayer_ip_address"
|
android:hint="@string/multiplayer_ip_address"
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_ip_port"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/multiplayer_ip_port"
|
android:hint="@string/multiplayer_ip_port"
|
||||||
|
@ -47,6 +49,7 @@
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_username"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/multiplayer_username"
|
android:hint="@string/multiplayer_username"
|
||||||
|
@ -89,6 +92,7 @@
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/layout_room_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/multiplayer_room_name"
|
android:hint="@string/multiplayer_room_name"
|
||||||
|
@ -125,6 +129,21 @@
|
||||||
android:text="@string/multiplayer_max_players_value" />
|
android:text="@string/multiplayer_max_players_value" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/lobby_visibility"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:hint="@string/multiplayer_lobby_type"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/dropdown_lobby_visibility"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn_confirm"
|
android:id="@+id/btn_confirm"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
1453
src/android/app/src/main/res/values-sr/strings.xml
Normal file
1453
src/android/app/src/main/res/values-sr/strings.xml
Normal file
File diff suppressed because it is too large
Load diff
|
@ -62,6 +62,7 @@
|
||||||
<item>@string/language_spanish</item>
|
<item>@string/language_spanish</item>
|
||||||
<item>@string/language_taiwanese</item>
|
<item>@string/language_taiwanese</item>
|
||||||
<item>@string/language_traditional_chinese</item>
|
<item>@string/language_traditional_chinese</item>
|
||||||
|
<item>@string/language_serbian</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<integer-array name="languageValues">
|
<integer-array name="languageValues">
|
||||||
|
@ -83,6 +84,7 @@
|
||||||
<item>5</item>
|
<item>5</item>
|
||||||
<item>11</item>
|
<item>11</item>
|
||||||
<item>16</item>
|
<item>16</item>
|
||||||
|
<item>18</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="rendererApiNames">
|
<string-array name="rendererApiNames">
|
||||||
|
|
|
@ -204,18 +204,22 @@
|
||||||
<string name="emulation_multiplayer">Multiplayer</string>
|
<string name="emulation_multiplayer">Multiplayer</string>
|
||||||
<string name="multiplayer_game_name">Preferred Games</string>
|
<string name="multiplayer_game_name">Preferred Games</string>
|
||||||
<string name="multiplayer_preferred_game_name">Preferred Game</string>
|
<string name="multiplayer_preferred_game_name">Preferred Game</string>
|
||||||
|
<string name="multiplayer_lobby_type">Lobby Type</string>
|
||||||
<string name="multiplayer_no_game">No Games Found</string>
|
<string name="multiplayer_no_game">No Games Found</string>
|
||||||
<string name="multiplayer_preferred_game_name_invalid">You must choose a Preferred Game to host a room.</string>
|
<string name="multiplayer_preferred_game_name_invalid">You must choose a Preferred Game to host a room.</string>
|
||||||
<string name="multiplayer_room_name_error">Must be between 3 and 20 characters</string>
|
<string name="multiplayer_room_name_error">Must be between 3 and 20 characters</string>
|
||||||
<string name="multiplayer_required">Required</string>
|
<string name="multiplayer_required">Required</string>
|
||||||
|
<string name="multiplayer_token_required">Web Token required, go to Advanced Settings -> System -> Network</string>
|
||||||
<string name="multiplayer_ip_error">Invalid IP format</string>
|
<string name="multiplayer_ip_error">Invalid IP format</string>
|
||||||
<string name="multiplayer_username_error">Must be at least 5 characters</string>
|
<string name="multiplayer_username_error">Must be between 4–20 characters</string>
|
||||||
|
<string name="multiplayer_token_error">Must be 48 characters, and lowercase a-z only</string>
|
||||||
<string name="multiplayer_port_error">Must be between 1 and 65535</string>
|
<string name="multiplayer_port_error">Must be between 1 and 65535</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="ok">Ok</string>
|
<string name="ok">Ok</string>
|
||||||
<string name="refresh">Refresh</string>
|
<string name="refresh">Refresh</string>
|
||||||
<string name="room_list">Room List</string>
|
<string name="room_list">Room List</string>
|
||||||
|
<string name="multiplayer_public_visibility">Public</string>
|
||||||
|
<string name="multiplayer_unlisted_visibility">Unlisted</string>
|
||||||
|
|
||||||
<!-- Setup strings -->
|
<!-- Setup strings -->
|
||||||
<string name="welcome">Welcome!</string>
|
<string name="welcome">Welcome!</string>
|
||||||
|
@ -443,12 +447,20 @@
|
||||||
<string name="use_custom_rtc_description">Allows you to set a custom real-time clock separate from your current system time.</string>
|
<string name="use_custom_rtc_description">Allows you to set a custom real-time clock separate from your current system time.</string>
|
||||||
<string name="set_custom_rtc">Set custom RTC</string>
|
<string name="set_custom_rtc">Set custom RTC</string>
|
||||||
|
|
||||||
|
<string name="generate">Generate</string>
|
||||||
|
|
||||||
<!-- Network settings strings -->
|
<!-- Network settings strings -->
|
||||||
<string name="web_token">Web Token</string>
|
<string name="web_token">Web Token</string>
|
||||||
<string name="web_token_description">Web token used for creating public lobbies. It is a 48-character string containing only lowercase a-z.</string>
|
<string name="web_token_description">Web token used for creating public lobbies. It is a 48-character string containing only lowercase a-z.</string>
|
||||||
|
<string name="web_username">Web Username</string>
|
||||||
|
<string name="web_username_description">Username to be shown in multiplayer lobbies. It must be 4–20 characters.</string>
|
||||||
<string name="network">Network</string>
|
<string name="network">Network</string>
|
||||||
|
|
||||||
<!-- Graphics settings strings -->
|
<!-- Graphics settings strings -->
|
||||||
|
<string name="backend">Backend</string>
|
||||||
|
<string name="display">Display</string>
|
||||||
|
<string name="processing">Post-Processing</string>
|
||||||
|
|
||||||
<string name="frame_skipping">WIP: Frameskip</string>
|
<string name="frame_skipping">WIP: Frameskip</string>
|
||||||
<string name="frame_skipping_description">Toggle frame skipping to improve performance by reducing the number of rendered frames. This feature is still being worked on and will be enabled in future releases.</string>
|
<string name="frame_skipping_description">Toggle frame skipping to improve performance by reducing the number of rendered frames. This feature is still being worked on and will be enabled in future releases.</string>
|
||||||
<string name="renderer_accuracy">Accuracy level</string>
|
<string name="renderer_accuracy">Accuracy level</string>
|
||||||
|
@ -820,6 +832,7 @@
|
||||||
<string name="language_simplified_chinese" translatable="false">简体中文</string>
|
<string name="language_simplified_chinese" translatable="false">简体中文</string>
|
||||||
<string name="language_traditional_chinese" translatable="false">正體中文</string>
|
<string name="language_traditional_chinese" translatable="false">正體中文</string>
|
||||||
<string name="language_brazilian_portuguese" translatable="false">Português do Brasil</string>
|
<string name="language_brazilian_portuguese" translatable="false">Português do Brasil</string>
|
||||||
|
<string name="language_serbian" translatable="false">српски</string>
|
||||||
|
|
||||||
<!-- Memory Sizes -->
|
<!-- Memory Sizes -->
|
||||||
<string name="memory_byte">Byte</string>
|
<string name="memory_byte">Byte</string>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "common/android/id_cache.h"
|
#include "common/android/id_cache.h"
|
||||||
|
@ -10,13 +10,17 @@
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "android/log.h"
|
#include "android/log.h"
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "web_service/web_backend.h"
|
||||||
|
#include "web_service/verify_user_jwt.h"
|
||||||
|
#include "web_service/web_result.h"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
namespace IDCache = Common::Android;
|
namespace IDCache = Common::Android;
|
||||||
|
|
||||||
AndroidMultiplayer::AndroidMultiplayer(Core::System& system_,
|
AndroidMultiplayer::AndroidMultiplayer(Core::System &system_,
|
||||||
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
|
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
|
||||||
: system{system_}, announce_multiplayer_session(session) {}
|
: system{system_}, announce_multiplayer_session(session) {}
|
||||||
|
|
||||||
|
@ -27,8 +31,8 @@ void AndroidMultiplayer::AddNetPlayMessage(jint type, jstring msg) {
|
||||||
IDCache::GetAddNetPlayMessage(), type, msg);
|
IDCache::GetAddNetPlayMessage(), type, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidMultiplayer::AddNetPlayMessage(int type, const std::string& msg) {
|
void AndroidMultiplayer::AddNetPlayMessage(int type, const std::string &msg) {
|
||||||
JNIEnv* env = IDCache::GetEnvForThread();
|
JNIEnv *env = IDCache::GetEnvForThread();
|
||||||
AddNetPlayMessage(type, Common::Android::ToJString(env, msg));
|
AddNetPlayMessage(type, Common::Android::ToJString(env, msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +50,7 @@ bool AndroidMultiplayer::NetworkInit() {
|
||||||
|
|
||||||
if (auto member = Network::GetRoomMember().lock()) {
|
if (auto member = Network::GetRoomMember().lock()) {
|
||||||
// register the network structs to use in slots and signals
|
// register the network structs to use in slots and signals
|
||||||
member->BindOnStateChanged([this](const Network::RoomMember::State& state) {
|
member->BindOnStateChanged([this](const Network::RoomMember::State &state) {
|
||||||
if (state == Network::RoomMember::State::Joined ||
|
if (state == Network::RoomMember::State::Joined ||
|
||||||
state == Network::RoomMember::State::Moderator) {
|
state == Network::RoomMember::State::Moderator) {
|
||||||
NetPlayStatus status;
|
NetPlayStatus status;
|
||||||
|
@ -64,7 +68,7 @@ bool AndroidMultiplayer::NetworkInit() {
|
||||||
AddNetPlayMessage(static_cast<int>(status), msg);
|
AddNetPlayMessage(static_cast<int>(status), msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
member->BindOnError([this](const Network::RoomMember::Error& error) {
|
member->BindOnError([this](const Network::RoomMember::Error &error) {
|
||||||
NetPlayStatus status;
|
NetPlayStatus status;
|
||||||
std::string msg;
|
std::string msg;
|
||||||
switch (error) {
|
switch (error) {
|
||||||
|
@ -107,29 +111,30 @@ bool AndroidMultiplayer::NetworkInit() {
|
||||||
}
|
}
|
||||||
AddNetPlayMessage(static_cast<int>(status), msg);
|
AddNetPlayMessage(static_cast<int>(status), msg);
|
||||||
});
|
});
|
||||||
member->BindOnStatusMessageReceived([this](const Network::StatusMessageEntry& status_message) {
|
member->BindOnStatusMessageReceived(
|
||||||
NetPlayStatus status = NetPlayStatus::NO_ERROR;
|
[this](const Network::StatusMessageEntry &status_message) {
|
||||||
std::string msg(status_message.nickname);
|
NetPlayStatus status = NetPlayStatus::NO_ERROR;
|
||||||
switch (status_message.type) {
|
std::string msg(status_message.nickname);
|
||||||
case Network::IdMemberJoin:
|
switch (status_message.type) {
|
||||||
status = NetPlayStatus::MEMBER_JOIN;
|
case Network::IdMemberJoin:
|
||||||
break;
|
status = NetPlayStatus::MEMBER_JOIN;
|
||||||
case Network::IdMemberLeave:
|
break;
|
||||||
status = NetPlayStatus::MEMBER_LEAVE;
|
case Network::IdMemberLeave:
|
||||||
break;
|
status = NetPlayStatus::MEMBER_LEAVE;
|
||||||
case Network::IdMemberKicked:
|
break;
|
||||||
status = NetPlayStatus::MEMBER_KICKED;
|
case Network::IdMemberKicked:
|
||||||
break;
|
status = NetPlayStatus::MEMBER_KICKED;
|
||||||
case Network::IdMemberBanned:
|
break;
|
||||||
status = NetPlayStatus::MEMBER_BANNED;
|
case Network::IdMemberBanned:
|
||||||
break;
|
status = NetPlayStatus::MEMBER_BANNED;
|
||||||
case Network::IdAddressUnbanned:
|
break;
|
||||||
status = NetPlayStatus::ADDRESS_UNBANNED;
|
case Network::IdAddressUnbanned:
|
||||||
break;
|
status = NetPlayStatus::ADDRESS_UNBANNED;
|
||||||
}
|
break;
|
||||||
AddNetPlayMessage(static_cast<int>(status), msg);
|
}
|
||||||
});
|
AddNetPlayMessage(static_cast<int>(status), msg);
|
||||||
member->BindOnChatMessageReceived([this](const Network::ChatEntry& chat) {
|
});
|
||||||
|
member->BindOnChatMessageReceived([this](const Network::ChatEntry &chat) {
|
||||||
NetPlayStatus status = NetPlayStatus::CHAT_MESSAGE;
|
NetPlayStatus status = NetPlayStatus::CHAT_MESSAGE;
|
||||||
std::string msg(chat.nickname);
|
std::string msg(chat.nickname);
|
||||||
msg += ": ";
|
msg += ": ";
|
||||||
|
@ -140,10 +145,14 @@ bool AndroidMultiplayer::NetworkInit() {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string& ipaddress, int port,
|
|
||||||
const std::string& username, const std::string &preferredGameName,
|
NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string &ipaddress, int port,
|
||||||
const u64 &preferredGameId, const std::string& password,
|
const std::string &username,
|
||||||
const std::string& room_name, int max_players) {
|
const std::string &preferredGameName,
|
||||||
|
const u64 &preferredGameId,
|
||||||
|
const std::string &password,
|
||||||
|
const std::string &room_name, int max_players,
|
||||||
|
bool isPublic) {
|
||||||
auto member = Network::GetRoomMember().lock();
|
auto member = Network::GetRoomMember().lock();
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return NetPlayStatus::NETWORK_ERROR;
|
return NetPlayStatus::NETWORK_ERROR;
|
||||||
|
@ -168,17 +177,55 @@ NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string& ipaddress
|
||||||
.id = preferredGameId,
|
.id = preferredGameId,
|
||||||
};
|
};
|
||||||
|
|
||||||
port = (port == 0) ? Network::DefaultRoomPort : static_cast<u16>(port);
|
port = (port == 0) ? Network::DefaultRoomPort : static_cast<u16>(port);
|
||||||
|
|
||||||
if (!room->Create(room_name, "", ipaddress, static_cast<u16>(port), password,
|
if (!room->Create(room_name, "", ipaddress, static_cast<u16>(port), password,
|
||||||
static_cast<u32>(std::min(max_players, 16)), username, game, std::make_unique<Network::VerifyUser::NullBackend>(), {})) {
|
static_cast<u32>(std::min(max_players, 16)), username, game,
|
||||||
|
CreateVerifyBackend(isPublic), {})) {
|
||||||
return NetPlayStatus::CREATE_ROOM_ERROR;
|
return NetPlayStatus::CREATE_ROOM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public announce session
|
||||||
|
if (isPublic) {
|
||||||
|
if (auto session = announce_multiplayer_session.lock()) {
|
||||||
|
WebService::WebResult result = session->Register();
|
||||||
|
if (result.result_code != WebService::WebResult::Code::Success) {
|
||||||
|
LOG_ERROR(WebService, "Failed to announce public room lobby");
|
||||||
|
room->Destroy();
|
||||||
|
return NetPlayStatus::CREATE_ROOM_ERROR;
|
||||||
|
}
|
||||||
|
session->Start();
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Network, "Failed to start announce session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Failsafe timer to avoid joining before creation
|
// Failsafe timer to avoid joining before creation
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
|
||||||
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP, password, "");
|
std::string token;
|
||||||
|
// TODO(alekpop): properly handle the compile definition, it's not working right
|
||||||
|
//#ifdef ENABLE_WEB_SERVICE
|
||||||
|
// LOG_INFO(WebService, "Web Service enabled");
|
||||||
|
if (isPublic) {
|
||||||
|
WebService::Client client(Settings::values.web_api_url.GetValue(),
|
||||||
|
Settings::values.eden_username.GetValue(),
|
||||||
|
Settings::values.eden_token.GetValue());
|
||||||
|
|
||||||
|
token = client.GetExternalJWT(room->GetVerifyUID()).returned_data;
|
||||||
|
|
||||||
|
if (token.empty()) {
|
||||||
|
LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
|
||||||
|
} else {
|
||||||
|
LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#else
|
||||||
|
// LOG_INFO(WebService, "Web Service disabled");
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP,
|
||||||
|
password, token);
|
||||||
|
|
||||||
// Failsafe timer to avoid joining before creation
|
// Failsafe timer to avoid joining before creation
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
|
@ -194,8 +241,9 @@ NetPlayStatus AndroidMultiplayer::NetPlayCreateRoom(const std::string& ipaddress
|
||||||
return NetPlayStatus::CREATE_ROOM_ERROR;
|
return NetPlayStatus::CREATE_ROOM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string& ipaddress, int port,
|
NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string &ipaddress, int port,
|
||||||
const std::string& username, const std::string& password) {
|
const std::string &username,
|
||||||
|
const std::string &password) {
|
||||||
auto member = Network::GetRoomMember().lock();
|
auto member = Network::GetRoomMember().lock();
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return NetPlayStatus::NETWORK_ERROR;
|
return NetPlayStatus::NETWORK_ERROR;
|
||||||
|
@ -209,7 +257,8 @@ NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string& ipaddress,
|
||||||
return NetPlayStatus::ALREADY_IN_ROOM;
|
return NetPlayStatus::ALREADY_IN_ROOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP, password, "");
|
member->Join(username, ipaddress.c_str(), static_cast<u16>(port), 0, Network::NoPreferredIP,
|
||||||
|
password, "");
|
||||||
|
|
||||||
// Wait a bit for the connection and join process to complete
|
// Wait a bit for the connection and join process to complete
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
|
@ -226,7 +275,7 @@ NetPlayStatus AndroidMultiplayer::NetPlayJoinRoom(const std::string& ipaddress,
|
||||||
return NetPlayStatus::WRONG_PASSWORD;
|
return NetPlayStatus::WRONG_PASSWORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidMultiplayer::NetPlaySendMessage(const std::string& msg) {
|
void AndroidMultiplayer::NetPlaySendMessage(const std::string &msg) {
|
||||||
if (auto room = Network::GetRoomMember().lock()) {
|
if (auto room = Network::GetRoomMember().lock()) {
|
||||||
if (room->GetState() != Network::RoomMember::State::Joined &&
|
if (room->GetState() != Network::RoomMember::State::Joined &&
|
||||||
room->GetState() != Network::RoomMember::State::Moderator) {
|
room->GetState() != Network::RoomMember::State::Moderator) {
|
||||||
|
@ -237,11 +286,11 @@ void AndroidMultiplayer::NetPlaySendMessage(const std::string& msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidMultiplayer::NetPlayKickUser(const std::string& username) {
|
void AndroidMultiplayer::NetPlayKickUser(const std::string &username) {
|
||||||
if (auto room = Network::GetRoomMember().lock()) {
|
if (auto room = Network::GetRoomMember().lock()) {
|
||||||
auto members = room->GetMemberInformation();
|
auto members = room->GetMemberInformation();
|
||||||
auto it = std::find_if(members.begin(), members.end(),
|
auto it = std::find_if(members.begin(), members.end(),
|
||||||
[&username](const Network::RoomMember::MemberInformation& member) {
|
[&username](const Network::RoomMember::MemberInformation &member) {
|
||||||
return member.nickname == username;
|
return member.nickname == username;
|
||||||
});
|
});
|
||||||
if (it != members.end()) {
|
if (it != members.end()) {
|
||||||
|
@ -250,11 +299,11 @@ void AndroidMultiplayer::NetPlayKickUser(const std::string& username) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidMultiplayer::NetPlayBanUser(const std::string& username) {
|
void AndroidMultiplayer::NetPlayBanUser(const std::string &username) {
|
||||||
if (auto room = Network::GetRoomMember().lock()) {
|
if (auto room = Network::GetRoomMember().lock()) {
|
||||||
auto members = room->GetMemberInformation();
|
auto members = room->GetMemberInformation();
|
||||||
auto it = std::find_if(members.begin(), members.end(),
|
auto it = std::find_if(members.begin(), members.end(),
|
||||||
[&username](const Network::RoomMember::MemberInformation& member) {
|
[&username](const Network::RoomMember::MemberInformation &member) {
|
||||||
return member.nickname == username;
|
return member.nickname == username;
|
||||||
});
|
});
|
||||||
if (it != members.end()) {
|
if (it != members.end()) {
|
||||||
|
@ -263,7 +312,7 @@ void AndroidMultiplayer::NetPlayBanUser(const std::string& username) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidMultiplayer::NetPlayUnbanUser(const std::string& username) {
|
void AndroidMultiplayer::NetPlayUnbanUser(const std::string &username) {
|
||||||
if (auto room = Network::GetRoomMember().lock()) {
|
if (auto room = Network::GetRoomMember().lock()) {
|
||||||
room->SendModerationRequest(Network::RoomMessageTypes::IdModUnban, username);
|
room->SendModerationRequest(Network::RoomMessageTypes::IdModUnban, username);
|
||||||
}
|
}
|
||||||
|
@ -278,7 +327,7 @@ std::vector<std::string> AndroidMultiplayer::NetPlayRoomInfo() {
|
||||||
auto room_info = room->GetRoomInformation();
|
auto room_info = room->GetRoomInformation();
|
||||||
info_list.push_back(room_info.name + "|" + std::to_string(room_info.member_slots));
|
info_list.push_back(room_info.name + "|" + std::to_string(room_info.member_slots));
|
||||||
// all members
|
// all members
|
||||||
for (const auto& member : members) {
|
for (const auto &member: members) {
|
||||||
info_list.push_back(member.nickname);
|
info_list.push_back(member.nickname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,14 +417,29 @@ std::vector<std::string> AndroidMultiplayer::NetPlayGetBanList() {
|
||||||
auto [username_bans, ip_bans] = room->GetBanList();
|
auto [username_bans, ip_bans] = room->GetBanList();
|
||||||
|
|
||||||
// Add username bans
|
// Add username bans
|
||||||
for (const auto& username : username_bans) {
|
for (const auto &username: username_bans) {
|
||||||
ban_list.push_back(username);
|
ban_list.push_back(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add IP bans
|
// Add IP bans
|
||||||
for (const auto& ip : ip_bans) {
|
for (const auto &ip: ip_bans) {
|
||||||
ban_list.push_back(ip);
|
ban_list.push_back(ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ban_list;
|
return ban_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Network::VerifyUser::Backend> AndroidMultiplayer::CreateVerifyBackend(bool use_validation) {
|
||||||
|
std::unique_ptr<Network::VerifyUser::Backend> verify_backend;
|
||||||
|
if (use_validation) {
|
||||||
|
//#ifdef ENABLE_WEB_SERVICE
|
||||||
|
verify_backend =
|
||||||
|
std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url.GetValue());
|
||||||
|
//#else
|
||||||
|
// verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
|
||||||
|
//#endif
|
||||||
|
} else {
|
||||||
|
verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
|
||||||
|
}
|
||||||
|
return verify_backend;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -66,7 +66,7 @@ public:
|
||||||
NetPlayStatus NetPlayCreateRoom(const std::string &ipaddress, int port,
|
NetPlayStatus NetPlayCreateRoom(const std::string &ipaddress, int port,
|
||||||
const std::string &username, const std::string &preferredGameName,
|
const std::string &username, const std::string &preferredGameName,
|
||||||
const u64 &preferredGameId, const std::string &password,
|
const u64 &preferredGameId, const std::string &password,
|
||||||
const std::string &room_name, int max_players);
|
const std::string &room_name, int max_players, bool isPublic);
|
||||||
|
|
||||||
NetPlayStatus NetPlayJoinRoom(const std::string &ipaddress, int port,
|
NetPlayStatus NetPlayJoinRoom(const std::string &ipaddress, int port,
|
||||||
const std::string &username, const std::string &password);
|
const std::string &username, const std::string &password);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -118,7 +121,7 @@ void LogSettings() {
|
||||||
LOG_INFO(Config, "yuzu Configuration:");
|
LOG_INFO(Config, "yuzu Configuration:");
|
||||||
for (auto& [category, settings] : values.linkage.by_category) {
|
for (auto& [category, settings] : values.linkage.by_category) {
|
||||||
for (const auto& setting : settings) {
|
for (const auto& setting : settings) {
|
||||||
if (setting->Id() == values.yuzu_token.Id()) {
|
if (setting->Id() == values.eden_token.Id()) {
|
||||||
// Hide the token secret, for security reasons.
|
// Hide the token secret, for security reasons.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -527,7 +527,7 @@ struct Values {
|
||||||
SwitchableSetting<Language, true> language_index{linkage,
|
SwitchableSetting<Language, true> language_index{linkage,
|
||||||
Language::EnglishAmerican,
|
Language::EnglishAmerican,
|
||||||
Language::Japanese,
|
Language::Japanese,
|
||||||
Language::PortugueseBrazilian,
|
Language::Serbian,
|
||||||
"language_index",
|
"language_index",
|
||||||
Category::System};
|
Category::System};
|
||||||
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
|
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
|
||||||
|
@ -700,9 +700,9 @@ struct Values {
|
||||||
// WebService
|
// WebService
|
||||||
Setting<std::string> web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url",
|
Setting<std::string> web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url",
|
||||||
Category::WebService};
|
Category::WebService};
|
||||||
Setting<std::string> yuzu_username{linkage, std::string(), "yuzu_username",
|
Setting<std::string> eden_username{linkage, std::string(), "eden_username",
|
||||||
Category::WebService};
|
Category::WebService};
|
||||||
Setting<std::string> yuzu_token{linkage, std::string(), "yuzu_token", Category::WebService};
|
Setting<std::string> eden_token{linkage, std::string(), "eden_token", Category::WebService};
|
||||||
|
|
||||||
// Add-Ons
|
// Add-Ons
|
||||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||||
|
|
|
@ -111,7 +111,7 @@ ENUM(AudioMode, Mono, Stereo, Surround);
|
||||||
|
|
||||||
ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
|
ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
|
||||||
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
|
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
|
||||||
ChineseSimplified, ChineseTraditional, PortugueseBrazilian);
|
ChineseSimplified, ChineseTraditional, PortugueseBrazilian, Serbian);
|
||||||
|
|
||||||
ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
|
ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
|
||||||
|
|
||||||
|
|
|
@ -345,14 +345,14 @@ void LaunchRoom(int argc, char** argv, bool called_by_option)
|
||||||
LOG_INFO(Network, "Hosting a public room");
|
LOG_INFO(Network, "Hosting a public room");
|
||||||
Settings::values.web_api_url = web_api_url;
|
Settings::values.web_api_url = web_api_url;
|
||||||
PadToken(token);
|
PadToken(token);
|
||||||
Settings::values.yuzu_username = UsernameFromDisplayToken(token);
|
Settings::values.eden_username = UsernameFromDisplayToken(token);
|
||||||
username = Settings::values.yuzu_username.GetValue();
|
username = Settings::values.eden_username.GetValue();
|
||||||
Settings::values.yuzu_token = TokenFromDisplayToken(token);
|
Settings::values.eden_token = TokenFromDisplayToken(token);
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Network, "Hosting a public room");
|
LOG_INFO(Network, "Hosting a public room");
|
||||||
Settings::values.web_api_url = web_api_url;
|
Settings::values.web_api_url = web_api_url;
|
||||||
Settings::values.yuzu_username = username;
|
Settings::values.eden_username = username;
|
||||||
Settings::values.yuzu_token = token;
|
Settings::values.eden_token = token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -13,9 +13,9 @@
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
|
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
//#ifdef ENABLE_WEB_SERVICE
|
||||||
#include "web_service/announce_room_json.h"
|
#include "web_service/announce_room_json.h"
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
@ -23,13 +23,13 @@ namespace Core {
|
||||||
static constexpr std::chrono::seconds announce_time_interval(15);
|
static constexpr std::chrono::seconds announce_time_interval(15);
|
||||||
|
|
||||||
AnnounceMultiplayerSession::AnnounceMultiplayerSession() {
|
AnnounceMultiplayerSession::AnnounceMultiplayerSession() {
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
//#ifdef ENABLE_WEB_SERVICE
|
||||||
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
|
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
|
||||||
Settings::values.yuzu_username.GetValue(),
|
Settings::values.eden_username.GetValue(),
|
||||||
Settings::values.yuzu_token.GetValue());
|
Settings::values.eden_token.GetValue());
|
||||||
#else
|
//#else
|
||||||
backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>();
|
// backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>();
|
||||||
#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
WebService::WebResult AnnounceMultiplayerSession::Register() {
|
WebService::WebResult AnnounceMultiplayerSession::Register() {
|
||||||
|
@ -156,11 +156,11 @@ bool AnnounceMultiplayerSession::IsRunning() const {
|
||||||
void AnnounceMultiplayerSession::UpdateCredentials() {
|
void AnnounceMultiplayerSession::UpdateCredentials() {
|
||||||
ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running");
|
ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running");
|
||||||
|
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
//#ifdef ENABLE_WEB_SERVICE
|
||||||
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
|
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
|
||||||
Settings::values.yuzu_username.GetValue(),
|
Settings::values.eden_username.GetValue(),
|
||||||
Settings::values.yuzu_token.GetValue());
|
Settings::values.eden_token.GetValue());
|
||||||
#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,52 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "yuzu/configuration/configure_web.h"
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#if QT_VERSION_MAJOR >= 6
|
||||||
|
#include <QRegularExpressionValidator>
|
||||||
|
#else
|
||||||
|
#include <QRegExpValidator>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "ui_configure_web.h"
|
#include "ui_configure_web.h"
|
||||||
#include "yuzu/configuration/configure_web.h"
|
|
||||||
#include "yuzu/uisettings.h"
|
#include "yuzu/uisettings.h"
|
||||||
|
|
||||||
// static constexpr char token_delimiter{':'};
|
|
||||||
|
|
||||||
// static std::string GenerateDisplayToken(const std::string& username, const std::string& token) {
|
|
||||||
// if (username.empty() || token.empty()) {
|
|
||||||
// return {};
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const std::string unencoded_display_token{username + token_delimiter + token};
|
|
||||||
// QByteArray b{unencoded_display_token.c_str()};
|
|
||||||
// QByteArray b64 = b.toBase64();
|
|
||||||
// return b64.toStdString();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static std::string UsernameFromDisplayToken(const std::string& display_token) {
|
|
||||||
// const std::string unencoded_display_token{
|
|
||||||
// QByteArray::fromBase64(display_token.c_str()).toStdString()};
|
|
||||||
// return unencoded_display_token.substr(0, unencoded_display_token.find(token_delimiter));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static std::string TokenFromDisplayToken(const std::string& display_token) {
|
|
||||||
// const std::string unencoded_display_token{
|
|
||||||
// QByteArray::fromBase64(display_token.c_str()).toStdString()};
|
|
||||||
// return unencoded_display_token.substr(unencoded_display_token.find(token_delimiter) + 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
|
: QWidget(parent)
|
||||||
|
, ui(std::make_unique<Ui::ConfigureWeb>())
|
||||||
|
, m_rng{QRandomGenerator::system()}
|
||||||
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->button_verify_login, &QPushButton::clicked, this, &ConfigureWeb::VerifyLogin);
|
|
||||||
connect(&verify_watcher, &QFutureWatcher<bool>::finished, this, &ConfigureWeb::OnLoginVerified);
|
QString user_regex = QStringLiteral(".{4,20}");
|
||||||
|
QString token_regex = QStringLiteral("[a-z]{48}");
|
||||||
|
|
||||||
|
#if QT_VERSION_MAJOR >= 6
|
||||||
|
QRegularExpressionValidator *username_validator = new QRegularExpressionValidator(this);
|
||||||
|
QRegularExpressionValidator *token_validator = new QRegularExpressionValidator(this);
|
||||||
|
|
||||||
|
username_validator->setRegularExpression(QRegularExpression(user_regex));
|
||||||
|
token_validator->setRegularExpression(QRegularExpression(token_regex));
|
||||||
|
#else
|
||||||
|
QRegExpValidator *username_validator = new QRegExpValidator(this);
|
||||||
|
QRegExpValidator *token_validator = new QRegExpValidator(this);
|
||||||
|
|
||||||
|
username_validator->setRegExp(QRegExp(user_regex));
|
||||||
|
token_validator->setRegExp(QRegExp(token_regex));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ui->edit_username->setValidator(username_validator);
|
||||||
|
ui->edit_token->setValidator(token_validator);
|
||||||
|
|
||||||
|
connect(ui->button_generate, &QPushButton::clicked, this, &ConfigureWeb::GenerateToken);
|
||||||
|
|
||||||
#ifndef USE_DISCORD_PRESENCE
|
#ifndef USE_DISCORD_PRESENCE
|
||||||
ui->discord_group->setVisible(false);
|
ui->discord_group->setVisible(false);
|
||||||
|
@ -60,87 +68,61 @@ void ConfigureWeb::changeEvent(QEvent* event) {
|
||||||
|
|
||||||
void ConfigureWeb::RetranslateUI() {
|
void ConfigureWeb::RetranslateUI() {
|
||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
|
|
||||||
ui->web_signup_link->setText(
|
|
||||||
tr("<a href='https://profile.yuzu-emu.org/'><span style=\"text-decoration: underline; "
|
|
||||||
"color:#039be5;\">Sign up</span></a>"));
|
|
||||||
|
|
||||||
ui->web_token_info_link->setText(
|
|
||||||
tr("<a href='https://evilperson1337.notion.site/Hosting-a-Room-Inside-of-Eden-20457c2edaf680108abac6215a79acdb'><span style=\"text-decoration: "
|
|
||||||
"underline; color:#039be5;\">What is my token?</span></a>"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::SetConfiguration() {
|
void ConfigureWeb::SetConfiguration() {
|
||||||
ui->web_credentials_disclaimer->setWordWrap(true);
|
connect(ui->edit_username, &QLineEdit::textChanged, this, &ConfigureWeb::VerifyLogin);
|
||||||
|
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::VerifyLogin);
|
||||||
|
|
||||||
ui->web_signup_link->setOpenExternalLinks(true);
|
ui->edit_username->setText(QString::fromStdString(Settings::values.eden_username.GetValue()));
|
||||||
ui->web_token_info_link->setOpenExternalLinks(true);
|
ui->edit_token->setText(QString::fromStdString(Settings::values.eden_token.GetValue()));
|
||||||
|
|
||||||
ui->edit_username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
|
VerifyLogin();
|
||||||
ui->edit_token->setText(QString::fromStdString(Settings::values.yuzu_token.GetValue()));
|
|
||||||
// ui->edit_token->setText(QString::fromStdString(GenerateDisplayToken(
|
|
||||||
// Settings::values.yuzu_username.GetValue(), Settings::values.yuzu_token.GetValue())));
|
|
||||||
|
|
||||||
// Connect after setting the values, to avoid calling OnLoginChanged now
|
|
||||||
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
|
|
||||||
|
|
||||||
user_verified = true;
|
|
||||||
|
|
||||||
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
|
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::ApplyConfiguration() {
|
void ConfigureWeb::GenerateToken() {
|
||||||
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
|
constexpr size_t length = 48;
|
||||||
Settings::values.yuzu_username = ui->edit_username->text().toStdString();
|
QString set = QStringLiteral("abcdefghijklmnopqrstuvwxyz");
|
||||||
Settings::values.yuzu_token = ui->edit_token->text().toStdString();
|
QString result;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
size_t idx = m_rng->bounded(set.length());
|
||||||
|
result.append(set.at(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->edit_token->setText(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::OnLoginChanged() {
|
void ConfigureWeb::ApplyConfiguration() {
|
||||||
if (ui->edit_token->text().isEmpty()) {
|
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
|
||||||
user_verified = true;
|
Settings::values.eden_username = ui->edit_username->text().toStdString();
|
||||||
// Empty = no icon
|
Settings::values.eden_token = ui->edit_token->text().toStdString();
|
||||||
ui->label_token_verified->setPixmap(QPixmap());
|
|
||||||
ui->label_token_verified->setToolTip(QString());
|
|
||||||
} else {
|
|
||||||
user_verified = false;
|
|
||||||
|
|
||||||
// Show an info icon if it's been changed, clearer than showing failure
|
|
||||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("info")).pixmap(16);
|
|
||||||
ui->label_token_verified->setPixmap(pixmap);
|
|
||||||
ui->label_token_verified->setToolTip(
|
|
||||||
tr("Unverified, please click Verify before saving configuration", "Tooltip"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::VerifyLogin() {
|
void ConfigureWeb::VerifyLogin() {
|
||||||
QMessageBox::warning(this,
|
const QPixmap checked = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||||
tr("Warning"),
|
const QPixmap failed = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||||
tr("Verification is currently nonfunctional, instead generate a random "
|
|
||||||
"48-character string with only lowercase a-z."));
|
|
||||||
// ui->button_verify_login->setDisabled(true);
|
|
||||||
// ui->button_verify_login->setText(tr("Verifying..."));
|
|
||||||
// ui->label_token_verified->setPixmap(QIcon::fromTheme(QStringLiteral("sync")).pixmap(16));
|
|
||||||
// ui->label_token_verified->setToolTip(tr("Verifying..."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigureWeb::OnLoginVerified() {
|
const bool username_good = ui->edit_username->hasAcceptableInput();
|
||||||
// ui->button_verify_login->setEnabled(true);
|
const bool token_good = ui->edit_token->hasAcceptableInput();
|
||||||
// ui->button_verify_login->setText(tr("Verify"));
|
|
||||||
// if (verify_watcher.result()) {
|
|
||||||
// user_verified = true;
|
|
||||||
|
|
||||||
// ui->label_token_verified->setPixmap(QIcon::fromTheme(QStringLiteral("checked")).pixmap(16));
|
if (username_good) {
|
||||||
// ui->label_token_verified->setToolTip(tr("Verified", "Tooltip"));
|
ui->label_username_verified->setPixmap(checked);
|
||||||
// ui->username->setText(
|
ui->label_username_verified->setToolTip(tr("All Good", "Tooltip"));
|
||||||
// QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString())));
|
} else {
|
||||||
// } else {
|
ui->label_username_verified->setPixmap(failed);
|
||||||
// ui->label_token_verified->setPixmap(QIcon::fromTheme(QStringLiteral("failed")).pixmap(16));
|
ui->label_username_verified->setToolTip(tr("Must be between 4-20 characters", "Tooltip"));
|
||||||
// ui->label_token_verified->setToolTip(tr("Verification failed", "Tooltip"));
|
}
|
||||||
// ui->username->setText(tr("Unspecified"));
|
|
||||||
// QMessageBox::critical(this, tr("Verification failed"),
|
if (token_good) {
|
||||||
// tr("Verification failed. Check that you have entered your token "
|
ui->label_token_verified->setPixmap(checked);
|
||||||
// "correctly, and that your internet connection is working."));
|
ui->label_token_verified->setToolTip(tr("All Good", "Tooltip"));
|
||||||
// }
|
} else {
|
||||||
|
ui->label_token_verified->setPixmap(failed);
|
||||||
|
ui->label_token_verified->setToolTip(tr("Must be 48 characters, and lowercase a-z", "Tooltip"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::SetWebServiceConfigEnabled(bool enabled) {
|
void ConfigureWeb::SetWebServiceConfigEnabled(bool enabled) {
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <QRandomGenerator>
|
||||||
#include <QFutureWatcher>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ConfigureWeb;
|
class ConfigureWeb;
|
||||||
|
@ -25,14 +29,12 @@ private:
|
||||||
void changeEvent(QEvent* event) override;
|
void changeEvent(QEvent* event) override;
|
||||||
void RetranslateUI();
|
void RetranslateUI();
|
||||||
|
|
||||||
void OnLoginChanged();
|
|
||||||
void VerifyLogin();
|
|
||||||
void OnLoginVerified();
|
|
||||||
|
|
||||||
void SetConfiguration();
|
void SetConfiguration();
|
||||||
|
|
||||||
bool user_verified = true;
|
|
||||||
QFutureWatcher<bool> verify_watcher;
|
|
||||||
|
|
||||||
std::unique_ptr<Ui::ConfigureWeb> ui;
|
std::unique_ptr<Ui::ConfigureWeb> ui;
|
||||||
|
QRandomGenerator *m_rng;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void GenerateToken();
|
||||||
|
void VerifyLogin();
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,42 +25,29 @@
|
||||||
<string>eden Web Service</string>
|
<string>eden Web Service</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayoutYuzuWebService">
|
<layout class="QVBoxLayout" name="verticalLayoutYuzuWebService">
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="web_credentials_disclaimer">
|
|
||||||
<property name="text">
|
|
||||||
<string>By providing your username and token, you agree to allow eden to collect additional usage data, which may include user identifying information.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayoutYuzuUsername">
|
<layout class="QGridLayout" name="gridLayoutYuzuUsername">
|
||||||
<item row="2" column="3">
|
<item row="1" column="0">
|
||||||
<widget class="QPushButton" name="button_verify_login">
|
<widget class="QLabel" name="label_token">
|
||||||
|
<property name="text">
|
||||||
|
<string>Token: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_username">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="layoutDirection">
|
|
||||||
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Verify</string>
|
<string>Username: </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="0" column="1" colspan="4">
|
||||||
<widget class="QLabel" name="web_signup_link">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Sign up</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1" colspan="3">
|
|
||||||
<widget class="QLineEdit" name="edit_username">
|
<widget class="QLineEdit" name="edit_username">
|
||||||
<property name="maxLength">
|
<property name="maxLength">
|
||||||
<number>20</number>
|
<number>20</number>
|
||||||
|
@ -70,25 +57,27 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="5">
|
||||||
<widget class="QLabel" name="label_token">
|
<widget class="QLabel" name="label_token_verified">
|
||||||
<property name="text">
|
<property name="sizePolicy">
|
||||||
<string>Token: </string>
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="4">
|
<item row="1" column="1" colspan="4">
|
||||||
<widget class="QLabel" name="label_token_verified"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_username">
|
|
||||||
<property name="text">
|
|
||||||
<string>Username: </string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1" colspan="3">
|
|
||||||
<widget class="QLineEdit" name="edit_token">
|
<widget class="QLineEdit" name="edit_token">
|
||||||
|
<property name="inputMethodHints">
|
||||||
|
<set>Qt::InputMethodHint::ImhLowercaseOnly</set>
|
||||||
|
</property>
|
||||||
<property name="maxLength">
|
<property name="maxLength">
|
||||||
<number>80</number>
|
<number>80</number>
|
||||||
</property>
|
</property>
|
||||||
|
@ -97,14 +86,27 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="0" column="5">
|
||||||
<widget class="QLabel" name="web_token_info_link">
|
<widget class="QLabel" name="label_username_verified">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>What is my token?</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="2" column="4">
|
||||||
|
<widget class="QPushButton" name="button_generate">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Generate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="3">
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Orientation::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
|
|
@ -602,6 +602,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent)
|
||||||
PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
|
PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
|
||||||
PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
|
PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
|
||||||
PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")),
|
PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")),
|
||||||
|
PAIR(Language, Serbian, tr("Serbian (српски)")),
|
||||||
}});
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
|
||||||
{
|
{
|
||||||
|
|
|
@ -3591,8 +3591,8 @@ void GMainWindow::OnMenuReportCompatibility() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Settings::values.yuzu_token.GetValue().empty() &&
|
if (!Settings::values.eden_token.GetValue().empty() &&
|
||||||
!Settings::values.yuzu_username.GetValue().empty()) {
|
!Settings::values.eden_username.GetValue().empty()) {
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Missing yuzu Account"),
|
this, tr("Missing yuzu Account"),
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QIntValidator>
|
#include <QIntValidator>
|
||||||
|
@ -38,9 +38,9 @@ DirectConnectWindow::DirectConnectWindow(Core::System& system_, QWidget* parent)
|
||||||
ui->nickname->setValidator(validation.GetNickname());
|
ui->nickname->setValidator(validation.GetNickname());
|
||||||
ui->nickname->setText(
|
ui->nickname->setText(
|
||||||
QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
|
QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
|
||||||
if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
|
if (ui->nickname->text().isEmpty() && !Settings::values.eden_username.GetValue().empty()) {
|
||||||
// Use yuzu Web Service user name as nickname by default
|
// Use yuzu Web Service user name as nickname by default
|
||||||
ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
|
ui->nickname->setText(QString::fromStdString(Settings::values.eden_username.GetValue()));
|
||||||
}
|
}
|
||||||
ui->ip->setValidator(validation.GetIP());
|
ui->ip->setValidator(validation.GetIP());
|
||||||
ui->ip->setText(QString::fromStdString(UISettings::values.multiplayer_ip.GetValue()));
|
ui->ip->setText(QString::fromStdString(UISettings::values.multiplayer_ip.GetValue()));
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
@ -59,9 +59,9 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
|
||||||
// Restore the settings:
|
// Restore the settings:
|
||||||
ui->username->setText(
|
ui->username->setText(
|
||||||
QString::fromStdString(UISettings::values.multiplayer_room_nickname.GetValue()));
|
QString::fromStdString(UISettings::values.multiplayer_room_nickname.GetValue()));
|
||||||
if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
|
if (ui->username->text().isEmpty() && !Settings::values.eden_username.GetValue().empty()) {
|
||||||
// Use eden Web Service user name as nickname by default
|
// Use eden Web Service user name as nickname by default
|
||||||
ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
|
ui->username->setText(QString::fromStdString(Settings::values.eden_username.GetValue()));
|
||||||
}
|
}
|
||||||
ui->room_name->setText(
|
ui->room_name->setText(
|
||||||
QString::fromStdString(UISettings::values.multiplayer_room_name.GetValue()));
|
QString::fromStdString(UISettings::values.multiplayer_room_name.GetValue()));
|
||||||
|
@ -167,7 +167,7 @@ void HostRoomWindow::Host() {
|
||||||
const bool created =
|
const bool created =
|
||||||
room->Create(ui->room_name->text().toStdString(),
|
room->Create(ui->room_name->text().toStdString(),
|
||||||
ui->room_description->toPlainText().toStdString(), "", port, password,
|
ui->room_description->toPlainText().toStdString(), "", port, password,
|
||||||
ui->max_player->value(), Settings::values.yuzu_username.GetValue(),
|
ui->max_player->value(), Settings::values.eden_username.GetValue(),
|
||||||
game, CreateVerifyBackend(is_public), ban_list);
|
game, CreateVerifyBackend(is_public), ban_list);
|
||||||
if (!created) {
|
if (!created) {
|
||||||
NetworkMessage::ErrorManager::ShowError(
|
NetworkMessage::ErrorManager::ShowError(
|
||||||
|
@ -206,8 +206,8 @@ void HostRoomWindow::Host() {
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
if (is_public) {
|
if (is_public) {
|
||||||
WebService::Client client(Settings::values.web_api_url.GetValue(),
|
WebService::Client client(Settings::values.web_api_url.GetValue(),
|
||||||
Settings::values.yuzu_username.GetValue(),
|
Settings::values.eden_username.GetValue(),
|
||||||
Settings::values.yuzu_token.GetValue());
|
Settings::values.eden_token.GetValue());
|
||||||
if (auto room = Network::GetRoom().lock()) {
|
if (auto room = Network::GetRoom().lock()) {
|
||||||
token = client.GetExternalJWT(room->GetVerifyUID()).returned_data;
|
token = client.GetExternalJWT(room->GetVerifyUID()).returned_data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
@ -67,9 +67,9 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
|
||||||
|
|
||||||
// Try find the best nickname by default
|
// Try find the best nickname by default
|
||||||
if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("eden")) {
|
if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("eden")) {
|
||||||
if (!Settings::values.yuzu_username.GetValue().empty()) {
|
if (!Settings::values.eden_username.GetValue().empty()) {
|
||||||
ui->nickname->setText(
|
ui->nickname->setText(
|
||||||
QString::fromStdString(Settings::values.yuzu_username.GetValue()));
|
QString::fromStdString(Settings::values.eden_username.GetValue()));
|
||||||
} else if (!GetProfileUsername().empty()) {
|
} else if (!GetProfileUsername().empty()) {
|
||||||
ui->nickname->setText(QString::fromStdString(GetProfileUsername()));
|
ui->nickname->setText(QString::fromStdString(GetProfileUsername()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -189,11 +189,11 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
|
||||||
QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_uid] {
|
QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_uid] {
|
||||||
std::string token;
|
std::string token;
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
if (!Settings::values.yuzu_username.GetValue().empty() &&
|
if (!Settings::values.eden_username.GetValue().empty() &&
|
||||||
!Settings::values.yuzu_token.GetValue().empty()) {
|
!Settings::values.eden_token.GetValue().empty()) {
|
||||||
WebService::Client client(Settings::values.web_api_url.GetValue(),
|
WebService::Client client(Settings::values.web_api_url.GetValue(),
|
||||||
Settings::values.yuzu_username.GetValue(),
|
Settings::values.eden_username.GetValue(),
|
||||||
Settings::values.yuzu_token.GetValue());
|
Settings::values.eden_token.GetValue());
|
||||||
token = client.GetExternalJWT(verify_uid).returned_data;
|
token = client.GetExternalJWT(verify_uid).returned_data;
|
||||||
if (token.empty()) {
|
if (token.empty()) {
|
||||||
LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
|
LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue