Styles was added

This commit is contained in:
2023-03-29 12:49:20 +02:00
parent 7a929eb757
commit 44dd3cdb58
26 changed files with 433 additions and 193 deletions

View File

@@ -16,9 +16,11 @@ set(TS_FILES beerlog_ru_RU.ts)
set(PROJECT_SOURCES set(PROJECT_SOURCES
main.cpp main.cpp
qml.qrc qml/qml.qrc
models/abstractmodel.h models/abstractmodel.cpp
models/summarymodel.h models/summarymodel.cpp models/summarymodel.h models/summarymodel.cpp
models/usersmodel.h models/usersmodel.cpp models/usersmodel.h models/usersmodel.cpp
viewmodels/usersviewmodel.h viewmodels/usersviewmodel.cpp
services/beerservice.h services/beerservice.cpp services/beerservice.h services/beerservice.cpp
services/settingsservice.h services/settingsservice.cpp services/settingsservice.h services/settingsservice.cpp
${TS_FILES} ${TS_FILES}
@@ -32,8 +34,8 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
${PROJECT_SOURCES} ${PROJECT_SOURCES}
) )
# Define target properties for Android with Qt 6 as: # Define target properties for Android with Qt 6 as:
# set_property(TARGET beerlog APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR set_property(TARGET beerlog APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android) ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})

View File

@@ -1,9 +1,9 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ru.ded.beerlog" android:installLocation="auto" android:versionCode="0.0.1" android:versionName="-- %%INSERT_VERSION_NAME%% --"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ru.ded.beerlog" android:installLocation="auto" android:versionCode="1" android:versionName="0.1">
<!-- %%INSERT_PERMISSIONS --> <!-- %%INSERT_PERMISSIONS -->
<!-- %%INSERT_FEATURES --> <!-- %%INSERT_FEATURES -->
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/> <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
<application android:name="org.qtproject.qt.android.bindings.QtApplication" android:extractNativeLibs="true" android:hardwareAccelerated="true" android:label="BeerLog" android:requestLegacyExternalStorage="true" android:allowNativeHeapPointerTagging="false"> <application android:name="org.qtproject.qt.android.bindings.QtApplication" android:extractNativeLibs="true" android:hardwareAccelerated="true" android:label="BeerLog" android:requestLegacyExternalStorage="true" android:allowNativeHeapPointerTagging="false" android:icon="@drawable/icon">
<activity android:name="org.qtproject.qt.android.bindings.QtActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:label="BeerLog" android:launchMode="singleTop" android:screenOrientation="unspecified"> <activity android:name="org.qtproject.qt.android.bindings.QtActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:label="BeerLog" android:launchMode="singleTop" android:screenOrientation="unspecified">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -4,31 +4,25 @@
<context> <context>
<name>main</name> <name>main</name>
<message> <message>
<location filename="main.qml" line="13"/> <location filename="qml/main.qml" line="14"/>
<source>Beer Log</source> <source>Beer Log</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="main.qml" line="19"/> <location filename="qml/main.qml" line="77"/>
<source></source> <source>BeerLog v0.1</source>
<translation type="unfinished"></translation> <oldsource>BeerLog v1.0.0</oldsource>
<translation></translation>
</message> </message>
<message> <message>
<location filename="main.qml" line="28"/> <location filename="qml/main.qml" line="82"/>
<source></source> <source>Settings</source>
<translation type="unfinished"></translation> <translation>Настройки</translation>
</message> </message>
<message> <message>
<source>Summary: %1 р.</source> <location filename="qml/main.qml" line="88"/>
<translation type="vanished">Итого: %1 р.</translation> <source>Quit</source>
</message> <translation>Выход</translation>
<message>
<source>Order</source>
<translation type="vanished">Заказать</translation>
</message>
<message>
<source>Ordered %1 items. Amount: %2 р.</source>
<translation type="vanished">Заказано %1 позиций на сумму %2 р.</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@@ -5,8 +5,7 @@
#include <QTranslator> #include <QTranslator>
#include <QQmlContext> #include <QQmlContext>
#include "models/summarymodel.h" #include "viewmodels/usersviewmodel.h"
#include "models/usersmodel.h"
#include "services/beerservice.h" #include "services/beerservice.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -34,9 +33,8 @@ int main(int argc, char *argv[])
QCoreApplication::exit(-1); QCoreApplication::exit(-1);
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
engine.rootContext()->setContextProperty("beerService", new BeerService(&engine)); engine.rootContext()->setContextProperty("beerService", BeerService::instance());
qmlRegisterType<SummaryModel>("ru.ded.beerlog", 1, 0, "SummaryModel"); qmlRegisterType<UsersViewModel>("ru.ded.beerlog", 1, 0, "UsersViewModel");
qmlRegisterType<UsersModel>("ru.ded.beerlog", 1, 0, "UsersModel");
engine.load(url); engine.load(url);

View File

@@ -1,63 +0,0 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtWebSockets
import ru.ded.beerlog 1.0
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Beer Log")
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
text: qsTr("")
onClicked: stack.pop()
}
ToolButton {
text: usersModel.selectedUserName
Layout.fillWidth: true
onClicked: usersMenu.open()
}
ToolButton {
text: qsTr("⋮")
onClicked: menu.open()
}
}
Menu {
id: usersMenu
Repeater {
model: usersModel.users
MenuItem {
text: modelData.name
onClicked: {
usersModel.selectedUser = modelData.id
}
}
}
}
}
UsersModel {
id: usersModel
Component.onCompleted: {
beerService.connectSrv(selectedUser)
beerService.connectListener(usersModel)
beerService.sendCommand("users", "get")
}
onSelectedUserChanged: {
beerService.connectSrv(selectedUser)
}
}
}

41
models/abstractmodel.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "abstractmodel.h"
#include "services/beerservice.h"
AbstractModel::AbstractModel(QObject *parent)
: QObject{parent}
{
}
void AbstractModel::created(const QVariant &data)
{
modified(data);
}
void AbstractModel::modified(const QVariant &data)
{
QVariantMap d = data.toMap();
m_data[d.value("id").toString()] = d;
emit dataChanged();
}
void AbstractModel::deleted(const QVariant &data)
{
QString id = data.toString();
m_data.remove(id);
emit dataChanged();
}
void AbstractModel::received(const QVariant &data)
{
m_data = data.toMap();
emit dataChanged();
}
BeerService *AbstractModel::service() const
{
return BeerService::instance();
}

34
models/abstractmodel.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef ABSTRACTMODEL_H
#define ABSTRACTMODEL_H
#include <QObject>
#include <QVariantMap>
class BeerService;
class AbstractModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString entity READ entity CONSTANT)
public:
explicit AbstractModel(QObject *parent = nullptr);
virtual QString entity() const = 0;
public slots:
void created(const QVariant &data);
void modified(const QVariant &data);
void deleted(const QVariant &data);
void received(const QVariant &data);
signals:
void dataChanged();
protected:
BeerService *service() const;
QVariantMap m_data;
};
#endif // ABSTRACTMODEL_H

View File

@@ -1,80 +1,42 @@
#include "usersmodel.h" #include "usersmodel.h"
#include "services/beerservice.h"
namespace Keys {
constexpr auto Users = "users";
constexpr auto Name = "name";
}
UsersModel::UsersModel(QObject *parent) UsersModel::UsersModel(QObject *parent)
: QObject{parent} : AbstractModel{parent}
{ {
setSelectedUser(m_settings.value("selected_user").toString()); service()->connectListener(this);
} service()->sendCommand(Keys::Users, "get");
void UsersModel::created(const QVariant &data)
{
modified(data);
}
void UsersModel::modified(const QVariant &data)
{
QVariantMap user = data.toMap();
m_users[user.value("id").toString()] = user;
emit usersChanged();
emit selectedUserNameChanged();
}
void UsersModel::deleted(const QVariant &data)
{
QString userId = data.toString();
m_users.remove(userId);
emit usersChanged();
emit selectedUserNameChanged();
}
void UsersModel::received(const QVariant &data)
{
m_users = data.toMap();
emit usersChanged();
emit selectedUserNameChanged();
}
void UsersModel::connected(const QVariant &data)
{
qInfo() << data.toMap().value("name").toString() << "connected";
}
void UsersModel::disconnected(const QVariant &data)
{
qInfo() << data.toMap().value("name").toString() << "disconnected";
} }
QString UsersModel::entity() const QString UsersModel::entity() const
{ {
return QStringLiteral("users"); return Keys::Users;
}
void UsersModel::connected(const QVariant &data)
{
qInfo() << data.toMap().value(Keys::Name).toString() << "connected";
}
void UsersModel::disconnected(const QVariant &data)
{
qInfo() << data.toMap().value(Keys::Name).toString() << "disconnected";
} }
QVariantList UsersModel::users() const QVariantList UsersModel::users() const
{ {
return m_users.values(); return m_data.values();
} }
QString UsersModel::selectedUser() const QString UsersModel::userName(const QString &userId) const
{ {
return m_selectedUser; return m_data.value(userId).toMap().value(Keys::Name).toString();
}
void UsersModel::setSelectedUser(const QString &newSelectedUser)
{
if (m_selectedUser == newSelectedUser) {
return;
}
m_selectedUser = newSelectedUser;
m_settings.setValue("selected_user", m_selectedUser);
emit selectedUserChanged();
emit selectedUserNameChanged();
}
QString UsersModel::selectedUserName() const
{
return m_users.value(m_selectedUser).toMap().value("name").toString();
} }

View File

@@ -5,43 +5,23 @@
#include <QVariantMap> #include <QVariantMap>
#include "services/settingsservice.h" #include "services/settingsservice.h"
#include "models/abstractmodel.h"
class UsersModel : public QObject class UsersModel : public AbstractModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString entity READ entity CONSTANT)
Q_PROPERTY(QVariantList users READ users NOTIFY usersChanged)
Q_PROPERTY(QString selectedUser READ selectedUser WRITE setSelectedUser NOTIFY selectedUserChanged)
Q_PROPERTY(QString selectedUserName READ selectedUserName NOTIFY selectedUserNameChanged)
public: public:
explicit UsersModel(QObject *parent = nullptr); explicit UsersModel(QObject *parent = nullptr);
QString entity() const; QString entity() const override;
QVariantList users() const; QVariantList users() const;
QString selectedUser() const; QString userName(const QString &userId) const;
void setSelectedUser(const QString &newSelectedUser);
QString selectedUserName() const;
public slots: public slots:
void created(const QVariant &data);
void modified(const QVariant &data);
void deleted(const QVariant &data);
void received(const QVariant &data);
void connected(const QVariant &data); void connected(const QVariant &data);
void disconnected(const QVariant &data); void disconnected(const QVariant &data);
signals:
void usersChanged();
void selectedUserChanged();
void selectedUserNameChanged();
private:
QVariantMap m_users;
QString m_selectedUser;
SettingsService m_settings;
}; };
#endif // USERSMODEL_H #endif // USERSMODEL_H

View File

@@ -0,0 +1,84 @@
import QtQuick 2.15
Item {
id: root
width: 40
height: 40
property double iconMarigns: 8
property double iconHeight: width - iconMarigns * 2
signal clicked()
signal back()
SystemPalette {
id: palette
}
MouseArea {
id: ma
anchors.fill: parent
}
Rectangle {
id: bar1
x: root.iconMarigns
y: root.iconMarigns + root.iconHeight / 6
width: root.iconHeight
height: root.iconHeight / 9
antialiasing: true
color: palette.button
}
Rectangle {
id: bar2
x: root.iconMarigns
y: root.iconMarigns + root.iconHeight / 2 - height / 2
width: root.iconHeight
height: root.iconHeight / 9
antialiasing: true
color: palette.button
}
Rectangle {
id: bar3
x: root.iconMarigns
y: root.iconMarigns + root.iconHeight / 2 + height * 2
width: root.iconHeight
height: root.iconHeight / 9
antialiasing: true
color: palette.button
}
property int animationDuration: 450
state: "menu"
states: [
State {
name: "menu"
PropertyChanges { target: ma; onClicked: root.clicked() }
},
State {
name: "back"
PropertyChanges { target: root; rotation: 180 }
PropertyChanges { target: bar1; rotation: 45; width: root.iconHeight / 3 * 2; x: root.iconMarigns + root.iconHeight / 2; y: root.iconMarigns + root.iconHeight / 4 }
PropertyChanges { target: bar2; width: root.iconHeight / 6 * 5 + 1; x: root.iconMarigns + root.iconHeight / 9 }
PropertyChanges { target: bar3; rotation: -45; width: root.iconHeight / 3 * 2; x: root.iconMarigns + root.iconHeight / 2; y: root.iconMarigns + root.iconHeight / 3 * 2 }
PropertyChanges { target: ma; onClicked: root.back() }
}
]
transitions: [
Transition {
RotationAnimation { target: root; direction: RotationAnimation.Clockwise; duration: animationDuration; easing.type: Easing.InOutQuad }
PropertyAnimation { target: bar1; properties: "rotation, width, x, y"; duration: animationDuration; easing.type: Easing.InOutQuad }
PropertyAnimation { target: bar2; properties: "rotation, width, x, y"; duration: animationDuration; easing.type: Easing.InOutQuad }
PropertyAnimation { target: bar3; properties: "rotation, width, x, y"; duration: animationDuration; easing.type: Easing.InOutQuad }
}
]
}

BIN
qml/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

94
qml/main.qml Normal file
View File

@@ -0,0 +1,94 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtWebSockets
import ru.ded.beerlog 1.0
import "Components"
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Beer Log")
header: ToolBar {
RowLayout {
anchors.fill: parent
MenuBackButton {
state: "menu"//stackView.depth > 1 ? "back" : "menu"
onClicked: drawer.open()
onBack: {
state = "menu"
}
}
ToolButton {
text: usersModel.selectedUserName
Layout.fillWidth: true
onClicked: usersMenu.open()
}
}
Menu {
id: usersMenu
UsersViewModel {
id: usersModel
}
Repeater {
model: usersModel.users
MenuItem {
text: modelData.name
onClicked: {
usersModel.selectedUser = modelData.id
}
}
}
}
}
Drawer {
id: drawer
width: parent.width * 0.66
height: parent.height
Column {
anchors.fill: parent
Row {
width: parent.width
height: 100
Image {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 10
source: "logo.png"
}
Label {
anchors.verticalCenter: parent.verticalCenter
font.pointSize: 20
text: qsTr("BeerLog v0.1")
}
}
ItemDelegate {
text: qsTr("Settings")
width: parent.width
onClicked: stackView.openPage("SettingsForm.qml")
}
ItemDelegate {
text: qsTr("Quit")
width: parent.width
onClicked: Qt.quit()
}
}
}
}

View File

@@ -1,6 +1,9 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>main.qml</file> <file>main.qml</file>
<file>Components/MenuBackButton.qml</file>
<file>qtquickcontrols2.conf</file>
<file>logo.png</file>
<file>beerlog_ru_RU.qm</file> <file>beerlog_ru_RU.qm</file>
</qresource> </qresource>
</RCC> </RCC>

13
qml/qtquickcontrols2.conf Normal file
View File

@@ -0,0 +1,13 @@
; This file can be edited to change the style of the application
; Read "Qt Quick Controls 2 Configuration File" for details:
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
Style=Material
[Material]
Theme=Dark
Primary=BlueGrey
Accent=Grey
;Foreground=Brown
;Background=Steel

View File

@@ -7,14 +7,8 @@
#include <QFile> #include <QFile>
#include <QDebug> #include <QDebug>
namespace { BeerService::BeerService()
: QObject{nullptr}
constexpr auto GuestUserId = "2641ffe8cd4311eda27f0242ac120002";
}
BeerService::BeerService(QObject *parent)
: QObject{parent}
{ {
restoreStash(); restoreStash();
@@ -59,8 +53,7 @@ void BeerService::connectSrv(const QString &userId)
} }
QNetworkRequest request(QUrl("ws://195.133.196.161:8000")); QNetworkRequest request(QUrl("ws://195.133.196.161:8000"));
QString authString = QString("%1:pass").arg(userId.isEmpty() ? GuestUserId : userId); request.setRawHeader("Authorization", "Basic " + QString("%1:pass").arg(userId).toLatin1().toBase64());
request.setRawHeader("Authorization", "Basic " + authString.toLatin1().toBase64());
m_socket.open(request); m_socket.open(request);
} }

View File

@@ -9,14 +9,21 @@ class BeerService : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit BeerService(QObject *parent = nullptr); static BeerService *instance()
~BeerService(); {
static BeerService i;
return &i;
}
Q_INVOKABLE void connectSrv(const QString &userId = QString()); Q_INVOKABLE void connectSrv(const QString &userId = QString());
Q_INVOKABLE void sendCommand(const QString &entity, const QString &action, const QVariantMap &data = QVariantMap());
Q_INVOKABLE void connectListener(QObject *listener); void sendCommand(const QString &entity, const QString &action, const QVariantMap &data = QVariantMap());
void connectListener(QObject *listener);
private: private:
BeerService();
~BeerService();
QString stashFileName() const; QString stashFileName() const;
void saveStash() const; void saveStash() const;
void restoreStash(); void restoreStash();

View File

@@ -1,5 +1,11 @@
#include "settingsservice.h" #include "settingsservice.h"
namespace Defaults {
constexpr auto GuestUserId = "2641ffe8cd4311eda27f0242ac120002";
}
QVariant SettingsService::value(const QString &key, const QVariant &defaultValue) const QVariant SettingsService::value(const QString &key, const QVariant &defaultValue) const
{ {
return m_settings.value(key, defaultValue); return m_settings.value(key, defaultValue);
@@ -9,3 +15,13 @@ void SettingsService::setValue(const QString &key, const QVariant &value)
{ {
m_settings.setValue(key, value); m_settings.setValue(key, value);
} }
QString SettingsService::selectedUserId() const
{
return m_settings.value("selected_user", Defaults::GuestUserId).toString();
}
void SettingsService::setSelectedUserId(const QString &userId)
{
m_settings.setValue("selected_user", userId);
}

View File

@@ -9,6 +9,9 @@ public:
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
void setValue(const QString &key, const QVariant &value); void setValue(const QString &key, const QVariant &value);
QString selectedUserId() const;
void setSelectedUserId(const QString &userId);
private: private:
QSettings m_settings = QSettings("DedSoft", "BeerLog"); QSettings m_settings = QSettings("DedSoft", "BeerLog");
}; };

View File

@@ -0,0 +1,43 @@
#include "usersviewmodel.h"
#include "services/beerservice.h"
UsersViewModel::UsersViewModel(QObject *parent)
: QObject{parent}
{
connect(this, &UsersViewModel::selectedUserChanged, this, [this]() {
BeerService::instance()->connectSrv(m_selectedUser);
});
setSelectedUser(m_settings.selectedUserId());
connect(&m_usersModel, &AbstractModel::dataChanged, this, &UsersViewModel::usersChanged);
connect(&m_usersModel, &AbstractModel::dataChanged, this, &UsersViewModel::selectedUserNameChanged);
}
QVariantList UsersViewModel::users() const
{
return m_usersModel.users();
}
QString UsersViewModel::selectedUser() const
{
return m_selectedUser;
}
void UsersViewModel::setSelectedUser(const QString &newSelectedUser)
{
if (m_selectedUser == newSelectedUser) {
return;
}
m_selectedUser = newSelectedUser;
m_settings.setSelectedUserId(m_selectedUser);
emit selectedUserChanged();
emit selectedUserNameChanged();
}
QString UsersViewModel::selectedUserName() const
{
return m_usersModel.userName(m_selectedUser);
}

View File

@@ -0,0 +1,36 @@
#ifndef USERSVIEWMODEL_H
#define USERSVIEWMODEL_H
#include <QObject>
#include "models/usersmodel.h"
class UsersViewModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList users READ users NOTIFY usersChanged)
Q_PROPERTY(QString selectedUser READ selectedUser WRITE setSelectedUser NOTIFY selectedUserChanged)
Q_PROPERTY(QString selectedUserName READ selectedUserName NOTIFY selectedUserNameChanged)
public:
explicit UsersViewModel(QObject *parent = nullptr);
QVariantList users() const;
QString selectedUser() const;
void setSelectedUser(const QString &newSelectedUser);
QString selectedUserName() const;
signals:
void usersChanged();
void selectedUserChanged();
void selectedUserNameChanged();
private:
QString m_selectedUser;
UsersModel m_usersModel;
SettingsService m_settings;
};
#endif // USERSVIEWMODEL_H