use super::events::{AppEvent, Event};
use crate::{
prelude::Point,
sys::{get_terminal_size_no_sys, Control},
};
use futures_lite::{io, Stream};
use std::{
pin::Pin,
task::{Context, Poll},
};
pub(crate) struct Resizer<C, S> {
inner: Pin<Box<S>>,
size: Option<Point>,
fails: bool,
control: Pin<Box<C>>,
}
impl<C, S, A: AppEvent> Resizer<C, S>
where
S: Stream<Item = io::Result<Event<A>>>,
{
pub fn new(inner: Pin<Box<S>>, control: Pin<Box<C>>) -> Self {
Self {
inner,
size: Default::default(),
fails: false,
control,
}
}
fn send(&mut self) -> Poll<Option<io::Result<Event<A>>>>
where
C: Control,
{
let new_size = match self.control.as_ref().get_size() {
Ok(size) => size,
Err(_) => {
self.fails = true;
get_terminal_size_no_sys().or(self.size).unwrap_or_default()
}
};
if Some(new_size) != self.size {
self.size = Some(new_size);
return Poll::Ready(Some(Ok(Event::Resize(new_size))));
}
Poll::Pending
}
}
impl<C, S, A: AppEvent> Stream for Resizer<C, S>
where
C: Control,
S: Stream<Item = io::Result<Event<A>>>,
{
type Item = io::Result<Event<A>>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
if self.size.is_none() {
return self.send();
}
if let ready @ Poll::Ready(_) = self.inner.as_mut().poll_next(cx) {
return ready;
}
if !self.fails {
return self.send();
}
Poll::Pending
}
}