[GUI] Use assets and balances in transfer form

This commit is contained in:
Nathan Hourt 2015-07-15 17:48:44 -04:00
parent 2ec17e2254
commit b433f90a55
7 changed files with 132 additions and 60 deletions

View file

@ -71,7 +71,7 @@ namespace graphene { namespace app {
*/
optional<signed_block> get_block(uint32_t block_num)const;
/**
/**
* @brief used to fetch an individual transaction.
*/
processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const;
@ -120,7 +120,7 @@ namespace graphene { namespace app {
/**
* @brief Get an account's balances in various assets
* @param id ID of the account to get balances for
* @param assets IDs of the assets to get balances of
* @param assets IDs of the assets to get balances of; if empty, get all assets account has a balance in
* @return Balances of the account
*/
vector<asset> get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const;
@ -194,7 +194,7 @@ namespace graphene { namespace app {
* @return Map of witness names to corresponding IDs
*/
map<string, witness_id_type> lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const;
/**
* @brief Get names and IDs for registered committee_members
* @param lower_bound_name Lower bound of the first name to return
@ -202,7 +202,7 @@ namespace graphene { namespace app {
* @return Map of committee_member names to corresponding IDs
*/
map<string, committee_member_id_type> lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const;
/**
* @brief Get a list of witnesses by ID
* @param witness_ids IDs of the witnesses to retrieve
@ -322,7 +322,7 @@ namespace graphene { namespace app {
unsigned limit = 100,
operation_history_id_type start = operation_history_id_type())const;
vector<bucket_object> get_market_history( asset_id_type a, asset_id_type b, uint32_t bucket_seconds,
vector<bucket_object> get_market_history( asset_id_type a, asset_id_type b, uint32_t bucket_seconds,
fc::time_point_sec start, fc::time_point_sec end )const;
flat_set<uint32_t> get_market_history_buckets()const;
private:

View file

@ -13,7 +13,10 @@ find_package(Qt5Quick)
file(GLOB QML qml/*)
qt5_add_resources(QML_QRC qml/qml.qrc)
# Skip building QRC in debug mode, since we access the QML files directly on disk in debug mode
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
qt5_add_resources(QML_QRC qml/qml.qrc)
endif()
add_executable(light_client ClientDataModel.cpp ClientDataModel.hpp main.cpp ${QML_QRC} ${QML})
if (CMAKE_VERSION VERSION_LESS 3.0)

View file

@ -11,16 +11,13 @@ ChainDataModel::ChainDataModel( fc::thread& t, QObject* parent )
:QObject(parent),m_thread(&t){}
Asset* ChainDataModel::getAsset(qint64 id)
Asset* ChainDataModel::getAsset(ObjectId id)
{
auto& by_id_idx = m_assets.get<::by_id>();
auto itr = by_id_idx.find(id);
if( itr == by_id_idx.end() )
{
auto tmp = new Asset;
QQmlEngine::setObjectOwnership(tmp, QQmlEngine::CppOwnership);
tmp->id = id; --m_account_query_num;
tmp->symbol = QString::number( --m_account_query_num);
auto tmp = new Asset(id, QString::number(--m_account_query_num), 0, this);
auto result = m_assets.insert( tmp );
assert( result.second );
@ -71,10 +68,7 @@ Asset* ChainDataModel::getAsset(QString symbol)
auto itr = by_symbol_idx.find(symbol);
if( itr == by_symbol_idx.end() )
{
auto tmp = new Asset;
QQmlEngine::setObjectOwnership(tmp, QQmlEngine::CppOwnership);
tmp->id = --m_account_query_num;
tmp->symbol = symbol;
auto tmp = new Asset(--m_account_query_num, symbol, 0, this);
auto result = m_assets.insert( tmp );
assert( result.second );
@ -123,10 +117,7 @@ Account* ChainDataModel::getAccount(ObjectId id)
auto itr = by_id_idx.find(id);
if( itr == by_id_idx.end() )
{
auto tmp = new Account;
QQmlEngine::setObjectOwnership(tmp, QQmlEngine::CppOwnership);
tmp->id = id; --m_account_query_num;
tmp->name = QString::number( --m_account_query_num);
auto tmp = new Account(id, QString::number(--m_account_query_num), this);
auto result = m_accounts.insert( tmp );
assert( result.second );
@ -174,10 +165,7 @@ Account* ChainDataModel::getAccount(QString name)
auto itr = by_name_idx.find(name);
if( itr == by_name_idx.end() )
{
auto tmp = new Account;
QQmlEngine::setObjectOwnership(tmp, QQmlEngine::CppOwnership);
tmp->id = --m_account_query_num;
tmp->name = name;
auto tmp = new Account(--m_account_query_num, name, this);
auto result = m_accounts.insert( tmp );
assert( result.second );
@ -221,6 +209,19 @@ Account* ChainDataModel::getAccount(QString name)
QQmlListProperty<Balance> Account::balances()
{
// This entire block is dummy data. Throw it away when this function gets a real implementation.
if (m_balances.empty())
{
auto asset = new Asset(0, QStringLiteral("CORE"), 5, this);
m_balances.append(new Balance);
m_balances.back()->setProperty("amount", 5000000);
m_balances.back()->setProperty("type", QVariant::fromValue(asset));
asset = new Asset(0, QStringLiteral("USD"), 2, this);
m_balances.append(new Balance);
m_balances.back()->setProperty("amount", 3099);
m_balances.back()->setProperty("type", QVariant::fromValue(asset));
}
return QQmlListProperty<Balance>(this, m_balances);
}

View file

@ -26,13 +26,21 @@ Q_DECLARE_METATYPE(std::function<void()>)
class GrapheneObject : public QObject
{
Q_OBJECT
Q_PROPERTY(ObjectId id MEMBER id NOTIFY idChanged)
Q_PROPERTY(ObjectId id MEMBER m_id READ id NOTIFY idChanged)
public:
ObjectId id;
ObjectId m_id;
Q_SIGNALS:
void idChanged();
public:
GrapheneObject(ObjectId id = -1, QObject* parent = nullptr)
: QObject(parent), m_id(id)
{}
ObjectId id() const {
return m_id;
}
Q_SIGNALS:
void idChanged();
};
class Crypto {
Q_GADGET
@ -45,19 +53,34 @@ public:
QML_DECLARE_TYPE(Crypto)
class Asset : public GrapheneObject {
class Asset : public GrapheneObject {
Q_OBJECT
Q_PROPERTY(QString symbol MEMBER symbol)
Q_PROPERTY(quint32 precision MEMBER precision)
Q_PROPERTY(QString symbol MEMBER m_symbol READ symbol NOTIFY symbolChanged)
Q_PROPERTY(quint32 precision MEMBER m_precision NOTIFY precisionChanged)
public:
QString symbol;
quint32 precision;
QString m_symbol;
quint32 m_precision;
public:
Asset(ObjectId id = -1, QString symbol = QString(), quint32 precision = 0, QObject* parent = nullptr)
: GrapheneObject(id, parent), m_symbol(symbol), m_precision(precision)
{}
Q_SIGNALS:
void symbolChanged();
QString symbol() const {
return m_symbol;
}
quint64 precisionPower() const {
quint64 power = 1;
for (int i = 0; i < m_precision; ++i)
power *= 10;
return power;
}
Q_SIGNALS:
void symbolChanged();
void precisionChanged();
};
struct by_id;
@ -65,45 +88,59 @@ struct by_symbol_name;
typedef multi_index_container<
Asset*,
indexed_by<
hashed_unique< tag<by_id>, member<GrapheneObject, qint64, &GrapheneObject::id > >,
ordered_unique< tag<by_symbol_name>, member<Asset, QString, &Asset::symbol> >
hashed_unique< tag<by_id>, const_mem_fun<GrapheneObject, ObjectId, &GrapheneObject::id > >,
ordered_unique< tag<by_symbol_name>, const_mem_fun<Asset, QString, &Asset::symbol> >
>
> asset_multi_index_type;
class Balance : public GrapheneObject {
Q_OBJECT
Q_PROPERTY(Asset* type MEMBER type)
Q_PROPERTY(qint64 amount MEMBER amount)
Q_PROPERTY(Asset* type MEMBER type NOTIFY typeChanged)
Q_PROPERTY(qint64 amount MEMBER amount NOTIFY amountChanged)
Asset* type;
qint64 amount;
public:
// This ultimately needs to be replaced with a string equivalent
Q_INVOKABLE qreal amountReal() const {
return amount / qreal(type->precisionPower());
}
Q_SIGNALS:
void typeChanged();
void amountChanged();
};
class Account : public GrapheneObject {
Q_OBJECT
Q_PROPERTY(QString name MEMBER name NOTIFY nameChanged)
Q_PROPERTY(QQmlListProperty<Balance> balances READ balances)
Q_PROPERTY(QString name MEMBER m_name READ name NOTIFY nameChanged)
Q_PROPERTY(QQmlListProperty<Balance> balances READ balances NOTIFY balancesChanged)
QString m_name;
QList<Balance*> m_balances;
public:
const QString& getName()const { return name; }
QQmlListProperty<Balance> balances();
public:
Account(ObjectId id = -1, QString name = QString(), QObject* parent = nullptr)
: GrapheneObject(id, parent), m_name(name)
{}
QString name;
QString name()const { return m_name; }
QQmlListProperty<Balance> balances();
Q_SIGNALS:
void nameChanged();
Q_SIGNALS:
void nameChanged();
void balancesChanged();
};
struct by_account_name;
typedef multi_index_container<
Account*,
indexed_by<
hashed_unique< tag<by_id>, member<GrapheneObject, ObjectId, &GrapheneObject::id > >,
ordered_unique< tag<by_account_name>, member<Account, QString, &Account::name> >
hashed_unique< tag<by_id>, const_mem_fun<GrapheneObject, ObjectId, &GrapheneObject::id > >,
ordered_unique< tag<by_account_name>, const_mem_fun<Account, QString, &Account::name> >
>
> account_multi_index_type;
@ -113,7 +150,7 @@ class ChainDataModel : public QObject {
public:
Q_INVOKABLE Account* getAccount(ObjectId id);
Q_INVOKABLE Account* getAccount(QString name);
Q_INVOKABLE Asset* getAsset(qint64 id);
Q_INVOKABLE Asset* getAsset(ObjectId id);
Q_INVOKABLE Asset* getAsset(QString symbol);
ChainDataModel(){}

View file

@ -28,6 +28,7 @@ int main(int argc, char *argv[])
#ifdef NDEBUG
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
#else
QQmlDebuggingEnabler enabler;
engine.load(QUrl(QStringLiteral("qml/main.qml")));
#endif

View file

@ -9,8 +9,11 @@ import "."
RowLayout {
property Account account
property var balances: account? Object.keys(account.balances).map(function(key){return account.balances[key]})
: null
property alias placeholderText: accountNameField.placeholderText
property int showBalance: -1
function setFocus() {
accountNameField.forceActiveFocus()
@ -29,25 +32,37 @@ RowLayout {
width: parent.width
onEditingFinished: accountDetails.update(text)
}
Label {
Text {
id: accountDetails
width: parent.width
height: text? implicitHeight : 0
Behavior on height { NumberAnimation{ easing.type: Easing.InOutQuad } }
function update(name) {
if (!name)
{
text = ""
account = null
return
}
account = app.model.getAccount(name)
if (account == null)
if (account == null) {
text = qsTr("Error fetching account.")
else
} else {
text = Qt.binding(function() {
if (account == null)
return qsTr("Account does not exist.")
return qsTr("Account ID: %1").arg(account.id < 0? qsTr("Loading...")
: account.id)
var text = qsTr("Account ID: %1").arg(account.id < 0? qsTr("Loading...")
: account.id)
if (showBalance >= 0) {
text += "\n" + qsTr("Balance: %1 %2").arg(balances[showBalance].amountReal())
.arg(balances[showBalance].type.symbol)
}
return text
})
}
}
Behavior on text {

View file

@ -27,28 +27,42 @@ Rectangle {
AccountPicker {
id: senderPicker
width: parent.width
Layout.minimumWidth: Scaling.cm(5)
Component.onCompleted: setFocus()
placeholderText: qsTr("Sender")
showBalance: balances? balances.reduce(function(foundIndex, balance, index) {
if (foundIndex >= 0) return foundIndex
return balance.type.symbol === assetBox.currentText? index : -1
}, -1) : -1
}
AccountPicker {
id: recipientPicker
width: parent.width
Layout.minimumWidth: Scaling.cm(5)
placeholderText: qsTr("Recipient")
layoutDirection: Qt.RightToLeft
}
RowLayout {
width: parent.width
SpinBox {
id: amountField
Layout.preferredWidth: Scaling.cm(4)
Layout.minimumWidth: Scaling.cm(1.5)
enabled: senderPicker.account
enabled: maxBalance
minimumValue: 0
maximumValue: Number.POSITIVE_INFINITY
maximumValue: maxBalance? maxBalance.amountReal() : 0
decimals: maxBalance? maxBalance.type.precision : 0
property Balance maxBalance: senderPicker.balances && senderPicker.showBalance >= 0?
senderPicker.balances[senderPicker.showBalance] : null
}
ComboBox {
id: assetBox
Layout.minimumWidth: Scaling.cm(3)
enabled: senderPicker.account
model: ["CORE", "USD", "GOLD"]
enabled: Boolean(senderPicker.balances)
model: enabled? senderPicker.balances.filter(function(balance) { return balance.amount > 0 })
.map(function(balance) { return balance.type.symbol })
: ["Asset Type"]
}
Item { Layout.fillWidth: true }
Button {
@ -58,6 +72,7 @@ Rectangle {
Button {
text: qsTr("Transfer")
enabled: senderPicker.account
onClicked: console.log(amountField.value)
}
}
}