use crate::action::{WuiIndexAction, WuiMoveAction};
use crate::reactive::WuiComputed;
use crate::views::WuiAnyViews;
use crate::{IntoFFI, WuiAnyView};
use core::fmt;
use nami::SignalExt;
use waterui::component::list::{ListConfig, ListItem, ListSection};
use waterui::text::styled::StyledStr;
use waterui::views::ViewsExt;
#[repr(C)]
#[derive(Debug)]
pub struct WuiListSection {
pub has_value: bool,
pub label: *mut WuiComputed<StyledStr>,
pub footer: *mut WuiComputed<StyledStr>,
}
#[repr(C)]
pub struct WuiListItem {
pub content: *mut WuiAnyView,
pub deletable: *mut WuiComputed<bool>,
pub selected: *mut WuiComputed<bool>,
pub section: WuiListSection,
}
impl fmt::Debug for WuiListItem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WuiListItem")
.field("content", &self.content)
.field("deletable", &self.deletable)
.field("section", &self.section)
.finish_non_exhaustive()
}
}
impl IntoFFI for Option<ListSection> {
type FFI = WuiListSection;
fn into_ffi(self) -> Self::FFI {
let Some(ListSection { label, footer }) = self else {
return WuiListSection {
has_value: false,
label: core::ptr::null_mut(),
footer: core::ptr::null_mut(),
};
};
let into_signal = |text: waterui::text::Text| text.into_config_without_env().content;
WuiListSection {
has_value: true,
label: label.map_or_else(core::ptr::null_mut, |label| into_signal(label).into_ffi()),
footer: footer
.map_or_else(core::ptr::null_mut, |footer| into_signal(footer).into_ffi()),
}
}
}
impl IntoFFI for ListItem {
type FFI = WuiListItem;
fn into_ffi(self) -> Self::FFI {
WuiListItem {
content: self.content.into_ffi(),
deletable: self.deletable.into_ffi(),
selected: self.selected.into_ffi(),
section: self.section.into_ffi(),
}
}
}
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_force_as_list_item(view: *mut WuiAnyView) -> WuiListItem {
let any: waterui::AnyView = unsafe { crate::IntoRust::into_rust(view) };
unsafe { (*any.downcast_unchecked::<ListItem>()).into_ffi() }
}
#[cfg(feature = "android-jni")]
#[unsafe(no_mangle)]
extern "system" fn Java_dev_waterui_android_ffi_WatcherJni_listItemId<'local>(
mut env: crate::jni::JNIEnv<'local>,
_class: crate::jni::JClass<'local>,
) -> crate::jni::jobject {
crate::jni::with_env(&mut env, |env| {
let type_id = crate::WuiTypeId::of::<ListItem>();
crate::jni::type_id_to_java(env, type_id).into_raw()
})
}
#[cfg(feature = "android-jni")]
#[unsafe(no_mangle)]
unsafe extern "system" fn Java_dev_waterui_android_ffi_WatcherJni_forceAsListItem<'local>(
mut env: crate::jni::JNIEnv<'local>,
_class: crate::jni::JClass<'local>,
view_ptr: crate::jni::jlong,
) -> crate::jni::jobject {
use crate::jni::convert::jlong_to_ptr_mut;
crate::jni::with_env(&mut env, |env| {
let view_ptr: *mut WuiAnyView = unsafe { jlong_to_ptr_mut(view_ptr) };
let any: waterui::AnyView = unsafe { crate::IntoRust::into_rust(view_ptr) };
let ffi_struct: WuiListItem = unsafe { (*any.downcast_unchecked::<ListItem>()).into_ffi() };
crate::jni::convert::struct_to_java(env, &ffi_struct).into_raw()
})
}
#[repr(C)]
#[derive(Debug)]
pub struct WuiList {
pub contents: *mut WuiAnyViews,
pub editing: *mut WuiComputed<bool>,
pub on_delete: *mut WuiIndexAction,
pub on_move: *mut WuiMoveAction,
pub target_index: *mut WuiComputed<i32>,
pub scroll_generation: *mut WuiComputed<i32>,
pub uses_sections: bool,
}
impl IntoFFI for ListConfig {
type FFI = WuiList;
fn into_ffi(self) -> Self::FFI {
let (target_index, scroll_generation) = self.scroll_controller.map_or_else(
|| (core::ptr::null_mut(), core::ptr::null_mut()),
|controller| {
(
controller
.target()
.map(|index| {
i32::try_from(index)
.expect("list scroll target exceeds the platform index range")
})
.computed()
.into_ffi(),
controller.generation().into_ffi(),
)
},
);
WuiList {
contents: self.contents.erase().into_ffi(),
editing: self.editing.into_ffi(),
on_delete: self.on_delete.into_ffi(),
on_move: self.on_move.into_ffi(),
target_index,
scroll_generation,
uses_sections: self.uses_sections,
}
}
}
ffi_view!(ListConfig, WuiList, list);