started to work over currencies
This commit is contained in:
parent
5c4bd18cdc
commit
45f924a4cf
@ -4,11 +4,13 @@
|
||||
set(HEADERS
|
||||
magpie.h
|
||||
assets.h
|
||||
currencies.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
magpie.cpp
|
||||
assets.cpp
|
||||
currencies.cpp
|
||||
)
|
||||
|
||||
target_sources(magpie PRIVATE ${SOURCES})
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
#include "utils/helpers.h"
|
||||
|
||||
const QHash<int, QByteArray> Models::Assets::roles({
|
||||
{Title, "title"}, {Icon, "icon"}, {Balance, "balance"}, {Archived, "archived"}, {Color, "color"}, {Id, "assetId"}
|
||||
});
|
||||
|
||||
Models::Assets::Assets (QObject* parent):
|
||||
QAbstractListModel(parent),
|
||||
records(),
|
||||
@ -17,7 +21,7 @@ void Models::Assets::clear () {
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void Models::Assets::addAsset (const Asset& asset) {
|
||||
void Models::Assets::add (const Asset& asset) {
|
||||
QModelIndex index = getIndex(asset.id);
|
||||
if (index.isValid())
|
||||
throw std::runtime_error("An attempt to insert a duplicating Asset to an asset model");
|
||||
@ -27,7 +31,7 @@ void Models::Assets::addAsset (const Asset& asset) {
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Models::Assets::addAssets (const std::deque<Asset>& assets) {
|
||||
void Models::Assets::add (const std::deque<Asset>& assets) {
|
||||
if (assets.empty())
|
||||
return;
|
||||
|
||||
@ -42,7 +46,7 @@ void Models::Assets::addAssets (const std::deque<Asset>& assets) {
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Models::Assets::deleteAsset (unsigned int id) {
|
||||
void Models::Assets::remove (unsigned int id) {
|
||||
QModelIndex index = getIndex(id);
|
||||
if (!index.isValid())
|
||||
throw std::runtime_error("An attempt to delete non existing Asset from asset model");
|
||||
@ -64,10 +68,7 @@ int Models::Assets::rowCount (const QModelIndex& parent) const {
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> Models::Assets::roleNames () const {
|
||||
static const QHash<int, QByteArray> roleNames({
|
||||
{Title, "title"}, {Icon, "icon"}, {Balance, "balance"}, {Archived, "archived"}, {Color, "color"}, {Id, "assetId"}
|
||||
});
|
||||
return roleNames;
|
||||
return roles;
|
||||
}
|
||||
|
||||
bool Models::Assets::canFetchMore (const QModelIndex& parent) const {
|
||||
|
@ -37,10 +37,10 @@ public:
|
||||
Id
|
||||
};
|
||||
|
||||
void clear();
|
||||
void addAsset(const Asset& asset);
|
||||
void addAssets(const std::deque<Asset>& assets);
|
||||
void deleteAsset(unsigned int id);
|
||||
void clear ();
|
||||
void add (const Asset& asset);
|
||||
void add (const std::deque<Asset>& assets);
|
||||
void remove (unsigned int id);
|
||||
|
||||
//Basic functionality:
|
||||
int rowCount (const QModelIndex& parent = QModelIndex()) const override;
|
||||
@ -51,16 +51,17 @@ public:
|
||||
void fetchMore (const QModelIndex& parent) override;
|
||||
QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
static bool deserialize(const QVariantList& from, std::deque<Asset>& out);
|
||||
static bool deserialize (const QVariantList& from, std::deque<Asset>& out);
|
||||
static const QHash<int, QByteArray> roles;
|
||||
|
||||
signals:
|
||||
void requestAssets();
|
||||
void requestAssets ();
|
||||
|
||||
public slots:
|
||||
void receivedAssets(const std::deque<Asset>& assets);
|
||||
void receivedAssets (const std::deque<Asset>& assets);
|
||||
|
||||
private:
|
||||
QModelIndex getIndex(unsigned int id) const;
|
||||
QModelIndex getIndex (unsigned int id) const;
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
|
132
models/currencies.cpp
Normal file
132
models/currencies.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
//SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
|
||||
//SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "currencies.h"
|
||||
|
||||
#include "utils/helpers.h"
|
||||
|
||||
const QHash<int, QByteArray> Models::Currencies::roles({
|
||||
{Id, "id"}, {Code, "code"}, {Title, "title"}, {Type, "type"}, {Value, "value"}, {Description, "description"}, {Icon, "icon"}
|
||||
});
|
||||
|
||||
Models::Currencies::Currencies (QObject* parent):
|
||||
QAbstractListModel(parent),
|
||||
order(),
|
||||
index(),
|
||||
map()
|
||||
{}
|
||||
|
||||
void Models::Currencies::clear () {
|
||||
beginResetModel();
|
||||
order.clear();
|
||||
index.clear();
|
||||
map.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void Models::Currencies::add (const Currency& currency) {
|
||||
if (map.count(currency.id))
|
||||
throw std::runtime_error("An attempt to insert a duplicating currency to a currency model");
|
||||
|
||||
beginInsertRows(QModelIndex(), index.size(), index.size());
|
||||
Order::iterator itr = order.insert(order.end(), currency);
|
||||
index.push_back(itr);
|
||||
map.emplace(currency.id, itr);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Models::Currencies::add (const std::deque<Currency>& currencies) {
|
||||
if (currencies.empty())
|
||||
return;
|
||||
|
||||
for (const Currency& currency : currencies)
|
||||
if (map.count(currency.id))
|
||||
throw std::runtime_error("An attempt to insert a duplicating currency to a currency model (bulk)");
|
||||
|
||||
beginInsertRows(QModelIndex(), index.size(), index.size() + currencies.size() - 1);
|
||||
for (const Currency& currency : currencies) {
|
||||
Order::iterator itr = order.insert(order.end(), currency);
|
||||
index.push_back(itr);
|
||||
map.emplace(currency.id, itr);
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Models::Currencies::remove (Currency::ID id) {
|
||||
Map::iterator mItr = map.find(id);
|
||||
if (mItr == map.end())
|
||||
throw std::runtime_error("An attempt to delete non existing currency from currency model");
|
||||
|
||||
Order::iterator itr = mItr->second;
|
||||
Index::iterator iItr = std::find(index.begin(), index.end(), itr);
|
||||
int row = std::distance(index.begin(), iItr);
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
map.erase(mItr);
|
||||
index.erase(iItr);
|
||||
order.erase(itr);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
int Models::Currencies::rowCount (const QModelIndex& parent) const {
|
||||
//For list models only the root node (an invalid parent) should return the
|
||||
//list's size. For all other (valid) parents, rowCount() should return 0 so
|
||||
//that it does not become a tree model.
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return index.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> Models::Currencies::roleNames () const {
|
||||
return roles;
|
||||
}
|
||||
|
||||
QVariant Models::Currencies::data (const QModelIndex& index, int role) const {
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
int row = index.row();
|
||||
if (row >= 0 && row < Currencies::index.size()) {
|
||||
const Order::iterator& itr = Currencies::index[row];
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
case Title:
|
||||
return itr->title;
|
||||
case Icon:
|
||||
return itr->icon;
|
||||
case Description:
|
||||
return itr->description;
|
||||
case Code:
|
||||
return itr->code;
|
||||
case Type:
|
||||
return itr->type;
|
||||
case Id:
|
||||
return itr->id;
|
||||
case Value:
|
||||
return itr->value;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool Models::Currencies::deserialize (const QVariantList& from, std::deque<Currency>& out) {
|
||||
for (const QVariant& item : from) {
|
||||
if (!item.canConvert<QVariantMap>())
|
||||
return false;
|
||||
|
||||
const QVariantMap& ser = qast<QVariantMap>(item);
|
||||
Currency& currency = out.emplace_back();
|
||||
currency.title = ser.value("title").toString();
|
||||
currency.icon = ser.value("icon", "").toString();
|
||||
currency.description = ser.value("archived", "").toString();
|
||||
currency.id = ser.value("id").toUInt();
|
||||
currency.code = ser.value("code").toString();
|
||||
currency.value = ser.value("value").toDouble();
|
||||
currency.type = ser.value("type", 1).toUInt();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
68
models/currencies.h
Normal file
68
models/currencies.h
Normal file
@ -0,0 +1,68 @@
|
||||
//SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
|
||||
//SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QAbstractListModel>
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
namespace Models {
|
||||
struct Currency {
|
||||
using ID = uint32_t;
|
||||
|
||||
ID id;
|
||||
QString code;
|
||||
QString title;
|
||||
unsigned int type;
|
||||
double value;
|
||||
QString description;
|
||||
QString icon;
|
||||
};
|
||||
|
||||
class Currencies : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
Currencies (QObject* parent = nullptr);
|
||||
|
||||
enum Roles {
|
||||
Id = Qt::UserRole + 1,
|
||||
Code,
|
||||
Title,
|
||||
Type,
|
||||
Value,
|
||||
Description,
|
||||
Icon
|
||||
};
|
||||
|
||||
void clear ();
|
||||
void add (const Currency& currency);
|
||||
void add (const std::deque<Currency>& currencies);
|
||||
void remove (Currency::ID id);
|
||||
|
||||
//Basic functionality:
|
||||
int rowCount (const QModelIndex& parent = QModelIndex()) const override;
|
||||
QHash<int, QByteArray> roleNames () const override;
|
||||
QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
static bool deserialize(const QVariantList& from, std::deque<Currency>& out);
|
||||
static const QHash<int, QByteArray> roles;
|
||||
|
||||
private:
|
||||
using Order = std::list<Currency>;
|
||||
using Index = std::deque<Order::iterator>;
|
||||
using Map = std::map<Currency::ID, Order::iterator>;
|
||||
|
||||
Order order;
|
||||
Index index;
|
||||
Map map;
|
||||
};
|
||||
|
||||
}
|
@ -18,7 +18,8 @@ Models::Magpie::Magpie (QObject* parent):
|
||||
renewToken(),
|
||||
api(),
|
||||
firstPoll(),
|
||||
pollRequestId(API::none)
|
||||
pollRequestId(API::none),
|
||||
requestingCurrencies(false)
|
||||
{
|
||||
firstPoll.setSingleShot(true);
|
||||
firstPoll.setInterval(2000);
|
||||
@ -89,6 +90,10 @@ Models::Assets* Models::Magpie::getAssets () {
|
||||
return &assets;
|
||||
}
|
||||
|
||||
Models::Currencies* Models::Magpie::getCurrencies () {
|
||||
return ¤cies;
|
||||
}
|
||||
|
||||
void Models::Magpie::requestAssets () {
|
||||
api->requestAssets(
|
||||
[this] (const QVariantList& list) {
|
||||
@ -101,10 +106,10 @@ void Models::Magpie::requestAssets () {
|
||||
qDebug() << "Assets successfully received";
|
||||
}
|
||||
|
||||
assets.addAssets(result);
|
||||
assets.add(result);
|
||||
},
|
||||
[this] (const QString& error, const std::optional<QVariantMap>& data) {
|
||||
assets.addAssets({});
|
||||
assets.add(std::deque<Asset>());
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -172,35 +177,55 @@ bool Models::Magpie::handleChanges (const QVariantMap& changes) {
|
||||
}
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
itr = changes.constFind("assets");
|
||||
if (itr != changes.constEnd() && itr.value().canConvert<QVariantMap>()) {
|
||||
const QVariantMap& assets = qast<QVariantMap>(itr.value());
|
||||
QVariantMap::ConstIterator aItr = assets.constFind("invalidate");
|
||||
if (aItr != assets.constEnd()) {
|
||||
if (itr != changes.constEnd() && itr.value().canConvert<QVariantMap>())
|
||||
result = handleAssetChanges(qast<QVariantMap>(itr.value()));
|
||||
|
||||
itr = changes.constFind("currencies");
|
||||
if (itr != changes.constEnd() && itr.value().canConvert<QVariantMap>())
|
||||
result = result && handleCurrenciesChanges(qast<QVariantMap>(itr.value()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Models::Magpie::handleAssetChanges (const QVariantMap& changes) {
|
||||
QVariantMap::ConstIterator aItr = changes.constFind("invalidate");
|
||||
if (aItr != changes.constEnd()) {
|
||||
const QVariant& vinv = aItr.value();
|
||||
if (vinv.canConvert<bool>() && vinv.toBool())
|
||||
Magpie::assets.clear();
|
||||
assets.clear();
|
||||
}
|
||||
|
||||
aItr = assets.constFind("added");
|
||||
if (aItr != assets.constEnd() && aItr.value().canConvert<QVariantList>()) {
|
||||
aItr = changes.constFind("added");
|
||||
if (aItr != changes.constEnd() && aItr.value().canConvert<QVariantList>()) {
|
||||
std::deque<Models::Asset> added;
|
||||
if (!Models::Assets::deserialize(qast<QVariantList>(aItr.value()), added))
|
||||
qDebug() << "Error deserializng added assets";
|
||||
else
|
||||
Magpie::assets.addAssets(added);
|
||||
assets.add(added);
|
||||
}
|
||||
|
||||
aItr = assets.constFind("removed");
|
||||
if (aItr != assets.constEnd() && aItr.value().canConvert<QVariantList>()) {
|
||||
aItr = changes.constFind("removed");
|
||||
if (aItr != changes.constEnd() && aItr.value().canConvert<QVariantList>()) {
|
||||
const QVariantList rem = qast<QVariantList>(aItr.value());
|
||||
for (const QVariant& vId : rem) {
|
||||
if (vId.isValid() && vId.canConvert<unsigned int>())
|
||||
Magpie::assets.deleteAsset(vId.toUInt());
|
||||
assets.remove(vId.toUInt());
|
||||
else
|
||||
qDebug() << "Error deserializing removed assets";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Models::Magpie::handleCurrenciesChanges (const QVariantMap& changes) {
|
||||
QVariantMap::ConstIterator aItr = changes.constFind("invalidate");
|
||||
if (aItr != changes.constEnd()) {
|
||||
const QVariant& vinv = aItr.value();
|
||||
if (vinv.canConvert<bool>() && vinv.toBool())
|
||||
requestCurrencies();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -208,4 +233,12 @@ bool Models::Magpie::handleChanges (const QVariantMap& changes) {
|
||||
|
||||
void Models::Magpie::resetAllModels () {
|
||||
assets.clear();
|
||||
requestCurrencies();
|
||||
}
|
||||
|
||||
void Models::Magpie::requestCurrencies () {
|
||||
if (requestingCurrencies)
|
||||
return;
|
||||
|
||||
currencies.clear();
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <QQmlEngine>
|
||||
#include <QTimer>
|
||||
|
||||
#include "currencies.h"
|
||||
#include "assets.h"
|
||||
|
||||
class API;
|
||||
@ -32,6 +33,7 @@ public:
|
||||
Q_PROPERTY(QUrl address READ getAddress NOTIFY addressChanged)
|
||||
Q_PROPERTY(State state READ getState NOTIFY stateChanged)
|
||||
Q_PROPERTY(Assets* assets READ getAssets CONSTANT)
|
||||
Q_PROPERTY(Currencies* currencies READ getCurrencies CONSTANT)
|
||||
|
||||
explicit Magpie(QObject *parent = nullptr);
|
||||
|
||||
@ -46,6 +48,7 @@ public:
|
||||
void setTokens(const QString access, const QString& renew, bool notify = false);
|
||||
void setState(State newState);
|
||||
Assets* getAssets();
|
||||
Currencies* getCurrencies();
|
||||
|
||||
signals:
|
||||
void addressChanged(const QUrl& path);
|
||||
@ -56,6 +59,7 @@ signals:
|
||||
|
||||
public:
|
||||
Assets assets;
|
||||
Currencies currencies;
|
||||
|
||||
private slots:
|
||||
void requestAssets();
|
||||
@ -67,7 +71,10 @@ private:
|
||||
void onPollSuccess(const QVariantMap& data);
|
||||
void onPollError(const QString& err, const std::optional<QVariantMap>& data);
|
||||
bool handleChanges(const QVariantMap& changes);
|
||||
bool handleAssetChanges(const QVariantMap& changes);
|
||||
bool handleCurrenciesChanges(const QVariantMap& changes);
|
||||
void resetAllModels();
|
||||
void requestCurrencies();
|
||||
|
||||
private:
|
||||
QUrl address;
|
||||
@ -77,6 +84,7 @@ private:
|
||||
std::shared_ptr<API> api;
|
||||
QTimer firstPoll;
|
||||
unsigned int pollRequestId;
|
||||
bool requestingCurrencies;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user