use crate::{
plugins::{
PluginActivitiesSummaryRow, PluginCaloriesSummaryRow, PluginName, PluginStepsSummaryRow,
PluginWeightSummaryRow,
},
prelude::*,
};
use adw::subclass::prelude::*;
use gtk::glib::{self, prelude::*};
use std::str::FromStr;
mod imp {
use crate::{plugins::PluginName, prelude::*};
use adw::subclass::prelude::*;
use gtk::{gio, glib, prelude::*};
use once_cell::unsync::OnceCell;
use std::str::FromStr;
#[repr(C)]
pub struct PluginSummaryRowClass {
pub parent_class: adw::ffi::AdwActionRowClass,
pub update: fn(&super::PluginSummaryRow) -> PinnedResultFuture<()>,
}
unsafe impl ClassStruct for PluginSummaryRowClass {
type Type = PluginSummaryRow;
}
impl std::ops::Deref for PluginSummaryRowClass {
type Target = glib::Class<glib::Object>;
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self).cast::<Self::Target>() }
}
}
impl std::ops::DerefMut for PluginSummaryRowClass {
fn deref_mut(&mut self) -> &mut glib::Class<glib::Object> {
unsafe { &mut *(self as *mut Self).cast::<glib::Class<glib::Object>>() }
}
}
#[derive(Debug, Default)]
pub struct PluginSummaryRow {
pub plugin_name: OnceCell<PluginName>,
}
fn update_default_trampoline(this: &super::PluginSummaryRow) -> PinnedResultFuture<()> {
PluginSummaryRow::from_obj(this).update(this)
}
pub(super) fn plugin_summary_row_update(
this: &super::PluginSummaryRow,
) -> PinnedResultFuture<()> {
let klass = this.class();
(klass.as_ref().update)(this)
}
impl PluginSummaryRow {
fn update(&self, obj: &super::PluginSummaryRow) -> PinnedResultFuture<()> {
Box::pin(gio::GioFuture::new(obj, move |_, _, send| {
send.resolve(Ok(()));
}))
}
}
#[glib::object_subclass]
impl ObjectSubclass for PluginSummaryRow {
const NAME: &'static str = "HealthPluginSummaryRow";
type ParentType = adw::ActionRow;
type Type = super::PluginSummaryRow;
type Class = PluginSummaryRowClass;
fn class_init(klass: &mut Self::Class) {
klass.update = update_default_trampoline;
}
}
impl ObjectImpl for PluginSummaryRow {
fn properties() -> &'static [glib::ParamSpec] {
use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecString::builder("plugin-name")
.construct_only()
.readwrite()
.build()]
});
PROPERTIES.as_ref()
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"plugin-name" => self.plugin_name.get().unwrap().to_value(),
_ => unimplemented!(),
}
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"plugin-name" => self
.plugin_name
.set(PluginName::from_str(value.get::<&str>().unwrap()).unwrap())
.unwrap(),
_ => unimplemented!(),
}
}
}
impl WidgetImpl for PluginSummaryRow {}
impl ListBoxRowImpl for PluginSummaryRow {}
impl PreferencesRowImpl for PluginSummaryRow {}
impl ActionRowImpl for PluginSummaryRow {}
}
glib::wrapper! {
pub struct PluginSummaryRow(ObjectSubclass<imp::PluginSummaryRow>)
@extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
impl PluginSummaryRow {
pub fn new(plugin_name: PluginName) -> Self {
glib::Object::builder()
.property("plugin-name", &plugin_name)
.build()
}
}
pub trait PluginSummaryRowExt {
fn update(&self) -> PinnedResultFuture<()>;
fn plugin_name(&self) -> PluginName;
}
impl<O: IsA<PluginSummaryRow>> PluginSummaryRowExt for O {
fn update(&self) -> PinnedResultFuture<()> {
imp::plugin_summary_row_update(self.upcast_ref())
}
fn plugin_name(&self) -> PluginName {
PluginName::from_str(&self.property::<String>("plugin-name")).unwrap()
}
}
pub trait PluginSummaryRowImpl: ActionRowImpl + 'static {
fn update(&self, obj: &PluginSummaryRow) -> PinnedResultFuture<()> {
self.parent_update(obj)
}
}
pub trait PluginSummaryRowImplExt: ObjectSubclass {
fn parent_update(&self, obj: &PluginSummaryRow) -> PinnedResultFuture<()>;
}
impl<T: PluginSummaryRowImpl> PluginSummaryRowImplExt for T {
fn parent_update(&self, obj: &PluginSummaryRow) -> PinnedResultFuture<()> {
unsafe {
let data = Self::type_data();
let parent_class = &*(data.as_ref().parent_class() as *mut imp::PluginSummaryRowClass);
(parent_class.update)(obj)
}
}
}
unsafe impl<T: PluginSummaryRowImpl> IsSubclassable<T> for PluginSummaryRow {
fn class_init(class: &mut glib::Class<Self>) {
<adw::ActionRow as IsSubclassable<T>>::class_init(class.upcast_ref_mut());
let klass = class.as_mut();
klass.update = update_trampoline::<T>;
}
fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) {
<adw::ActionRow as IsSubclassable<T>>::instance_init(instance);
}
}
fn update_trampoline<T: ObjectSubclass>(this: &PluginSummaryRow) -> PinnedResultFuture<()>
where
T: PluginSummaryRowImpl,
{
let imp = T::from_obj(this.dynamic_cast_ref::<T::Type>().unwrap());
imp.update(this)
}
impl From<PluginName> for PluginSummaryRow {
fn from(plugin_name: PluginName) -> Self {
match plugin_name {
PluginName::Activities => PluginActivitiesSummaryRow::new(plugin_name).upcast(),
PluginName::Calories => PluginCaloriesSummaryRow::new(plugin_name).upcast(),
PluginName::Steps => PluginStepsSummaryRow::new(plugin_name).upcast(),
PluginName::Weight => PluginWeightSummaryRow::new(plugin_name).upcast(),
}
}
}
#[cfg(test)]
mod test {
use super::{PluginName, PluginSummaryRow};
use crate::utils::init_gtk;
#[gtk::test]
fn new() {
init_gtk();
PluginSummaryRow::new(PluginName::Activities);
}
}