Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial RGB support #97

Merged
merged 10 commits into from
Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mycitadel-desktop"
version = "1.3.0"
version = "2.0.0"
authors = ["Dr Maxim Orlovsky <[email protected]>"]
description = "Bitcoin, Lightning and RGB wallet; part of MyCitadel software suite."
repository = "https://github.com/mycitadel/mycitadel-desktop"
Expand Down Expand Up @@ -68,3 +68,4 @@ serde = ["serde_with", "serde_yaml",

[patch.crates-io]
bpro = { git = "https://github.com/pandora-prime/bpro", branch = "v0.5" }
rgb-std = { git = "https://github.com/RGB-WG/rgb-wallet", branch = "develop" }
28 changes: 28 additions & 0 deletions src/model/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// MyCitadel desktop wallet: bitcoin & RGB wallet based on GTK framework.
//
// Written in 2022 by
// Dr. Maxim Orlovsky <[email protected]>
//
// Copyright (C) 2022 by Pandora Prime SA, Switzerland.
//
// This software is distributed without any warranty. You should have received
// a copy of the AGPL-3.0 License along with this software. If not, see
// <https://www.gnu.org/licenses/agpl-3.0-standalone.html>.

use bpro::{OnchainStatus, OnchainTxid};

pub trait FormatDate {
fn format_date(&self) -> String;
}

impl FormatDate for OnchainTxid {
fn format_date(&self) -> String {
match self.status {
OnchainStatus::Blockchain(height) => self
.date_time()
.map(|dt| dt.format("%F %H:%M").to_string())
.unwrap_or_else(|| format!("{height}")),
OnchainStatus::Mempool => s!("mempool"),
}
}
}
2 changes: 2 additions & 0 deletions src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// a copy of the AGPL-3.0 License along with this software. If not, see
// <https://www.gnu.org/licenses/agpl-3.0-standalone.html>.

mod format;
mod ui;

pub use format::FormatDate;
pub use ui::{Notification, UI};
103 changes: 96 additions & 7 deletions src/view/wallet/asset_row/view_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@ use glib::subclass::prelude::*;
use gtk::prelude::*;
use gtk::subclass::prelude::ListModelImpl;
use gtk::{gio, glib};
use rgbstd::contract::ContractId;
use rgbstd::stl::{DivisibleAssetSpec, Timestamp};

// The actual data structure that stores our values. This is not accessible
// directly from the outside.
#[derive(Default)]
pub struct AssetInner {
name: RefCell<String>,
amount: RefCell<String>,
ticker: RefCell<String>,
name: RefCell<String>,
details: RefCell<String>,
issue: RefCell<String>,
amount: RefCell<u64>,
precision: RefCell<u8>,
contract: RefCell<String>,
}

Expand Down Expand Up @@ -53,10 +58,35 @@ impl ObjectImpl for AssetInner {
glib::ParamFlags::READWRITE,
),
glib::ParamSpecString::new(
"details",
"Details",
"Details",
None, // Default value
glib::ParamFlags::READWRITE,
),
glib::ParamSpecString::new(
"issue",
"Issue",
"Issue",
None, // Default value
glib::ParamFlags::READWRITE,
),
glib::ParamSpecUInt64::new(
"amount",
"Amount",
"Amount",
None,
0,
u64::MAX,
0,
glib::ParamFlags::READWRITE,
),
glib::ParamSpecUChar::new(
"precision",
"Precision",
"Precision",
0,
u8::MAX,
0,
glib::ParamFlags::READWRITE,
),
glib::ParamSpecString::new(
Expand Down Expand Up @@ -87,12 +117,30 @@ impl ObjectImpl for AssetInner {
.expect("type conformity checked by `Object::set_property`");
self.name.replace(name);
}
"details" => {
let details = value
.get()
.expect("type conformity checked by `Object::set_property`");
self.details.replace(details);
}
"issue" => {
let issue = value
.get()
.expect("type conformity checked by `Object::set_property`");
self.issue.replace(issue);
}
"amount" => {
let amount = value
.get()
.expect("type conformity checked by `Object::set_property`");
self.amount.replace(amount);
}
"precision" => {
let amount = value
.get()
.expect("type conformity checked by `Object::set_property`");
self.precision.replace(amount);
}
"ticker" => {
let ticker = value
.get()
Expand All @@ -112,7 +160,10 @@ impl ObjectImpl for AssetInner {
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"name" => self.name.borrow().to_value(),
"details" => self.details.borrow().to_value(),
"issue" => self.issue.borrow().to_value(),
"amount" => self.amount.borrow().to_value(),
"precision" => self.precision.borrow().to_value(),
"ticker" => self.ticker.borrow().to_value(),
"contract" => self.contract.borrow().to_value(),
_ => unimplemented!(),
Expand All @@ -125,30 +176,68 @@ glib::wrapper! {
}

impl AssetInfo {
pub fn btc(testnet: bool, amount: u64) -> AssetInfo {
let (btc, bitcoin) = match testnet {
true => ("tBTC", "Test bitcoin"),
false => ("BTC", "Bitcoin"),
};
AssetInfo::with_raw(bitcoin, btc, "", "", amount, 8, "-")
}

pub fn with(
spec: DivisibleAssetSpec,
issue: Timestamp,
amount: u64,
contract_id: ContractId,
) -> AssetInfo {
let issue = issue
.to_local()
.map(|local| local.format("%F %H:%M").to_string())
.unwrap_or_else(|| s!("invalid"));
Self::with_raw(
spec.name(),
spec.ticker(),
spec.details().unwrap_or_default(),
&issue,
amount,
spec.precision as u8,
&contract_id.to_string(),
)
}

fn with_raw(
name: &str,
ticker: &str,
details: &str,
issue: &str,
amount: u64,
precision: u8,
contract_name: &str,
) -> AssetInfo {
let precision = precision as u32;
let amount = amount as f64 / 10_i32.pow(precision) as f64;
glib::Object::new(&[
("name", &name),
("amount", &format!("{}", amount)),
("details", &details),
("issue", &issue),
("amount", &amount),
("precision", &precision),
("ticker", &ticker),
("contract", &contract_name),
])
}

pub fn name(&self) -> String { self.property::<String>("name") }

pub fn details(&self) -> String { self.property::<String>("details") }

pub fn issue(&self) -> String { self.property::<String>("issue") }

pub fn ticker(&self) -> String { self.property::<String>("ticker") }

pub fn contract_name(&self) -> String { self.property::<String>("contract") }

pub fn amount(&self) -> String { self.property::<String>("amount") }
pub fn amount(&self) -> u64 { self.property::<u64>("amount") }

pub fn precision(&self) -> u8 { self.property::<u8>("precision") }
}

#[derive(Debug, Default)]
Expand Down
11 changes: 11 additions & 0 deletions src/view/wallet/asset_row/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ impl RowWidgets {

asset
.bind_property("amount", &self.amount_lbl, "label")
.transform_to(|binding, value: u64| {
let precision = binding.source().unwrap().property::<u8>("precision");
let pow = 10u64.pow(precision as u32);
let int = value / pow;
let mut fract = (value - int * pow) as f64 / pow as f64;
if fract > 0.0 && fract < 0.01 {
fract = 0.01;
}
let fract = format!("{:.2}", fract);
Some(format!("{int}.{}", fract.trim_start_matches("0.")))
})
.flags(flags)
.build();
}
Expand Down
Loading