411 lines
14 KiB
QML
411 lines
14 KiB
QML
/*
|
|
DasSchmalter - The smart switch
|
|
Copyright (C) 2019 Itsblue Development ( contact@itsblue.de )
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import QtQuick 2.9
|
|
import QtQuick.Window 2.2
|
|
import QtQuick.Controls 2.4
|
|
import com.itsblue.dasschmalter 1.0
|
|
|
|
Window {
|
|
visible: true
|
|
width: 640
|
|
height: 480
|
|
title: qsTr("DasSchmalter")
|
|
|
|
Page {
|
|
id: app
|
|
state: "CONNECTING"
|
|
anchors.fill: parent
|
|
|
|
property string ipAdress: settings.read("ip-adress")
|
|
|
|
AppSettings {
|
|
id: settings
|
|
}
|
|
|
|
Label {
|
|
id: currentStateLa
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.topMargin: parent.height * 0.01
|
|
anchors.top: parent.top
|
|
font.pixelSize: app.landscape() ? parent.height * 0.1:parent.width * 0.1
|
|
|
|
text: "current state: " + app.state
|
|
}
|
|
|
|
Button {
|
|
id: onOffBt
|
|
|
|
property int animationDuration: 300
|
|
property int animationDelay: 50
|
|
|
|
width: app.landscape() ? parent.height * 0.8:parent.width * 0.8
|
|
height: width
|
|
anchors.centerIn: parent
|
|
|
|
background: Item {
|
|
id: lamp
|
|
|
|
Image {
|
|
id: lampOn1
|
|
source: "on1.png"
|
|
anchors.fill: parent
|
|
scale: 0
|
|
Behavior on scale {
|
|
SequentialAnimation {
|
|
PauseAnimation {
|
|
duration: onOffBt.animationDelay * 0
|
|
}
|
|
NumberAnimation {
|
|
duration: onOffBt.animationDuration
|
|
properties: "scale"
|
|
from: app.state === "ON" ? 0:1
|
|
to: app.state === "ON" ? 1:0
|
|
target: lampOn1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Image {
|
|
id: lampOn2
|
|
source: "on2.png"
|
|
anchors.fill: parent
|
|
scale: 0
|
|
Behavior on scale {
|
|
SequentialAnimation {
|
|
PauseAnimation {
|
|
duration: onOffBt.animationDelay * 1
|
|
}
|
|
NumberAnimation {
|
|
duration: onOffBt.animationDuration
|
|
properties: "scale"
|
|
from: app.state === "ON" ? 0:1
|
|
to: app.state === "ON" ? 1:0
|
|
target: lampOn2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Image {
|
|
id: lampOn3
|
|
source: "on3.png"
|
|
anchors.fill: parent
|
|
scale: 0
|
|
Behavior on scale {
|
|
SequentialAnimation {
|
|
PauseAnimation {
|
|
duration: onOffBt.animationDelay * 2
|
|
}
|
|
NumberAnimation {
|
|
duration: onOffBt.animationDuration
|
|
properties: "scale"
|
|
from: app.state === "ON" ? 0:1
|
|
to: app.state === "ON" ? 1:0
|
|
target: lampOn3
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Image {
|
|
id: lampOn4
|
|
source: "on4.png"
|
|
anchors.fill: parent
|
|
scale: 0
|
|
Behavior on scale {
|
|
SequentialAnimation {
|
|
PauseAnimation {
|
|
duration: onOffBt.animationDelay * 3
|
|
}
|
|
NumberAnimation {
|
|
duration: onOffBt.animationDuration
|
|
properties: "scale"
|
|
from: app.state === "ON" ? 0:1
|
|
to: app.state === "ON" ? 1:0
|
|
target: lampOn4
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Image {
|
|
id: lampOn5
|
|
source: "on5.png"
|
|
anchors.fill: parent
|
|
scale: 0
|
|
Behavior on scale {
|
|
SequentialAnimation {
|
|
PauseAnimation {
|
|
duration: onOffBt.animationDelay * 4
|
|
}
|
|
NumberAnimation {
|
|
duration: onOffBt.animationDuration
|
|
properties: "scale"
|
|
from: app.state === "ON" ? 0:1
|
|
to: app.state === "ON" ? 1:0
|
|
target: lampOn5
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Image {
|
|
id: lampOff
|
|
source: "off.png"
|
|
anchors.fill: parent
|
|
scale: 1
|
|
}
|
|
Image {
|
|
id: lampOn0
|
|
source: "on0.png"
|
|
anchors.fill: parent
|
|
opacity: 0
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: 200
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onClicked: {
|
|
app.toggleLigth()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: lampCrossLineRa
|
|
|
|
anchors.centerIn: onOffBt
|
|
anchors.verticalCenterOffset: 15
|
|
height: onOffBt.height * 0.7
|
|
width: onOffBt.width * 0.03
|
|
|
|
radius: width * 0.2
|
|
|
|
rotation: 30
|
|
opacity: 1
|
|
|
|
color: Qt.darker("grey", 1.5)
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: 200
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: settingsBt
|
|
anchors {
|
|
bottom: parent.bottom
|
|
left: parent.left
|
|
leftMargin: ( app.width - width ) * 0.5
|
|
}
|
|
|
|
text: "settings"
|
|
|
|
onClicked: {
|
|
settingsDia.open()
|
|
}
|
|
}
|
|
|
|
Dialog {
|
|
id: settingsDia
|
|
|
|
modal: true
|
|
|
|
x: ( app.width - width ) * 0.5
|
|
y: ( app.height - height ) * 0.5
|
|
|
|
title: "Settings"
|
|
|
|
contentItem: Item {
|
|
Row {
|
|
spacing: 10
|
|
Label {
|
|
id: settingsIpAdressLa
|
|
text: "ip-adress"
|
|
}
|
|
TextField {
|
|
id: settingsIpAdressTf
|
|
text: settings.read("ip-adress")
|
|
anchors.verticalCenter: settingsIpAdressLa.verticalCenter
|
|
onTextChanged: {
|
|
settings.write("ip-adress", text)
|
|
app.ipAdress = text
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Timer {
|
|
id: refreshTimer
|
|
running: true
|
|
repeat: false
|
|
interval: 100
|
|
onTriggered: {
|
|
// sync state
|
|
app.getState();
|
|
}
|
|
}
|
|
|
|
states: [
|
|
State {
|
|
name: "ON"
|
|
PropertyChanges { target: onOffBt; opacity: 1; enabled: true; }
|
|
|
|
PropertyChanges { target: lampOn0; opacity: 1; }
|
|
PropertyChanges { target: lampOn1; scale: 1; }
|
|
PropertyChanges { target: lampOn2; scale: 1; }
|
|
PropertyChanges { target: lampOn3; scale: 1; }
|
|
PropertyChanges { target: lampOn4; scale: 1; }
|
|
PropertyChanges { target: lampOn5; scale: 1; }
|
|
|
|
PropertyChanges { target: lampCrossLineRa; opacity: 0; }
|
|
},
|
|
State {
|
|
name: "OFF"
|
|
PropertyChanges { target: onOffBt; opacity: 1; enabled: true; }
|
|
|
|
PropertyChanges { target: lampOn0; opacity: 0; }
|
|
PropertyChanges { target: lampOn1; scale: 0; }
|
|
PropertyChanges { target: lampOn2; scale: 0; }
|
|
PropertyChanges { target: lampOn3; scale: 0; }
|
|
PropertyChanges { target: lampOn4; scale: 0; }
|
|
PropertyChanges { target: lampOn5; scale: 0; }
|
|
|
|
PropertyChanges { target: lampCrossLineRa; opacity: 0; }
|
|
},
|
|
State {
|
|
name: "ERROR"
|
|
PropertyChanges { target: onOffBt; opacity: 0.5; enabled: false; }
|
|
|
|
PropertyChanges { target: lampOn0; opacity: 0; }
|
|
PropertyChanges { target: lampOn1; scale: 0; }
|
|
PropertyChanges { target: lampOn2; scale: 0; }
|
|
PropertyChanges { target: lampOn3; scale: 0; }
|
|
PropertyChanges { target: lampOn4; scale: 0; }
|
|
PropertyChanges { target: lampOn5; scale: 0; }
|
|
|
|
PropertyChanges { target: lampCrossLineRa; opacity: 1; }
|
|
},
|
|
State {
|
|
name: "CONNECTING"
|
|
PropertyChanges { target: onOffBt; opacity: 0.5; enabled: false; }
|
|
|
|
PropertyChanges { target: lampOn0; opacity: 0; }
|
|
PropertyChanges { target: lampOn1; scale: 0; }
|
|
PropertyChanges { target: lampOn2; scale: 0; }
|
|
PropertyChanges { target: lampOn3; scale: 0; }
|
|
PropertyChanges { target: lampOn4; scale: 0; }
|
|
PropertyChanges { target: lampOn5; scale: 0; }
|
|
|
|
PropertyChanges { target: lampCrossLineRa; opacity: 0; }
|
|
}
|
|
]
|
|
|
|
// -----------------
|
|
// --- functions ---
|
|
// -----------------
|
|
|
|
function getState(){
|
|
// function to sync the state of the app with the state of the schmalter
|
|
sendRequest("http://"+app.ipAdress+"/api/state")
|
|
}
|
|
|
|
function toggleLigth(){
|
|
// function to toggle the remote schmalter
|
|
|
|
if(app.state == 'OFF'){
|
|
sendRequest("http://"+app.ipAdress+"/api/on")
|
|
}
|
|
else if(app.state == 'ON'){
|
|
sendRequest("http://"+app.ipAdress+"/api/off")
|
|
}
|
|
else{
|
|
alert("ERROR! " + currentState);
|
|
}
|
|
|
|
// sync state
|
|
getState();
|
|
}
|
|
|
|
function sendRequest(link){
|
|
// function to send a http request
|
|
|
|
// create request object
|
|
var xmlhttp = new XMLHttpRequest();
|
|
|
|
// define a function to be executed after the request finished
|
|
xmlhttp.onreadystatechange = (function(response) {
|
|
return function(){
|
|
app.processResponse(response)
|
|
}})(xmlhttp);
|
|
|
|
// prepare the request
|
|
xmlhttp.open("GET", link);
|
|
|
|
// send the request
|
|
xmlhttp.send();
|
|
}
|
|
|
|
function processResponse(response){
|
|
// function to handle sensponses from das schmalter
|
|
|
|
if(response.readyState === 4){
|
|
switch (response.status){
|
|
case 200: {
|
|
// success
|
|
|
|
if(response.responseText !== ""){
|
|
// if the response was not empty
|
|
|
|
// get the data out of the json formatted string
|
|
var responseObj = JSON.parse(response.responseText);
|
|
|
|
if(responseObj["command"] === "state"){
|
|
// if the request was a state check
|
|
|
|
if(app.state !== responseObj["response"]){
|
|
// if the current state of the schmalter doesn't match the current state of the app -> update the app's state
|
|
app.state = responseObj["response"]
|
|
}
|
|
}
|
|
}
|
|
break
|
|
}
|
|
default: {
|
|
// error
|
|
console.log("ERROR: " + response.status)
|
|
// set the app state to ERROR
|
|
app.state = "ERROR"
|
|
}
|
|
}
|
|
|
|
// start the refresh timer
|
|
refreshTimer.start()
|
|
}
|
|
}
|
|
|
|
function landscape(){
|
|
return(app.width > app.height)
|
|
}
|
|
}
|
|
}
|