2018-07-04 23:40:21 +00:00
|
|
|
import QtQuick 2.9
|
|
|
|
import QtQuick.Controls 2.2
|
2018-07-05 01:48:09 +00:00
|
|
|
import QtQuick.Dialogs 1.3
|
2018-07-08 05:58:41 +00:00
|
|
|
import QtQuick.Layouts 1.3
|
2018-07-04 23:40:21 +00:00
|
|
|
|
|
|
|
import ComputerModel 1.0
|
|
|
|
|
2018-07-06 05:08:55 +00:00
|
|
|
import ComputerManager 1.0
|
2018-07-26 07:41:46 +00:00
|
|
|
import StreamingPreferences 1.0
|
2018-07-06 05:08:55 +00:00
|
|
|
|
2018-07-06 03:11:35 +00:00
|
|
|
GridView {
|
2018-07-06 06:12:55 +00:00
|
|
|
property ComputerModel computerModel : createModel()
|
|
|
|
|
2018-07-09 06:05:36 +00:00
|
|
|
id: pcGrid
|
2018-07-04 23:52:16 +00:00
|
|
|
anchors.fill: parent
|
2018-07-09 06:37:00 +00:00
|
|
|
anchors.leftMargin: (parent.width % (cellWidth + anchors.rightMargin)) / 2
|
2018-07-27 05:47:48 +00:00
|
|
|
anchors.topMargin: 20
|
2018-07-06 03:11:35 +00:00
|
|
|
anchors.rightMargin: 5
|
|
|
|
anchors.bottomMargin: 5
|
|
|
|
cellWidth: 350; cellHeight: 350;
|
|
|
|
focus: true
|
2018-07-08 05:15:02 +00:00
|
|
|
objectName: "Computers"
|
2018-07-06 03:11:35 +00:00
|
|
|
|
2018-07-09 05:07:20 +00:00
|
|
|
// The StackView will trigger a visibility change when
|
|
|
|
// we're pushed onto it, causing our onVisibleChanged
|
|
|
|
// routine to run, but only if we start as invisible
|
|
|
|
visible: false
|
2018-07-06 07:34:16 +00:00
|
|
|
|
2018-07-26 07:41:46 +00:00
|
|
|
StreamingPreferences {
|
|
|
|
id: prefs
|
|
|
|
}
|
|
|
|
|
2018-07-09 05:07:20 +00:00
|
|
|
Component.onCompleted: {
|
2018-07-06 07:34:16 +00:00
|
|
|
// Setup signals on CM
|
|
|
|
ComputerManager.computerAddCompleted.connect(addComplete)
|
2018-07-26 07:41:46 +00:00
|
|
|
|
|
|
|
if (!prefs.hasAnyHardwareAcceleration()) {
|
|
|
|
noHwDecoderDialog.open()
|
|
|
|
}
|
2018-07-06 05:08:55 +00:00
|
|
|
}
|
|
|
|
|
2018-07-09 05:07:20 +00:00
|
|
|
onVisibleChanged: {
|
|
|
|
if (visible) {
|
|
|
|
// Start polling when this view is shown
|
|
|
|
ComputerManager.startPolling()
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Stop polling when this view is not top-most
|
|
|
|
ComputerManager.stopPollingAsync()
|
|
|
|
}
|
2018-07-06 05:08:55 +00:00
|
|
|
}
|
|
|
|
|
2018-07-06 06:12:55 +00:00
|
|
|
function pairingComplete(error)
|
|
|
|
{
|
|
|
|
// Close the PIN dialog
|
|
|
|
pairDialog.close()
|
|
|
|
|
|
|
|
// Start polling again
|
|
|
|
ComputerManager.startPolling()
|
|
|
|
|
|
|
|
// Display a failed dialog if we got an error
|
|
|
|
if (error !== null) {
|
2018-07-06 07:34:16 +00:00
|
|
|
errorDialog.text = error
|
|
|
|
errorDialog.open()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function addComplete(success)
|
|
|
|
{
|
|
|
|
if (!success) {
|
|
|
|
errorDialog.text = "Unable to connect to the specified PC. Ensure GameStream is enabled in GeForce Experience."
|
|
|
|
errorDialog.open()
|
2018-07-06 06:12:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 05:08:55 +00:00
|
|
|
function createModel()
|
|
|
|
{
|
|
|
|
var model = Qt.createQmlObject('import ComputerModel 1.0; ComputerModel {}', parent, '')
|
|
|
|
model.initialize(ComputerManager)
|
2018-07-06 06:12:55 +00:00
|
|
|
model.pairingCompleted.connect(pairingComplete)
|
2018-07-06 05:08:55 +00:00
|
|
|
return model
|
|
|
|
}
|
|
|
|
|
2018-08-02 04:29:03 +00:00
|
|
|
model: computerModel
|
2018-07-06 03:11:35 +00:00
|
|
|
|
|
|
|
delegate: Item {
|
|
|
|
width: 300; height: 300;
|
|
|
|
|
|
|
|
Image {
|
|
|
|
id: pcIcon
|
2018-08-05 19:47:08 +00:00
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
2018-07-06 03:11:35 +00:00
|
|
|
source: {
|
2018-07-09 06:27:20 +00:00
|
|
|
model.addPc ? "qrc:/res/ic_add_to_queue_white_48px.svg" : "qrc:/res/ic_tv_white_48px.svg"
|
2018-07-04 23:40:21 +00:00
|
|
|
}
|
2018-07-06 03:11:35 +00:00
|
|
|
sourceSize {
|
|
|
|
width: 200
|
|
|
|
height: 200
|
2018-07-04 23:40:21 +00:00
|
|
|
}
|
2018-07-06 03:11:35 +00:00
|
|
|
}
|
|
|
|
|
2018-08-05 18:47:14 +00:00
|
|
|
Image {
|
|
|
|
// TODO: Tooltip
|
|
|
|
id: stateIcon
|
2018-08-05 19:47:08 +00:00
|
|
|
anchors.horizontalCenter: pcIcon.horizontalCenter
|
|
|
|
anchors.verticalCenter: pcIcon.verticalCenter
|
|
|
|
anchors.verticalCenterOffset: -10
|
2018-08-05 19:13:08 +00:00
|
|
|
visible: !model.addPc && !model.statusUnknown && (!model.online || !model.paired)
|
2018-08-05 18:47:14 +00:00
|
|
|
source: !model.online ? "qrc:/res/baseline-warning-24px.svg" : "qrc:/res/baseline-lock-24px.svg"
|
|
|
|
sourceSize {
|
2018-08-05 19:47:08 +00:00
|
|
|
width: 75
|
|
|
|
height: 75
|
2018-08-05 18:47:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-05 19:13:08 +00:00
|
|
|
BusyIndicator {
|
|
|
|
id: statusUnknownSpinner
|
2018-08-05 19:47:08 +00:00
|
|
|
anchors.horizontalCenter: pcIcon.horizontalCenter
|
|
|
|
anchors.verticalCenter: pcIcon.verticalCenter
|
|
|
|
anchors.verticalCenterOffset: -10
|
|
|
|
width: 75
|
|
|
|
height: 75
|
2018-08-05 19:13:08 +00:00
|
|
|
visible: !model.addPc && model.statusUnknown
|
|
|
|
}
|
|
|
|
|
2018-07-06 03:11:35 +00:00
|
|
|
Text {
|
|
|
|
id: pcNameText
|
|
|
|
text: model.name
|
|
|
|
color: "white"
|
|
|
|
|
|
|
|
width: parent.width
|
|
|
|
anchors.top: pcIcon.bottom
|
2018-07-07 23:47:39 +00:00
|
|
|
font.pointSize: 36
|
2018-07-06 03:11:35 +00:00
|
|
|
horizontalAlignment: Text.AlignHCenter
|
2018-07-07 23:47:39 +00:00
|
|
|
wrapMode: Text.Wrap
|
2018-07-06 03:11:35 +00:00
|
|
|
}
|
2018-07-04 23:40:21 +00:00
|
|
|
|
2018-07-29 23:04:45 +00:00
|
|
|
Menu {
|
|
|
|
id: pcContextMenu
|
|
|
|
MenuItem {
|
|
|
|
text: "Wake PC"
|
|
|
|
onTriggered: computerModel.wakeComputer(index)
|
2018-08-06 00:09:29 +00:00
|
|
|
visible: !model.addPc && !model.online && model.wakeable
|
2018-08-01 05:10:38 +00:00
|
|
|
height: visible ? implicitHeight : 0
|
2018-07-29 23:04:45 +00:00
|
|
|
}
|
|
|
|
MenuItem {
|
|
|
|
text: "Delete PC"
|
|
|
|
onTriggered: {
|
|
|
|
deletePcDialog.pcIndex = index
|
|
|
|
// get confirmation first, actual closing is called from the dialog
|
|
|
|
deletePcDialog.open()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 03:11:35 +00:00
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
2018-07-29 23:04:45 +00:00
|
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton;
|
2018-07-06 03:11:35 +00:00
|
|
|
onClicked: {
|
2018-07-29 23:04:45 +00:00
|
|
|
if(mouse.button === Qt.LeftButton) {
|
|
|
|
if (model.addPc) {
|
|
|
|
addPcDialog.open()
|
2018-07-06 03:37:51 +00:00
|
|
|
}
|
2018-07-29 23:04:45 +00:00
|
|
|
else if (model.online) {
|
|
|
|
if (model.paired) {
|
|
|
|
// go to game view
|
|
|
|
var component = Qt.createComponent("AppView.qml")
|
|
|
|
var appView = component.createObject(stackView)
|
|
|
|
appView.computerIndex = index
|
|
|
|
appView.objectName = model.name
|
|
|
|
stackView.push(appView)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!model.busy) {
|
|
|
|
var pin = ("0000" + Math.floor(Math.random() * 10000)).slice(-4)
|
2018-07-06 06:12:55 +00:00
|
|
|
|
2018-07-29 23:04:45 +00:00
|
|
|
// Stop polling, since pairing may make GFE unresponsive
|
|
|
|
ComputerManager.stopPollingAsync()
|
2018-07-06 06:12:55 +00:00
|
|
|
|
2018-07-29 23:04:45 +00:00
|
|
|
// Kick off pairing in the background
|
|
|
|
computerModel.pairComputer(index, pin)
|
2018-07-06 06:12:55 +00:00
|
|
|
|
2018-07-29 23:04:45 +00:00
|
|
|
// Display the pairing dialog
|
|
|
|
pairDialog.pin = pin
|
|
|
|
pairDialog.open()
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// cannot pair while something is streaming or attempting to pair
|
|
|
|
errorDialog.text = "This PC is currently busy. Make sure to quit any running games and try again."
|
|
|
|
errorDialog.open()
|
|
|
|
}
|
2018-07-06 03:37:51 +00:00
|
|
|
}
|
2018-07-29 23:13:42 +00:00
|
|
|
} else if(!model.online) {
|
|
|
|
pcContextMenu.open()
|
2018-07-06 03:37:51 +00:00
|
|
|
}
|
2018-07-29 23:04:45 +00:00
|
|
|
|
2018-07-06 03:37:51 +00:00
|
|
|
}
|
2018-07-29 23:04:45 +00:00
|
|
|
else { // right click
|
|
|
|
if(!model.addPc) { // but only for actual PCs, not the add-pc option
|
|
|
|
pcContextMenu.open()
|
|
|
|
}
|
2018-07-05 01:48:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 03:49:10 +00:00
|
|
|
MessageDialog {
|
2018-07-06 07:34:16 +00:00
|
|
|
id: errorDialog
|
2018-07-06 03:49:10 +00:00
|
|
|
// don't allow edits to the rest of the window while open
|
|
|
|
modality:Qt.WindowModal
|
2018-07-06 06:12:55 +00:00
|
|
|
icon: StandardIcon.Critical
|
2018-07-06 04:16:32 +00:00
|
|
|
standardButtons: StandardButton.Ok
|
2018-07-06 03:49:10 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 07:41:46 +00:00
|
|
|
MessageDialog {
|
|
|
|
id: noHwDecoderDialog
|
|
|
|
modality:Qt.WindowModal
|
|
|
|
icon: StandardIcon.Warning
|
|
|
|
standardButtons: StandardButton.Ok | StandardButton.Help
|
|
|
|
text: "No functioning hardware accelerated H.264 video decoder was detected by Moonlight. " +
|
|
|
|
"Your streaming performance may be severely degraded in this configuration. " +
|
|
|
|
"Click the Help button for more information on solving this problem."
|
|
|
|
onHelp: {
|
|
|
|
Qt.openUrlExternally("https://github.com/moonlight-stream/moonlight-docs/wiki/Fixing-Hardware-Decoding-Problems");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-05 01:48:09 +00:00
|
|
|
MessageDialog {
|
|
|
|
id: pairDialog
|
|
|
|
// don't allow edits to the rest of the window while open
|
|
|
|
modality:Qt.WindowModal
|
2018-07-06 04:16:32 +00:00
|
|
|
property string pin : "0000"
|
|
|
|
text:"Please enter " + pin + " on your GameStream PC. This dialog will close when pairing is completed."
|
|
|
|
standardButtons: StandardButton.Cancel
|
2018-07-05 01:48:09 +00:00
|
|
|
onRejected: {
|
2018-07-06 03:37:51 +00:00
|
|
|
// FIXME: We should interrupt pairing here
|
2018-07-05 01:48:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-29 23:04:45 +00:00
|
|
|
MessageDialog {
|
|
|
|
id: deletePcDialog
|
|
|
|
// don't allow edits to the rest of the window while open
|
|
|
|
modality:Qt.WindowModal
|
|
|
|
property int pcIndex : -1;
|
2018-08-01 05:10:38 +00:00
|
|
|
text:"Are you sure you want to remove this PC?"
|
2018-08-02 04:29:03 +00:00
|
|
|
standardButtons: StandardButton.Yes | StandardButton.No
|
2018-07-29 23:04:45 +00:00
|
|
|
onYes: {
|
|
|
|
console.log("deleting PC pairing for PC at index: " + pcIndex)
|
|
|
|
computerModel.deleteComputer(pcIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-05 01:48:09 +00:00
|
|
|
Dialog {
|
2018-07-06 03:37:51 +00:00
|
|
|
id: addPcDialog
|
|
|
|
property string label: "Enter the IP address of your GameStream PC"
|
|
|
|
property string hint: "192.168.1.100"
|
2018-07-05 01:48:09 +00:00
|
|
|
property alias editText : editTextItem
|
|
|
|
|
|
|
|
standardButtons: StandardButton.Ok | StandardButton.Cancel
|
|
|
|
onVisibleChanged: {
|
|
|
|
editTextItem.focus = true
|
|
|
|
editTextItem.selectAll()
|
|
|
|
}
|
|
|
|
onAccepted: {
|
2018-07-06 07:34:16 +00:00
|
|
|
ComputerManager.addNewHost(editText.text, false)
|
2018-07-05 01:48:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
Text {
|
2018-07-06 03:37:51 +00:00
|
|
|
id: addPcDialogLabel
|
|
|
|
text: addPcDialog.label
|
2018-07-05 01:48:09 +00:00
|
|
|
}
|
|
|
|
Rectangle {
|
|
|
|
implicitWidth: parent.parent.width
|
|
|
|
height: editTextItem.height
|
|
|
|
|
|
|
|
TextInput {
|
|
|
|
id: editTextItem
|
|
|
|
inputMethodHints: Qt.ImhPreferUppercase
|
2018-07-06 03:37:51 +00:00
|
|
|
text: addPcDialog.hint
|
2018-07-04 23:40:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-09 06:05:36 +00:00
|
|
|
|
|
|
|
ScrollBar.vertical: ScrollBar {
|
|
|
|
parent: pcGrid.parent
|
|
|
|
anchors {
|
|
|
|
top: pcGrid.top
|
|
|
|
left: pcGrid.right
|
|
|
|
bottom: pcGrid.bottom
|
|
|
|
|
|
|
|
leftMargin: -10
|
|
|
|
}
|
|
|
|
}
|
2018-07-04 23:40:21 +00:00
|
|
|
}
|