started to work over currencies

This commit is contained in:
Blue 2024-01-24 18:00:15 -03:00
parent 5c4bd18cdc
commit 45f924a4cf
Signed by: blue
GPG Key ID: 9B203B252A63EE38
7 changed files with 287 additions and 42 deletions

View File

@ -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})

View File

@ -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 {

View File

@ -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
View 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
View 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;
};
}

View File

@ -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 &currencies;
}
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()) {
const QVariant& vinv = aItr.value();
if (vinv.canConvert<bool>() && vinv.toBool())
Magpie::assets.clear();
}
if (itr != changes.constEnd() && itr.value().canConvert<QVariantMap>())
result = handleAssetChanges(qast<QVariantMap>(itr.value()));
aItr = assets.constFind("added");
if (aItr != assets.constEnd() && aItr.value().canConvert<QVariantList>()) {
std::deque<Models::Asset> added;
if (!Models::Assets::deserialize(qast<QVariantList>(aItr.value()), added))
qDebug() << "Error deserializng added assets";
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())
assets.clear();
}
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
assets.add(added);
}
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>())
assets.remove(vId.toUInt());
else
Magpie::assets.addAssets(added);
qDebug() << "Error deserializing removed assets";
}
}
aItr = assets.constFind("removed");
if (aItr != assets.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());
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();
}

View File

@ -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;
};
}