4
1
mirror of https://github.com/QuasarApp/Snake.git synced 2025-05-09 07:59:48 +00:00

ref tmp commit

This commit is contained in:
Andrei Yankovich 2021-05-25 17:18:56 +03:00
parent bd78303d02
commit ee5a3be629
104 changed files with 5198 additions and 68 deletions
CMakeLists.txt
src/ClientLib

@ -20,8 +20,8 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Test QUIET)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test QUIET)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Test REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test REQUIRED)
include(submodules/QuasarAppLib/CMake/QuasarApp.cmake)

@ -27,12 +27,13 @@ endif()
set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Private")
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick REQUIRED)
add_library(${PROJECT_NAME} ${SOURCE_CPP} ${SOURCE_QRC})
if (${QT_VERSION_MAJOR})
target_link_libraries(${PROJECT_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick)
target_include_directories(${PROJECT_NAME} PUBLIC ${PUBLIC_INCUDE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${PRIVATE_INCUDE_DIR})

@ -2,5 +2,28 @@
<qresource prefix="/">
<file>SnakeProjectModule/qmldir</file>
<file>SnakeProjectModule/SnakeProject.qml</file>
<file>SnakeProjectModule/About.qml</file>
<file>SnakeProjectModule/AboutPage.qml</file>
<file>SnakeProjectModule/BasePopUp.qml</file>
<file>SnakeProjectModule/FrameView.qml</file>
<file>SnakeProjectModule/GraphicItem.qml</file>
<file>SnakeProjectModule/ImageView.qml</file>
<file>SnakeProjectModule/LeftBoxSideBar.qml</file>
<file>SnakeProjectModule/LeftSideBar.qml</file>
<file>SnakeProjectModule/LoginView.qml</file>
<file>SnakeProjectModule/MainMenu.qml</file>
<file>SnakeProjectModule/MainMenuButton.qml</file>
<file>SnakeProjectModule/Metrix.qml</file>
<file>SnakeProjectModule/NotificationForm.qml</file>
<file>SnakeProjectModule/NotificationServiceView.qml</file>
<file>SnakeProjectModule/PagePopUp.qml</file>
<file>SnakeProjectModule/PropertyView.qml</file>
<file>SnakeProjectModule/Scene.qml</file>
<file>SnakeProjectModule/SelectLevelScene.qml</file>
<file>SnakeProjectModule/SettingsView.qml</file>
<file>SnakeProjectModule/SideBar.qml</file>
<file>SnakeProjectModule/SnakeItem.qml</file>
<file>SnakeProjectModule/TextInput.qml</file>
<file>SnakeProjectModule/UserView.qml</file>
</qresource>
</RCC>

@ -0,0 +1,180 @@
#include "mainclient.h"
#include "notificationservice.h"
#include "playerclientdata.h"
#include <QSharedPointer>
OnlineStatus MainClient::onlineStatus() const {
return _onlineStatus;
}
void MainClient::setOnlineStatus(OnlineStatus onlineStatus) {
if (_onlineStatus == onlineStatus)
return;
emit sigOnlineStatusChanged(_onlineStatus = onlineStatus);
pushNotify(onlineStatus);
}
void MainClient::clientStatusChanged() {
auto status = OnlineStatus::ClientIsOffline;
if (isOnline()) {
status = OnlineStatus::AuthorizationRequired;
}
if (isLogin()) {
status = OnlineStatus::Success;
}
setOnlineStatus(status);
}
void MainClient::pushNotify(OnlineStatus onlineStatus) {
switch (onlineStatus) {
case OnlineStatus::Success: {
NotificationService::getService()->setNotify(
NotificationData(tr("Login status"), tr("Success")));
break;
}
case OnlineStatus::AuthorizationRequired: {
NotificationService::getService()->setNotify(
NotificationData(tr("Login status"), tr("Authorization Required")));
break;
}
case OnlineStatus::WaitForAnswer: {
NotificationService::getService()->setNotify(
NotificationData(tr("Login status"), tr("Wait for answer")));
break;
}
case OnlineStatus::AuthorizationFail: {
NotificationService::getService()->setNotify(
NotificationData(tr("Login result"), tr("Authorization fail") , "", NotificationData::Error));
break;
}
case OnlineStatus::ClientIsOffline: {
NotificationService::getService()->setNotify(
NotificationData(tr("Login result"), tr("Client is offline"), "", NotificationData::Warning));
break;
}
case OnlineStatus::OfflineMode: {
NotificationService::getService()->setNotify(
NotificationData(tr("Login result"), tr("Offline Mode")));
break;
}
default: break;
}
}
void MainClient::handleReceivePackage(ClientProtocol::Command cmd, const QByteArray &obj) {
switch (cmd) {
case ClientProtocol::Command::Player: {
auto playerData = QSharedPointer<PlayerClientData>::create();
playerData->fromBytes(obj);
_users [playerData->id()] = playerData;
if (playerData->id() == _currentUserId) {
emit currentUserDataChanged(_users [playerData->id()]);
}
break;
}
case ClientProtocol::Command::BadRequest: {
NotificationService::getService()->setNotify(
NotificationData(tr("Request"), tr("Bad Request"), "",
NotificationData::Error));
break;
}
default: return;
}
}
void MainClient::handleLoginChanged(bool logined) {
this->setSubscribe(ClientProtocol::Command::Player, logined, _currentUserId);
clientStatusChanged();
}
void MainClient::handleOnlineChanged(bool) {
clientStatusChanged();
}
MainClient::MainClient(const QString &addrress, unsigned short port, QObject *ptr):
ClientProtocol::Client (addrress, port, ptr) {
connect(this, &MainClient::sigIncommingData,
this, &MainClient::handleReceivePackage);
connect(this, &MainClient::onlineChanged,
this, &MainClient::handleOnlineChanged);
connect(this, &MainClient::loginChanged,
this, &MainClient::handleLoginChanged);
}
bool MainClient::login(const QString &gmail, const QByteArray &pass, bool) {
if (!ClientProtocol::Client::login(gmail, pass)) {
setOnlineStatus(OnlineStatus::AuthorizationFail);
return false;
}
return true;
}
bool MainClient::registration(const QString &gmail,
const QByteArray &pass) {
if (!ClientProtocol::Client::registration(gmail, pass)) {
setOnlineStatus(OnlineStatus::AuthorizationFail);
return false;
}
return true;
}
void MainClient::playOffline() {
if (_onlineStatus == OnlineStatus::ClientIsOffline) {
setOnlineStatus(OfflineMode);
}
}
void MainClient::tryConnect(const QString &addrress, unsigned short port) {
setOnlineStatus(ClientIsOffline);
connectToHost(addrress, port);
}
MainClient::~MainClient() {
for (auto &i: _users) {
i.clear();
}
_users.clear();
}

@ -0,0 +1,51 @@
#ifndef MAINCLIENT_H
#define MAINCLIENT_H
#include <client.h>
class PlayerClientData;
enum OnlineStatus: int {
Success = 0x0,
AuthorizationRequired,
WaitForAnswer,
AuthorizationFail,
ClientIsOffline,
OfflineMode
};
class MainClient: public ClientProtocol::Client
{
Q_OBJECT
private:
QHash<int, QSharedPointer<PlayerClientData>> _users;
OnlineStatus _onlineStatus = ClientIsOffline;
void setOnlineStatus(OnlineStatus onlineStatus);
void clientStatusChanged();
void pushNotify(OnlineStatus onlineStatus);
private slots:
void handleReceivePackage(ClientProtocol::Command cmd, const QByteArray& obj);
void handleLoginChanged(bool);
void handleOnlineChanged(bool);
public:
MainClient(const QString& addrress = LOCAL_SNAKE_SERVER,
unsigned short port = DEFAULT_SNAKE_PORT,
QObject * ptr = nullptr);
bool login(const QString& gmail, const QByteArray &pass, bool registerNewUser = false) override;
bool registration(const QString& gmail,
const QByteArray &pass) override;
void playOffline();
void tryConnect(const QString &addrress, unsigned short port);
~MainClient() override;
OnlineStatus onlineStatus() const;
signals:
void sigOnlineStatusChanged(OnlineStatus);
void currentUserDataChanged(QSharedPointer<PlayerClientData>);
};
#endif // MAINCLIENT_H

@ -0,0 +1,59 @@
#include "mainmenumodel.h"
#include "settingsviewmodel.h"
#include "userview.h"
#include <back-end/settings.h>
#include <quasarapp.h>
#include "mainclient.h"
MainMenuModel::MainMenuModel(QObject *ptr): QObject (ptr) {
if(!ClientProtocol::initClientProtockol()) {
QuasarAppUtils::Params::verboseLog("client protockol not inited", QuasarAppUtils::Error);
}
_userViewModel = new UserView (this);
_conf = Settings::get();
_userSettingsModel = new SettingsViewModel(this);
auto adderss = _conf->getValue(SERVER_ADDRESS, SERVER_ADDRESS_DEFAULT).toString();
auto port = _conf->getValue(SERVER_ADDRESS_PORT, SERVER_ADDRESS_DEFAULT_PORT).toInt();
_client = new MainClient(adderss, static_cast<unsigned short>(port), this);
connect(_client, &MainClient::sigOnlineStatusChanged,
this , &MainMenuModel::onlineStatusChanged);
connect(_client, &MainClient::currentUserDataChanged,
_userViewModel , &UserView::setSource);
}
QObject *MainMenuModel::userViewModel() const {
return _userViewModel;
}
int MainMenuModel::onlineStatus() const {
return _client->onlineStatus();
}
void MainMenuModel::playOffline() {
_client->playOffline();
_userViewModel->setOffline(true);
}
void MainMenuModel::tryConnect() {
auto adderss = _conf->getValue(SERVER_ADDRESS, SERVER_ADDRESS_DEFAULT).toString();
auto port = _conf->getValue(SERVER_ADDRESS_PORT, SERVER_ADDRESS_DEFAULT_PORT).toInt();
_client->tryConnect(adderss, static_cast<unsigned short>(port));
}
QObject *MainMenuModel::userSettingsModel() const {
return _userSettingsModel;
}
void MainMenuModel::login(const QString &email, const QString &pass) {
_client->login(email, pass.toUtf8());
}
void MainMenuModel::registerNewUser(const QString &email,
const QString &pass) {
_client->registration(email, pass.toUtf8());
}

@ -0,0 +1,51 @@
#ifndef NETWORKPROFILEMAINMODEL_H
#define NETWORKPROFILEMAINMODEL_H
#include "mainclient.h"
#include <QObject>
#include "./../settings.h"
class UserView;
class MainClient;
class SettingsViewModel;
class MainMenuModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* userViewModel READ userViewModel NOTIFY userViewModelChanged)
Q_PROPERTY(QObject* userSettingsModel READ userSettingsModel NOTIFY userSettingsModelChanged)
Q_PROPERTY(int onlineStatus READ onlineStatus NOTIFY onlineStatusChanged)
private:
UserView* _userViewModel = nullptr;
SettingsViewModel* _userSettingsModel = nullptr;
MainClient *_client = nullptr;
Settings *_conf = nullptr;
public:
MainMenuModel(QObject *ptr = nullptr);
QObject* userViewModel() const;
QObject* userSettingsModel() const;
int onlineStatus() const;
Q_INVOKABLE void playOffline();
Q_INVOKABLE void tryConnect();
public slots:
void login(const QString& email, const QString& pass);
void registerNewUser(const QString& email, const QString& pass);
signals:
void userViewModelChanged(QObject* userViewModel);
void newGame();
void onlinelChanged(bool online);
void loginChanged(bool login);
void onlineStatusChanged();
void userSettingsModelChanged(QObject* userSettingsModel);
};
#endif // NETWORKPROFILEMAINMODEL_H

@ -0,0 +1,23 @@
#include "networkclient.h"
#include "playerclientdata.h"
#include <updateplayerdata.h>
int NetworkClient::loginedPlayer() const {
return _loginedPlayer;
}
void NetworkClient::handleReceiveData(ClientProtocol::Command cmd,
const QByteArray &obj) {
if (cmd == ClientProtocol::Command::Player) {
PlayerClientData data;
data.fromBytes(obj);
_playersDats[data.id()] = data;
}
}
NetworkClient::NetworkClient() {
}

@ -0,0 +1,21 @@
#ifndef CLIENT_H
#define CLIENT_H
#include "playerclientdata.h"
#include <client.h>
class NetworkClient : public ClientProtocol::Client
{
Q_OBJECT
private:
QHash<int, PlayerClientData> _playersDats;
int _loginedPlayer;
private slots:
void handleReceiveData(ClientProtocol::Command cmd, const QByteArray& obj);
public:
NetworkClient();
int loginedPlayer() const;
};
#endif // CLIENT_H

@ -0,0 +1,38 @@
#include "notificationdata.h"
NotificationData::NotificationData(const QString &title,
const QString &text,
const QString &img, Type type) {
_text = text;
_title = title;
_img = img;
_type = type;
}
QString NotificationData::text() const {
return _text;
}
QString NotificationData::img() const {
return _img;
}
QString NotificationData::title() const {
return _title;
}
bool NotificationData::operator ==(const NotificationData &righ) {
return _title == righ._title &&
_text == righ._text &&
_img == righ._img &&
_type == righ._type;
}
bool NotificationData::operator !=(const NotificationData &righ) {
return !operator==(righ);
}
int NotificationData::type() const {
return _type;
}

@ -0,0 +1,41 @@
#ifndef NOTIFICATIONDATA_H
#define NOTIFICATIONDATA_H
#include <QObject>
class NotificationData
{
Q_GADGET
Q_PROPERTY(QString text READ text)
Q_PROPERTY(QString img READ img)
Q_PROPERTY(QString title READ title)
Q_PROPERTY(int type READ type)
QString _text;
QString _img;
QString _title;
int _type;
public:
enum Type {
Normal,
Warning = 1,
Error = 2,
};
explicit NotificationData(const QString& title = "",
const QString& text = "",
const QString& img = "",
Type type = Type::Normal);
Q_INVOKABLE QString text() const;
Q_INVOKABLE QString img() const;
Q_INVOKABLE QString title() const;
Q_INVOKABLE int type() const;
bool operator ==(const NotificationData &righ);
bool operator !=(const NotificationData &righ);
};
#endif // NOTIFICATIONDATA_H

@ -0,0 +1,38 @@
#include "notificationservice.h"
NotificationService::NotificationService(QObject * ptr): QObject (ptr) {
qRegisterMetaType<NotificationData>("NotificationData");
qRegisterMetaType<QList<NotificationData>> ("QList<NotificationData>");
}
NotificationData NotificationService::notify() const {
return _notify;
}
void NotificationService::setNotify(const NotificationData& notify) {
if (_notify != notify)
_history.push_back(_notify);
_notify = notify;
emit notifyChanged();
}
void NotificationService::setNotify(const QString &title,
const QString &text,
const QString &img,
int type) {
setNotify(NotificationData(title, text, img,
static_cast<NotificationData::Type>(type)));
}
NotificationService *NotificationService::getService() {
static auto service = new NotificationService;
return service;
}
const QList<NotificationData> &NotificationService::history() const {
return _history;
}

@ -0,0 +1,39 @@
#ifndef NOTIFICATIONSERVICE_H
#define NOTIFICATIONSERVICE_H
#include "notificationdata.h"
#include <QObject>
class NotificationService: public QObject
{
Q_OBJECT
Q_PROPERTY(NotificationData notify READ notify NOTIFY notifyChanged)
Q_PROPERTY(QList<NotificationData> history READ history NOTIFY notifyChanged)
private:
explicit NotificationService(QObject *ptr = nullptr);
NotificationData _notify;
QList<NotificationData> _history;
public:
NotificationData notify() const;
void setNotify(const NotificationData &notify);
Q_INVOKABLE void setNotify(const QString& title = "",
const QString& text = "",
const QString& img = "",
int type = NotificationData::Normal);
static NotificationService* getService();
const QList<NotificationData> & history() const;
signals:
void notifyChanged();
};
#endif // NOTIFICATIONSERVICE_H

@ -0,0 +1,6 @@
#include "playerclientdata.h"
PlayerClientData::PlayerClientData()
{
}

@ -0,0 +1,11 @@
#ifndef PLAYERCLIENTDATA_H
#define PLAYERCLIENTDATA_H
#include <player.h>
class PlayerClientData: public ClientProtocol::Player
{
public:
PlayerClientData();
};
#endif // PLAYERCLIENTDATA_H

@ -0,0 +1,57 @@
#include "settingsviewmodel.h"
#include <QSettings>
#include "settings.h"
void SettingsViewModel::handleValueChanged(QString key, QVariant value) {
if (key == SERVER_ADDRESS) {
emit hostChanged(value.toString());
} else if (key == SERVER_ADDRESS_PORT) {
emit portChanged(value.toInt());
} else if (key == THEME) {
emit themeChanged(value.toInt());
}
}
SettingsViewModel::SettingsViewModel(QObject *ptr):
QObject (ptr) {
_cfg = Settings::get();
connect(_cfg, &Settings::valueChanged, this , &SettingsViewModel::handleValueChanged);
}
int SettingsViewModel::port() const {
return _cfg->getValue(SERVER_ADDRESS_PORT, SERVER_ADDRESS_DEFAULT_PORT).toInt();
}
QString SettingsViewModel::host() const {
return _cfg->getValue(SERVER_ADDRESS, SERVER_ADDRESS_DEFAULT).toString();
}
int SettingsViewModel::theme() const {
return _cfg->getValue(THEME, THEME_DEFAULT).toInt();
}
void SettingsViewModel::forceUpdate() {
emit hostChanged("");
emit portChanged(0);
emit themeChanged(0);
}
void SettingsViewModel::toDefault() {
setPort(SERVER_ADDRESS_DEFAULT_PORT);
setHost(SERVER_ADDRESS_DEFAULT);
setTheme(THEME_DEFAULT);
}
void SettingsViewModel::setPort(int port) {
_cfg->setValue(SERVER_ADDRESS_PORT, port);
}
void SettingsViewModel::setHost(const QString& host) {
_cfg->setValue(SERVER_ADDRESS, host);
}
void SettingsViewModel::setTheme(int theme) {
_cfg->setValue(THEME, theme);
}

@ -0,0 +1,42 @@
#ifndef SETTINGSVIEWMODEL_H
#define SETTINGSVIEWMODEL_H
#include <QObject>
#include "./../settings.h"
class SettingsViewModel: public QObject
{
Q_OBJECT
Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged)
Q_PROPERTY(QString host READ host WRITE setHost NOTIFY hostChanged)
Q_PROPERTY(int theme READ theme WRITE setTheme NOTIFY themeChanged)
private:
Settings *_cfg = nullptr;
private slots:
void handleValueChanged(QString key, QVariant value);
public:
SettingsViewModel(QObject* ptr = nullptr);
int port() const;
QString host() const;
int theme() const;
Q_INVOKABLE void forceUpdate();
Q_INVOKABLE void toDefault();
public slots:
void setPort(int port);
void setHost(const QString &host);
void setTheme(int theme);
signals:
void portChanged(int port);
void hostChanged(const QString &host);
void themeChanged(int theme);
};
#endif // SETTINGSVIEWMODEL_H

@ -0,0 +1,78 @@
#include "userview.h"
const PlayerClientData *UserView::getSource() const {
return _source.data();
}
void UserView::setSource(QSharedPointer<PlayerClientData> data) {
_offline = data == nullptr;
if (data->id() != _source->id()) {
_source = data;
emit sourceChanged();
}
}
bool UserView::offline() const {
return _offline;
}
void UserView::setOffline(bool offline) {
if (_offline != offline) {
emit offlineChanged(_offline = offline);
}
}
UserView::UserView(QObject *parent) : QObject(parent) {
}
QString UserView::name() const {
if (!_source) {
return tr("Undefined name");
}
return _source->getName();
}
QString UserView::gmail() const {
if (!_source) {
return tr("Undefined gmail");
}
return _source->getGmail();
}
int UserView::money() const {
if (!_source) {
return -1;
}
return static_cast<int>(_source->getMany());
}
int UserView::record() const {
if (!_source) {
return -1;
}
return static_cast<int>(_source->getRecord());
}
int UserView::avgRecord() const {
if (!_source) {
return -1;
}
return static_cast<int>(_source->getAvgRecord());
}
int UserView::cureentSnake() const {
if (!_source) {
return -1;
}
return _source->getCureentSnake();
}
int UserView::id() const {
if (!_source) {
return -1;
}
return _source->id();
}

@ -0,0 +1,52 @@
#ifndef USERVIEW_H
#define USERVIEW_H
#include "playerclientdata.h"
#include <QObject>
class UserView : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY sourceChanged)
Q_PROPERTY(QString gmail READ gmail NOTIFY sourceChanged)
Q_PROPERTY(int money READ money NOTIFY sourceChanged)
Q_PROPERTY(int record READ record NOTIFY sourceChanged)
Q_PROPERTY(int avgRecord READ avgRecord NOTIFY sourceChanged)
Q_PROPERTY(int cureentSnake READ cureentSnake NOTIFY sourceChanged)
Q_PROPERTY(int id READ id NOTIFY sourceChanged)
Q_PROPERTY(bool offline READ offline NOTIFY offlineChanged)
private:
QSharedPointer<PlayerClientData> _source = nullptr;
bool _offline = false;
public:
explicit UserView(QObject *parent = nullptr);
QString name() const;
QString gmail() const;
int money() const;
int record() const;
int avgRecord() const;
int cureentSnake() const;
int id() const;
const PlayerClientData *getSource() const;
bool offline() const;
void setOffline(bool offline);
signals:
void sourceChanged();
void offlineChanged(bool offline);
public slots:
void setSource(QSharedPointer<PlayerClientData> data);
};
#endif // USERVIEW_H

@ -1,19 +0,0 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the lgplv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "SnakeProject.h"
namespace SnakeProject {
bool init() {
initSnakeProjectResources();
return true;
}
}

@ -1,16 +0,0 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the lgplv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "SnakeProject_global.h"
inline void initSnakeProjectResources() { Q_INIT_RESOURCE(SnakeProject); }
namespace SnakeProject {
bool SnakeProject_EXPORT init();
};

@ -1,20 +0,0 @@
//#
//# Copyright (C) 2018-2021 QuasarApp.
//# Distributed under the lgplv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef SnakeProject_GLOBAL_H
#define SnakeProject_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(SnakeProject_LIBRARY)
# define SnakeProject_EXPORT Q_DECL_EXPORT
#else
# define SnakeProject_EXPORT Q_DECL_IMPORT
#endif
#endif //SnakeProject_GLOBAL_H

@ -0,0 +1,23 @@
#include "asyncimageresponse.h"
AsyncImageResponse::AsyncImageResponse() = default;
AsyncImageResponse::~AsyncImageResponse() = default;
QQuickTextureFactory *AsyncImageResponse::textureFactory() const {
return _texture;
}
// memory leak ?
void AsyncImageResponse::setResult(const QImage& image) {
_texture = QQuickTextureFactory::textureFactoryForImage(image);
emit finished();
// deleteLater();
}
void AsyncImageResponse::error(const QString &err) {
_errorString = " " + err;
}
QString AsyncImageResponse::errorString() const {
return QQuickImageResponse::errorString() + _errorString;
}

@ -0,0 +1,24 @@
#ifndef ASYNCIMAGERESPONSE_H
#define ASYNCIMAGERESPONSE_H
#include <QQuickImageResponse>
class AsyncImageResponse : public QQuickImageResponse {
private:
QQuickTextureFactory *_texture = nullptr;
QString _errorString;
public:
AsyncImageResponse ();
~AsyncImageResponse () override;
QQuickTextureFactory *textureFactory() const override;
void setResult(const QImage &image);
void error(const QString &err);
QString errorString() const override;
};
#endif // ASYNCIMAGERESPONSE_H

@ -0,0 +1,20 @@
#include "background.h"
BackGround::BackGround(double x, double y): ItemWorld (x, y) {
this->setSize(200, 400);
this->setTexture("qrc:/texture/asphalt");
setBeckGroundObject(true);
}
void BackGround::render() {
auto wPart = w() / 2;
if (m_x + wPart < 200) {
setX(wPart);
}
}
void BackGround::reset() {
setX(0 - w());
render();
}

@ -0,0 +1,16 @@
#ifndef BACKGROUND_H
#define BACKGROUND_H
#include "itemworld.h"
class BackGround : public ItemWorld
{
public:
BackGround(double x, double y);
void render() override;
void reset() override;
};
#endif // BACKGROUND_H

@ -0,0 +1,19 @@
#include "backgrounditem.h"
#include <QColor>
BackGroundItem::BackGroundItem(double x, double y):
ItemWorld (x, y) {
setBeckGroundObject(true);
reset();
}
void BackGroundItem::reset() {
auto tempColor = QColor(rand() % 255, rand() % 255, rand() % 255, 10);
setColor(tempColor.name(QColor::HexArgb));
auto radius = rand() % 200;
setSize(radius , radius);
setRadius(radius / 2);
}

@ -0,0 +1,15 @@
#ifndef BACKGROUNDITEM_H
#define BACKGROUNDITEM_H
#include "itemworld.h"
class BackGroundItem : public ItemWorld
{
public:
BackGroundItem(double x, double y);
void reset() override;
};
#endif // BACKGROUNDITEM_H

@ -0,0 +1,17 @@
#include "baseclass.h"
void BaseClass::setName(const QString &value) {
name = value;
}
BaseClass::BaseClass() :
name("BaseClass") {
}
BaseClass::~BaseClass() {
}
QString BaseClass::getName() const {
return name;
}

@ -0,0 +1,17 @@
#ifndef BASECLASS_H
#define BASECLASS_H
#include <QString>
class BaseClass
{
private:
QString name;
public:
BaseClass();
virtual void render() = 0;
virtual ~BaseClass();
QString getName() const;
void setName(const QString &value);
};
#endif // BASECLASS_H

@ -0,0 +1,12 @@
#include "box.h"
#include <QColor>
Box::Box(double x, double y):
ItemWorld (x, y) {
this->setSize(10, 10);
setColor(QColor(100, 100, 100).name());
}

@ -0,0 +1,13 @@
#ifndef BOX_H
#define BOX_H
#include "itemworld.h"
class Box: public ItemWorld
{
public:
Box(double x, double y);
};
#endif // BOX_H

@ -0,0 +1,50 @@
#include "clientapp.h"
#include "imageprovider.h"
#include "ProfileViewItems/userview.h"
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <back-end/ProfileViewItems/mainmenumodel.h>
#include <back-end/ProfileViewItems/notificationservice.h>
QByteArray ClientApp::initTheme() {
int themeIndex = Settings::get()->getValue(THEME, THEME_DEFAULT).toInt();
switch (themeIndex) {
case 1: return "Dark";
default: return "Light";
}
}
ClientApp::ClientApp() {
}
ClientApp::~ClientApp() {
}
bool ClientApp::init(QQmlApplicationEngine *engine) {
qputenv("QT_QUICK_CONTROLS_MATERIAL_THEME", initTheme());
qmlRegisterType <GuiObject> ();
qmlRegisterType <Diff> ();
qmlRegisterType <MainMenuModel> ();
qmlRegisterType <UserView> ();
auto root = engine->rootContext();
if (!root)
return false;
engine->addImageProvider(QLatin1String("userItems"), new ImageProvider());
root->setContextProperty("contr", &contr);
root->setContextProperty("notificationService", NotificationService::getService());
engine->load(QUrl(QStringLiteral("qrc:/front-end/main.qml")));
if (engine->rootObjects().isEmpty())
return false;
return true;
}

@ -0,0 +1,22 @@
#ifndef CLIENTAPP_H
#define CLIENTAPP_H
#include "controller.h"
#include "diff.h"
class QQmlApplicationEngine;
class ClientApp
{
private:
Controller contr;
QByteArray initTheme();
public:
ClientApp();
~ClientApp();
bool init(QQmlApplicationEngine* engine);
};
#endif // CLIENTAPP_H

@ -0,0 +1,154 @@
#include "controller.h"
#include <cmath>
#include <ctime>
#include "diff.h"
#include <lvls.h>
#include "ProfileViewItems/mainmenumodel.h"
#include <back-end/ProfileViewItems/notificationservice.h>
Controller::Controller() {
srand(static_cast<unsigned int>(time(nullptr)));
timer = new QTimer();
timer->setInterval(1);
_networkModel = new MainMenuModel(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
connect(_networkModel, &MainMenuModel::newGame, this, &Controller::handleNewGame);
}
Controller::~Controller() {
}
bool Controller::nextLvl() {
if (lvl + 1 >= lvls.size()) {
return true;
}
m_generalLong += static_cast<int>(world.getCurrentLong());
generateDiff(world.init(lvls.value(++lvl)));
startTimer();
return false;
}
void Controller::generateDiff(const QMap<int, GuiObject *>& objs) {
auto removeIds = objectsContainer.keys();
QList<int> addedIds;
for (auto i = objs.begin(); i != objs.end(); ++i) {
if (objectsContainer.contains(i.key())) {
removeIds.removeOne(i.key());
} else {
objectsContainer.insert(i.key(), i.value());
addedIds.push_back(i.key());
}
}
if (removeIds.size() || addedIds.size()) {
Diff diff;
diff.setRemoveIds(removeIds);
diff.setAddedIds(addedIds);
emit gameObjectsChanged(diff);
}
}
void Controller::update() {
if (pause) {
return;
}
world.render();
if(world.isDefiat()) {
stopTimer();
if (!_showMenu) {
setShowMenu(true);
}
handleNewGame();
}
if (world.isEnd()) {
stopTimer();
if (!_showMenu) {
NotificationData notify(tr(" Next Lvl!!!"),
tr(" You anblock next lvl (%0)" ).arg(lvl),
"qrc:/texture/up");
NotificationService::getService()->setNotify(notify);
}
nextLvl();
}
long_changed(static_cast<int>(world.getCurrentLong()));
generalLongchanged(generalLong());
}
void Controller::handleNewGame() {
world.resetPosition();
WorldRules newGameRules = lvls.first();
lvl = 0;
m_generalLong = 0;
generateDiff(world.init(newGameRules));
startTimer();
}
QObject *Controller::getGameObject(int id) {
return objectsContainer.value(id, nullptr);
}
void Controller::startTimer() {
timer->start();
}
void Controller::stopTimer() {
timer->stop();
}
int Controller::long_() const {
return static_cast<int>(world.getCurrentLong());
}
int Controller::generalLong() const {
return m_generalLong + long_();
}
QObject *Controller::mainMenuModel() const {
return _networkModel;
}
void Controller::buttonPress() {
world.reversClick();
}
void Controller::setPause(bool p){
pause = p;
if (!pause) {
world.unPause();
}
}
bool Controller::showMenu() const {
return _showMenu;
}
void Controller::setShowMenu(bool showMenu) {
if (_showMenu == showMenu)
return;
_showMenu = showMenu;
emit showMenuChanged(_showMenu);
}

@ -0,0 +1,88 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
#include <QTimer>
#include <QTime>
#include "diff.h"
#include "snake.h"
#include "world.h"
class MainMenuModel;
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(int long_ READ long_ NOTIFY long_changed)
Q_PROPERTY(int generalLong READ generalLong NOTIFY generalLongchanged)
Q_PROPERTY(QObject* mainMenuModel READ mainMenuModel NOTIFY mainMenuModelchanged)
Q_PROPERTY(bool showMenu READ showMenu WRITE setShowMenu NOTIFY showMenuChanged)
private:
World world;
QMap<int, GuiObject *> objectsContainer;
QTimer *timer = nullptr;
int lvl = 0;
int m_generalLong = 0;
bool pause = false;
bool _showMenu = true;
void generateDiff(const QMap<int, GuiObject *> &);
MainMenuModel* _networkModel = nullptr;
public:
Controller();
~Controller();
void startTimer();
void stopTimer();
int long_() const;
int generalLong() const;
bool showMenu() const;
QObject* mainMenuModel() const;
public slots:
void buttonPress();
void setPause(bool);
void update();
/**
* @brief nextLvl - switch to next lvl from array lvels
* @return true if all levels are passed
*/
bool nextLvl();
/**
* @brief newGame - start game from first lvl
*/
void handleNewGame();
/**
* @brief getGameObject
* @param id - id of guiObject;
* @return guiObject if (id is not valid return nullptr)
*/
QObject* getGameObject(int id);
void setShowMenu(bool showMenu);
signals:
/**
* @brief gameObjectsChanged
* @param dif
*/
void gameObjectsChanged(const Diff &dif);
void long_changed(int m_long);
void generalLongchanged(int generalLong);
void mainMenuModelchanged(QObject* mainMenuModel);
void showMenuChanged(bool showMenu);
};
#endif // CONTROLLER_H

@ -0,0 +1,21 @@
#include "diff.h"
QList<int> Diff::getRemoveIds() const {
return removeIds;
}
void Diff::setRemoveIds(const QList<int> &value) {
removeIds = value;
}
QList<int> Diff::getAddedIds() const {
return addedIds;
}
void Diff::setAddedIds(const QList<int> &value) {
addedIds = value;
}
Diff::Diff(){
}

@ -0,0 +1,23 @@
#ifndef DIFF_H
#define DIFF_H
#include <QObject>
class Diff
{
Q_GADGET
private:
QList<int> removeIds;
QList<int> addedIds;
public:
explicit Diff();
Q_INVOKABLE QList<int> getRemoveIds() const;
void setRemoveIds(const QList<int> &value);
Q_INVOKABLE QList<int> getAddedIds() const;
void setAddedIds(const QList<int> &value);
};
Q_DECLARE_METATYPE(Diff)
#endif // DIFF_H

@ -0,0 +1,116 @@
#include "guiobject.h"
GuiObject::GuiObject(const QString &viewTempalte, QObject *ptr):
QObject (ptr) {
m_viewTemplate = viewTempalte;
generateId();
}
double GuiObject::angle() const {
return m_angle;
}
QString GuiObject::texture() const {
return m_texture;
}
void GuiObject::render() {
}
QRectF GuiObject::rect() const {
return QRectF(m_x - m_w / 2, m_y - m_h / 2, m_w, m_h);
}
void GuiObject::setAngle(double angle) {
m_angle = angle;
emit angleChanged(m_angle);
}
int GuiObject::guiId() const {
return m_guiId;
}
QString GuiObject::color() const {
return m_color;
}
void GuiObject::setColor(QString color) {
if (m_color == color)
return;
m_color = color;
emit colorChanged(m_color);
}
double GuiObject::x() const {
return m_x;
}
double GuiObject::y() const {
return m_y;
}
double GuiObject::w() const {
return m_w;
}
double GuiObject::h() const {
return m_h;
}
void GuiObject::generateId() {
static int id = 0;
m_guiId = id++;
}
void GuiObject::setH(double h) {
m_h = h;
emit hChanged(m_h);
}
void GuiObject::reset() {
setX(-1);
setY(-1);
}
int GuiObject::radius() const {
return m_radius;
}
QString GuiObject::viewTemplate() const {
return m_viewTemplate;
}
void GuiObject::setRadius(int radius) {
if (m_radius == radius)
return;
m_radius = radius;
emit radiusChanged(m_radius);
}
void GuiObject::setW(double w) {
m_w = w;
emit wChanged(m_w);
}
void GuiObject::setY(double y) {
m_y = y;
emit yChanged(m_y);
}
void GuiObject::setX(double x) {
m_x = x;
emit xChanged(m_x);
}
void GuiObject::setTexture(const QString &texture) {
m_texture = texture;
emit textureChanged(m_texture);
}

@ -0,0 +1,91 @@
#ifndef GUIOBJECT_H
#define GUIOBJECT_H
#include "baseclass.h"
#include "QObject"
#include <QRectF>
class GuiObject:public QObject, public BaseClass
{
Q_OBJECT
// @todo: add color
Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(double angle READ angle NOTIFY angleChanged)
Q_PROPERTY(QString texture READ texture NOTIFY textureChanged)
Q_PROPERTY(int guiId READ guiId NOTIFY guiIdChanged)
Q_PROPERTY(QString viewTemplate READ viewTemplate NOTIFY viewTemplateChanged)
Q_PROPERTY(int radius READ radius WRITE setRadius NOTIFY radiusChanged)
Q_PROPERTY(double x READ x NOTIFY xChanged)
Q_PROPERTY(double y READ y NOTIFY yChanged)
Q_PROPERTY(double w READ w NOTIFY wChanged)
Q_PROPERTY(double h READ h NOTIFY hChanged)
private:
void generateId();
QString m_viewTemplate;
protected:
int m_guiId = -1;
double m_angle = 0;
QString m_texture = "";
QString m_color = "";
int m_radius = 0;
double m_x = 0;
double m_y = 0;
double m_w = 0;
double m_h = 0;
void setTexture(const QString &texture);
public:
GuiObject(const QString& viewTempalte = "GraphicItem", QObject *ptr = nullptr);
double angle() const;
QString texture() const;
void render() override;
QRectF rect() const;
virtual void setAngle(double angle);
int guiId() const;
QString color() const;
void setColor(QString color);
double x() const;
double y() const;
double w() const;
double h() const;
void setX(double x);
void setY(double y);
void setW(double w);
void setH(double h);
virtual void reset();
int radius() const;
QString viewTemplate() const;
public slots:
void setRadius(int radius);
signals:
void angleChanged(double angle);
void textureChanged(QString texture);
void guiIdChanged(int guiId);
void colorChanged(QString color);
void xChanged(double x);
void yChanged(double y);
void wChanged(double w);
void hChanged(double h);
void radiusChanged(int radius);
void viewTemplateChanged(QString viewTemplate);
};
#endif // GUIOBJECT_H

@ -0,0 +1,23 @@
#include "guiobjectfactory.h"
#include "box.h"
#include <snakeutils.h>
#include "head.h"
#include "background.h"
#include "backgrounditem.h"
GuiObjectFactory::GuiObjectFactory() {}
ItemWorld *GuiObjectFactory::generate(const QString &name) {
ItemWorld *obj = nullptr;
if (name == "Box") {
obj = new Box(rand() % 400, 0);
}
else if (name == "BackGround") {
obj = new BackGround(0, 0);
}
else if (name == "BackGroundItem") {
obj = new BackGroundItem(0, 0);
}
return obj;
}

@ -0,0 +1,27 @@
#ifndef GUIOBJECTFACTORY_H
#define GUIOBJECTFACTORY_H
#include <QString>
class ItemWorld;
/**
* @brief The GuiObjectFactory class
* factory of gui ojects;
*/
class GuiObjectFactory
{
public:
GuiObjectFactory();
/**
* @brief generate - generate the child of GuiObject
* by object name.
* @param name - name of class of genereta object
* @return pointer of generated object.
* If method called with not valid name then return nullptr.
*/
static ItemWorld* generate(const QString& name);
};
#endif // GUIOBJECTFACTORY_H

@ -0,0 +1,58 @@
#include "head.h"
#include <cmath>
#include <QDateTime>
void Head::render() {
qint64 tempTime = QDateTime::currentMSecsSinceEpoch() - time;
time = QDateTime::currentMSecsSinceEpoch();
double my = (m_y + (*speed * 0.55) * sin(m_angle * TO_RADIAN));
m_y += (my - m_y) / 1000 * tempTime;
if (*speed < 1) {
setColor(generalSpeadColor);
setRadius(static_cast<int>(m_w * 0.4));
} else if (*speed < normSpead) {
setColor(normSpeadColor);
setRadius(static_cast<int>(m_w * 0.5));
} else if (*speed < fastSpead) {
setColor(fastSpeadColor);
setRadius(static_cast<int>(m_w * 0.5));
} else if (*speed < megaFastSpead) {
setColor(megaFastSpeadColor);
setRadius(static_cast<int>(m_w * 0.4));
}
emit yChanged(m_y);
}
void Head::reset() {
}
void Head::unPause() {
time = QDateTime::currentMSecsSinceEpoch();
}
Head::Head(double x, double y, double h, double w, double *spead):
GuiObject ("SnakeItem") {
setX(x);
setY(y);
setW(w);
setH(h);
this->speed = spead;
}
void Head::setAngle(double angle) {
m_angle = angle;
emit angleChanged(m_angle);
}
Head::~Head() {
}

@ -0,0 +1,32 @@
#ifndef HEAD_H
#define HEAD_H
#define TO_RADIAN 0.017453293
#include "guiobject.h"
#include <QString>
class Head : public GuiObject
{
private:
qint64 time;
double *speed;
const int megaFastSpead = 200;
const int fastSpead = 100;
const int normSpead = 50;
const QString generalSpeadColor = "#616a6b";
const QString normSpeadColor = "#5d6d7e";
const QString fastSpeadColor = "#eb984e";
const QString megaFastSpeadColor = "#ec7063";
public:
Head(double x , double y, double h, double w, double *speed);
void setAngle(double angle) override;
void render() override;
void reset() override;
void unPause();
~Head() override;
};
#endif // HEAD_H

@ -0,0 +1,37 @@
#include "asyncimageresponse.h"
#include "imageprovider.h"
#include <QQuickImageResponse>
#include <QtConcurrent>
ImageProvider::ImageProvider() = default;
ImageProvider::~ImageProvider() = default;
QQuickImageResponse *ImageProvider::requestImageResponse(const QString &id,
const QSize &requestedSize) {
AsyncImageResponse* response = new AsyncImageResponse();
auto readImage = [id, requestedSize, response]() mutable {
Q_UNUSED(requestedSize);
auto params = id.split("/");
if (params.contains("player")) {
response->setResult(QImage(":/img/defaultuser").
scaled(requestedSize, Qt::KeepAspectRatioByExpanding));
} else if (params.contains("item")) {
response->setResult(QImage(":/img/defaultsnake").
scaled(requestedSize, Qt::KeepAspectRatioByExpanding));
} else {
response->error("Wrong first parametr example 'first/last'");
}
};
QtConcurrent::run(readImage);
return response;
}

@ -0,0 +1,19 @@
#ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H
#include <QQuickAsyncImageProvider>
#include <QPixmap>
class ImageProvider: public QQuickAsyncImageProvider
{
private:
public:
explicit ImageProvider();
~ImageProvider() override;
QQuickImageResponse *requestImageResponse(const QString &id,
const QSize &requestedSize) override;
};
#endif // IMAGEPROVIDER_H

@ -0,0 +1,48 @@
#include "itemworld.h"
#include "snakeutils.h"
#include <cmath>
#include <QDebug>
#include <QRectF>
#define POINT 100
ItemWorld::ItemWorld(double x, double y, const QString& guiTemplate):
GuiObject (guiTemplate) {
setLoc(x, y);
}
void ItemWorld::setBeckGroundObject(bool value) {
beckGroundObject = value;
}
void ItemWorld::setSize(double h, double w) {
setH(h);
setW(w);
}
void ItemWorld::setLoc(double x, double y) {
setX(x);
setY(y);
}
void ItemWorld::render() {
if (m_x + w() < 0) {
m_x = (rand() % 400) + 200;
m_y = rand() % 100;
emit xChanged(m_x);
emit yChanged(m_y);
}
}
bool ItemWorld::move(const GuiObject *snakeRiger, double dx) {
m_x -= dx;
emit xChanged(m_x);
return snakeRiger->rect().intersects(rect()) && !beckGroundObject;
}
bool ItemWorld::isBeckGroundObject() {
return beckGroundObject;
}
ItemWorld::~ItemWorld() {}

@ -0,0 +1,26 @@
#ifndef ITEMWORLD_H
#define ITEMWORLD_H
#include "guiobject.h"
#include <QString>
class ItemWorld : public GuiObject
{
private:
bool beckGroundObject = false;
protected:
virtual void setSize(double h, double w);
virtual void setLoc(double x, double y);
void setBeckGroundObject(bool value);
public:
ItemWorld(double x, double y, const QString& GuiTemplate = "GraphicItem");
void render();
virtual bool move(const GuiObject* snakeRiger, double dx);
bool isBeckGroundObject();
~ItemWorld();
};
#endif // ITEMWORLD_H

@ -0,0 +1,11 @@
#include "lvls.h"
QList<WorldRules> lvls {
WorldRules{{"Long", 500}, {"Box", 2}, {"Spead", 10}, {"BackGroundItem", 10}},
WorldRules{{"Long", 1000}, {"Box", 4}, {"Spead", 10}, {"BackGroundItem", 10}},
WorldRules{{"Long", 2000}, {"Box", 8}, {"Spead", 10}, {"BackGroundItem", 10}},
WorldRules{{"Long", 4000}, {"Box", 16}, {"Spead", 10}, {"BackGroundItem", 10}},
WorldRules{{"Long", 8000}, {"Box", 32}, {"Spead", 10}, {"BackGroundItem", 10}},
WorldRules{{"Long", 16000}, {"Box", 64}, {"Spead", 10}, {"BackGroundItem", 10}}
};

@ -0,0 +1,9 @@
#ifndef LVLS_H
#define LVLS_H
#include <QList>
#include "snakeutils.h"
extern QList<WorldRules> lvls;
#endif // LVLS_H

@ -0,0 +1,20 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "clientapp.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
ClientApp client;
if (!client.init(&engine)) {
return 1;
}
return app.exec();
}

@ -0,0 +1,7 @@
[Controls]
Style=Material
[Material]
Accent=Teal
Primary=BlueGrey
;Theme=Light

@ -0,0 +1 @@
#include "settings.h"

@ -0,0 +1,17 @@
#ifndef SNAKESETTINGS_H
#define SNAKESETTINGS_H
#include <config.h>
#include <quasarapp.h>
#define SERVER_ADDRESS "SERVER_ADDRESS"
#define SERVER_ADDRESS_PORT "SERVER_ADDRESS_PORT"
#define THEME "THEME_GUI"
#define SERVER_ADDRESS_DEFAULT "quasarapp.ddns.net"
//#define SERVER_ADDRESS_DEFAULT "127.0.0.1"
#define SERVER_ADDRESS_DEFAULT_PORT DEFAULT_SNAKE_PORT
#define THEME_DEFAULT 0
using Settings = QuasarAppUtils::Settings;
#endif // SNAKESETTINGS_H

@ -0,0 +1,200 @@
#include "snake.h"
#include "guiobject.h"
#include <QDateTime>
#include <QMap>
#include <QRectF>
#include <cmath>
Snake::Snake() {
}
const QVector<Head *> &Snake::getItems() const {
return items;
}
void Snake::render() {
auto centerX = [](const Head* head) {
return head->x()/* + (head->w() / 2)*/;
};
auto centerY = [](const Head* head) {
return head->y() /*+ (head->h() / 2)*/;
};
for (int i = items.length() - 1; i >= 0; --i) {
if (dead) {
items[i]->render();
continue;
}
if (i == 0) {
if (isClick) {
if (countClick & 1){
items[i]->setAngle(45);
} else {
items[i]->setAngle(315);
}
isClick = false;
}
} else {
double _atan2 = atan2(centerY(items[i - 1]) - centerY(items[i]),
centerX(items[i - 1]) - centerX(items[i])) * 90;
items[i]->setAngle(_atan2);
}
items[i]->render();
}
}
double Snake::checDistance(int i) {
auto result = (items[i]->rect().y() -
items[i - 1]->rect().y()) / rataticonDistance;
return result;
}
double Snake::getRataticonDistance() const {
return rataticonDistance;
}
void Snake::setRataticonDistance(double value) {
rataticonDistance = value;
}
void Snake::unPause() {
for ( int i = 0; i < items.size(); ++i ) {
items[i]->unPause();
}
}
double Snake::sizeByLvl(double lvl , int count) const {
double maxSize = 9;
double minSize = 5;
double pos = (1 - (lvl / count));
QList<QPair<double, double>> snakeGradientSize {
{1, 4},
{0.99, 7},
{0.8, 5},
{0.6, 6},
{0.0, 3}
};
double local = 0;
int index = 0;
while (index + 1 < snakeGradientSize.size()
&& pos <= snakeGradientSize[index].first) {
maxSize = snakeGradientSize[index].second;
minSize = snakeGradientSize[index + 1].second;
auto range = snakeGradientSize[index].first -
snakeGradientSize[index + 1].first;
local = ( range - (snakeGradientSize[index].first - pos)) /
range;
index++;
}
return local * (maxSize - minSize) + minSize;
}
void Snake::changeCountObjects(int count) {
if (count > 0) {
double margin = 60.0 / count;
for ( int i = 0; i < count; ++i ) {
auto size = sizeByLvl(i, count);
auto obj = new Head(margin * (count - i),
50, size , size,
this->speed);
obj->setY(50 + obj->h() / 2);
items.push_back(obj);
}
} else {
for ( int i = count; i < 0; ++i ) {
auto obj = items.first();
items.removeFirst();
delete obj;
}
}
}
QMap<int, GuiObject*> Snake::init(int size, double *speed) {
QMap<int, GuiObject*> res;
if (size <= 0) {
return res;
}
this->speed = speed;
changeCountObjects(size - items.size());
for (auto i : items) {
res[i->guiId()] = i;
}
dead = false;
return res;
}
bool Snake::isInited() const {
return items.size();
}
void Snake::clearItems() {
for (auto i : items) {
delete i;
}
items.clear();
}
void Snake::resetPosotion() {
double margin = 60.0 / items.size();
for ( int i = 0; i < items.size(); ++i ) {
items[i]->setX(margin * (items.size() - i));
items[i]->setY(50 + items[i]->h() / 2);
items[i]->setAngle(0);
}
}
void Snake::kill() {
dead = true;
}
bool Snake::isDead() const {
return dead;
}
Snake::~Snake() {
clearItems();
}
void Snake::clear() {
clearItems();
}
void Snake::reverse() {
if (isClick) {
return;
}
isClick = true;
countClick++;
}

@ -0,0 +1,52 @@
#ifndef SNAKE_H
#define SNAKE_H
#define SPEEDSNAKE 10
#include <QVector>
#include "head.h"
#include "baseclass.h"
class GuiObject;
class Snake : public BaseClass
{
private:
double rataticonDistance = 1;
QVector<Head*> items;
double *speed = nullptr;
bool isClick = false;
int countClick = 0;
bool dead = false;
double sizeByLvl(double lvl, int count) const;
void changeCountObjects(int count);
double checDistance(int i);
void clearItems();
public:
Snake();
~Snake() override;
void clear();
void resetPosotion();
void kill();
bool isDead() const;
void reverse();
void render() override;
QMap<int, GuiObject *> init(int size, double *speed);
bool isInited() const;
const QVector<Head*>& getItems() const;
double getMovedLong() const;
double getRataticonDistance() const;
void setRataticonDistance(double value);
int getDeadTimer() const;
void setDeadTimer(int value);
void unPause();
};
#endif // SNAKE_H

@ -0,0 +1,3 @@
#include "snakeutils.h"

@ -0,0 +1,20 @@
#ifndef SNAKEUTILS_H
#define SNAKEUTILS_H
#include <QMap>
#include <QPoint>
#include <QVariant>
/**
* @brief WorldRules
* this map conteins:
* 1. list of generated objects and they count.
* 2. long of world (Long),
* 3. spead of world (Spead),
* !!!Note: all object show on map alltime.
*/
typedef QMap<QString, int> WorldRules;
#endif // SNAKEUTILS_H

@ -0,0 +1,173 @@
#include "background.h"
#include "world.h"
#include <QMap>
#include "guiobject.h"
#include "guiobjectfactory.h"
#include <QDateTime>
#include <QDebug>
World::World() {
currentLong = 0;
endLong = 0;
background = "";
}
void World::clear() {
clearItems();
snake.clear();
}
double World::getCurrentLong() const {
return currentLong;
}
QMultiMap<QString, ItemWorld *> World::getItems() const
{
return items;
}
void World::unPause() {
time = QDateTime::currentMSecsSinceEpoch();
snake.unPause();
}
void World::clearItems() {
for (auto i : items) {
delete i;
}
oldRules.clear();
items.clear();
spead = 0;
d_spead = 0;
}
void World::changeCountObjects(const QString &name, int count) {
if (count > 0) {
for ( int i = 0; i < count; ++i ) {
auto obj = GuiObjectFactory::generate(name);
if (!obj) {
qWarning() <<"object not created line:" << Q_FUNC_INFO;
break;
}
items.insertMulti(name, obj);
}
} else {
for ( int i = count; i < 0; ++i ) {
auto obj = items.value(name);
if (1 != items.remove(name, obj)) {
qWarning() << "World::changeCountObjects error delete object!";
}
delete obj;
}
}
}
QMap<int, GuiObject *> World::init(WorldRules rules) {
QMap<int, GuiObject*> res;
// rules["BackGround"] = 1;
currentLong = -1;
for (auto i = rules.begin(); i != rules.end(); ++i) {
if (i.key() == "Long") {
endLong = rules["Long"];
currentLong = 0;
}
else if (i.key() == "Spead") {
d_spead = rules["Spead"];
}
else {
changeCountObjects(i.key(), i.value() - oldRules.value(i.key()));
}
}
auto snakeItems = snake.init(20, &spead);
for (auto i = snakeItems.begin(); i != snakeItems.end(); ++i) {
res.insert(i.key(), i.value());
}
for (auto i : items) {
res[i->guiId()] = i;
}
oldRules = rules;
time = QDateTime::currentMSecsSinceEpoch();
defiat = false;
return res;
}
World::~World() {
clearItems();
}
void World::render() {
qint64 tempTime = QDateTime::currentMSecsSinceEpoch() - time;
time = QDateTime::currentMSecsSinceEpoch();
double dx = spead / 1000 * tempTime;
spead -= 0.0310 * tempTime;
if (spead < 0)
spead = 0;
snake.render();
auto rig = snake.getItems().first();
for (auto i = items.begin(); i != items.end(); ++i) {
defiat |= (*i)->move(rig, dx);
(*i)->render();
}
defiat |= (rig->y()< 0 || rig->y() > 100);
if (!snake.isDead() && defiat) {
snake.kill();
}
currentLong += dx;
}
void World::resetPosition() {
for (auto i : items) {
i->reset();
}
spead = 0;
snake.resetPosotion();
}
bool World::move() {
return isEnd();
}
bool World::isEnd() {
return currentLong >= endLong;
}
bool World::isDefiat() const {
return defiat && !static_cast<bool>(spead);
}
WorldRules World::currentRules() const {
return oldRules;
}
void World::reversClick() {
if (snake.isDead()) {
spead = 0;
return;
}
snake.reverse();
spead += d_spead;
}

@ -0,0 +1,47 @@
#ifndef WORLD_H
#define WORLD_H
#define SPEEDWORLD 10
#include <QVector>
#include "itemworld.h"
#include "baseclass.h"
#include "snakeutils.h"
#include "snake.h"
class World : public BaseClass
{
private:
Snake snake;
QMultiMap<QString, ItemWorld*> items;
double currentLong = 0;
int endLong;
double spead = 0, d_spead = 0;
QString background;
qint64 time;
bool defiat = false;
WorldRules oldRules;
void clearItems();
void changeCountObjects(const QString &name, int count);
public:
World();
void clear();
QMap<int, GuiObject*> init(WorldRules rules);
~World() override;
void render() override;
void resetPosition();
bool move();
bool isEnd();
bool isDefiat() const;
WorldRules currentRules() const;
void reversClick();
double getCurrentLong() const;
QMultiMap<QString, ItemWorld *> getItems() const;
void unPause();
};
#endif // WORLD_H

@ -0,0 +1,29 @@
import QtQuick 2.9
import QtQuick.Controls.Material 2.0
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
Page {
signal close();
title: "Page"
header: Rectangle {
height: parent.height * 0.1
color: "#cccccc"
Label {
id: title
text: qsTr("About")
font.pointSize: 13
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent;
anchors.margins: 5
}
}
contentItem: AboutPage{
}
}

@ -0,0 +1,72 @@
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
Item {
clip: true
ColumnLayout {
id: columnLayout
anchors.fill: parent
spacing: 10
Rectangle {
Layout.preferredHeight: parent.width / 4
Layout.preferredWidth: parent.width / 4
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
color: "#00000000"
Image {
id: aboutLogo
fillMode: Image.PreserveAspectFit
source: "qrc:/logo/logo"
anchors.margins: 10
anchors.fill: parent
}
}
Flickable {
id: flickable
clip: true
flickableDirection: Flickable.VerticalFlick
Layout.preferredHeight: parent.height - parent.height / 2.8
TextArea.flickable: TextArea {
id: textArea
textFormat: Qt.RichText
wrapMode: TextArea.Wrap
readOnly: true
persistentSelection: true
leftPadding: 6
rightPadding: 6
topPadding: 0
bottomPadding: 0
background: null
text: qsTr("Product of QuasarrApp");
font.family: "Verdana"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
onLinkActivated: Qt.openUrlExternally(link)
}
ScrollBar.vertical: ScrollBar { }
Layout.fillWidth: true
}
}
}
/*##^## Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

@ -0,0 +1,71 @@
import QtQuick 2.11
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Dialog {
id : basePopup
width: 200
height: 100
x: 0
y: 0
transformOrigin: Item.Center
property bool autoClose: true
property bool clickClose: true
property int closeInterval: 15000;
property int margin : 0
property color backgroundColor: Material.background
background: Item {
id: bacground
Rectangle{
anchors.fill: parent
id: backCorner
color: backgroundColor
radius: metrix.mm
}
DropShadow {
anchors.fill: parent
source: backCorner
color: "#80000000"
verticalOffset: 10
samples: 30
}
}
function _show() {
if (autoClose) {
timerAutoClose.start();
}
open();
}
Timer {
id: timerAutoClose;
running: false;
repeat: false;
interval: closeInterval;
onTriggered: {
close();
}
}
onClosed: {
if (autoClose)
opacity = 0;
}
closePolicy: (!clickClose || autoClose)? Popup.NoAutoClose: Popup.CloseOnReleaseOutside
onRejected: close()
}

@ -0,0 +1,32 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Frame {
id: frameVew
property bool translucent: true
property bool showBorder: true
function _backGroundColor() {
if (translucent) {
if (Material.theme == Material.Dark) {
return "#50000000";
}
return "#50ffffff";
}
return Material.background;
}
background: Rectangle {
color: _backGroundColor()
border.color: (Material.theme == Material.Dark)? "#000000": "#cfcfcf"
border.width: (showBorder)? 1 : 0
radius: metrix.mm
}
padding: 3 * metrix.mm
}

@ -0,0 +1,38 @@
import QtQuick 2.9
Rectangle {
id: graphicItem
property var model: null
property real angle: (model) ? model.angle : 0;
property string texture: (model) ? model.texture : "";
property int guiId: (model) ? model.guiId : -1;
z:-1
property double devX: width / 2
property double devY: height / 2
Image {
id: name
visible: texture.length
source: texture
anchors.fill: parent;
}
color: (model) ? model.color : "#11ff32";
width: (model) ? model.w * metrix.gamePt: 0;
height: (model) ? model.h * metrix.gamePt: 0;
x: (model) ? model.x * metrix.gamePt - devX: 0;
y: (model) ? model.y * metrix.gamePt - devY: 0;
radius: (model) ? model.radius * metrix.gamePt : 0;
transform: Rotation {
origin.x: devX;
origin.y: devY;
angle: graphicItem.angle;
}
}

@ -0,0 +1,83 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Item {
id: imageView
property int size: 50
property double ratio: 1
property string drawItem: ""
property bool hovered: false
property bool hold: false
signal clicked();
width: size * ratio
height: size
Image {
id: img
fillMode: Image.PreserveAspectFit
source: drawItem
sourceSize: Qt.size(width, height)
smooth: true
visible: false
anchors.fill: parent
}
DropShadow {
anchors.fill: img
horizontalOffset: (hold)? 20: (hovered)? 10: 5
verticalOffset: (hold)? 20: (hovered)? 10: 5
radius: 8.0
samples: 17
Behavior on horizontalOffset {
ColorAnimation {
duration: 200
}
}
Behavior on verticalOffset {
ColorAnimation {
duration: 200
}
}
Behavior on color {
ColorAnimation {
duration: 200
}
}
color: (hold)? "#80000000": (hovered)? "#60000000": "#40000000"
source: img
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
parent.hovered = true;
}
onExited: {
parent.hovered = false;
}
onReleased: {
parent.hold = false;
imageView.clicked();
}
onPressed: {
parent.hold = true;
}
}
}

@ -0,0 +1,13 @@
import QtQuick 2.0
LeftSideBar {
resizeHeight: true;
closedHeight: closedWidth;
openHeight: 10 * metrix.pt;
openWidth: 10 * metrix.pt;
anchors.left: parent.left;
anchors.top: undefined;
anchors.bottom: undefined;
}

@ -0,0 +1,35 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
SideBar {
id: leftSideBar
anchors.left: parent.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
closedWidth: closeButton.width + padding * 2;
openWidth: 10 * metrix.pt;
resizeHeight: false;
header:
RowLayout {
Button {
id: closeButton
text: leftSideBar.isOpened? "<" : ">"
Layout.preferredHeight: metrix.controlPtMaterial;
Layout.preferredWidth: metrix.controlPtMaterial;
Layout.alignment: Qt.AlignRight | Qt.AlignTop
onClicked: {
if (leftSideBar.isOpened)
leftSideBar.hide();
else
leftSideBar.show();
}
}
}
}

@ -0,0 +1,301 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Item {
id: element
property int loginStatus : 0
readonly property int currentView: tabBar.currentIndex
readonly property var resultEnum: [
qsTr("Success"), // 0
qsTr("Password must be at least 8 characters"), // 1
qsTr("Name must be at least 1 characters"), // 2
qsTr("Passwords must match"), // 3
qsTr("The letter must match the pattern 'X@xxxx.xxx'") // 4
]
signal sigNewUser(var gmail, var password);
signal sigLogin(var gmail, var password);
signal toOffline();
function _checkLogin() {
const pass = loginPass.text;
const email = loginEmail.text;
if (pass.length < 8) {
return 1;
}
if (email.search(/[a-z\-A-Z0-9_]+@[a-z\-A-Z0-9_]+\.[a-z\-A-Z0-9_]+/) < 0) {
return 4;
}
return 0;
}
function _checkRegister () {
const pass = registerPassword.text;
const pass2 = registerPassword2.text;
const email = registerEmail.text;
if (pass.length < 8) {
return 1;
}
if (pass !== pass2) {
return 3;
}
if (email.search(/[a-z\-A-Z0-9_]+@[a-z\-A-Z0-9_]+\.[a-z\-A-Z0-9_]+/) < 0) {
return 4;
}
return 0;
}
function checkData(isregisterForm) {
if (isregisterForm) {
return _checkRegister();
}
return _checkLogin();
}
SwipeView {
id: swipeView
anchors.bottom: bottons.top
anchors.top: tabBar.bottom
anchors.left: parent.left
anchors.right: parent.right
clip: true
currentIndex: tabBar.currentIndex
Item {
id: loginPage
GridLayout {
id: columnLayout
anchors.fill: parent
columns: 2
rows: 2
Label {
text: qsTr("Email")
}
TextField {
id: loginEmail
placeholderText: "Enter Your Email"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
}
Label {
text: qsTr("Passsword")
}
TextField {
id: loginPass
placeholderText: qsTr("Enter Your passsword")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
echoMode: TextInput.Password
cursorVisible: true
Layout.fillWidth: true
}
}
}
Item {
id: rigisterPage
GridLayout {
anchors.fill: parent
columns: 2
rows: 3
Label {
text: qsTr("Email")
}
TextField {
id: registerEmail;
placeholderText: qsTr("Enter Your Email")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
}
Label {
text: qsTr("Password")
}
TextField {
id: registerPassword;
placeholderText: qsTr("Enter Your passsword")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
echoMode: TextInput.Password
cursorVisible: true
}
Label {
text: qsTr("Repeat password")
}
TextField {
id: registerPassword2;
placeholderText: qsTr("Enter Your passsword again")
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
echoMode: TextInput.Password
cursorVisible: true
}
}
}
}
TabBar {
id: tabBar
anchors.top: parent.top
anchors.topMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
TabButton {
id: login
text: qsTr("Sign in")
checkable: false
}
TabButton {
id: register
text: qsTr("Sign Up")
}
}
RowLayout {
id : bottons
Button {
text: qsTr("Cancel")
onClicked: {
Qt.quit()
}
}
Item {
Layout.fillWidth: true
}
Button {
text: tabBar.currentItem.text
onClicked: {
const messageIndex = checkData(tabBar.currentIndex);
if (messageIndex === 0) {
if (tabBar.currentIndex) {
// register request
sigNewUser(registerEmail.text, registerPassword);
} else {
//login request
sigLogin(loginEmail.text, loginPass.text);
}
} else {
notificationService.setNotify(qsTr("Error"),
resultEnum[messageIndex],
"",
2);
}
}
}
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
onLoginStatusChanged: {
if (loginStatus === 2)
busy._show();
else {
busy.close();
}
}
PagePopUp {
id: busy
modal: true
autoClose: false;
clickClose: false;
BusyIndicator {
running: true
anchors.fill: parent
}
height: 2 * metrix.controlPtMaterial
width: height
}
FrameView {
visible: loginStatus === 4
anchors.fill: parent
translucent: false
showBorder: false
ColumnLayout {
anchors.fill: parent
Label {
text: qsTr("You need connect to server");
font.pixelSize: metrix.controlPtMaterial;
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillHeight: true
Layout.fillWidth: true
}
Button {
text: qsTr("Use OfflineMode");
Layout.alignment: Qt.AlignHCenter
onClicked: {
toOffline();
}
}
}
}
}
/*##^## Designer {
D{i:0;autoSize:true;height:480;width:640}D{i:3;anchors_height:100;anchors_width:100;anchors_x:228;anchors_y:63}
D{i:1;anchors_height:200;anchors_width:200;anchors_x:205;anchors_y:53}D{i:11;anchors_width:240;anchors_x:226;anchors_y:21}
}
##^##*/

@ -0,0 +1,196 @@
import QtQuick 2.9
import QtQuick.Controls.Material 2.0
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
Item {
id: item1
property var model: null
readonly property int onlineStatus: (model)? model.onlineStatus: false
visible: true
z: 1
signal playGame();
onOnlineStatusChanged: {
if (onlineStatus && onlineStatus !== 5) {
loginPopUp._show();
} else {
loginPopUp.close();
}
}
LeftSideBar {
id: userViewSideBar
openWidth: 7 * metrix.pt;
openHeight: columnLayout.height
source: UserView {
anchors.fill: parent;
model: (item1.model)? item1.model.userViewModel: null
visible: userViewSideBar.openFinished
onTryConnect: {
if (item1.model)
item1.model.tryConnect();
}
}
}
GridLayout {
id: columnLayout
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: userViewSideBar.right
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.topMargin: 0
columns: 3
rows: 2
transformOrigin: Item.Center
MainMenuButton {
id: play
text: qsTr("Play game")
onClicked: {
playGame();
if (model)
model.newGame();
}
}
MainMenuButton {
id: store
text: qsTr("Store")
}
MainMenuButton {
id: invitar
text: qsTr("My Items")
}
MainMenuButton {
id: freands
text: qsTr("My friends")
}
MainMenuButton {
id: settings
text: qsTr("My Settings")
onClicked: {
settingsPopUp._show();
}
}
MainMenuButton {
id: exit
text: qsTr("Exit")
onClicked: {
Qt.quit();
}
}
}
PagePopUp {
id: about;
width: parent.width / 2
height: parent.height / 2;
source: About {}
}
PagePopUp {
id: settingsPopUp
source: SettingsView {
id: settingsView
model: item1.model ? item1.model.userSettingsModel: null
}
standardButtons: Dialog.Save | Dialog.Cancel | Dialog.RestoreDefaults
modal: false;
autoClose: false
clickClose: true
width: 12 * metrix.controlPtMaterial
height: 8 * metrix.controlPtMaterial;
onAccepted: {
settingsView.save();
}
onReset: {
settingsView.reset();
}
onOpened: {
settingsView.update();
}
}
PagePopUp {
id: loginPopUp
source: LoginView {
id: loginView
loginStatus: onlineStatus
onSigLogin: {
if (!model) {
return;
}
model.login(gmail, password);
}
onSigNewUser: {
if (!model) {
return;
}
model.registerNewUser(gmail, password);
}
onToOffline: {
if (!model) {
return;
}
model.playOffline();
}
}
visible: true;
modal: true;
autoClose: false
clickClose: false
width: 12 * metrix.controlPtMaterial
height: ((loginView.currentView)? 9 : 7) * metrix.controlPtMaterial;
}
}
/*##^## Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

@ -0,0 +1,17 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
Button {
id: exit
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.pixelSize: height * 0.1
display: AbstractButton.TextBesideIcon
spacing: 4
focusPolicy: Qt.StrongFocus
Layout.preferredHeight: parent.height / (parent.rows + 1)
Layout.preferredWidth: parent.width / (parent.columns + 1)
}

@ -0,0 +1,27 @@
import QtQuick 2.0
import QtQuick.Window 2.12
import QtQuick.Controls.Material 2.0
import QtQuick.Controls 2.3
Item {
readonly property int pointCount: 100;
readonly property real mm: Screen.pixelDensity
readonly property real sm: 10 * mm
readonly property real dsm: Math.sqrt(Math.pow(Screen.desktopAvailableWidth, 2) + Math.pow(Screen.desktopAvailableHeight, 2)) / sm
readonly property real pt: getfactor(dsm) * sm
readonly property real controlPtMaterial: Material.buttonHeight
readonly property real gamePt: (width < height) ? width / pointCount : height / pointCount;
function getfactor(dsm) {
if (dsm < 30) {
return 0.5
} else if ( dsm < 70) {
return 1
} else if (dsm < 140) {
return 2;
} else
return 4;
}
anchors.fill: parent;
}

@ -0,0 +1,84 @@
import QtQuick 2.11
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
BasePopUp {
id : popup
property string text: qsTr("Message")
property string img: ""
property string titleText: qsTr("Message")
property int type: 0
function _getBackGraundColor(type) {
switch(type) {
case 1: return "#FFC107"
case 2: return "#FF5722"
}
return Material.background
}
autoClose: true;
closeInterval: 5000
margins: 0
margin: 0
spacing: 0
backgroundColor: _getBackGraundColor(type);
Page {
id: page
anchors.fill: parent
spacing: 0
background: Rectangle {
color: "#00000000"
}
header: Label {
text: titleText
horizontalAlignment: Text.AlignHCenter
}
contentItem:
RowLayout {
id: rowLayout
spacing: 5
clip: true
Rectangle {
color: "#00000000"
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.preferredWidth: rowLayout.height;
Layout.preferredHeight: rowLayout.height;
Image {
id: image
fillMode: Image.PreserveAspectCrop
clip: true
anchors.fill: parent;
source: img
}
}
Label {
id: message
text: popup.text
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.fillHeight: true;
Layout.fillWidth: true;
clip: true
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
}
}

@ -0,0 +1,30 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Item {
readonly property var model: notificationService;
readonly property var msg: model.notify
readonly property var history: model.history
NotificationForm {
id: notyfyView
titleText : msg.title;
text: (msg)? msg.text: "";
img: (msg)? msg.img: "";
type: (msg)? msg.type: 0;
x: parent.width - width - margin;
y: margin;
width: 6 * metrix.controlPtMaterial;
height: width * 0.5
}
onMsgChanged: {
notyfyView._show();
}
}

@ -0,0 +1,26 @@
import QtQuick 2.11
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
BasePopUp {
id: pagePopUp
property var source: null
autoClose: false
Item {
id: sourceVal
anchors.fill: parent
}
onSourceChanged: {
if (!source)
return;
source.parent = sourceVal;
source.anchors.fill = sourceVal;
}
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
}

@ -0,0 +1,124 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Item {
id: properyView
height: 1 * metrix.pt
property string keyImage: "";
property string keyText: "";
property string valueImage: "";
property string valueText: "";
property int lineWidth : 0.5 * metrix.mm
property bool hovered: false
property bool hold: false
Rectangle {
id:background
anchors.fill: parent
color: "#00000000"
Rectangle {
height: lineWidth
color: (hold)? Material.accent: (hovered)? Material.foreground:"#aaa"
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
Behavior on color {
ColorAnimation {
duration: 100
}
}
}
}
DropShadow {
anchors.fill: background
horizontalOffset: 2
verticalOffset: 2
radius: 8.0
samples: 17
color: "#80000000";
source: background
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
parent.hovered = true;
}
onExited: {
parent.hovered = false;
}
onReleased: {
parent.hold = false;
}
onPressed: {
parent.hold = true;
}
}
RowLayout {
Label {
text: keyText
visible: keyText
Layout.alignment: Qt.AlignLeft
horizontalAlignment: Text.AlignLeft
}
ImageView {
visible: keyImage
drawItem: keyImage
size: parent.height * 0.75
Layout.alignment: Qt.AlignLeft
}
Label {
text: valueText
visible: valueText
horizontalAlignment: Text.AlignRight
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight
}
ImageView {
drawItem: valueImage
size: parent.height * 0.75
visible: valueImage
Layout.alignment: Qt.AlignRight
}
anchors.fill: parent
}
}
/*##^## Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

@ -0,0 +1,228 @@
import QtQuick 2.11
import QtQuick.Controls.Material 2.0
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
Item {
id: scene;
z: -2
Rectangle {
id: background;
color: "#ffffff"
anchors.fill: parent;
Behavior on color {
ColorAnimation {
duration: 5000
}
}
z: -3
}
property var model: null;
property var arrayObjects: []
readonly property bool showMenu: (model)? model.showMenu: false
property bool isPause: false
function add (cppObjId) {
if (!model) {
console.log("create object fail")
return;
}
var objModel = model.getGameObject(cppObjId);
if (!objModel) {
console.log("object model not found");
return;
}
var viewTemplate = objModel.viewTemplate;
var temp = Qt.createComponent( viewTemplate + ".qml")
if (temp.status === Component.Ready) {
var obj = temp.createObject(parent) // parent - это обьект на который будет помещен соззданный элемент
obj.model = model.getGameObject(cppObjId);
obj.z = -2;
arrayObjects.push(obj)
} else {
console.log("wrong viewTemplate in model");
}
}
function remove(id) {
if (typeof id !== "number" || id < 0) {
console.log("id not found");
return;
}
for (var i = 0; i < arrayObjects.length; ++i) {
if (id === arrayObjects[i].guiId) {
arrayObjects.splice(i,1);
}
}
}
function updateBackgroundColor(lvl) {
switch(lvl % 7) {
case 0: background.color = "#d6eaf8"; break;
case 1: background.color = "#d0ece7"; break;
case 2: background.color = "#d4efdf"; break;
case 3: background.color = "#fcf3cf"; break;
case 4: background.color = "#f6ddcc"; break;
case 5: background.color = "#f2d7d5"; break;
case 6: background.color = "#ebdef0"; break;
case 7: background.color = "#fbfcfc"; break;
}
}
Timer {
id: autoTimer;
repeat: true;
running: showMenu;
interval: 1000
onTriggered: {
interval = Math.random() * 600
scene.model.buttonPress();
}
}
Connections {
target: model;
onGameObjectsChanged: {
if (!dif) {
console.log("dif not found");
return;
}
var tempDifRem = [];
tempDifRem = dif.getRemoveIds();
var tempDifAdd = [];
tempDifAdd = dif.getAddedIds();
for (var i = 0; i < tempDifAdd.length; ++i) {
add(tempDifAdd[i]);
}
for (i = 0; i < tempDifRem.length; ++i) {
remove(tempDifRem[i]);
}
}
}
Component.onCompleted: {
updateBackgroundColor(0);
model.handleNewGame();
}
MouseArea {
anchors.fill: parent;
onClicked: {
if (!model || showMenu) {
return;
}
model.buttonPress();
}
}
Button {
id: returnToMenu;
text: "<<"
anchors.left: parent.left
anchors.leftMargin: metrix.gamePt
anchors.top: parent.top
anchors.topMargin: metrix.gamePt
z: 1
onClicked: {
if (model)
model.showMenu = true;
}
visible: !showMenu
}
Button {
id: pause
text: (isPause)? "▶" :"||"
anchors.left: returnToMenu.right
anchors.leftMargin: metrix.gamePt
anchors.top: parent.top
anchors.topMargin: metrix.gamePt
z: returnToMenu.z
onClicked: {
isPause = !isPause;
if (model) model.setPause(isPause);
}
visible: !showMenu
}
Button {
id: long_
Label {
anchors.fill: parent;
textFormat: Text.AutoText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: qsTr("lvl long: ") + ((model)? model.long_: "0")
}
width: 35 * metrix.gamePt;
height: pause.height;
anchors.left: pause.right
anchors.leftMargin: metrix.gamePt
anchors.top: parent.top
anchors.topMargin: metrix.gamePt
z: returnToMenu.z
visible: !showMenu
}
Button {
Label {
anchors.fill: parent;
textFormat: Text.AutoText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: qsTr("general long: ") + ((model)? model.generalLong: "0")
}
width: 35 * metrix.gamePt;
height: long_.height;
anchors.left: long_.right
anchors.leftMargin: metrix.gamePt
anchors.top: parent.top
anchors.topMargin: metrix.gamePt
z: returnToMenu.z
visible: !showMenu
}
}

@ -0,0 +1,217 @@
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
Item {
id: item1
GridLayout {
id: gridLayout
rows: 8
columnSpacing: 5
rowSpacing: 5
anchors.rightMargin: 200
anchors.leftMargin: 200
anchors.bottomMargin: 100
anchors.topMargin: 50
anchors.fill: parent
columns: 8
RoundButton {
id: roundButton
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "1"
}
RoundButton {
id: roundButton1
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "2"
}
RoundButton {
id: roundButton2
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "3"
}
RoundButton {
id: roundButton3
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "4"
}
RoundButton {
id: roundButton4
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "5"
}
RoundButton {
id: roundButton5
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "6"
}
RoundButton {
id: roundButton6
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "7"
}
RoundButton {
id: roundButton7
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "8"
}
RoundButton {
id: roundButton8
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "9"
}
RoundButton {
id: roundButton9
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "10"
}
RoundButton {
id: roundButton10
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "11"
}
RoundButton {
id: roundButton11
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "12"
}
RoundButton {
id: roundButton12
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "13"
}
RoundButton {
id: roundButton13
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "14"
}
RoundButton {
id: roundButton14
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "15"
}
RoundButton {
id: roundButton15
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "16"
}
RoundButton {
id: roundButton16
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "17"
}
RoundButton {
id: roundButton17
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "18"
}
RoundButton {
id: roundButton18
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "19"
}
RoundButton {
id: roundButton19
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "20"
}
RoundButton {
id: roundButton20
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "21"
}
RoundButton {
id: roundButton21
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "22"
}
RoundButton {
id: roundButton22
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "23"
}
RoundButton {
id: roundButton23
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "24"
}
RoundButton {
id: roundButton24
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "25"
}
RoundButton {
id: roundButton25
width: 10*mainWindow.point
height: 10*mainWindow.point
text: "26"
}
}
Label {
id: label
x: 187
color: "#795548"
text: qsTr("Select Level")
font.bold: true
font.pixelSize: 30
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 30
}
}

@ -0,0 +1,122 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
Item {
id: settingsView
property var model: null
function save() {
if (!model) {
return;
}
model.setPort(port.value);
model.setHost(host.text);
model.setTheme(themeBox.currentIndex);
}
function reset() {
if (!model) {
return;
}
model.toDefault();
}
function update() {
if (!model) {
return;
}
model.forceUpdate();
}
GridLayout {
id: columnLayout
rows: 4
columns: 2
anchors.fill: parent
Label {
text: qsTr("Game Host")
Layout.fillWidth: true
}
TextField {
id: host;
text: (model)? model.host: "localhost"
Layout.fillHeight: false
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
Label {
text: qsTr("Game Port")
Layout.fillWidth: true
}
SpinBox {
id: port;
Layout.fillWidth: true
to: 10000
from: 7000
antialiasing: false
scale: 1
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
value: (model)? model.port: 7777
}
Label {
text: qsTr("Use Them")
Layout.fillWidth: true
}
ComboBox {
id: themeBox;
Layout.fillWidth: true
focusPolicy: Qt.NoFocus
model: [qsTr("Light"), qsTr("Dark")];
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
currentIndex: (settingsView.model)? settingsView.model.theme: 0
onCurrentIndexChanged: {
if (((settingsView.model)? settingsView.model.theme: 0)
!== currentIndex) {
themeWarning.visible = true;
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
Label {
id: themeWarning
text: qsTr("In order for the new theme to take effect, you need to reload the game.");
color: "#FF0000"
wrapMode: Label.WordWrap
Layout.maximumWidth: themeBox.width
visible: false;
}
}
}

@ -0,0 +1,103 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
FrameView {
id: sideBar
property int openHeight: 10 * metrix.pt
property int closedHeight: 1 * metrix.pt
property int openWidth: 10 * metrix.pt
property int closedWidth: 1 * metrix.pt
property int headerHeight : 1 * metrix.controlPtMaterial
clip: true;
property bool resizeWidth: true
property bool resizeHeight: true
property bool isOpened: true
property bool chainAnimation: true
property var source: null
property var header: null
readonly property bool openFinished: openHeight === height && openWidth == width;
readonly property bool closeFinished: closedHeight === height && closedWidth == width;
function show() {
if (resizeWidth && !(chainAnimation && resizeHeight))
width = openWidth;
if (resizeHeight )
height = openHeight;
isOpened = true;
}
function hide() {
if (resizeWidth && !(chainAnimation && resizeHeight))
width = closedWidth;
if (resizeHeight )
height = closedHeight;
isOpened = false;
}
Component.onCompleted: {
show();
}
onHeightChanged: {
if (isOpened) {
if (height === openHeight) {
sideBar.width = openWidth
}
}
else {
if (height === closedHeight) {
sideBar.width = closedWidth
}
}
}
Behavior on width {
PropertyAnimation {
duration: 1000
easing.type: Easing.OutBounce
}
}
Behavior on height {
PropertyAnimation {
duration: 1000
easing.type: Easing.OutBounce
}
}
Item {
id: headerVal
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: headerHeight
}
Item {
id: sourceVal
anchors.left: parent.left
anchors.right: parent.right
anchors.top: headerVal.bottom
anchors.bottom: parent.bottom
}
onSourceChanged: {
source.parent = sourceVal;
source.anchors.fill = sourceVal;
}
onHeaderChanged: {
header.parent = headerVal;
header.anchors.fill = headerVal;
}
}

@ -0,0 +1,17 @@
import QtQuick 2.9
GraphicItem {
Behavior on color {
ColorAnimation {
duration: 2000
}
}
Behavior on radius {
NumberAnimation {
duration: 2000
}
}
}

@ -1,12 +1,40 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the lgplv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick 2.15
ApplicationWindow {
id: mainWindow;
visible: true;
width: 640;
height: 480;
title: qsTr("SnakeOnTheRoad");
Item {
// Component.onCompleted: {
// mainWindow.showFullScreen();
// }
Metrix {id: metrix}
Scene {
id: scane;
model: contr;
anchors.fill: parent;
}
MainMenu {
model: (contr)? contr.mainMenuModel: null;
anchors.fill: parent;
visible: scane.showMenu;
onPlayGame: {
contr.showMenu = false;
}
}
NotificationServiceView {
anchors.fill: parent;
}
}

@ -0,0 +1,47 @@
import QtQuick 2.11
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
Item {
signal close();
RowLayout {
anchors.fill: parent
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
Label {
text: qsTr("Write you name ");
}
TextField {
id: input;
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
}
Button {
id: ok
text: qsTr("Ok")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
if (contr) {
var rec = contr.getRecords()
rec.append(input.text, contr.generalLong);
}
close();
}
}
}
}

@ -0,0 +1,112 @@
import QtQuick 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.12
Flickable {
id: userVewFlic
contentWidth: userVew.width
contentHeight: userVew.height
flickableDirection: Flickable.VerticalFlick;
property var model: null
signal tryConnect();
ScrollBar.vertical: ScrollBar {
width: metrix.pt
}
Item {
id: userVew
width: userVewFlic.width
ColumnLayout {
id: columnLayout
anchors.fill: parent
visible: (model)? !model.offline: false;
ImageView {
drawItem: "image://userItems/player/" + ((model)? model.id: -1).toString()
Layout.fillWidth: true
Layout.fillHeight: true
}
PropertyView {
Layout.fillWidth: true
keyText: qsTr("You ");
valueText : (model)? model.name: -1
}
PropertyView {
valueText : ((model)? model.gmail: -1).toString()
Layout.fillWidth: true
keyText: qsTr("You gmail");
}
PropertyView {
keyText: qsTr("Money ");
valueText : ((model)? model.money: -1).toString()
Layout.fillWidth: true
}
PropertyView {
keyText: qsTr("Record ");
valueText : ((model)? model.record: -1).toString()
Layout.fillWidth: true
}
PropertyView {
keyText: qsTr("AvgRecord ");
valueText : ((model)? model.avgRecord: -1).toString()
Layout.fillWidth: true
}
PropertyView {
keyText: qsTr("Snake ");
valueImage : "image://userItems/item/" + ((model)? model.cureentSnake: -1).toString()
Layout.fillWidth: true
}
}
ColumnLayout {
visible: (model)? model.offline: false;
anchors.fill: parent
Label {
wrapMode: Text.WordWrap
Layout.fillWidth: true
text: qsTr("Offline mode. Your statistics will be frozen until you login your profile.");
}
Button {
text: qsTr("try conect to server ");
Layout.alignment: Qt.AlignHCenter
onClicked: {
tryConnect();
}
}
Item {
Layout.fillHeight: true
}
}
}
}

@ -0,0 +1,79 @@
<?xml version="1.0"?>
<manifest package="quasar.app.snake" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:icon="@drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="landscape" android:launchMode="singleTop" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Application arguments -->
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
<!-- Application arguments -->
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Used to specify custom system library path to run with local system libs -->
<!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> -->
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Splash screen -->
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
<!-- Splash screen -->
<!-- Background running -->
<!-- Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after
"applicationStateChanged(Qt::ApplicationSuspended)"
signal is sent! -->
<meta-data android:name="android.app.background_running" android:value="false"/>
<!-- Background running -->
<!-- auto screen scale factor -->
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
<!-- auto screen scale factor -->
<!-- extract android style -->
<!-- available android:values :
* full - useful QWidget & Quick Controls 1 apps
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
* none - useful for apps that don't use any of the above Qt modules
-->
<meta-data android:name="android.app.extract_android_style" android:value="full"/>
<!-- extract android style -->
</activity>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
</application>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
</manifest>

@ -0,0 +1,57 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'
}
}
repositories {
google()
jcenter()
}
apply plugin: 'com.android.application'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
android {
/*******************************************************
* The following variables:
* - androidBuildToolsVersion,
* - androidCompileSdkVersion
* - qt5AndroidDir - holds the path to qt android files
* needed to build any Qt application
* on Android.
*
* are defined in gradle.properties file. This file is
* updated by QtCreator and androiddeployqt tools.
* Changing them manually might break the compilation!
*******************************************************/
compileSdkVersion androidCompileSdkVersion.toInteger()
buildToolsVersion androidBuildToolsVersion
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
res.srcDirs = [qt5AndroidDir + '/res', 'res']
resources.srcDirs = ['src']
renderscript.srcDirs = ['src']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
lintOptions {
abortOnError false
}
}

Binary file not shown.

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
src/ClientLib/android/gradlew vendored Executable file

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
src/ClientLib/android/gradlew.bat vendored Normal file

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

Binary file not shown.

After

(image error) Size: 2.4 KiB

Binary file not shown.

After

(image error) Size: 2.4 KiB

Binary file not shown.

After

(image error) Size: 2.4 KiB

@ -0,0 +1,25 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<array name="qt_sources">
<item>https://download.qt.io/ministro/android/qt5/qt-5.9</item>
</array>
<!-- The following is handled automatically by the deployment tool. It should
not be edited manually. -->
<array name="bundled_libs">
<!-- %%INSERT_EXTRA_LIBS%% -->
</array>
<array name="qt_libs">
<!-- %%INSERT_QT_LIBS%% -->
</array>
<array name="bundled_in_lib">
<!-- %%INSERT_BUNDLED_IN_LIB%% -->
</array>
<array name="bundled_in_assets">
<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->
</array>
</resources>

@ -1,4 +1,287 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>About</name>
<message>
<source>About</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AboutPage</name>
<message>
<source>Product of QuasarrApp</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Controller</name>
<message>
<source> Next Lvl!!!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source> You anblock next lvl (%0)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LoginView</name>
<message>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Password must be at least 8 characters</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Name must be at least 1 characters</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Passwords must match</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>The letter must match the pattern &apos;X@xxxx.xxx&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Email</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Passsword</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enter Your passsword</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enter Your Email</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Repeat password</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enter Your passsword again</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Sign in</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Sign Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You need connect to server</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use OfflineMode</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainClient</name>
<message>
<source>Login status</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Authorization Required</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Wait for answer</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Login result</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Authorization fail</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Client is offline</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Offline Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Request</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Bad Request</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainMenu</name>
<message>
<source>Play game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Store</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>My Items</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>My friends</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>My Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotificationForm</name>
<message>
<source>Message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Scene</name>
<message>
<source>lvl long: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>general long: </source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SelectLevelScene</name>
<message>
<source>Select Level</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsView</name>
<message>
<source>Game Host</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Game Port</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Them</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In order for the new theme to take effect, you need to reload the game.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SnakeProject</name>
<message>
<source>SnakeOnTheRoad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TextInput</name>
<message>
<source>Write you name </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ok</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UserView</name>
<message>
<source>You </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You gmail</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Money </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Record </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AvgRecord </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Snake </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Offline mode. Your statistics will be frozen until you login your profile.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>try conect to server </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Undefined name</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Undefined gmail</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

Binary file not shown.

After

(image error) Size: 28 KiB

Binary file not shown.

After

(image error) Size: 186 KiB

Binary file not shown.

After

(image error) Size: 79 KiB

@ -0,0 +1 @@
<svg aria-hidden="true" data-prefix="fas" data-icon="cogs" class="svg-inline--fa fa-cogs fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M512.1 191l-8.2 14.3c-3 5.3-9.4 7.5-15.1 5.4-11.8-4.4-22.6-10.7-32.1-18.6-4.6-3.8-5.8-10.5-2.8-15.7l8.2-14.3c-6.9-8-12.3-17.3-15.9-27.4h-16.5c-6 0-11.2-4.3-12.2-10.3-2-12-2.1-24.6 0-37.1 1-6 6.2-10.4 12.2-10.4h16.5c3.6-10.1 9-19.4 15.9-27.4l-8.2-14.3c-3-5.2-1.9-11.9 2.8-15.7 9.5-7.9 20.4-14.2 32.1-18.6 5.7-2.1 12.1.1 15.1 5.4l8.2 14.3c10.5-1.9 21.2-1.9 31.7 0L552 6.3c3-5.3 9.4-7.5 15.1-5.4 11.8 4.4 22.6 10.7 32.1 18.6 4.6 3.8 5.8 10.5 2.8 15.7l-8.2 14.3c6.9 8 12.3 17.3 15.9 27.4h16.5c6 0 11.2 4.3 12.2 10.3 2 12 2.1 24.6 0 37.1-1 6-6.2 10.4-12.2 10.4h-16.5c-3.6 10.1-9 19.4-15.9 27.4l8.2 14.3c3 5.2 1.9 11.9-2.8 15.7-9.5 7.9-20.4 14.2-32.1 18.6-5.7 2.1-12.1-.1-15.1-5.4l-8.2-14.3c-10.4 1.9-21.2 1.9-31.7 0zm-10.5-58.8c38.5 29.6 82.4-14.3 52.8-52.8-38.5-29.7-82.4 14.3-52.8 52.8zM386.3 286.1l33.7 16.8c10.1 5.8 14.5 18.1 10.5 29.1-8.9 24.2-26.4 46.4-42.6 65.8-7.4 8.9-20.2 11.1-30.3 5.3l-29.1-16.8c-16 13.7-34.6 24.6-54.9 31.7v33.6c0 11.6-8.3 21.6-19.7 23.6-24.6 4.2-50.4 4.4-75.9 0-11.5-2-20-11.9-20-23.6V418c-20.3-7.2-38.9-18-54.9-31.7L74 403c-10 5.8-22.9 3.6-30.3-5.3-16.2-19.4-33.3-41.6-42.2-65.7-4-10.9.4-23.2 10.5-29.1l33.3-16.8c-3.9-20.9-3.9-42.4 0-63.4L12 205.8c-10.1-5.8-14.6-18.1-10.5-29 8.9-24.2 26-46.4 42.2-65.8 7.4-8.9 20.2-11.1 30.3-5.3l29.1 16.8c16-13.7 34.6-24.6 54.9-31.7V57.1c0-11.5 8.2-21.5 19.6-23.5 24.6-4.2 50.5-4.4 76-.1 11.5 2 20 11.9 20 23.6v33.6c20.3 7.2 38.9 18 54.9 31.7l29.1-16.8c10-5.8 22.9-3.6 30.3 5.3 16.2 19.4 33.2 41.6 42.1 65.8 4 10.9.1 23.2-10 29.1l-33.7 16.8c3.9 21 3.9 42.5 0 63.5zm-117.6 21.1c59.2-77-28.7-164.9-105.7-105.7-59.2 77 28.7 164.9 105.7 105.7zm243.4 182.7l-8.2 14.3c-3 5.3-9.4 7.5-15.1 5.4-11.8-4.4-22.6-10.7-32.1-18.6-4.6-3.8-5.8-10.5-2.8-15.7l8.2-14.3c-6.9-8-12.3-17.3-15.9-27.4h-16.5c-6 0-11.2-4.3-12.2-10.3-2-12-2.1-24.6 0-37.1 1-6 6.2-10.4 12.2-10.4h16.5c3.6-10.1 9-19.4 15.9-27.4l-8.2-14.3c-3-5.2-1.9-11.9 2.8-15.7 9.5-7.9 20.4-14.2 32.1-18.6 5.7-2.1 12.1.1 15.1 5.4l8.2 14.3c10.5-1.9 21.2-1.9 31.7 0l8.2-14.3c3-5.3 9.4-7.5 15.1-5.4 11.8 4.4 22.6 10.7 32.1 18.6 4.6 3.8 5.8 10.5 2.8 15.7l-8.2 14.3c6.9 8 12.3 17.3 15.9 27.4h16.5c6 0 11.2 4.3 12.2 10.3 2 12 2.1 24.6 0 37.1-1 6-6.2 10.4-12.2 10.4h-16.5c-3.6 10.1-9 19.4-15.9 27.4l8.2 14.3c3 5.2 1.9 11.9-2.8 15.7-9.5 7.9-20.4 14.2-32.1 18.6-5.7 2.1-12.1-.1-15.1-5.4l-8.2-14.3c-10.4 1.9-21.2 1.9-31.7 0zM501.6 431c38.5 29.6 82.4-14.3 52.8-52.8-38.5-29.6-82.4 14.3-52.8 52.8z"></path></svg>

After

(image error) Size: 2.5 KiB

Binary file not shown.

After

(image error) Size: 18 KiB

Some files were not shown because too many files have changed in this diff Show More