Compare commits
11 Commits
28b18aa67b
...
2d2d5032c0
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d2d5032c0 | |||
| 9d054d4119 | |||
| 4814d9002d | |||
| 5dd32e92b8 | |||
| dc4e547c62 | |||
| f11ac5cbfc | |||
| 786f423394 | |||
| 7c4f64e32d | |||
| 4590aeaee8 | |||
| 856d7ff67f | |||
| 394fa90d0d |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
cmake-build-*
|
||||
build/
|
||||
|
||||
10
App.cpp
Normal file
10
App.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by selim on 01.10.22.
|
||||
//
|
||||
|
||||
#include "App.h"
|
||||
|
||||
App &App::instance() {
|
||||
static App app("pro.aliencat.autocat");
|
||||
return app;
|
||||
}
|
||||
17
App.h
Normal file
17
App.h
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by selim on 01.10.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_APP_H
|
||||
#define AUTOCAT_GNOME_APP_H
|
||||
|
||||
#include "gtkpp/Application.h"
|
||||
|
||||
class App: public gtkpp::Application {
|
||||
public:
|
||||
using gtkpp::Application::Application;
|
||||
static App& instance();
|
||||
};
|
||||
|
||||
|
||||
#endif //AUTOCAT_GNOME_APP_H
|
||||
@ -1,17 +1,28 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(autocat_gnome)
|
||||
include(ExternalProject)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines")
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
#if(APPLE)
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-coroutines-ts")
|
||||
#endif()
|
||||
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -g -Og")
|
||||
|
||||
if(APPLE)
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/opt/libsoup@2/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig")
|
||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
|
||||
set(OPENSSL_LIBRARIES /usr/local/opt/openssl/lib)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(folly REQUIRED)
|
||||
find_package(concurrencpp REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
|
||||
pkg_check_modules(GTK REQUIRED gtk4)
|
||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||
@ -64,7 +75,17 @@ add_executable(autocat_gnome main.cpp
|
||||
gtkpp/MessageDialog.cpp
|
||||
gtkpp/MessageDialog.h
|
||||
gtkpp/Leaflet.cpp
|
||||
gtkpp/Leaflet.h)
|
||||
gtkpp/Leaflet.h
|
||||
gtkpp/Dialog.cpp
|
||||
gtkpp/Dialog.h
|
||||
gui/AddNumberDialog.cpp
|
||||
gui/AddNumberDialog.h
|
||||
gui/custom/PlateView.h
|
||||
gui/custom/PlateView.c
|
||||
App.cpp
|
||||
App.h
|
||||
models/Vehicle.cpp
|
||||
models/Vehicle.h services/Storage.cpp services/Storage.h models/Engine.cpp models/Engine.h services/IDBEntity.h models/JsonOptional.h services/IDBEntity.cpp gtkpp/ScrolledWindow.cpp gtkpp/ScrolledWindow.h gtkpp/ListView.cpp gtkpp/ListView.h gtkpp/SelectionModel.cpp gtkpp/SelectionModel.h gtkpp/ListItemFactory.cpp gtkpp/ListItemFactory.h models/VehiclesListFactory.cpp models/VehiclesListFactory.h gtkpp/Separator.cpp gtkpp/Separator.h gtkpp/Label.cpp gtkpp/Label.h)
|
||||
|
||||
target_link_libraries(autocat_gnome ${GTK_LIBRARIES}
|
||||
${GLIB_LIBRARIES}
|
||||
@ -72,7 +93,10 @@ target_link_libraries(autocat_gnome ${GTK_LIBRARIES}
|
||||
${LIBADWAITA_LIBRARIES}
|
||||
${LIBSIGCPP_LIBRARIES}
|
||||
nlohmann_json::nlohmann_json
|
||||
Folly::folly)
|
||||
concurrencpp::concurrencpp
|
||||
Threads::Threads
|
||||
SQLite::SQLite3
|
||||
fmt::fmt)
|
||||
|
||||
set(XML gui/MainWindow.xml)
|
||||
|
||||
|
||||
15
coro/Coro.h
15
coro/Coro.h
@ -5,19 +5,26 @@
|
||||
#ifndef AUTOCAT_GNOME_CORO_H
|
||||
#define AUTOCAT_GNOME_CORO_H
|
||||
|
||||
#include <coroutine>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
#if __cpp_lib_coroutine
|
||||
#include <coroutine>
|
||||
namespace corons = std;
|
||||
#else
|
||||
#include <experimental/coroutine>
|
||||
namespace corons = std::experimental;
|
||||
#endif
|
||||
|
||||
template<typename... Args>
|
||||
struct std::coroutine_traits<void, Args...> {
|
||||
struct corons::coroutine_traits<void, Args...> {
|
||||
struct promise_type {
|
||||
void get_return_object() noexcept {}
|
||||
|
||||
std::suspend_never initial_suspend() const noexcept {
|
||||
corons::suspend_never initial_suspend() const noexcept {
|
||||
return {};
|
||||
}
|
||||
std::suspend_never final_suspend() const noexcept {
|
||||
corons::suspend_never final_suspend() const noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include "GLibMainContextExecutor.h"
|
||||
#include <glib.h>
|
||||
|
||||
/*
|
||||
|
||||
int callback(void* data) {
|
||||
auto executor = reinterpret_cast<GLibMainContextExecutor*>(data);
|
||||
executor->runFront();
|
||||
@ -30,3 +32,4 @@ folly::Executor::KeepAlive<GLibMainContextExecutor> GLibMainContextExecutor::ins
|
||||
static GLibMainContextExecutor instance;
|
||||
return folly::getKeepAliveToken(instance);
|
||||
}
|
||||
*/
|
||||
|
||||
@ -5,20 +5,16 @@
|
||||
#ifndef AUTOCAT_GNOME_GLIBMAINCONTEXTEXECUTOR_H
|
||||
#define AUTOCAT_GNOME_GLIBMAINCONTEXTEXECUTOR_H
|
||||
|
||||
#include <folly/Executor.h>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
class GLibMainContextExecutor: public folly::Executor {
|
||||
class GLibMainContextExecutor {
|
||||
private:
|
||||
std::queue<folly::Func> _tasks;
|
||||
//std::queue<folly::Func> _tasks;
|
||||
std::mutex _mutex;
|
||||
|
||||
public:
|
||||
static folly::Executor::KeepAlive<GLibMainContextExecutor> instance();
|
||||
~GLibMainContextExecutor() override = default;
|
||||
void add(folly::Func func) override;
|
||||
void runFront();
|
||||
//~GLibMainContextExecutor() override = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ namespace gtkpp {
|
||||
}
|
||||
|
||||
Application::Application(const std::string &id) {
|
||||
_app = adw_application_new(id.c_str(), G_APPLICATION_FLAGS_NONE);
|
||||
_app = adw_application_new(id.c_str(), G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect(_app, "activate", G_CALLBACK(activateCallback), this);
|
||||
}
|
||||
|
||||
|
||||
@ -4,14 +4,22 @@
|
||||
|
||||
#include "Box.h"
|
||||
|
||||
gtkpp::Box::Box(GtkOrientation orientation, int spacing) : Widget() {
|
||||
_widget = gtk_box_new(orientation, spacing);
|
||||
}
|
||||
namespace gtkpp {
|
||||
|
||||
void gtkpp::Box::append(const gtkpp::Widget& widget) {
|
||||
gtk_box_append(GTK_BOX(_widget), widget.gobj());
|
||||
}
|
||||
Box::Box(GtkWidget *widget): Widget() {
|
||||
_widget = widget;
|
||||
}
|
||||
|
||||
Box::Box(GtkOrientation orientation, int spacing) : Widget() {
|
||||
_widget = gtk_box_new(orientation, spacing);
|
||||
}
|
||||
|
||||
void Box::append(const gtkpp::Widget& widget) {
|
||||
gtk_box_append(GTK_BOX(_widget), widget.gobj());
|
||||
}
|
||||
|
||||
void Box::append(GtkWidget *widget) {
|
||||
gtk_box_append(GTK_BOX(_widget), widget);
|
||||
}
|
||||
|
||||
void gtkpp::Box::append(GtkWidget *widget) {
|
||||
gtk_box_append(GTK_BOX(_widget), widget);
|
||||
}
|
||||
|
||||
@ -11,8 +11,9 @@
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class Box: public Widget{
|
||||
class Box: public Widget {
|
||||
public:
|
||||
Box(GtkWidget* widget);
|
||||
Box(GtkOrientation orientation, int spacing);
|
||||
void append(const Widget& widget);
|
||||
void append(GtkWidget* widget);
|
||||
|
||||
@ -6,22 +6,17 @@
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
void clickedCallback(GtkButton*, void* data) {
|
||||
auto button = reinterpret_cast<Button*>(data);
|
||||
button->_signalClicked.emit();
|
||||
}
|
||||
|
||||
Button::Button() : Widget() {
|
||||
_widget = gtk_button_new();
|
||||
g_signal_connect(_widget, "clicked", G_CALLBACK(clickedCallback), this);
|
||||
setupSignals();
|
||||
}
|
||||
|
||||
void Button::setTitle(const std::string &title) {
|
||||
gtk_button_set_label(GTK_BUTTON(_widget), title.c_str());
|
||||
}
|
||||
|
||||
void Button::onClick(const std::function<void()> &callback) {
|
||||
_signalClicked.connect(callback);
|
||||
void Button::setIconName(const std::string &name) {
|
||||
gtk_button_set_icon_name(GTK_BUTTON(_widget), name.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,21 +7,15 @@
|
||||
|
||||
#include "Widget.h"
|
||||
#include <string>
|
||||
#include <sigc++/sigc++.h>
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class Button: public Widget {
|
||||
private:
|
||||
sigc::signal<void()> _signalClicked;
|
||||
|
||||
private:
|
||||
friend void clickedCallback(GtkButton*, void* data);
|
||||
|
||||
public:
|
||||
using Widget::Widget;
|
||||
Button();
|
||||
void setTitle(const std::string& title);
|
||||
void onClick(const std::function<void()>& callback);
|
||||
void setIconName(const std::string& name);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
60
gtkpp/Dialog.cpp
Normal file
60
gtkpp/Dialog.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// Created by selim on 17.05.2022.
|
||||
//
|
||||
|
||||
#include "Dialog.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
void responseCallback(GtkDialog*, GtkResponseType responseId, void* data) {
|
||||
auto dialog = reinterpret_cast<Dialog*>(data);
|
||||
dialog->_response = responseId;
|
||||
dialog->_signalResponse.emit(responseId);
|
||||
}
|
||||
|
||||
Dialog::Dialog(Window* parent) {
|
||||
|
||||
auto flags = static_cast<GtkDialogFlags>(GTK_DIALOG_DESTROY_WITH_PARENT
|
||||
| GTK_DIALOG_MODAL
|
||||
| GTK_DIALOG_USE_HEADER_BAR);
|
||||
|
||||
auto dialog = gtk_dialog_new_with_buttons("Add plate number",
|
||||
parent->gobj(),
|
||||
flags,
|
||||
"OK", GTK_RESPONSE_OK,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
nullptr);
|
||||
_window = GTK_WINDOW(dialog);
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
|
||||
_responseHandlerId = g_signal_connect (dialog, "response", G_CALLBACK(responseCallback), this);
|
||||
}
|
||||
|
||||
void Dialog::onResponse(const std::function<void(GtkResponseType)> &callback) {
|
||||
_signalResponse.connect(callback);
|
||||
}
|
||||
|
||||
cc::result<GtkResponseType> Dialog::responseAsync() {
|
||||
auto promise = std::make_shared<cc::result_promise<GtkResponseType>>();
|
||||
auto result = promise->get_result();
|
||||
|
||||
_signalResponse.connect([promise](GtkResponseType response){
|
||||
promise->set_result(response);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Dialog::~Dialog() {
|
||||
g_signal_handler_disconnect(_window, _responseHandlerId);
|
||||
}
|
||||
|
||||
GtkResponseType Dialog::currentResponse() const {
|
||||
return _response;
|
||||
}
|
||||
|
||||
Box Dialog::contentWidget() const {
|
||||
auto contentArea = gtk_dialog_get_content_area (GTK_DIALOG(_window));
|
||||
return {contentArea};
|
||||
}
|
||||
|
||||
}
|
||||
37
gtkpp/Dialog.h
Normal file
37
gtkpp/Dialog.h
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by selim on 17.05.2022.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_DIALOG_H
|
||||
#define AUTOCAT_GNOME_DIALOG_H
|
||||
|
||||
#include "Window.h"
|
||||
#include "Box.h"
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <concurrencpp/concurrencpp.h>
|
||||
|
||||
namespace cc = concurrencpp;
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class Dialog: public Window {
|
||||
private:
|
||||
GtkResponseType _response = GTK_RESPONSE_NONE;
|
||||
gulong _responseHandlerId;
|
||||
sigc::signal<void(GtkResponseType)> _signalResponse;
|
||||
friend void responseCallback(GtkDialog*, GtkResponseType responseId, void* data);
|
||||
|
||||
public:
|
||||
void onResponse(const std::function<void(GtkResponseType)>& callback);
|
||||
|
||||
public:
|
||||
explicit Dialog(Window* parent);
|
||||
~Dialog();
|
||||
cc::result<GtkResponseType> responseAsync();
|
||||
GtkResponseType currentResponse() const;
|
||||
Box contentWidget() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_DIALOG_H
|
||||
@ -13,7 +13,11 @@ namespace gtkpp {
|
||||
|
||||
Entry::Entry() : Widget() {
|
||||
_widget = gtk_entry_new();
|
||||
g_signal_connect(_widget, "changed", G_CALLBACK(changedCallback), this);
|
||||
_changedHandlerId = g_signal_connect(_widget, "changed", G_CALLBACK(changedCallback), this);
|
||||
}
|
||||
|
||||
Entry::~Entry() {
|
||||
g_signal_handler_disconnect(_widget, _changedHandlerId);
|
||||
}
|
||||
|
||||
void Entry::setPlaceholder(const std::string &placeholder) {
|
||||
|
||||
@ -13,6 +13,7 @@ namespace gtkpp {
|
||||
|
||||
class Entry: public Widget {
|
||||
private:
|
||||
gulong _changedHandlerId;
|
||||
sigc::signal<void()> _signalChanged;
|
||||
|
||||
private:
|
||||
@ -20,6 +21,7 @@ namespace gtkpp {
|
||||
|
||||
public:
|
||||
Entry();
|
||||
~Entry();
|
||||
void setPlaceholder(const std::string& placeholder);
|
||||
void setPurpose(GtkInputPurpose purpose);
|
||||
void setVisibility(bool visibility);
|
||||
|
||||
@ -18,4 +18,12 @@ namespace gtkpp {
|
||||
void HeaderBar::setTitle(const std::string& title) {
|
||||
adw_header_bar_set_title_widget(ADW_HEADER_BAR(_widget), gtk_label_new(title.c_str()));
|
||||
}
|
||||
|
||||
void HeaderBar::showEndButtons(bool show) {
|
||||
adw_header_bar_set_show_end_title_buttons(ADW_HEADER_BAR(_widget), show);
|
||||
}
|
||||
|
||||
void HeaderBar::packStart(const Widget &widget) {
|
||||
adw_header_bar_pack_start(ADW_HEADER_BAR(_widget), widget.gobj());
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,8 @@ namespace gtkpp {
|
||||
HeaderBar();
|
||||
explicit HeaderBar(const std::string& title);
|
||||
void setTitle(const std::string& title);
|
||||
void showEndButtons(bool show);
|
||||
void packStart(const Widget& widget);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
17
gtkpp/Label.cpp
Normal file
17
gtkpp/Label.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by selim on 18.12.22.
|
||||
//
|
||||
|
||||
#include "Label.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
Label::Label(): Widget() {
|
||||
_widget = gtk_label_new("");
|
||||
}
|
||||
|
||||
void Label::setText(const std::string& text) {
|
||||
gtk_label_set_text(GTK_LABEL(_widget), text.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
23
gtkpp/Label.h
Normal file
23
gtkpp/Label.h
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by selim on 18.12.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_LABEL_H
|
||||
#define AUTOCAT_GNOME_LABEL_H
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class Label: public Widget {
|
||||
public:
|
||||
Label();
|
||||
using Widget::Widget;
|
||||
|
||||
public:
|
||||
void setText(const std::string& text);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_LABEL_H
|
||||
@ -11,8 +11,8 @@ namespace gtkpp {
|
||||
_widget = adw_leaflet_new();
|
||||
}
|
||||
|
||||
void Leaflet::append(Widget *widget) {
|
||||
adw_leaflet_append(ADW_LEAFLET(_widget), widget->gobj());
|
||||
void Leaflet::append(const Widget& widget) {
|
||||
adw_leaflet_append(ADW_LEAFLET(_widget), widget.gobj());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ namespace gtkpp {
|
||||
class Leaflet: public Widget {
|
||||
public:
|
||||
Leaflet();
|
||||
void append(Widget* widget);
|
||||
void append(const Widget& widget);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
32
gtkpp/ListItemFactory.cpp
Normal file
32
gtkpp/ListItemFactory.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#include "ListItemFactory.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
void setupListItemCallback(GtkListItemFactory* factory, GtkListItem* list_item, void* data) {
|
||||
auto self = reinterpret_cast<ListItemFactory*>(data);
|
||||
auto widget = self->setup();
|
||||
gtk_list_item_set_child(list_item, widget);
|
||||
}
|
||||
|
||||
void bindListItemCallback(GtkListItemFactory* factory, GtkListItem* list_item, void* data) {
|
||||
auto self = reinterpret_cast<ListItemFactory*>(data);
|
||||
auto widget = gtk_list_item_get_child(list_item);
|
||||
auto item = gtk_list_item_get_item (list_item);
|
||||
self->bind(widget);
|
||||
}
|
||||
|
||||
ListItemFactory::ListItemFactory() {
|
||||
_factory = gtk_signal_list_item_factory_new();
|
||||
g_signal_connect(_factory, "setup", G_CALLBACK(setupListItemCallback), this);
|
||||
g_signal_connect(_factory, "bind", G_CALLBACK(bindListItemCallback), this);
|
||||
}
|
||||
|
||||
GtkListItemFactory *ListItemFactory::gobj() const {
|
||||
return _factory;
|
||||
}
|
||||
|
||||
}
|
||||
28
gtkpp/ListItemFactory.h
Normal file
28
gtkpp/ListItemFactory.h
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_LISTITEMFACTORY_H
|
||||
#define AUTOCAT_GNOME_LISTITEMFACTORY_H
|
||||
|
||||
#include "Widget.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class ListItemFactory {
|
||||
private:
|
||||
GtkListItemFactory* _factory;
|
||||
|
||||
public:
|
||||
ListItemFactory();
|
||||
[[nodiscard]] GtkListItemFactory* gobj() const;
|
||||
|
||||
public:
|
||||
virtual GtkWidget* setup() = 0;
|
||||
virtual void bind(GtkWidget* widget) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_LISTITEMFACTORY_H
|
||||
13
gtkpp/ListView.cpp
Normal file
13
gtkpp/ListView.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#include "ListView.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
ListView::ListView(SelectionModel selectionModel, ListItemFactory* factory) {
|
||||
_widget = gtk_list_view_new(selectionModel.gobj(), factory->gobj());
|
||||
}
|
||||
|
||||
}
|
||||
21
gtkpp/ListView.h
Normal file
21
gtkpp/ListView.h
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_LISTVIEW_H
|
||||
#define AUTOCAT_GNOME_LISTVIEW_H
|
||||
|
||||
#include "Widget.h"
|
||||
#include "SelectionModel.h"
|
||||
#include "ListItemFactory.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class ListView: public Widget {
|
||||
public:
|
||||
ListView(SelectionModel selectionModel, ListItemFactory* factory);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_LISTVIEW_H
|
||||
15
gtkpp/ScrolledWindow.cpp
Normal file
15
gtkpp/ScrolledWindow.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#include "ScrolledWindow.h"
|
||||
|
||||
#include <gtk/gtkscrolledwindow.h>
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
ScrolledWindow::ScrolledWindow() {
|
||||
_widget = gtk_scrolled_window_new();
|
||||
}
|
||||
|
||||
}
|
||||
19
gtkpp/ScrolledWindow.h
Normal file
19
gtkpp/ScrolledWindow.h
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_SCROLLEDWINDOW_H
|
||||
#define AUTOCAT_GNOME_SCROLLEDWINDOW_H
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class ScrolledWindow: public Widget {
|
||||
public:
|
||||
ScrolledWindow();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_SCROLLEDWINDOW_H
|
||||
26
gtkpp/SelectionModel.cpp
Normal file
26
gtkpp/SelectionModel.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#include "SelectionModel.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
SelectionModel::SelectionModel(gtkpp::Selection selection) {
|
||||
|
||||
const char *array[] = { "one", "two", "three", "four", nullptr };
|
||||
GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
|
||||
|
||||
switch (selection) {
|
||||
case None:
|
||||
_model = GTK_SELECTION_MODEL(gtk_no_selection_new(G_LIST_MODEL(sl)));
|
||||
case Single:
|
||||
_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(sl)));
|
||||
}
|
||||
}
|
||||
|
||||
GtkSelectionModel *SelectionModel::gobj() const {
|
||||
return _model;
|
||||
}
|
||||
|
||||
}
|
||||
29
gtkpp/SelectionModel.h
Normal file
29
gtkpp/SelectionModel.h
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_SELECTIONMODEL_H
|
||||
#define AUTOCAT_GNOME_SELECTIONMODEL_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gio/glistmodel.h>
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
enum Selection {
|
||||
None,
|
||||
Single
|
||||
};
|
||||
|
||||
class SelectionModel {
|
||||
private:
|
||||
GtkSelectionModel* _model;
|
||||
|
||||
public:
|
||||
explicit SelectionModel(Selection selection);
|
||||
[[nodiscard]] GtkSelectionModel* gobj() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_SELECTIONMODEL_H
|
||||
9
gtkpp/Separator.cpp
Normal file
9
gtkpp/Separator.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by selim on 15.11.22.
|
||||
//
|
||||
|
||||
#include "Separator.h"
|
||||
|
||||
gtkpp::Separator::Separator(GtkOrientation orientation) {
|
||||
_widget = gtk_separator_new(orientation);
|
||||
}
|
||||
19
gtkpp/Separator.h
Normal file
19
gtkpp/Separator.h
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by selim on 15.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_SEPARATOR_H
|
||||
#define AUTOCAT_GNOME_SEPARATOR_H
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
class Separator: public Widget {
|
||||
public:
|
||||
explicit Separator(GtkOrientation orientation);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_SEPARATOR_H
|
||||
@ -4,35 +4,78 @@
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
GtkWidget *gtkpp::Widget::gobj() const {
|
||||
return _widget;
|
||||
}
|
||||
namespace gtkpp {
|
||||
|
||||
void gtkpp::Widget::setMargins(int margin) {
|
||||
gtk_widget_set_margin_top(_widget, margin);
|
||||
gtk_widget_set_margin_bottom(_widget, margin);
|
||||
gtk_widget_set_margin_start(_widget, margin);
|
||||
gtk_widget_set_margin_end(_widget, margin);
|
||||
}
|
||||
void clickedCallback(GtkButton*, void* data) {
|
||||
auto widget = reinterpret_cast<Widget*>(data);
|
||||
widget->_signalClicked.emit();
|
||||
}
|
||||
|
||||
void gtkpp::Widget::setVAlign(GtkAlign align) {
|
||||
gtk_widget_set_valign(_widget, align);
|
||||
}
|
||||
void Widget::onClick(const std::function<void()> &callback) {
|
||||
_signalClicked.connect(callback);
|
||||
}
|
||||
|
||||
void gtkpp::Widget::setVExpand(bool expand) {
|
||||
gtk_widget_set_vexpand(_widget, expand);
|
||||
}
|
||||
Widget::Widget() {
|
||||
_widget = nullptr;
|
||||
}
|
||||
|
||||
void gtkpp::Widget::setHorizontalMargins(int margin) {
|
||||
gtk_widget_set_margin_start(_widget, margin);
|
||||
gtk_widget_set_margin_end(_widget, margin);
|
||||
}
|
||||
Widget::Widget(GtkWidget *widget) {
|
||||
_widget = widget;
|
||||
//g_signal_connect(_widget, "clicked", G_CALLBACK(clickedCallback), this);
|
||||
}
|
||||
|
||||
void gtkpp::Widget::setVerticalMargins(int margin) {
|
||||
gtk_widget_set_margin_top(_widget, margin);
|
||||
gtk_widget_set_margin_bottom(_widget, margin);
|
||||
}
|
||||
Widget::Widget(GtkBuilder *builder, const char *id) {
|
||||
_widget = GTK_WIDGET(gtk_builder_get_object(builder, id));
|
||||
g_signal_connect(_widget, "clicked", G_CALLBACK(clickedCallback), this);
|
||||
}
|
||||
|
||||
GtkWidget *Widget::gobj() const {
|
||||
return _widget;
|
||||
}
|
||||
|
||||
void Widget::setMargins(int margin) {
|
||||
gtk_widget_set_margin_top(_widget, margin);
|
||||
gtk_widget_set_margin_bottom(_widget, margin);
|
||||
gtk_widget_set_margin_start(_widget, margin);
|
||||
gtk_widget_set_margin_end(_widget, margin);
|
||||
}
|
||||
|
||||
void Widget::setVAlign(GtkAlign align) {
|
||||
gtk_widget_set_valign(_widget, align);
|
||||
}
|
||||
|
||||
void Widget::setVExpand(bool expand) {
|
||||
gtk_widget_set_vexpand(_widget, expand);
|
||||
}
|
||||
|
||||
void Widget::setHExpand(bool expand) {
|
||||
gtk_widget_set_hexpand(_widget, expand);
|
||||
}
|
||||
|
||||
void Widget::setHorizontalMargins(int margin) {
|
||||
gtk_widget_set_margin_start(_widget, margin);
|
||||
gtk_widget_set_margin_end(_widget, margin);
|
||||
}
|
||||
|
||||
void Widget::setVerticalMargins(int margin) {
|
||||
gtk_widget_set_margin_top(_widget, margin);
|
||||
gtk_widget_set_margin_bottom(_widget, margin);
|
||||
}
|
||||
|
||||
void Widget::setEnabled(bool enabled) {
|
||||
gtk_widget_set_sensitive(_widget, enabled);
|
||||
}
|
||||
|
||||
void Widget::setupSignals() {
|
||||
g_signal_connect(_widget, "clicked", G_CALLBACK(clickedCallback), this);
|
||||
}
|
||||
|
||||
void Widget::show() {
|
||||
gtk_widget_show(_widget);
|
||||
}
|
||||
|
||||
void Widget::hide() {
|
||||
gtk_widget_hide(_widget);
|
||||
}
|
||||
|
||||
void gtkpp::Widget::setEnabled(bool enabled) {
|
||||
gtk_widget_set_sensitive(_widget, enabled);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#define AUTOCAT_GNOME_WIDGET_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sigc++/sigc++.h>
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
@ -13,14 +14,32 @@ namespace gtkpp {
|
||||
protected:
|
||||
GtkWidget* _widget;
|
||||
|
||||
private:
|
||||
sigc::signal<void()> _signalClicked;
|
||||
|
||||
private:
|
||||
friend void clickedCallback(GtkButton*, void* data);
|
||||
|
||||
protected:
|
||||
void setupSignals();
|
||||
|
||||
public:
|
||||
void onClick(const std::function<void()>& callback);
|
||||
|
||||
public:
|
||||
Widget();
|
||||
explicit Widget(GtkWidget* widget);
|
||||
Widget(GtkBuilder* builder, const char* id);
|
||||
[[nodiscard]] GtkWidget* gobj() const;
|
||||
void setMargins(int margin);
|
||||
void setVerticalMargins(int margin);
|
||||
void setHorizontalMargins(int margin);
|
||||
void setVAlign(GtkAlign align);
|
||||
void setVExpand(bool expand);
|
||||
void setHExpand(bool expand);
|
||||
void setEnabled(bool enabled);
|
||||
void show();
|
||||
void hide();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "Window.h"
|
||||
#include "../App.h"
|
||||
|
||||
namespace gtkpp {
|
||||
|
||||
@ -10,29 +11,31 @@ namespace gtkpp {
|
||||
return wnd1._window == wnd2._window;
|
||||
}
|
||||
|
||||
Window::Window(std::shared_ptr<Application> app, bool isAppWindow) {
|
||||
Window::Window() {
|
||||
_window = nullptr;
|
||||
_builder = nullptr;
|
||||
}
|
||||
|
||||
Window::Window(bool isAppWindow): _isAppWindow(isAppWindow) {
|
||||
if(isAppWindow) {
|
||||
_window = GTK_WINDOW(adw_application_window_new(GTK_APPLICATION(app->gobj())));
|
||||
auto app = GTK_APPLICATION(App::instance().gobj());
|
||||
_window = GTK_WINDOW(adw_application_window_new(app));
|
||||
} else {
|
||||
_window = GTK_WINDOW(adw_window_new());
|
||||
}
|
||||
|
||||
_app = app;
|
||||
_builder = nullptr;
|
||||
}
|
||||
|
||||
Window::Window(std::shared_ptr<Application> app, const char* resourceName) {
|
||||
_app = app;
|
||||
// _builder = gtk_builder_new();
|
||||
//
|
||||
// GError* error = nullptr;
|
||||
// gtk_builder_add_from_resource(_builder, resourceName, &error);
|
||||
// if(error) {
|
||||
// throw std::runtime_error(error->message);
|
||||
// }
|
||||
|
||||
Window::Window(const char* resourceName, const char* id) {
|
||||
_builder = gtk_builder_new_from_resource(resourceName);
|
||||
_window = GTK_WINDOW(gtk_builder_get_object(_builder, "adw_main_window"));
|
||||
_window = GTK_WINDOW(gtk_builder_get_object(_builder, id));
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
if(_window) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::show() {
|
||||
@ -51,12 +54,32 @@ namespace gtkpp {
|
||||
gtk_window_set_default_size(GTK_WINDOW(_window), width, height);
|
||||
}
|
||||
|
||||
std::shared_ptr<Application> Window::application() const {
|
||||
return _app.lock();
|
||||
}
|
||||
|
||||
void Window::hide() {
|
||||
gtk_window_close(GTK_WINDOW(_window));
|
||||
}
|
||||
|
||||
void Window::destroy() {
|
||||
gtk_window_destroy(GTK_WINDOW(_window));
|
||||
}
|
||||
|
||||
void Window::setTransientFor(const Window* window) {
|
||||
gtk_window_set_transient_for(_window, window->gobj());
|
||||
}
|
||||
|
||||
void Window::setModal() {
|
||||
gtk_window_set_modal(_window, true);
|
||||
}
|
||||
|
||||
void Window::setContent(const Widget& widget) {
|
||||
if(_isAppWindow) {
|
||||
adw_application_window_set_content(ADW_APPLICATION_WINDOW(_window), widget.gobj());
|
||||
} else {
|
||||
adw_window_set_content(ADW_WINDOW(_window), widget.gobj());
|
||||
}
|
||||
}
|
||||
|
||||
void Window::setResizable(bool resizable) {
|
||||
gtk_window_set_resizable(_window, resizable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#define AUTOCAT_GNOME_WINDOW_H
|
||||
|
||||
#include "Application.h"
|
||||
#include "Widget.h"
|
||||
|
||||
#include <adwaita.h>
|
||||
#include <memory>
|
||||
|
||||
@ -15,22 +17,29 @@ namespace gtkpp {
|
||||
protected:
|
||||
GtkBuilder* _builder;
|
||||
GtkWindow* _window;
|
||||
std::weak_ptr<Application> _app;
|
||||
bool _isAppWindow;
|
||||
|
||||
private:
|
||||
friend bool operator==(const Window& wnd1, const Window& wnd2);
|
||||
|
||||
public:
|
||||
Window(std::shared_ptr<Application> app, bool isAppWindow);
|
||||
Window(std::shared_ptr<Application> app, const char* resourceName);
|
||||
Window();
|
||||
explicit Window(bool isAppWindow);
|
||||
Window(const char* resourceName, const char* id);
|
||||
virtual ~Window();
|
||||
void show();
|
||||
void hide();
|
||||
void destroy();
|
||||
void setTitle(const std::string& title);
|
||||
void setDefaultSize(int width, int height);
|
||||
void setTransientFor(const Window* window);
|
||||
void setModal();
|
||||
[[nodiscard]] GtkWindow* gobj() const;
|
||||
[[nodiscard]] std::shared_ptr<Application> application() const;
|
||||
void setContent(const Widget& widget);
|
||||
void setResizable(bool resizable);
|
||||
};
|
||||
|
||||
using WindowPtr = std::shared_ptr<Window>;
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_WINDOW_H
|
||||
|
||||
35
gui/AddNumberDialog.cpp
Normal file
35
gui/AddNumberDialog.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by selim on 17.05.2022.
|
||||
//
|
||||
|
||||
#include "AddNumberDialog.h"
|
||||
#include "../services/Api.h"
|
||||
#include "../services/Storage.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
AddNumberDialog::AddNumberDialog(gtkpp::Window* parent): gtkpp::Dialog(parent) {
|
||||
auto content = contentWidget();
|
||||
_entry.setMargins(16);
|
||||
_entry.setPlaceholder("Plate number");
|
||||
content.append(_entry);
|
||||
content.append(_spinner);
|
||||
_spinner.setMargins(16);
|
||||
_spinner.hide();
|
||||
}
|
||||
|
||||
std::string AddNumberDialog::text() const {
|
||||
return _entry.text();
|
||||
}
|
||||
|
||||
cc::result<void> AddNumberDialog::checkNumber() {
|
||||
_spinner.show();
|
||||
_spinner.start();
|
||||
std::string text = _entry.text();
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](unsigned char c){ return std::toupper(c); });
|
||||
auto vehicle = co_await Api::check(text);
|
||||
Storage::instance().insert(&vehicle);
|
||||
}
|
||||
|
||||
29
gui/AddNumberDialog.h
Normal file
29
gui/AddNumberDialog.h
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// Created by selim on 17.05.2022.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_ADDNUMBERDIALOG_H
|
||||
#define AUTOCAT_GNOME_ADDNUMBERDIALOG_H
|
||||
|
||||
#include "../gtkpp/Dialog.h"
|
||||
#include "../gtkpp/Entry.h"
|
||||
#include "../gtkpp/Spinner.h"
|
||||
|
||||
#include <concurrencpp/concurrencpp.h>
|
||||
#include <vector>
|
||||
|
||||
namespace cc = concurrencpp;
|
||||
|
||||
class AddNumberDialog: public gtkpp::Dialog {
|
||||
private:
|
||||
gtkpp::Entry _entry;
|
||||
gtkpp::Spinner _spinner;
|
||||
|
||||
public:
|
||||
explicit AddNumberDialog(gtkpp::Window* parent);
|
||||
std::string text() const;
|
||||
cc::result<void> checkNumber();
|
||||
};
|
||||
|
||||
|
||||
#endif //AUTOCAT_GNOME_ADDNUMBERDIALOG_H
|
||||
@ -5,17 +5,14 @@
|
||||
#include "LoginWindow.h"
|
||||
#include "MainWindow.h"
|
||||
#include "../services/Api.h"
|
||||
#include "../coro/GLibMainContextExecutor.h"
|
||||
|
||||
#include "../gtkpp/HeaderBar.h"
|
||||
#include "../gtkpp/MessageDialog.h"
|
||||
#include "../App.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <folly/experimental/coro/Task.h>
|
||||
#include <folly/executors/IOThreadPoolExecutor.h>
|
||||
|
||||
LoginWindow::LoginWindow(std::shared_ptr<gtkpp::Application> app): gtkpp::Window(std::move(app), false) {
|
||||
LoginWindow::LoginWindow(): gtkpp::Window(false) {
|
||||
|
||||
setDefaultSize(640, 480);
|
||||
|
||||
@ -46,7 +43,7 @@ LoginWindow::LoginWindow(std::shared_ptr<gtkpp::Application> app): gtkpp::Window
|
||||
rootBox.append(gtkpp::HeaderBar("Login"));
|
||||
rootBox.append(contentBox);
|
||||
|
||||
adw_window_set_content(ADW_WINDOW(_window), rootBox.gobj());
|
||||
setContent(rootBox);
|
||||
}
|
||||
|
||||
void LoginWindow::loginClicked() {
|
||||
@ -57,14 +54,12 @@ void LoginWindow::loginClicked() {
|
||||
_spinner.start();
|
||||
|
||||
try {
|
||||
User user = co_await Api::login(email, password).scheduleOn(GLibMainContextExecutor::instance());
|
||||
if(auto app = this->application()) {
|
||||
auto mainWindow = std::make_shared<MainWindow>(app);
|
||||
mainWindow->show();
|
||||
app->addWindow(mainWindow);
|
||||
app->removeWindow(this);
|
||||
hide();
|
||||
}
|
||||
User user = co_await Api::login(email, password);
|
||||
auto mainWindow = std::make_shared<MainWindow>();
|
||||
mainWindow->show();
|
||||
App::instance().addWindow(mainWindow);
|
||||
App::instance().removeWindow(this);
|
||||
hide();
|
||||
} catch (std::exception& ex) {
|
||||
enableControls(true);
|
||||
_spinner.stop();
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "../gtkpp/Entry.h"
|
||||
#include "../gtkpp/Button.h"
|
||||
#include "../gtkpp/Spinner.h"
|
||||
#include "../gtkpp/Application.h"
|
||||
|
||||
class LoginWindow: public gtkpp::Window {
|
||||
private:
|
||||
@ -21,7 +20,7 @@ private:
|
||||
gtkpp::Spinner _spinner;
|
||||
|
||||
public:
|
||||
explicit LoginWindow(std::shared_ptr<gtkpp::Application> app);
|
||||
LoginWindow();
|
||||
|
||||
void loginClicked();
|
||||
void validateFields();
|
||||
|
||||
@ -3,15 +3,62 @@
|
||||
//
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "../gtkpp/Box.h"
|
||||
#include "AddNumberDialog.h"
|
||||
#include "../gtkpp/MessageDialog.h"
|
||||
#include "../coro/Coro.h"
|
||||
#include "../services/Storage.h"
|
||||
#include "../gtkpp/HeaderBar.h"
|
||||
#include "../gtkpp/Separator.h"
|
||||
#include "../gtkpp/SelectionModel.h"
|
||||
|
||||
MainWindow::MainWindow(std::shared_ptr<gtkpp::Application> app): gtkpp::Window(std::move(app), "/gui/MainWindow.xml") {
|
||||
#include <iostream>
|
||||
|
||||
// gtkpp::Box rootBox(GTK_ORIENTATION_VERTICAL, 0);
|
||||
// rootBox.append(gtkpp::HeaderBar("Main"));
|
||||
//
|
||||
// _leaflet.append(&rootBox);
|
||||
//
|
||||
// adw_application_window_set_content(ADW_APPLICATION_WINDOW(_window), _leaflet.gobj());
|
||||
MainWindow::MainWindow(): gtkpp::Window(true),
|
||||
_vehiclesListView(gtkpp::SelectionModel(gtkpp::Selection::Single),
|
||||
&_vehiclesListFactory) {
|
||||
|
||||
setDefaultSize(640, 480);
|
||||
setResizable(true);
|
||||
|
||||
_addNumberButton.setIconName("list-add-symbolic");
|
||||
_addNumberButton.onClick([this] {
|
||||
showCheckDialog();
|
||||
});
|
||||
|
||||
gtkpp::HeaderBar leftHeader("Vehicles");
|
||||
leftHeader.showEndButtons(false);
|
||||
leftHeader.packStart(_addNumberButton);
|
||||
|
||||
gtkpp::Box leftPanel(GTK_ORIENTATION_VERTICAL, 0);
|
||||
leftPanel.append(leftHeader);
|
||||
leftPanel.append(_vehiclesListView);
|
||||
|
||||
gtkpp::HeaderBar rightHeader;
|
||||
gtkpp::Box rightPanel(GTK_ORIENTATION_VERTICAL, 0);
|
||||
rightPanel.append(rightHeader);
|
||||
rightPanel.setHExpand(true);
|
||||
|
||||
_leaflet.append(leftPanel);
|
||||
_leaflet.append(gtkpp::Separator(GTK_ORIENTATION_VERTICAL));
|
||||
_leaflet.append(rightPanel);
|
||||
_leaflet.setVExpand(true);
|
||||
|
||||
setContent(_leaflet);
|
||||
|
||||
auto vehicles = Storage::instance().select<Vehicle>();
|
||||
std::cout << "" << std::endl;
|
||||
}
|
||||
|
||||
void MainWindow::showCheckDialog() {
|
||||
AddNumberDialog dialog(this);
|
||||
dialog.show();
|
||||
GtkResponseType response = co_await dialog.responseAsync();
|
||||
|
||||
if(response == GTK_RESPONSE_OK) {
|
||||
try {
|
||||
co_await dialog.checkNumber();
|
||||
} catch(std::exception& ex) {
|
||||
gtkpp::MessageDialog::showError(this, ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,13 +7,21 @@
|
||||
|
||||
#include "../gtkpp/Window.h"
|
||||
#include "../gtkpp/Leaflet.h"
|
||||
#include "../gtkpp/Button.h"
|
||||
#include "../gtkpp/ListView.h"
|
||||
#include "../models/VehiclesListFactory.h"
|
||||
|
||||
class MainWindow: public gtkpp::Window {
|
||||
private:
|
||||
gtkpp::Leaflet _leaflet;
|
||||
gtkpp::Button _addNumberButton;
|
||||
|
||||
VehiclesListFactory _vehiclesListFactory;
|
||||
gtkpp::ListView _vehiclesListView;
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::shared_ptr<gtkpp::Application> app);
|
||||
explicit MainWindow();
|
||||
void showCheckDialog();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -31,6 +31,12 @@
|
||||
</object>
|
||||
</property>
|
||||
|
||||
<child type="start">
|
||||
<object class="GtkButton" id="add_number_button">
|
||||
<property name="icon-name">list-add</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child type="end">
|
||||
<object class="GtkMenuButton" id="gtk_btnHeaderHelp">
|
||||
<property name="direction">none</property>
|
||||
|
||||
5
gui/custom/PlateView.c
Normal file
5
gui/custom/PlateView.c
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by selim on 01.06.2022.
|
||||
//
|
||||
|
||||
#include "PlateView.h"
|
||||
25
gui/custom/PlateView.h
Normal file
25
gui/custom/PlateView.h
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by selim on 01.06.2022.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_PLATEVIEW_H
|
||||
#define AUTOCAT_GNOME_PLATEVIEW_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define PLATEVIEW(obj) GTK_CHECK_CAST(obj, plateview_get_type(), PlateView)
|
||||
#define PLATEVIEW_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, plateview_get_type(), PlateViewClass)
|
||||
|
||||
typedef struct {
|
||||
|
||||
} PlateView;
|
||||
|
||||
typedef struct {
|
||||
GtkWidgetClass parent_class;
|
||||
} PlateViewClass;
|
||||
|
||||
guint plateview_get_type (void);
|
||||
GtkWidget* plateview_new (void);
|
||||
void plateview_clear (PlateView* view);
|
||||
|
||||
#endif //AUTOCAT_GNOME_PLATEVIEW_H
|
||||
19
main.cpp
19
main.cpp
@ -3,32 +3,31 @@
|
||||
#include "services/Settings.h"
|
||||
#include "gtkpp/Application.h"
|
||||
#include "gtkpp/Window.h"
|
||||
#include "App.h"
|
||||
|
||||
#include <memory>
|
||||
#include <folly/init/Init.h>
|
||||
#include <iostream>
|
||||
|
||||
std::shared_ptr<gtkpp::Window> createMainWindow(std::shared_ptr<gtkpp::Application> app) {
|
||||
std::shared_ptr<gtkpp::Window> createMainWindow() {
|
||||
auto settings = Settings::instance();
|
||||
if(settings.user().token.empty()) {
|
||||
return std::make_shared<LoginWindow>(app);
|
||||
return std::make_shared<LoginWindow>();
|
||||
} else {
|
||||
return std::make_shared<MainWindow>(app);
|
||||
return std::make_shared<MainWindow>();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
folly::init(&argc, &argv);
|
||||
g_resources_register(g_resource_load("resources.gresource", nullptr));
|
||||
|
||||
auto app = std::make_shared<gtkpp::Application>("pro.aliencat.autocat");
|
||||
auto app = App::instance(); //std::make_shared<gtkpp::Application>("pro.aliencat.autocat");
|
||||
|
||||
app->onActivate([&](){
|
||||
auto window = createMainWindow(app);
|
||||
app->addWindow(window);
|
||||
app.onActivate([&](){
|
||||
auto window = createMainWindow();
|
||||
app.addWindow(window);
|
||||
window->show();
|
||||
});
|
||||
|
||||
return app->run(argc, argv);
|
||||
return app.run(argc, argv);
|
||||
}
|
||||
|
||||
5
models/Engine.cpp
Normal file
5
models/Engine.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by selim on 06.11.22.
|
||||
//
|
||||
|
||||
#include "Engine.h"
|
||||
21
models/Engine.h
Normal file
21
models/Engine.h
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by selim on 06.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_ENGINE_H
|
||||
#define AUTOCAT_GNOME_ENGINE_H
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
class Engine {
|
||||
public:
|
||||
std::string number;
|
||||
int volume;
|
||||
float powerHp;
|
||||
float powerKw;
|
||||
std::string fuelType;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Engine, number, volume, powerHp, powerKw, fuelType)
|
||||
};
|
||||
|
||||
#endif //AUTOCAT_GNOME_ENGINE_H
|
||||
75
models/JsonOptional.h
Normal file
75
models/JsonOptional.h
Normal file
@ -0,0 +1,75 @@
|
||||
//
|
||||
// Created by selim on 06.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_JSONOPTIONAL_H
|
||||
#define AUTOCAT_GNOME_JSONOPTIONAL_H
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace nlohmann {
|
||||
|
||||
template<class J, class T>
|
||||
void optional_to_json(J& j, const char* name, const std::optional<T>& value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
j[name] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
template<class J, class T>
|
||||
void optional_from_json(const J& j, const char* name, std::optional<T>& value)
|
||||
{
|
||||
const auto it = j.find(name);
|
||||
if (it != j.end())
|
||||
{
|
||||
if(j.at(name).is_null()) {
|
||||
value = std::nullopt;
|
||||
} else {
|
||||
value = it->template get<T>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename>
|
||||
constexpr bool is_optional = false;
|
||||
template <typename T>
|
||||
constexpr bool is_optional<std::optional<T>> = true;
|
||||
|
||||
template <typename T>
|
||||
void extended_to_json(const char *key, nlohmann::json &j, const T &value) {
|
||||
if constexpr (is_optional<T>)
|
||||
optional_to_json(j, key, value);
|
||||
else
|
||||
j[key] = value;
|
||||
}
|
||||
template <typename T>
|
||||
void extended_from_json(const char *key, const nlohmann::json &j, T &value) {
|
||||
//std::cout << "parsing key " << key << std::endl;
|
||||
if constexpr (is_optional<T>) {
|
||||
optional_from_json(j, key, value);
|
||||
} else {
|
||||
j.at(key).get_to(value);
|
||||
}
|
||||
}
|
||||
|
||||
#define EXTEND_JSON_TO(v1) extended_to_json(#v1, nlohmann_json_j, nlohmann_json_t.v1);
|
||||
#define EXTEND_JSON_FROM(v1) extended_from_json(#v1, nlohmann_json_j, nlohmann_json_t.v1);
|
||||
|
||||
#define NLOHMANN_JSONIFY_ALL_THINGS(Type, ...) \
|
||||
friend void to_json(nlohmann::json &nlohmann_json_j, const Type &nlohmann_json_t) { \
|
||||
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_TO, __VA_ARGS__)) \
|
||||
} \
|
||||
friend void from_json(const nlohmann::json &nlohmann_json_j, Type &nlohmann_json_t) { \
|
||||
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_FROM, __VA_ARGS__)) \
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //AUTOCAT_GNOME_JSONOPTIONAL_H
|
||||
@ -19,6 +19,7 @@ public:
|
||||
public:
|
||||
User() = default;
|
||||
User(const User& user) = default;
|
||||
User(User&&) = default;
|
||||
User(std::string_view email, std::string_view token);
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(User, email, token)
|
||||
|
||||
91
models/Vehicle.cpp
Normal file
91
models/Vehicle.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// Created by selim on 03.10.22.
|
||||
//
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include "Vehicle.h"
|
||||
|
||||
std::string Vehicle::createTableQuery() {
|
||||
return R"(
|
||||
CREATE TABLE IF NOT EXISTS vehicles(
|
||||
number TEXT NOT NULL PRIMARY KEY,
|
||||
currentNumber TEXT,
|
||||
color TEXT,
|
||||
category TEXT,
|
||||
year INT,
|
||||
addedDate REAL,
|
||||
updatedDate REAL,
|
||||
vin1 TEXT,
|
||||
vin2 TEXT,
|
||||
sts TEXT,
|
||||
pts TEXT,
|
||||
addedBy TEXT,
|
||||
engineNumber TEXT,
|
||||
engineVolume INT,
|
||||
enginePowerHp REAL,
|
||||
enginePowerKw REAL,
|
||||
engineFuelType TEXT
|
||||
);
|
||||
)";
|
||||
}
|
||||
|
||||
std::string Vehicle::insertQuery() {
|
||||
return fmt::format(R"(
|
||||
INSERT INTO vehicles(number,
|
||||
currentNumber,
|
||||
color,
|
||||
category,
|
||||
year,
|
||||
addedDate,
|
||||
updatedDate,
|
||||
vin1, vin2,
|
||||
sts, pts,
|
||||
addedBy,
|
||||
engineNumber,
|
||||
engineVolume,
|
||||
enginePowerHp,
|
||||
enginePowerKw,
|
||||
engineFuelType)
|
||||
VALUES('{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}')
|
||||
)",
|
||||
number,
|
||||
currentNumber,
|
||||
color.value_or("NULL"),
|
||||
category,
|
||||
year,
|
||||
addedDate,
|
||||
updatedDate,
|
||||
vin1,
|
||||
vin2.value_or("NULL"),
|
||||
sts, pts,
|
||||
addedBy,
|
||||
engine.number,
|
||||
engine.volume,
|
||||
engine.powerHp,
|
||||
engine.powerKw,
|
||||
engine.fuelType);
|
||||
}
|
||||
|
||||
std::string Vehicle::selectQuery() {
|
||||
return "SELECT * FROM vehicles";
|
||||
}
|
||||
|
||||
Vehicle::Vehicle(sqlite3_stmt *stmt) {
|
||||
number = readString(stmt, 0);
|
||||
currentNumber = readString(stmt, 1);
|
||||
color = readStringOptional(stmt, 2);
|
||||
category = readString(stmt, 3);
|
||||
year = readInt(stmt, 4);
|
||||
addedDate = readDouble(stmt, 5);
|
||||
updatedDate = readDouble(stmt, 6);
|
||||
vin1 = readString(stmt, 7);
|
||||
vin2 = readStringOptional(stmt, 8);
|
||||
sts = readString(stmt, 9);
|
||||
pts = readString(stmt, 10);
|
||||
addedBy = readString(stmt, 11);
|
||||
engine.number = readString(stmt, 12);
|
||||
engine.volume = readInt(stmt, 13);
|
||||
engine.powerHp = readDouble(stmt, 14);
|
||||
engine.powerKw = readDouble(stmt, 15);
|
||||
engine.fuelType = readString(stmt, 16);
|
||||
}
|
||||
42
models/Vehicle.h
Normal file
42
models/Vehicle.h
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// Created by selim on 03.10.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_VEHICLE_H
|
||||
#define AUTOCAT_GNOME_VEHICLE_H
|
||||
|
||||
#include "../services/IDBEntity.h"
|
||||
#include "Engine.h"
|
||||
#include "JsonOptional.h"
|
||||
|
||||
#include <optional>
|
||||
#include <sqlite3.h>
|
||||
|
||||
class Vehicle: public IDBEntity {
|
||||
public:
|
||||
std::string number;
|
||||
std::string currentNumber;
|
||||
std::optional<std::string> color;
|
||||
std::string category;
|
||||
int year;
|
||||
double addedDate;
|
||||
double updatedDate;
|
||||
std::string vin1;
|
||||
std::optional<std::string> vin2;
|
||||
std::string sts;
|
||||
std::string pts;
|
||||
std::string addedBy;
|
||||
Engine engine;
|
||||
|
||||
public:
|
||||
Vehicle() = default;
|
||||
explicit Vehicle(sqlite3_stmt* stmt);
|
||||
static std::string createTableQuery();
|
||||
static std::string selectQuery();
|
||||
std::string insertQuery() override;
|
||||
|
||||
NLOHMANN_JSONIFY_ALL_THINGS(Vehicle, number, currentNumber, color, category, year, addedDate, updatedDate, vin1, vin2, sts, pts, addedBy, engine)
|
||||
};
|
||||
|
||||
|
||||
#endif //AUTOCAT_GNOME_VEHICLE_H
|
||||
21
models/VehiclesListFactory.cpp
Normal file
21
models/VehiclesListFactory.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#include "VehiclesListFactory.h"
|
||||
#include "../gtkpp/Label.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
VehiclesListFactory::VehiclesListFactory() {
|
||||
}
|
||||
|
||||
GtkWidget* VehiclesListFactory::setup() {
|
||||
gtkpp::Label label;
|
||||
return label.gobj();
|
||||
}
|
||||
|
||||
void VehiclesListFactory::bind(GtkWidget *widget) {
|
||||
gtkpp::Label label(widget);
|
||||
label.setText("qwe");
|
||||
}
|
||||
20
models/VehiclesListFactory.h
Normal file
20
models/VehiclesListFactory.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by selim on 13.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_VEHICLESLISTFACTORY_H
|
||||
#define AUTOCAT_GNOME_VEHICLESLISTFACTORY_H
|
||||
|
||||
#include "../gtkpp/ListItemFactory.h"
|
||||
|
||||
class VehiclesListFactory: public gtkpp::ListItemFactory {
|
||||
public:
|
||||
VehiclesListFactory();
|
||||
|
||||
public:
|
||||
GtkWidget* setup() override;
|
||||
void bind(GtkWidget* widget) override;
|
||||
};
|
||||
|
||||
|
||||
#endif //AUTOCAT_GNOME_VEHICLESLISTFACTORY_H
|
||||
@ -5,53 +5,45 @@
|
||||
#include "Api.h"
|
||||
#include "Settings.h"
|
||||
#include <memory>
|
||||
#include <folly/futures/Promise.h>
|
||||
|
||||
template<class...Args>
|
||||
struct Callback {
|
||||
void(*function)(Args..., void*) = nullptr;
|
||||
void* state = nullptr;
|
||||
};
|
||||
|
||||
template<typename... Args, typename Lambda>
|
||||
Callback<Args...> voidify(Lambda&& l) {
|
||||
using Func = typename std::decay<Lambda>::type;
|
||||
auto data = new Func(std::forward<Lambda>(l));
|
||||
return {
|
||||
+[](Args... args, void* v)->void {
|
||||
Func* f = static_cast< Func* >(v);
|
||||
(*f)(std::forward<Args>(args)...);
|
||||
delete f;
|
||||
},
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
const std::string Api::_baseUrl = "https://vps.aliencat.pro:8443/";
|
||||
const std::string Api::_baseUrl = "http://127.0.0.1:3000/"; //"https://vps.aliencat.pro:8443/";
|
||||
SoupSession* Api::_session = soup_session_new();
|
||||
|
||||
template<typename T>
|
||||
folly::Future<T> Api::post(const std::string &method, const nlohmann::json& params) {
|
||||
void callback(SoupSession* session, SoupMessage* message, gpointer userData) {
|
||||
auto promise = reinterpret_cast<cc::result_promise<T>*>(userData);
|
||||
|
||||
if(message->status_code >= 200 && message->status_code < 300) {
|
||||
auto responseString = std::string(message->response_body->data, message->response_body->length);
|
||||
auto json = nlohmann::json::parse(responseString);
|
||||
if(json["success"].get<bool>()) {
|
||||
//std::cout << "response: " << responseString << std::endl;
|
||||
auto data = json["data"].get<T>();
|
||||
promise->set_result(data);
|
||||
} else {
|
||||
auto error = json["error"].get<std::string>();
|
||||
promise->set_exception(std::make_exception_ptr(std::runtime_error(error)));
|
||||
}
|
||||
} else {
|
||||
promise->set_exception(std::make_exception_ptr(std::runtime_error(message->reason_phrase)));
|
||||
}
|
||||
|
||||
delete promise;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
cc::result<T> Api::post(const std::string &method, const nlohmann::json& params) {
|
||||
std::string url = _baseUrl + method;
|
||||
auto msg = soup_message_new(SOUP_METHOD_POST, url.c_str());
|
||||
|
||||
auto promise = std::make_shared<folly::Promise<T>>();
|
||||
auto callback = voidify<SoupSession*, SoupMessage*>([&, promise](SoupSession* session, SoupMessage* message) {
|
||||
if(message->status_code >= 200 && message->status_code < 300) {
|
||||
auto responseString = std::string(message->response_body->data, message->response_body->length);
|
||||
auto json = nlohmann::json::parse(responseString);
|
||||
if(json["success"].get<bool>()) {
|
||||
//std::cout << "response: " << responseString << std::endl;
|
||||
auto user = json["data"].get<T>();
|
||||
promise->setValue(user);
|
||||
} else {
|
||||
auto error = json["error"].get<std::string>();
|
||||
promise->setException(std::runtime_error(error));
|
||||
}
|
||||
} else {
|
||||
promise->setException(std::runtime_error(message->reason_phrase));
|
||||
}
|
||||
});
|
||||
auto token = Settings::instance().user().token;
|
||||
if(!token.empty()) {
|
||||
auto authHeader = "Bearer " + token;
|
||||
soup_message_headers_append(msg->request_headers, "Authorization", authHeader.c_str());
|
||||
}
|
||||
|
||||
auto promise = new cc::result_promise<T>();
|
||||
auto result = promise->get_result();
|
||||
|
||||
auto jsonStr = params.dump();
|
||||
|
||||
@ -60,12 +52,12 @@ folly::Future<T> Api::post(const std::string &method, const nlohmann::json& para
|
||||
jsonStr.c_str(),
|
||||
jsonStr.size());
|
||||
|
||||
soup_session_queue_message(_session, msg, callback.function, callback.state);
|
||||
soup_session_queue_message(_session, msg, callback<T>, promise);
|
||||
|
||||
return promise->getFuture();
|
||||
return result;
|
||||
}
|
||||
|
||||
fc::Task<User> Api::login(std::string email, std::string password) {
|
||||
cc::result<User> Api::login(std::string email, std::string password) {
|
||||
|
||||
nlohmann::json params = {
|
||||
{ "email", email },
|
||||
@ -81,3 +73,12 @@ fc::Task<User> Api::login(std::string email, std::string password) {
|
||||
|
||||
co_return user;
|
||||
}
|
||||
|
||||
cc::result<Vehicle> Api::check(const std::string& number, bool force) {
|
||||
nlohmann::json params = {
|
||||
{ "number", number },
|
||||
{ "forceUpdate", force }
|
||||
};
|
||||
|
||||
return post<Vehicle>("vehicles/check", params);
|
||||
}
|
||||
|
||||
@ -8,13 +8,13 @@
|
||||
#include <string>
|
||||
#include <libsoup/soup.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <folly/futures/Future.h>
|
||||
#include <folly/experimental/coro/Task.h>
|
||||
#include <concurrencpp/concurrencpp.h>
|
||||
|
||||
#include "../models/User.h"
|
||||
#include "../models/Vehicle.h"
|
||||
#include "../coro/Coro.h"
|
||||
|
||||
namespace fc = folly::coro;
|
||||
namespace cc = concurrencpp;
|
||||
|
||||
class Api {
|
||||
private:
|
||||
@ -23,10 +23,11 @@ private:
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static folly::Future<T> post(const std::string& method, const nlohmann::json& params);
|
||||
static cc::result<T> post(const std::string& method, const nlohmann::json& params);
|
||||
|
||||
public:
|
||||
static fc::Task<User> login(std::string email, std::string password);
|
||||
static cc::result<User> login(std::string email, std::string password);
|
||||
static cc::result<Vehicle> check(const std::string& number, bool force = false);
|
||||
};
|
||||
|
||||
|
||||
|
||||
41
services/IDBEntity.cpp
Normal file
41
services/IDBEntity.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by selim on 09.11.22.
|
||||
//
|
||||
|
||||
#include "IDBEntity.h"
|
||||
|
||||
std::string IDBEntity::readString(sqlite3_stmt *stmt, int column) {
|
||||
return { reinterpret_cast<const char*>(sqlite3_column_text(stmt, column)) };
|
||||
}
|
||||
|
||||
int IDBEntity::readInt(sqlite3_stmt *stmt, int column) {
|
||||
return sqlite3_column_int(stmt, column);
|
||||
}
|
||||
|
||||
double IDBEntity::readDouble(sqlite3_stmt *stmt, int column) {
|
||||
return sqlite3_column_double(stmt, column);
|
||||
}
|
||||
|
||||
StringOptional IDBEntity::readStringOptional(sqlite3_stmt *stmt, int column) {
|
||||
if(sqlite3_column_type(stmt, column) == SQLITE_NULL) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return readString(stmt, column);
|
||||
}
|
||||
}
|
||||
|
||||
IntOptional IDBEntity::readIntOptional(sqlite3_stmt *stmt, int column) {
|
||||
if(sqlite3_column_type(stmt, column) == SQLITE_NULL) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return readInt(stmt, column);
|
||||
}
|
||||
}
|
||||
|
||||
DoubleOptional IDBEntity::readDoubleOptional(sqlite3_stmt *stmt, int column) {
|
||||
if(sqlite3_column_type(stmt, column) == SQLITE_NULL) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return readDouble(stmt, column);
|
||||
}
|
||||
}
|
||||
31
services/IDBEntity.h
Normal file
31
services/IDBEntity.h
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by selim on 06.11.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_IDBENTITY_H
|
||||
#define AUTOCAT_GNOME_IDBENTITY_H
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <sqlite3.h>
|
||||
|
||||
using StringOptional = std::optional<std::string>;
|
||||
using IntOptional = std::optional<int>;
|
||||
using DoubleOptional = std::optional<double>;
|
||||
|
||||
struct IDBEntity {
|
||||
public:
|
||||
virtual std::string insertQuery() = 0;
|
||||
|
||||
protected:
|
||||
static std::string readString(sqlite3_stmt* stmt, int column);
|
||||
static int readInt(sqlite3_stmt* stmt, int column);
|
||||
static double readDouble(sqlite3_stmt* stmt, int column);
|
||||
static StringOptional readStringOptional(sqlite3_stmt* stmt, int column);
|
||||
static IntOptional readIntOptional(sqlite3_stmt* stmt, int column);
|
||||
static DoubleOptional readDoubleOptional(sqlite3_stmt* stmt, int column);
|
||||
};
|
||||
|
||||
#endif //AUTOCAT_GNOME_IDBENTITY_H
|
||||
@ -9,17 +9,15 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
fs::path getDataPath() {
|
||||
fs::path Settings::getDataPath() {
|
||||
auto dataDir = std::getenv("XDG_DATA_HOME");
|
||||
if(dataDir) {
|
||||
return fs::path(dataDir);
|
||||
return fs::path(dataDir) / "autocat";
|
||||
}
|
||||
|
||||
auto home = std::getenv("HOME");
|
||||
if(home) {
|
||||
return fs::path(home) / ".local" / "share";
|
||||
return fs::path(home) / ".local" / "share" / "autocat";
|
||||
}
|
||||
|
||||
throw std::runtime_error("Failed to find data home directory");
|
||||
@ -46,7 +44,7 @@ Settings Settings::instance() {
|
||||
}
|
||||
|
||||
Settings::Settings() {
|
||||
_dataPath = getDataPath() / "autocat";
|
||||
_dataPath = getDataPath();
|
||||
if(!fs::exists(_dataPath)) {
|
||||
fs::create_directories(_dataPath);
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include "../models/User.h"
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class Settings {
|
||||
private:
|
||||
std::filesystem::path _dataPath;
|
||||
@ -15,6 +17,7 @@ private:
|
||||
public:
|
||||
static Settings instance();
|
||||
Settings();
|
||||
static fs::path getDataPath();
|
||||
|
||||
[[nodiscard]] User user() const;
|
||||
void setUser(const User& user);
|
||||
|
||||
42
services/Storage.cpp
Normal file
42
services/Storage.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// Created by selim on 25.10.22.
|
||||
//
|
||||
|
||||
#include "Storage.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
Storage Storage::instance() {
|
||||
static Storage instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Storage::Storage(): _sqlite(nullptr) {
|
||||
auto path = Settings::getDataPath() / "vehicles.sqlite";
|
||||
int result = sqlite3_open(path.c_str(), &_sqlite);
|
||||
if(result != SQLITE_OK) {
|
||||
throw std::runtime_error(sqlite3_errmsg(_sqlite));
|
||||
}
|
||||
|
||||
executeQuery(Vehicle::createTableQuery());
|
||||
}
|
||||
|
||||
Storage::~Storage() {
|
||||
if(_sqlite) {
|
||||
sqlite3_close(_sqlite);
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::executeQuery(const std::string& query) {
|
||||
char* error = nullptr;
|
||||
sqlite3_exec(_sqlite, query.c_str(), nullptr, nullptr, &error);
|
||||
if(error) {
|
||||
throw std::runtime_error(error);
|
||||
// TODO: error buffer should be deallocated with sqlite3_free()
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::insert(IDBEntity *entity) {
|
||||
executeQuery(entity->insertQuery());
|
||||
}
|
||||
64
services/Storage.h
Normal file
64
services/Storage.h
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by selim on 25.10.22.
|
||||
//
|
||||
|
||||
#ifndef AUTOCAT_GNOME_STORAGE_H
|
||||
#define AUTOCAT_GNOME_STORAGE_H
|
||||
|
||||
#include "../models/Vehicle.h"
|
||||
#include "IDBEntity.h"
|
||||
|
||||
#include <utility>
|
||||
#include <sqlite3.h>
|
||||
|
||||
class Storage {
|
||||
private:
|
||||
sqlite3* _sqlite;
|
||||
|
||||
private:
|
||||
void executeQuery(const std::string& query);
|
||||
|
||||
public:
|
||||
Storage();
|
||||
~Storage();
|
||||
static Storage instance();
|
||||
void insert(IDBEntity* entity);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> select() {
|
||||
auto sql = T::selectQuery();
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
std::vector<T> rows;
|
||||
|
||||
int result = sqlite3_prepare_v2(_sqlite, sql.c_str(), sql.size(), &stmt, nullptr);
|
||||
if(result != SQLITE_OK) {
|
||||
throw std::runtime_error(sqlite3_errmsg(_sqlite));
|
||||
}
|
||||
|
||||
do {
|
||||
result = sqlite3_step(stmt);
|
||||
switch(result) {
|
||||
case SQLITE_BUSY:
|
||||
// TODO: Rollback transaction
|
||||
break;
|
||||
case SQLITE_ERROR:
|
||||
throw std::runtime_error(sqlite3_errmsg(_sqlite));
|
||||
case SQLITE_ROW:
|
||||
rows.emplace_back(stmt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (result == SQLITE_ROW);
|
||||
|
||||
result = sqlite3_finalize(stmt);
|
||||
if(result != SQLITE_OK) {
|
||||
throw std::runtime_error(sqlite3_errmsg(_sqlite));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //AUTOCAT_GNOME_STORAGE_H
|
||||
Loading…
Reference in New Issue
Block a user