Исправлена структура каталогов

This commit is contained in:
2024-05-16 16:26:38 +02:00
parent 53659cea38
commit fe298f0631
17 changed files with 22 additions and 66 deletions

View 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
}

View 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
}
}

View 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)
}
}
}
}
}
}

View 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)
}
}

View 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)
})
}
}

View 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)
}
}
}
}
}

View 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
}
}
}
}
}

View 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
View 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()
}
}
}