]> Some of my projects - tim.git/commitdiff
Client
authorAPTX <marek321@gmail.com>
Mon, 10 Jan 2011 02:16:25 +0000 (03:16 +0100)
committerAPTX <marek321@gmail.com>
Mon, 10 Jan 2011 02:16:25 +0000 (03:16 +0100)
16 files changed:
chatclient.cpp [new file with mode: 0644]
chatclient.h [new file with mode: 0644]
main.cpp
qml/tim-game/Components/ChatView.qml
qml/tim-game/Components/HighScoreForm.qml
qml/tim-game/Components/Input.qml
qml/tim-game/Components/LoginForm.qml
qml/tim-game/Components/MessageBox.qml [new file with mode: 0644]
qml/tim-game/Components/RegistrationForm.qml
qml/tim-game/Components/ScoreDelegate.qml [new file with mode: 0644]
qml/tim-game/main.qml
serverreplyparser.cpp [new file with mode: 0644]
serverreplyparser.h [new file with mode: 0644]
tim-game.pro
timgame.cpp [new file with mode: 0644]
timgame.h [new file with mode: 0644]

diff --git a/chatclient.cpp b/chatclient.cpp
new file mode 100644 (file)
index 0000000..8e174ae
--- /dev/null
@@ -0,0 +1,81 @@
+#include "chatclient.h"
+
+#include <QtNetwork/QTcpSocket>
+
+ChatClient::ChatClient(const QString &host, int port, QObject *parent) :
+    QObject(parent)
+{
+       socket = new QTcpSocket(this);
+       m_tcphost = host;
+       m_port = port;
+
+       connect(socket, SIGNAL(connected()), this, SLOT(onConnected()));
+       connect(socket, SIGNAL(readyRead()), this, SLOT(onMessageRecieved()));
+       connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError()));
+}
+
+QString ChatClient::chatLog() const
+{
+       return m_chatLog;
+}
+
+void ChatClient::setChatLog(const QString &chatLog)
+{
+       if (m_chatLog == chatLog)
+               return;
+       m_chatLog = chatLog;
+       emit chatLogChanged(m_chatLog);
+}
+
+void ChatClient::appendToChatLog(const QString &message)
+{
+       if (message.isEmpty())
+               return;
+       m_chatLog += message;
+       emit chatLogChanged(m_chatLog);
+}
+
+void ChatClient::startChat(const QString &sessionkey)
+{
+       m_sessionkey = sessionkey;
+       socket->connectToHost(m_tcphost, m_port);
+       setChatLog("");
+}
+
+void ChatClient::stopChat()
+{
+       socket->disconnectFromHost();
+       m_sessionkey = "";
+}
+
+void ChatClient::onConnected()
+{
+       QString messageToSend = m_sessionkey + QChar('\n');
+       socket->write(messageToSend.toUtf8());
+}
+
+void ChatClient::onMessageRecieved()
+{
+       QByteArray data = socket->readAll();
+       QString message = QString::fromUtf8(data.constData(), data.size());
+       appendToChatLog(message);
+}
+
+void ChatClient::onError()
+{
+       systemMessage("Connection error: " + socket->errorString() + "\n");
+       if (socket->isOpen())
+               socket->close();
+}
+
+void ChatClient::sendMessage(const QString &message)
+{
+       QString messageToSend = message + QChar('\n');
+       socket->write(messageToSend.toUtf8());
+       appendToChatLog("You: " + messageToSend);
+}
+
+void ChatClient::systemMessage(const QString &message)
+{
+       appendToChatLog(">> " + message);
+}
diff --git a/chatclient.h b/chatclient.h
new file mode 100644 (file)
index 0000000..fcc7075
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef CHATCLIENT_H
+#define CHATCLIENT_H
+
+#include <QObject>
+
+class QTcpSocket;
+
+class ChatClient : public QObject
+{
+    Q_OBJECT
+       Q_PROPERTY(QString chatLog READ chatLog NOTIFY chatLogChanged)
+public:
+       explicit ChatClient(const QString &host, int port, QObject *parent = 0);
+
+       QString chatLog() const;
+
+signals:
+       void chatLogChanged(const QString &chatLog);
+
+public slots:
+       void startChat(const QString &sessionkey);
+       void stopChat();
+
+       void sendMessage(const QString &message);
+       void systemMessage(const QString &message);
+
+private slots:
+       void onConnected();
+       void onMessageRecieved();
+       void onError();
+
+private:
+       void setChatLog(const QString &chatLog);
+       void appendToChatLog(const QString &message);
+
+       QString m_sessionkey;
+       QString m_chatLog;
+
+       QTcpSocket *socket;
+
+       QString m_tcphost;
+       int m_port;
+};
+
+#endif // CHATCLIENT_H
index 24382850948af90c975daba9bde08e49c5e8cb38..9c157bd5cb9ac8adf678462c98c6c09a9b8195fe 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -1,16 +1,30 @@
 #include <QtGui/QApplication>
 //#include <QtOpenGL/QGLWidget>
+#include <QtDeclarative/QDeclarativeContext>
 
 #include "qmlapplicationviewer.h"
+#include "timgame.h"
+#include "chatclient.h"
 
 int main(int argc, char *argv[])
 {
+       QString serverUrl = "http://localhost/tim/index.php";
+       QString tcphost = "localhost";
+       int tcpport = 8547;
+
     QApplication app(argc, argv);
+       QCoreApplication::setApplicationName("Tim Game");
+
+       TimGame timGame(serverUrl);
+       ChatClient chatClient(tcphost, tcpport);
 
     QmlApplicationViewer viewer;
     viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
-    viewer.setMainQmlFile(QLatin1String("qml/tim-game/main.qml"));
+       viewer.rootContext()->setContextProperty("timGame", &timGame);
+       viewer.rootContext()->setContextProperty("chatClient", &chatClient);
+       viewer.setMainQmlFile(QLatin1String("qml/tim-game/main.qml"));
 //     viewer.setViewport(new QGLWidget());
+       viewer.setWindowTitle(QCoreApplication::applicationName());
     viewer.show();
 
     return app.exec();
index e8f54ff0c0c665256aefdd918e0cfc41d0b4bbd3..73b120243c6c3af2377af00f57db3573ff060c37 100644 (file)
@@ -2,23 +2,39 @@ import Qt 4.7
 
 FocusScope {
        id: wrapper
+       Flickable {
+               id: chatViewContainer
 
-       ListView {
-               id: chatView
-               x: 0; y: 0
-               height: parent.height - 80
-               anchors.right: parent.right
-               anchors.left: parent.left
-               anchors.top: parent.top
+               x: 4; y: 4
+               height: parent.height - 84
+               width: parent.width - x * 2
                anchors.topMargin: 0
                anchors.rightMargin: 0
                anchors.leftMargin: 0
+
+               contentWidth: chatView.paintedWidth
+               contentHeight: chatView.paintedHeight
+               clip: true
+               flickableDirection: Flickable.VerticalFlick
+
+               contentY: contentHeight - chatView.height
+
+               TextEdit {
+                       id: chatView
+                       readOnly: true
+                       width: chatViewContainer.width
+                       height: chatViewContainer.height
+                       text: chatClient.chatLog
+                       color: "orange"
+                       font.pixelSize: 15
+                       wrapMode: TextEdit.Wrap
+               }
        }
 
        Input {
                id: inputLine
                focus: true
-               anchors.top: chatView.bottom
+               anchors.top: chatViewContainer.bottom
                anchors.topMargin: 0
 
                anchors.right: sendButton.left
@@ -39,6 +55,7 @@ FocusScope {
                                exitChatView()
                                return;
                        }
+                       chatClient.sendMessage(message);
                }
 
                function exitChatView() {
@@ -46,13 +63,14 @@ FocusScope {
                        screen.state = ""
                }
        }
+
        Button {
                width: 80
                id: sendButton
                text: ">"
                anchors.bottom: parent.bottom
                anchors.bottomMargin: 0
-               anchors.top: chatView.bottom
+               anchors.top: chatViewContainer.bottom
                anchors.topMargin: 0
                anchors.right: parent.right
                anchors.rightMargin: 0
index c0fa2f4496f0191673b4bbb3d55ce9e42481fb90..660d91fee1ceeeb5c140b5ea370bea21eb95e6bf 100644 (file)
@@ -43,6 +43,8 @@ FocusScope {
                                                return;
                                        screen.focus = true;
                                        screen.state = "";
+                                       timGame.uploadScore(highScore.text);
+                                       highScore.text = "";
                                }
                        }
 
index bae3decf1bd6fab05b22b53c2abd99d1b4529352..3f365e36ae10e5dcbf68b68e820f940f9b03d31d 100644 (file)
@@ -13,8 +13,8 @@ FocusScope {
     TextInput{
         id: input
         width: parent.width - 12
-        anchors.centerIn: parent
-        maximumLength:21
+               anchors.centerIn: parent
+               maximumLength:500
                font.pixelSize: 24;
         font.bold: true
         color: "#151515"; selectionColor: "mediumseagreen"
index e023c9c0edb61820d5909e2f7d5d201b3451e14a..82c7fb3eb7d221cb660d930ed8daad66b7c8f6a5 100644 (file)
@@ -52,8 +52,10 @@ FocusScope {
                                        if (wrapper.state=="invalidinput")
                                                return;
                                        screen.focus = true;
-                                       screen.state = "";
-                                       screen.logIn();
+                                       screen.state = "loggingOutState";
+                                       timGame.login(user.text, pass.text);
+                                       user.text = "";
+                                       pass.text = "";
                                }
                        }
 
@@ -74,7 +76,7 @@ FocusScope {
 
                                function goBack() {
                                        screen.focus = true;
-                                       screen.state = ""
+                                       screen.state = "";
                                }
                        }
                }
@@ -82,7 +84,7 @@ FocusScope {
     states:
     State {
         name: "invalidinput"
-               when: user.text=="" || pass.text==""
+               when: user.text === "" || pass.text === ""
                PropertyChanges { target: loginButton ; opacity: 0.6 ; }
     }
     transitions:
diff --git a/qml/tim-game/Components/MessageBox.qml b/qml/tim-game/Components/MessageBox.qml
new file mode 100644 (file)
index 0000000..28687ff
--- /dev/null
@@ -0,0 +1,28 @@
+import Qt 4.7
+
+Rectangle {
+       property variant message: ""
+       signal accepted
+
+       id: messageBox
+
+       width: screen.width
+       height: 50
+       color: "#FFD700"
+
+       Text {
+               id: textBox
+               text: message
+               font.pixelSize: 40
+               horizontalAlignment: Text.AlignHCenter
+               anchors.fill: parent
+       }
+
+       MouseArea {
+               width: screen.width
+               height: screen.height
+               onClicked: {
+                       messageBox.accepted()
+               }
+       }
+}
index b9bd13e61a96424607ecf2d6db9c693f27372271..6e7c545903723fcbeaeecd29e35dbb13e1299539 100644 (file)
@@ -64,6 +64,10 @@ FocusScope {
                                                return;
                                        screen.focus = true;
                                        screen.state = ""
+                                       timGame.registration(user.text, pass.text);
+                                       user.text = "";
+                                       pass.text = "";
+                                       passRetyped.text = "";
                                }
                        }
                        Button {
@@ -83,7 +87,7 @@ FocusScope {
 
                                function goBack() {
                                        screen.focus = true;
-                                       screen.state = ""
+                                       screen.state = "";
                                }
                        }
                }
@@ -91,7 +95,7 @@ FocusScope {
     states:
     State {
         name: "invalidinput"
-               when: user.text == "" || pass.text == "" || pass.text != passRetyped.text
+               when: user.text === "" || pass.text === "" || pass.text != passRetyped.text
                PropertyChanges { target: registerButton ; opacity: 0.6 ; }
     }
     transitions:
diff --git a/qml/tim-game/Components/ScoreDelegate.qml b/qml/tim-game/Components/ScoreDelegate.qml
new file mode 100644 (file)
index 0000000..3ef5d19
--- /dev/null
@@ -0,0 +1,78 @@
+import Qt 4.7
+
+Component {
+       Item {
+               id: wrapper
+
+               height: 50 + (position == 1 ? 20 : 0)
+               x: 5
+               width: wrapper.ListView.view.width - 10
+
+               function color(position)
+               {
+                       if (position == 1)
+                               return "gold";
+                       else if (position == 2)
+                               return "silver";
+                       else if(position == 3)
+                               return "brown";
+                       else
+                               return "white";
+               }
+
+               function fontSize(position)
+               {
+                       if (position == 1)
+                               return 50;
+                       else if (position == 2)
+                               return 40;
+                       else if(position == 3)
+                               return 30
+                       else
+                               return 20
+               }
+
+               Rectangle
+               {
+                       id: background
+                       color: "gray"
+                       opacity: 0.2
+                       radius: 10
+                       y: 2
+                       height: parent.height - y * 2
+                       width: parent.width
+               }
+
+               Text {
+                       id: positionText
+                       text: position + "."
+
+
+                       color: wrapper.color(position)
+                       font.pixelSize: wrapper.fontSize(position)
+                       anchors.leftMargin: 4
+                       anchors.left: background.left
+                       anchors.verticalCenter: background.verticalCenter
+               }
+
+               Text {
+                       id: scoreText
+                       text: score
+
+                       color: wrapper.color(position)
+                       font.pixelSize: wrapper.fontSize(position)
+                       anchors.horizontalCenter: background.horizontalCenter
+                       anchors.verticalCenter: background.verticalCenter
+               }
+
+               Text {
+                       id: userNameText
+                       text: userName
+                       color: wrapper.color(position)
+                       font.pixelSize: wrapper.fontSize(position)
+                       anchors.rightMargin: 4
+                       anchors.right: background.right
+                       anchors.verticalCenter: background.verticalCenter
+               }
+       }
+}
index 792faca423db4dd7cf21b737f8d4e58cbbb84f37..a1df435dfbdfbe17660f99fc2cfe42cacb906861 100644 (file)
@@ -4,14 +4,37 @@ import "Components" 1.0 as Components
 Item {
        id: screen; width: 520; height: 480
 
-       property bool loggedIn: false
-       property variant sessionId: ""
+       property bool loggedIn: false;
 
        function logOut() {
-               loggedIn = false; sessionId = "";
+               timGame.logout();
                screen.state = "";
+               chatClient.stopChat();
+       }
+
+       Connections {
+               target: timGame
+               onError: {
+                       messageBox.message = "Error: " + timGame.error;
+                       messageBox.state = "showMessageBox";
+                       screen.state = ""
+               }
+               onLoggedIn: {
+                       messageBox.message = "Logged In!";
+                       messageBox.state = "showMessageBox";
+                       screen.state = ""
+                       chatClient.startChat(timGame.sessionkey);
+               }
+               onRegistered: {
+                       messageBox.message = "Registration complete!";
+                       messageBox.state = "showMessageBox";
+               }
+               onScoreUploaded: {
+                       messageBox.message = "Score uploaded!";
+                       messageBox.state = "showMessageBox";
+                       scoreModel.reload();
+               }
        }
-       function logIn(sessionId) { loggedIn = true; sessionId = sessionId;}
 
        Timer {
                id: loggingOutTimer
@@ -19,16 +42,27 @@ Item {
                onTriggered: { logOut() }
        }
 
+       Timer {
+               id: loggingInTimer
+               interval: 500
+               onTriggered: screen.state = "";
+       }
+
        Rectangle {
                id: background
                anchors.fill: parent; color: "#343434";
 
-               state:"searchquery"
                Image { source: "Components/images/stripes.png"; fillMode: Image.Tile; anchors.fill: parent; opacity: 0.3 }
 
+               Components.ScoreModel { id: scoreModel }
+               Components.Loading {anchors.centerIn: parent; visible: scoreModel.status == XmlListModel.Loading;}
+
                ListView {
-                       id: highScoreTable;// model: rssModel.model; delegate: fatDelegate;
-                       width: parent.width; height: parent.height; x: 0; cacheBuffer: 100;
+                       id: highScoreTable;
+                       model: scoreModel.model
+                       delegate: Components.ScoreDelegate {}
+                       width: parent.width - 8; height: parent.height - 8; x: 4; y: 4; cacheBuffer: 100;
+
                }
 
                Components.LoginForm
@@ -84,7 +118,7 @@ Item {
                        states: [
                                State {
                                        name: "loggedIn"
-                                       when: screen.loggedIn
+                                       when: timGame.loggedIn
                                        PropertyChanges {
                                                target: toolBar
 
@@ -110,16 +144,28 @@ Item {
                                }
                        ]
                }
+
+               Components.MessageBox {
+                       id: messageBox
+                       y: -screen.height * 2
+                       onAccepted: state = ""
+                       states: [
+                               State {
+                                       name: "showMessageBox"
+                                       PropertyChanges { target: messageBox; y: 150 }
+                               }
+                       ]
+                       transitions: [
+                               Transition { NumberAnimation { properties: "x,y,opacity"; duration: 500; easing.type: Easing.InOutQuad } }
+                       ]
+               }
        }
        states: [
                State {
                        name: "showLoginForm";
                        PropertyChanges { target: loginForm; x: 0; focus:true}
                        PropertyChanges { target: highScoreTable; x: -(parent.width * 1.5) }
-                       //PropertyChanges { target: titleBar; y: -80 }
                        PropertyChanges { target: toolBar; y: screen.height }
-                       //PropertyChanges { target: toolBar }
-                       //PropertyChanges { target: title; opacity:1}
                },
                State {
                        name: "showRegistrationForm";
diff --git a/serverreplyparser.cpp b/serverreplyparser.cpp
new file mode 100644 (file)
index 0000000..43fb4d8
--- /dev/null
@@ -0,0 +1,128 @@
+#include "serverreplyparser.h"
+
+#include <QDebug>
+
+ServerReplyParser::ServerReplyParser(QObject *parent) :
+    QObject(parent)
+{
+       reset();
+}
+
+ServerReplyParser::ReplyType ServerReplyParser::replyType()
+{
+       return m_replyType;
+}
+
+QString ServerReplyParser::error()
+{
+       return m_error;
+}
+
+QString ServerReplyParser::userName()
+{
+       return m_userName;
+}
+
+int ServerReplyParser::userId()
+{
+       return m_userId;
+}
+
+QString ServerReplyParser::sessionkey()
+{
+       return m_sessionkey;
+}
+
+bool ServerReplyParser::read(QIODevice *dev)
+{
+       reset();
+       xml.setDevice(dev);
+
+       if (xml.readNextStartElement())
+       {
+               if (xml.name() == "message")
+                       readMessage();
+               else
+                       xml.raiseError(QObject::tr("Unknown reply format"));
+       }
+
+       return !xml.hasError();
+}
+
+void ServerReplyParser::readMessage()
+{
+       Q_ASSERT(xml.isStartElement() && xml.name() == "message");
+
+       while (xml.readNextStartElement()) {
+               if (xml.name() == "error")
+                       readError();
+               else if (xml.name() == "login")
+                       readLogin();
+               else if (xml.name() == "register")
+                       readRegister();
+               else if (xml.name() == "setscore")
+                       readSetScore();
+               else
+                       xml.skipCurrentElement();
+       }
+}
+
+void ServerReplyParser::readError()
+{
+       setReplyType(ErrorReply);
+       m_error = xml.readElementText();
+}
+
+void ServerReplyParser::readLogin()
+{
+       Q_ASSERT(xml.isStartElement() && xml.name() == "login");
+
+       setReplyType(LoginReply);
+       while (xml.readNextStartElement()) {
+               if (xml.name() == "sessionkey") {
+                       m_sessionkey = xml.readElementText(); continue;
+               }
+               else if (xml.name() == "user") {
+                       m_userName = xml.readElementText(); continue;
+               }
+               else if (xml.name() == "userid") {
+                       m_userId = xml.readElementText().toInt(); continue;
+               }
+               else
+                       xml.skipCurrentElement();
+       }
+}
+
+void ServerReplyParser::readRegister()
+{
+       setReplyType(RegistrationReply);
+       xml.readNext();
+}
+
+void ServerReplyParser::readSetScore()
+{
+       setReplyType(SetScoreReply);
+       xml.readNext();
+}
+
+
+void ServerReplyParser::setReplyType(ServerReplyParser::ReplyType replyType)
+{
+       if (typeDetermined)
+               return;
+       m_replyType = replyType;
+       typeDetermined = true;
+}
+
+void ServerReplyParser::reset()
+{
+       xml.clear();
+       typeDetermined = false;
+       m_replyType = UnknownReply;
+       m_error = "";
+       m_userName = "";
+       m_userId = 0;
+       m_sessionkey = "";
+}
+
+
diff --git a/serverreplyparser.h b/serverreplyparser.h
new file mode 100644 (file)
index 0000000..14d218c
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SERVERREPLYPARSER_H
+#define SERVERREPLYPARSER_H
+
+#include <QObject>
+#include <QXmlStreamReader>
+
+class QIODevice;
+
+class ServerReplyParser : public QObject
+{
+    Q_OBJECT
+public:
+       enum ReplyType
+       {
+               UnknownReply,
+               ErrorReply,
+               LoginReply,
+               RegistrationReply,
+               SetScoreReply
+       };
+
+    explicit ServerReplyParser(QObject *parent = 0);
+
+       ReplyType replyType();
+
+       QString error();
+
+       QString userName();
+       int userId();
+       QString sessionkey();
+
+       bool read(QIODevice *dev);
+
+protected:
+       void readMessage();
+       void readError();
+
+       void readLogin();
+       void readRegister();
+       void readSetScore();
+
+signals:
+
+private:
+       void setReplyType(ReplyType replyType);
+       void reset();
+
+       QXmlStreamReader xml;
+
+       ReplyType m_replyType;
+       QString m_error;
+       QString m_userName;
+       int m_userId;
+       QString m_sessionkey;
+
+       bool typeDetermined;
+};
+
+#endif // SERVERREPLYPARSER_H
index f42433bdd0b2b0c6f7338c7e6981e258181e7d38..fa9b6f3ade5829e600d1d0d76f902e43de06699a 100644 (file)
@@ -1,3 +1,5 @@
+QT += network
+
 # Add more folders to ship with the application, here
 folder_01.source = qml/tim-game
 folder_01.target = qml
@@ -25,7 +27,10 @@ symbian:TARGET.UID3 = 0xE45C3B88
 # MOBILITY +=
 
 # The .cpp file which was generated for your project. Feel free to hack it.
-SOURCES += main.cpp
+SOURCES += main.cpp \
+    timgame.cpp \
+    serverreplyparser.cpp \
+    chatclient.cpp
 
 # Please do not modify the following two lines. Required for deployment.
 include(qmlapplicationviewer/qmlapplicationviewer.pri)
@@ -39,3 +44,8 @@ unix:!symbian {
     }
     INSTALLS += target
 }
+
+HEADERS += \
+    timgame.h \
+    serverreplyparser.h \
+    chatclient.h
diff --git a/timgame.cpp b/timgame.cpp
new file mode 100644 (file)
index 0000000..a8be295
--- /dev/null
@@ -0,0 +1,170 @@
+#include "timgame.h"
+
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkReply>
+
+#include "serverreplyparser.h"
+
+TimGame::TimGame(const QString &serverUrl, QObject *parent) :
+    QObject(parent)
+{
+       networkManager = new QNetworkAccessManager(this);
+       replyParser = new ServerReplyParser(this);
+
+       m_loggedIn = false;
+       m_userId = 0;
+
+       m_serverUrl = serverUrl;
+}
+
+bool TimGame::isLoggedIn() const
+{
+       return m_loggedIn;
+}
+
+void TimGame::setLoggedIn(bool isLoggedIn)
+{
+       if (isLoggedIn == m_loggedIn)
+               return;
+       m_loggedIn = isLoggedIn;
+       emit loggedInChanged(m_loggedIn);
+}
+
+QString TimGame::user() const
+{
+       return m_user;
+}
+
+void TimGame::setUser(const QString &name)
+{
+       if (m_user == name)
+               return;
+       m_user = name;
+       emit userChanged(m_user);
+}
+
+int TimGame::userId() const
+{
+       return m_userId;
+}
+
+void TimGame::setUserId(int userId)
+{
+       if (m_userId == userId)
+               return;
+       m_userId = userId;
+       emit userIdChanged(m_userId);
+}
+
+QString TimGame::error() const
+{
+       return m_error;
+}
+
+void TimGame::setError(const QString &error)
+{
+       if (m_error == error)
+               return;
+       m_error = error;
+       emit errorChanged(m_error);
+}
+
+QString TimGame::sessionkey() const
+{
+       return m_sessionkey;
+}
+
+void TimGame::setSessionkey(const QString &sessionkey)
+{
+       if (m_sessionkey == sessionkey)
+               return;
+       m_sessionkey = sessionkey;
+       emit sessionkeyChanged(m_sessionkey);
+}
+
+
+QString TimGame::serverUrl() const
+{
+       return m_serverUrl;
+}
+
+void TimGame::registration(const QString &user, const QString &pass)
+{
+       QNetworkRequest registrationRequest(QUrl::fromUserInput(m_serverUrl + QString("?a=register&user=%1&pass=%2").arg(user, pass)));
+       QNetworkReply *registrationReply = networkManager->get(registrationRequest);
+       connect(registrationReply, SIGNAL(finished()), this, SLOT(networkRequestComplete()));
+}
+
+void TimGame::login(const QString &user, const QString &pass)
+{
+       QNetworkRequest loginRequest(QUrl::fromUserInput(m_serverUrl + QString("?a=login&user=%1&pass=%2").arg(user, pass)));
+       QNetworkReply *loginReply = networkManager->get(loginRequest);
+       connect(loginReply, SIGNAL(finished()), this, SLOT(networkRequestComplete()));
+}
+
+void TimGame::logout()
+{
+       m_sessionkey = "";
+       setLoggedIn(false);
+}
+
+void TimGame::uploadScore(int score)
+{
+       if (!isLoggedIn())
+               return;
+       QNetworkRequest scoreRequest(QUrl::fromUserInput(m_serverUrl + QString("?a=setscore&s=%1&score=%2").arg(m_sessionkey).arg(score)));
+       QNetworkReply *scoreReply = networkManager->get(scoreRequest);
+       connect(scoreReply, SIGNAL(finished()), this, SLOT(networkRequestComplete()));
+}
+
+void TimGame::networkRequestComplete()
+{
+       QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
+
+       if (!reply)
+               return;
+
+       if (reply->error() != QNetworkReply::NoError)
+       {
+               m_error = "Network error";
+               emit error(m_error);
+               goto finish;
+       }
+
+       if (!replyParser->read(reply))
+       {
+               m_error = "Unexpected Reply From Server (xml)";
+               emit error(m_error);
+               goto finish;
+       }
+
+       switch (replyParser->replyType())
+       {
+               case ServerReplyParser::UnknownReply:
+                       m_error = "Unexpected Reply From Server";
+                       emit error(m_error);
+                       goto finish;
+               break;
+               case ServerReplyParser::ErrorReply:
+                       m_error = replyParser->error();
+                       emit error(m_error);
+               break;
+               case ServerReplyParser::LoginReply:
+                       setUser(replyParser->userName());
+                       setUserId(replyParser->userId());
+                       m_sessionkey = replyParser->sessionkey();
+                       setLoggedIn(true);
+                       emit loggedIn();
+               break;
+               case ServerReplyParser::RegistrationReply:
+                       emit registered();
+               break;
+               case ServerReplyParser::SetScoreReply:
+                       emit scoreUploaded();
+               break;
+       }
+
+finish:
+       reply->deleteLater();
+}
diff --git a/timgame.h b/timgame.h
new file mode 100644 (file)
index 0000000..318253b
--- /dev/null
+++ b/timgame.h
@@ -0,0 +1,76 @@
+#ifndef TIMGAME_H
+#define TIMGAME_H
+
+#include <QObject>
+class QNetworkAccessManager;
+class ServerReplyParser;
+
+class TimGame : public QObject
+{
+    Q_OBJECT
+
+       Q_PROPERTY(bool loggedIn READ isLoggedIn NOTIFY loggedInChanged)
+       Q_PROPERTY(QString user READ user NOTIFY userChanged)
+       Q_PROPERTY(int userId READ userId NOTIFY userIdChanged)
+       Q_PROPERTY(QString error READ error NOTIFY errorChanged)
+       Q_PROPERTY(QString sessionkey READ sessionkey NOTIFY sessionkeyChanged)
+
+       Q_PROPERTY(QString serverUrl READ serverUrl NOTIFY serverUrlChanged)
+
+public:
+       explicit TimGame(const QString &serverUrl, QObject *parent = 0);
+
+       bool isLoggedIn() const;
+       QString user() const;
+       int userId() const;
+       QString error() const;
+       QString sessionkey() const;
+
+       QString serverUrl() const;
+
+signals:
+       void error(const QString &error);
+
+       void loggedIn();
+       void loggedInChanged(bool oggedIn);
+
+       void registered();
+       void scoreUploaded();
+
+       void userChanged(const QString &name);
+       void userIdChanged(int id);
+       void errorChanged(const QString &error);
+       void sessionkeyChanged(const QString &sessionkey);
+       void serverUrlChanged(const QString &serverUrl);
+
+public slots:
+       void registration(const QString &user, const QString &pass);
+       void login(const QString &user, const QString &pass);
+       void logout();
+
+       void uploadScore(int score);
+
+private slots:
+       void networkRequestComplete();
+
+private:
+       void setLoggedIn(bool isLoggedIn);
+       void setUser(const QString &name);
+       void setUserId(int userId);
+       void setError(const QString &error);
+       void setSessionkey(const QString &sessionkey);
+
+       bool m_loggedIn;
+       QString m_user;
+       int m_userId;
+       QString m_error;
+
+       QString m_sessionkey;
+
+       QString m_serverUrl;
+
+       QNetworkAccessManager *networkManager;
+       ServerReplyParser *replyParser;
+};
+
+#endif // TIMGAME_H