use std::cell::RefCell;
use std::str::FromStr;
use bitcoin::util::address;
use bitcoin::Address;
use glib::subclass::prelude::*;
use gtk::prelude::*;
use gtk::subclass::prelude::ListModelImpl;
use gtk::{gio, glib};
use wallet::scripts::address::AddressCompat;
#[derive(Default)]
pub struct BeneficiaryInner {
address: RefCell<String>,
amount: RefCell<u64>,
}
#[glib::object_subclass]
impl ObjectSubclass for BeneficiaryInner {
const NAME: &'static str = "Beneficiary";
type Type = Beneficiary;
type ParentType = glib::Object;
}
impl ObjectImpl for BeneficiaryInner {
fn properties() -> &'static [glib::ParamSpec] {
use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpecString::new(
"address",
"Address",
"Address",
None, glib::ParamFlags::READWRITE,
),
glib::ParamSpecUInt64::new(
"amount",
"Amount",
"Amount",
0,
21_000_000 * 100_000_00,
0, glib::ParamFlags::READWRITE,
),
]
});
PROPERTIES.as_ref()
}
fn set_property(
&self,
_obj: &Self::Type,
_id: usize,
value: &glib::Value,
pspec: &glib::ParamSpec,
) {
match pspec.name() {
"address" => {
let address = value
.get()
.expect("type conformity checked by `Object::set_property`");
self.address.replace(address);
}
"amount" => {
let amount = value
.get()
.expect("type conformity checked by `Object::set_property`");
self.amount.replace(amount);
}
_ => unimplemented!(),
}
}
fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"address" => self.address.borrow().to_value(),
"amount" => self.amount.borrow().to_value(),
_ => unimplemented!(),
}
}
}
glib::wrapper! {
pub struct Beneficiary(ObjectSubclass<BeneficiaryInner>);
}
impl Beneficiary {
pub fn new() -> Beneficiary {
glib::Object::new(&[("address", &""), ("amount", &0u64)])
.expect("Failed to create row data")
}
pub fn with(address: AddressCompat, amount: u64) -> Beneficiary {
glib::Object::new(&[("address", &address.to_string()), ("amount", &amount)])
.expect("Failed to create row data")
}
pub fn address(&self) -> Result<Address, address::Error> {
Address::from_str(&self.property::<String>("address"))
}
pub fn address_compat(&self) -> Result<AddressCompat, address::Error> {
AddressCompat::from_str(&self.property::<String>("address"))
}
pub fn amount(&self) -> f64 {
let sats = self.amount_sats();
sats as f64 / 100_000_000.0
}
pub fn amount_sats(&self) -> u64 { self.property::<u64>("amount") }
}
#[derive(Debug, Default)]
pub struct BeneficiaryModelInner(pub RefCell<Vec<Beneficiary>>);
#[glib::object_subclass]
impl ObjectSubclass for BeneficiaryModelInner {
const NAME: &'static str = "BeneficiaryModel";
type Type = BeneficiaryModel;
type ParentType = glib::Object;
type Interfaces = (gio::ListModel,);
}
impl ObjectImpl for BeneficiaryModelInner {}
impl ListModelImpl for BeneficiaryModelInner {
fn item_type(&self, _list_model: &Self::Type) -> glib::Type { Beneficiary::static_type() }
fn n_items(&self, _list_model: &Self::Type) -> u32 { self.0.borrow().len() as u32 }
fn item(&self, _list_model: &Self::Type, position: u32) -> Option<glib::Object> {
self.0
.borrow()
.get(position as usize)
.map(|o| o.clone().upcast::<glib::Object>())
}
}
glib::wrapper! {
pub struct BeneficiaryModel(ObjectSubclass<BeneficiaryModelInner>) @implements gio::ListModel;
}
impl BeneficiaryModel {
#[allow(clippy::new_without_default)]
pub fn new() -> BeneficiaryModel {
glib::Object::new(&[]).expect("Failed to create BeneficiaryModel")
}
pub fn append(&self, obj: &Beneficiary) {
let imp = self.imp();
let index = {
let mut data = imp.0.borrow_mut();
data.push(obj.clone());
data.len() - 1
};
self.items_changed(index as u32, 0, 1);
}
pub fn clear(&self) {
let imp = self.imp();
let n = self.n_items();
imp.0.borrow_mut().clear();
self.items_changed(0, n, 0);
}
pub fn remove(&self, index: u32) {
let imp = self.imp();
imp.0.borrow_mut().remove(index as usize);
self.items_changed(index, 1, 0);
}
}