use cranpose_core::remember;
use cranpose_services::{SaveableRegistration, SaveableScope};
use cranpose_ui::{
LazyGridState, LazyListState, LazyStaggeredGridState, PagerState, ScrollState, composable,
};
fn format_position((index, offset): (usize, f32)) -> String {
format!("{index} {offset}")
}
fn parse_position(stored: &str) -> Option<(usize, f32)> {
let (index, offset) = stored.split_once(' ')?;
Some((index.parse().ok()?, offset.parse().ok()?))
}
fn remember_saved<S, P>(
key: &'static str,
parse: fn(&str) -> Option<P>,
format: fn(P) -> String,
create: impl FnOnce(Option<P>) -> S,
read: fn(&S) -> Option<P>,
) -> S
where
S: Clone + 'static,
P: 'static,
{
remember(move || {
let scope = SaveableScope::current();
let state = create(scope.restore(key).as_deref().and_then(parse));
let saved = state.clone();
let registration: SaveableRegistration =
scope.register(key, move || read(&saved).map(format));
(state, registration)
})
.with(|(state, _)| state.clone())
}
#[composable]
pub fn rememberSaveableLazyListState(key: &'static str) -> LazyListState {
remember_saved(
key,
parse_position,
format_position,
|restored| {
let (index, offset) = restored.unwrap_or_default();
LazyListState::new(index, offset)
},
LazyListState::try_position,
)
}
#[composable]
pub fn rememberSaveableLazyGridState(key: &'static str) -> LazyGridState {
remember_saved(
key,
parse_position,
format_position,
|restored| {
let state = LazyGridState::new();
if let Some((index, offset)) = restored {
state.scroll_to_item(index, offset);
}
state
},
LazyGridState::try_position,
)
}
#[composable]
pub fn rememberSaveableLazyStaggeredGridState(key: &'static str) -> LazyStaggeredGridState {
remember_saved(
key,
parse_position,
format_position,
|restored| {
let (index, offset) = restored.unwrap_or_default();
LazyStaggeredGridState::new(index, offset)
},
LazyStaggeredGridState::try_position,
)
}
#[composable]
pub fn rememberSaveablePagerState(key: &'static str, initial_page: usize) -> PagerState {
remember_saved(
key,
|stored| stored.parse().ok(),
|page: usize| page.to_string(),
|restored| PagerState::new(restored.unwrap_or(initial_page)),
PagerState::try_first_page,
)
}
#[composable]
pub fn rememberSaveableScrollState(key: &'static str) -> ScrollState {
remember_saved(
key,
|stored| stored.parse().ok(),
|value: f32| value.to_string(),
|restored| ScrollState::new(restored.unwrap_or_default()),
ScrollState::try_value,
)
}