Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 165 additions & 1 deletion app/gui/SettingsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,30 @@ Flickable {

// Highlight the first item if a gamepad is connected
if (SdlGamepadKeyNavigation.getConnectedGamepads() > 0) {
resolutionComboBox.forceActiveFocus(Qt.TabFocus)
if (StreamingPreferences.hasProfiles) {
profilesComboBox.forceActiveFocus(Qt.TabFocus)
}
else {
resolutionComboBox.forceActiveFocus(Qt.TabFocus)
}
}

//listen for the active profile name changing, as the whole view is reloaded when that happens
StreamingPreferences.onActiveProfileNameChanged.connect(forceReload)
}

StackView.onDeactivating: {
SdlGamepadKeyNavigation.setUiNavMode(false)

// Save the prefs so the Session can observe the changes
StreamingPreferences.save()

StreamingPreferences.onActiveProfileNameChanged.disconnect(forceReload)
}

function forceReload()
{
window.reloadSettingsView()
}

Component.onDestruction: {
Expand All @@ -53,6 +68,110 @@ Flickable {
width: settingsPage.width / 2
spacing: 15

GroupBox {
id: profileChangeGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding))
padding: 12
title: "<font color=\"skyblue\">" + qsTr("Change Profile") + "</font>"
font.pointSize: 12
visible: StreamingPreferences.hasProfiles
enabled: StreamingPreferences.hasProfiles

Column {
anchors.fill: parent
spacing: 5

Label {
width: parent.width
id: resActiveProfiletitle
text: qsTr("Active Profile")
font.pointSize: 12
wrapMode: Text.Wrap
}

Row {
spacing: 15
width: parent.width

AutoResizingComboBox {
function createModel() {
var profilesListModel = Qt.createQmlObject('import QtQuick 2.0; ListModel {}', parent, '')

var profilesList = StreamingPreferences.profiles

for( var i in profilesList)
{
profilesListModel.append({"text" : profilesList[i].name})
}

return profilesListModel
}

function reinitialize() {
model = createModel()

var activeProfileName = StreamingPreferences.activeProfileName
currentIndex = 0
for (var i = 0; i < model.count; i++) {
var profileName = model.get(i).text

// Pick the highest value lesser or equal to the saved FPS
if (profileName == activeProfileName) {
currentIndex = i
}
}

// Persist the selected value
activated(currentIndex)
}

// ignore setting the index at first, and actually set it when the component is loaded
Component.onCompleted: {
reinitialize()
StreamingPreferences.onProfilesChanged.connect(reinitialize)
}

Component.onDestruction: {
StreamingPreferences.onProfilesChanged.disconnect(reinitialize)
}

id: profilesComboBox
maximumWidth: parent.width / 2
textRole: "text"
// ::onActivated must be used, as it only listens for when the index is changed by a human
onActivated : {
var item = model.get(currentIndex)
if (item)
{
var selectedProfileName = item.text

if (StreamingPreferences.activeProfileName !== selectedProfileName) {
StreamingPreferences.changeActiveProfile(selectedProfileName)
}
}
}
}

Button {
id: deleteActiveProfileButton
text: qsTr("Delete Profile")
onClicked: deleteProfileDialog.open()
}
}

NavigableMessageDialog {
id: deleteProfileDialog
standardButtons: Dialog.Yes | Dialog.No
title: qsTr("Confirm profile deletion")
text: qsTr("Are you sure you want to delete the profile named %1?").arg(StreamingPreferences.activeProfileName)

onAccepted: {
StreamingPreferences.deleteProfile(StreamingPreferences.activeProfileName)
}
}
}
}

GroupBox {
id: basicSettingsGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding))
Expand Down Expand Up @@ -1356,5 +1475,50 @@ Flickable {
}
}
}

GroupBox {
id: profileCreationGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding))
padding: 12
title: "<font color=\"skyblue\">" + qsTr("Save As New Profile") + "</font>"
font.pointSize: 12

NavigableMessageDialog {
id: profileCreationFailedDialog
standardButtons: Dialog.Ok
title: qsTr("Failed to create profile")
text: qsTr("A profile named %1 already exists.").arg(newProfileNameField.text)
}

Row {
anchors.fill: parent
padding: 5
spacing: 15

TextField {
id: newProfileNameField
maximumLength: 16
placeholderText: qsTr("Profile Name")
validator: RegExpValidator { regExp: /[0-9A-Za-z\s-_]+/ }
}

Button {
id: createNewProfileButton
text: qsTr("Create")
enabled: newProfileNameField.text.length > 0
onClicked: {
//store a local reference to the window, as a successful call to createNewProfile will destroy the SettingsView
//component and lose the reference to window
var storedWindow = window
if (StreamingPreferences.createNewProfile(newProfileNameField.text)) {
storedWindow.showNewProfileCreatedDialog(newProfileNameField.text)
}
else {
profileCreationFailedDialog.open()
}
}
}
}
}
}
}
35 changes: 34 additions & 1 deletion app/gui/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ ApplicationWindow {
// a retranslate() because AppView breaks for some reason.
property bool clearOnBack: false

property string settingsViewPath: "qrc:/gui/SettingsView.qml"

id: window
visible: true
width: 1280
Expand Down Expand Up @@ -47,6 +49,13 @@ ApplicationWindow {
}
}

function reloadSettingsView()
{
//pop the current settings view and immediately push a new one, so that the entire view is refreshed
stackView.pop(StackView.Immediate)
stackView.push(settingsViewPath, StackView.Immediate)
}

StackView {
id: stackView
initialItem: initialView
Expand Down Expand Up @@ -258,6 +267,15 @@ ApplicationWindow {
verticalAlignment: Qt.AlignVCenter
}

Label {
id: activeProfileNameLabel
visible: stackView.currentItem.objectName !== "Settings" && StreamingPreferences.hasProfiles
text: "<b>" + qsTr("Profile") + "</b> <br>" + StreamingPreferences.activeProfileName
font.pointSize: 12
horizontalAlignment: Qt.AlignRight
verticalAlignment: Qt.AlignVCenter
}

NavigableToolButton {
id: discordButton
visible: SystemProperties.hasBrowser &&
Expand Down Expand Up @@ -390,7 +408,7 @@ ApplicationWindow {

iconSource: "qrc:/res/settings.svg"

onClicked: navigateTo("qrc:/gui/SettingsView.qml", qsTr("Settings"))
onClicked: navigateTo(settingsViewPath, qsTr("Settings"))

Keys.onDownPressed: {
stackView.currentItem.forceActiveFocus(Qt.TabFocus)
Expand Down Expand Up @@ -518,4 +536,19 @@ ApplicationWindow {
}
}
}

//This dialog belongs in SettingsView, but when a new profile is created the view is reloaded, meaning that it cannot show any dialogs
//at the same time. Instead, it's hosted here as this component is never destroyed.
NavigableMessageDialog {
id: newProfileCreatedDialog
standardButtons: Dialog.Ok
title: qsTr("New profile created")
text: qsTr("A profile named %1 has been created and set as the active profile.").arg(profileName)
property string profileName: ""
}

function showNewProfileCreatedDialog(profileName) {
newProfileCreatedDialog.profileName = profileName
newProfileCreatedDialog.open()
}
}
Loading