Исправлена структура каталогов
This commit is contained in:
BIN
resources/images/lamp.png
Normal file
BIN
resources/images/lamp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/images/off.png
Normal file
BIN
resources/images/off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
34
resources/qml/GradientButton.qml
Normal file
34
resources/qml/GradientButton.qml
Normal file
@@ -0,0 +1,34 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls.Material 2.2
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
signal clicked()
|
||||
|
||||
Gradient {
|
||||
id: pressedGradient
|
||||
|
||||
GradientStop {position: 0.0; color: Material.color(Material.Grey, Material.Shade300)}
|
||||
GradientStop {position: 0.5; color: Material.color(Material.BlueGrey, Material.Shade300)}
|
||||
GradientStop {position: 1.0; color: Material.color(Material.Brown, Material.Shade300)}
|
||||
}
|
||||
|
||||
Gradient {
|
||||
id: normalGradient
|
||||
|
||||
GradientStop {position: 0.0; color: Material.color(Material.Grey)}
|
||||
GradientStop {position: 0.5; color: Material.color(Material.BlueGrey)}
|
||||
GradientStop {position: 1.0; color: Material.color(Material.Brown)}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: ma
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
gradient: ma.pressed ? pressedGradient : normalGradient
|
||||
}
|
||||
31
resources/qml/HomeForm.qml
Normal file
31
resources/qml/HomeForm.qml
Normal file
@@ -0,0 +1,31 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
|
||||
Page {
|
||||
title: qsTr("nooLight")
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 5
|
||||
|
||||
model: lightsModel
|
||||
spacing: 5
|
||||
|
||||
delegate: LightGroup {
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
title: groupName || ""
|
||||
lights: channels
|
||||
|
||||
onChannelClicked: {
|
||||
lightsModel.switchChannel(channelId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
running: lightsModel.isLoading
|
||||
}
|
||||
}
|
||||
84
resources/qml/LightGroup.qml
Normal file
84
resources/qml/LightGroup.qml
Normal file
@@ -0,0 +1,84 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string title: ""
|
||||
property QtObject lights: undefined
|
||||
|
||||
signal channelClicked(int channelId)
|
||||
|
||||
Column {
|
||||
width: root.width
|
||||
|
||||
spacing: 5
|
||||
|
||||
GradientButton {
|
||||
width: root.width
|
||||
height: 40
|
||||
|
||||
visible: Boolean(root.title)
|
||||
radius: 5
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: root.title
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 5
|
||||
width: height
|
||||
|
||||
source: "/images/off.png"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonsRow
|
||||
|
||||
width: root.width
|
||||
height: childrenRect.height
|
||||
|
||||
spacing: 5
|
||||
|
||||
Repeater {
|
||||
model: root.lights
|
||||
|
||||
width: root.width
|
||||
|
||||
GradientButton {
|
||||
id: button
|
||||
|
||||
width: (root.width - buttonsRow.spacing * (root.lights.count - 1)) / root.lights.count
|
||||
height: width / 2
|
||||
radius: 5
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
|
||||
Image {
|
||||
height: button.height * 0.5
|
||||
width: height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
source: "/images/lamp.png"
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.horizontalCenter
|
||||
text: name
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.channelClicked(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
resources/qml/LightsModel.qml
Normal file
56
resources/qml/LightsModel.qml
Normal file
@@ -0,0 +1,56 @@
|
||||
import QtQml.Models 2.1
|
||||
|
||||
ListModel {
|
||||
id: root
|
||||
|
||||
readonly property var client: NooLiteClient {
|
||||
id: nooLiteClient
|
||||
|
||||
onError: (text) => {
|
||||
root.error(text)
|
||||
root.isLoading = false
|
||||
}
|
||||
|
||||
onModelLoad: (data) => {
|
||||
root.populateModel(data)
|
||||
root.isLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
property alias serviceUrl: nooLiteClient.serviceUrl
|
||||
property bool isLoading: false
|
||||
|
||||
property int channelsCount: 0
|
||||
|
||||
signal error(string text)
|
||||
|
||||
onServiceUrlChanged: reload()
|
||||
|
||||
function reload() {
|
||||
root.client.loadModel()
|
||||
root.isLoading = true
|
||||
}
|
||||
|
||||
function populateModel(data) {
|
||||
root.clear()
|
||||
root.channelsCount = 0
|
||||
|
||||
data.groups.forEach(function (group) {
|
||||
root.append(group)
|
||||
|
||||
root.channelsCount += group.channels.length
|
||||
})
|
||||
}
|
||||
|
||||
function switchChannel(channelId) {
|
||||
root.client.sendCommand("switch", channelId)
|
||||
}
|
||||
|
||||
function bindChannel(channelId) {
|
||||
root.client.sendCommand("bind", channelId)
|
||||
}
|
||||
|
||||
function unbindChannel(channelId) {
|
||||
root.client.sendCommand("unbind", channelId)
|
||||
}
|
||||
}
|
||||
50
resources/qml/NooLiteClient.qml
Normal file
50
resources/qml/NooLiteClient.qml
Normal file
@@ -0,0 +1,50 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
property string serviceUrl: undefined
|
||||
|
||||
signal modelLoad(var data)
|
||||
signal error(string text)
|
||||
|
||||
function _get(url, callback) {
|
||||
var request = new XMLHttpRequest()
|
||||
|
||||
request.open('GET', url)
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState !== XMLHttpRequest.DONE) {
|
||||
return
|
||||
}
|
||||
|
||||
if (request.status === 200) {
|
||||
if (callback !== undefined) {
|
||||
callback(JSON.parse(request.responseText))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
root.error(qsTr("[%1] Request error: %2").
|
||||
arg(request.status).
|
||||
arg(request.statusText))
|
||||
}
|
||||
|
||||
request.send()
|
||||
}
|
||||
|
||||
function loadModel() {
|
||||
_get(root.serviceUrl + '/static/channels.js', root.modelLoad)
|
||||
}
|
||||
|
||||
function sendCommand(command, channelId) {
|
||||
_get(root.serviceUrl + '/noolite/%1/%2'.arg(command).arg(channelId), function (data) {
|
||||
if (data.error) {
|
||||
root.error(qsTr("Server error: %1").arg(data.error))
|
||||
return
|
||||
}
|
||||
|
||||
console.log(data.command, data.channel)
|
||||
})
|
||||
}
|
||||
}
|
||||
40
resources/qml/ServiceForm.qml
Normal file
40
resources/qml/ServiceForm.qml
Normal file
@@ -0,0 +1,40 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
title: qsTr("Service")
|
||||
|
||||
ListView {
|
||||
model: lightsModel.channelsCount
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
delegate: Row {
|
||||
spacing: 4
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Button {
|
||||
width: 160
|
||||
|
||||
text: qsTr("Bind channel %1").arg(index)
|
||||
|
||||
onClicked: {
|
||||
lightsModel.bindChannel(index)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 160
|
||||
|
||||
text: qsTr("Unbind channel %1").arg(index)
|
||||
|
||||
onClicked: {
|
||||
lightsModel.unbindChannel(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
resources/qml/SettingsForm.qml
Normal file
64
resources/qml/SettingsForm.qml
Normal file
@@ -0,0 +1,64 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
title: qsTr("Settings")
|
||||
|
||||
ListModel {
|
||||
id: settingsModel
|
||||
|
||||
ListElement {
|
||||
name: "serviceUrl"
|
||||
title: qsTr("nooLite service URL")
|
||||
inputMethodHint: Qt.ImhUrlCharactersOnly
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
model: settingsModel
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
delegate: SubtitledItemDelegate {
|
||||
width: parent.width
|
||||
text: model.title
|
||||
subtitle: settings[model.name]
|
||||
|
||||
onClicked: inputDialog.open()
|
||||
|
||||
Dialog {
|
||||
id: inputDialog
|
||||
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
parent: ApplicationWindow.overlay
|
||||
|
||||
focus: true
|
||||
modal: true
|
||||
title: model.title
|
||||
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||
|
||||
Column {
|
||||
spacing: 20
|
||||
anchors.fill: parent
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
|
||||
width: parent.width
|
||||
focus: true
|
||||
inputMethodHints: Qt.ImhNoAutoUppercase | model.inputMethodHint
|
||||
placeholderText: model.title
|
||||
text: settings[model.name]
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
settings[model.name] = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
resources/qml/SubtitledItemDelegate.qml
Normal file
24
resources/qml/SubtitledItemDelegate.qml
Normal file
@@ -0,0 +1,24 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
ItemDelegate {
|
||||
id: root
|
||||
|
||||
property string subtitle: ""
|
||||
|
||||
contentItem: Column {
|
||||
Label {
|
||||
id: titleLabel
|
||||
|
||||
width: parent.width
|
||||
text: root.text
|
||||
}
|
||||
|
||||
Label {
|
||||
width: parent.width
|
||||
font.pixelSize: titleLabel.font.pixelSize - 2
|
||||
text: root.subtitle ? root.subtitle : qsTr("undefined")
|
||||
opacity: 0.8
|
||||
}
|
||||
}
|
||||
}
|
||||
111
resources/qml/main.qml
Normal file
111
resources/qml/main.qml
Normal file
@@ -0,0 +1,111 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import ru.ded.components 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
|
||||
visible: true
|
||||
width: 640
|
||||
height: 480
|
||||
title: qsTr("Stack")
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
|
||||
property string serviceUrl: ""
|
||||
}
|
||||
|
||||
LightsModel {
|
||||
id: lightsModel
|
||||
|
||||
serviceUrl: settings.serviceUrl
|
||||
|
||||
onError: (text) => stackView.showError(text)
|
||||
}
|
||||
|
||||
header: ToolBar {
|
||||
contentHeight: 36
|
||||
|
||||
MenuBackButton {
|
||||
id: menuButton
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
|
||||
state: stackView.depth > 1 ? "back" : "menu"
|
||||
|
||||
onClicked: {
|
||||
mainMenu.open()
|
||||
}
|
||||
|
||||
onBack: {
|
||||
stackView.pop()
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: stackView.currentItem.title
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MainMenu {
|
||||
id: mainMenu
|
||||
|
||||
readonly property var actions: {
|
||||
"service": () => { stackView.openPage("ServiceForm.qml") },
|
||||
"settings": () => { stackView.openPage("SettingsForm.qml") },
|
||||
"quit": () => { Qt.quit() }
|
||||
}
|
||||
|
||||
logo: "/images/lamp.png"
|
||||
appName: qsTr("nooLight v1.0")
|
||||
|
||||
model: ListModel {
|
||||
ListElement {
|
||||
title: qsTr("Service")
|
||||
action: "service"
|
||||
}
|
||||
ListElement {
|
||||
title: qsTr("Settings")
|
||||
action: "settings"
|
||||
}
|
||||
ListElement {
|
||||
title: qsTr("Quit")
|
||||
action: "quit"
|
||||
}
|
||||
}
|
||||
|
||||
onActionSelected: (action) => actions[action]()
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: stackView
|
||||
initialItem: "HomeForm.qml"
|
||||
anchors.fill: parent
|
||||
|
||||
function openPage(page) {
|
||||
if (depth > 1) {
|
||||
pop()
|
||||
}
|
||||
|
||||
push(page)
|
||||
mainMenu.close()
|
||||
}
|
||||
|
||||
function showError(text) {
|
||||
ToolTip.show(text, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
if (stackView.depth > 1) {
|
||||
close.accepted = false
|
||||
stackView.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
13
resources/qtquickcontrols2.conf
Normal file
13
resources/qtquickcontrols2.conf
Normal file
@@ -0,0 +1,13 @@
|
||||
; This file can be edited to change the style of the application
|
||||
; Read "Qt Quick Controls 2 Configuration File" for details:
|
||||
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
|
||||
|
||||
[Controls]
|
||||
Style=Material
|
||||
|
||||
[Material]
|
||||
Theme=Dark
|
||||
Primary=BlueGrey
|
||||
Accent=Grey
|
||||
;Foreground=Brown
|
||||
;Background=Steel
|
||||
16
resources/resources.qrc
Normal file
16
resources/resources.qrc
Normal file
@@ -0,0 +1,16 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>qml/main.qml</file>
|
||||
<file>qtquickcontrols2.conf</file>
|
||||
<file>qml/HomeForm.qml</file>
|
||||
<file>qml/SettingsForm.qml</file>
|
||||
<file>qml/SubtitledItemDelegate.qml</file>
|
||||
<file>qml/LightsModel.qml</file>
|
||||
<file>qml/LightGroup.qml</file>
|
||||
<file>qml/GradientButton.qml</file>
|
||||
<file>images/lamp.png</file>
|
||||
<file>images/off.png</file>
|
||||
<file>qml/NooLiteClient.qml</file>
|
||||
<file>qml/ServiceForm.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Reference in New Issue
Block a user