use std::{
cell::RefCell,
rc::{Rc, Weak},
};
use cacao::{
listview::{ListView, ListViewDelegate, ListViewRow},
view::{View, ViewDelegate},
};
use crate::{app::AppState, element::Element, widgets::Widget};
const REACTIVE_ROW: &str = "ReactiveViewRowCell";
pub struct ReactiveListView {
app: Rc<RefCell<Option<Weak<RefCell<AppState>>>>>,
pub rows: RefCell<Vec<Box<Element>>>,
view: Option<ListView>,
}
impl ReactiveListView {
pub fn with(
app: Rc<RefCell<Option<Weak<RefCell<AppState>>>>>,
rows: Vec<Box<Element>>,
) -> Self {
Self {
app,
rows: RefCell::new(rows),
view: None,
}
}
}
impl ListViewDelegate for ReactiveListView {
const NAME: &'static str = "ReactiveListView";
fn did_load(&mut self, view: ListView) {
view.register(REACTIVE_ROW, ReactiveViewRow::default);
self.view = Some(view);
}
fn number_of_items(&self) -> usize {
self.rows.borrow().len()
}
fn item_for(&self, row: usize) -> ListViewRow {
let mut view = self
.view
.as_ref()
.expect("item_for before the list view loaded")
.dequeue::<ReactiveViewRow>(REACTIVE_ROW);
let app = match self.app.borrow().as_ref().and_then(Weak::upgrade) {
Some(app) => app,
None => return view.into_row(),
};
let app_state = match app.try_borrow() {
Ok(app) => app,
Err(_) => return view.into_row(),
};
if let Some(element) = self.rows.borrow().get(row).cloned() {
if let Some(delegate) = view.delegate.as_mut() {
delegate.content = None;
delegate.content = Some(app_state.mount_row(&delegate.view, &element));
}
}
view.into_row()
}
}
#[derive(Default)]
pub struct ReactiveViewRow {
view: View,
content: Option<Widget>,
}
impl ViewDelegate for ReactiveViewRow {
const NAME: &'static str = "ReactiveViewRow";
fn did_load(&mut self, view: View) {
self.view = view;
}
}