winio-ui-android 0.1.0

Android backend for winio.
use jni::refs::Global;
use winio_handle::{AsContainer, AsWidget, BorrowedWidget};
use winio_primitive::{Point, Size};

use crate::{
    BaseWidget, Result, current_activity,
    java::android::widget::{
        FrameLayout, HorizontalScrollView as AHorizontalScrollView, ScrollView as AScrollView,
    },
    vm_exec,
};

#[derive(Debug)]
pub struct ScrollView {
    parent: Global<FrameLayout<'static>>,
    vertical: BaseWidget<AScrollView<'static>>,
    horizontal: BaseWidget<AHorizontalScrollView<'static>>,
    inner_view: BaseWidget<FrameLayout<'static>>,
    enable_vertical: bool,
    enable_horizontal: bool,
}

impl ScrollView {
    pub fn new(parent: impl AsContainer) -> Result<Self> {
        vm_exec(|env| {
            let context = current_activity(env)?;
            let vertical = AScrollView::new(env, &context)?;
            let horizontal = AHorizontalScrollView::new(env, &context)?;
            let inner_view = FrameLayout::new(env, &context)?;
            vertical.as_view_group().add_view(env, &horizontal)?;
            horizontal.as_view_group().add_view(env, &inner_view)?;
            let p = parent.as_container();
            let parent = env.new_local_ref(p.to_android())?;
            let parent =
                env.new_global_ref(unsafe { FrameLayout::from_raw(env, parent.into_raw()) })?;
            let vertical = BaseWidget::new_with_env(env, p, vertical)?;
            let horizontal = env.new_global_ref(horizontal)?.into();
            let inner_view = env.new_global_ref(inner_view)?.into();
            Ok(Self {
                parent,
                vertical,
                horizontal,
                inner_view,
                enable_vertical: true,
                enable_horizontal: true,
            })
        })
    }

    pub fn is_visible(&self) -> Result<bool> {
        self.inner_view.is_visible()
    }

    pub fn set_visible(&mut self, v: bool) -> Result<()> {
        self.inner_view.set_visible(v)
    }

    pub fn is_enabled(&self) -> Result<bool> {
        self.inner_view.is_enabled()
    }

    pub fn set_enabled(&mut self, v: bool) -> Result<()> {
        self.inner_view.set_enabled(v)
    }

    pub fn loc(&self) -> Result<Point> {
        if self.enable_vertical {
            self.vertical.loc()
        } else if self.enable_horizontal {
            self.horizontal.loc()
        } else {
            self.inner_view.loc()
        }
    }

    pub fn set_loc(&mut self, p: Point) -> Result<()> {
        if self.enable_vertical {
            self.vertical.set_loc(p)?;
            self.horizontal.set_loc(Point::zero())?;
            self.inner_view.set_loc(Point::zero())?;
        } else if self.enable_horizontal {
            self.horizontal.set_loc(p)?;
            self.inner_view.set_loc(Point::zero())?;
        } else {
            self.inner_view.set_loc(p)?;
        }
        Ok(())
    }

    pub fn size(&self) -> Result<Size> {
        if self.enable_vertical {
            self.vertical.size()
        } else if self.enable_horizontal {
            self.horizontal.size()
        } else {
            self.inner_view.size()
        }
    }

    pub fn set_size(&mut self, v: Size) -> Result<()> {
        if self.enable_vertical {
            self.vertical.set_size(v)?;
            self.horizontal.set_wrap_content()?;
            self.inner_view.set_wrap_content()?;
        } else if self.enable_horizontal {
            self.horizontal.set_size(v)?;
            self.inner_view.set_wrap_content()?;
        } else {
            self.inner_view.set_size(v)?;
        }
        Ok(())
    }

    fn detach(&mut self) -> Result<()> {
        vm_exec(|env| {
            if self.enable_vertical {
                self.parent
                    .as_view_group()
                    .remove_view(env, self.vertical.as_view())?;
                if self.enable_horizontal {
                    // V > H > I
                    self.vertical
                        .as_view_group()
                        .remove_view(env, self.horizontal.as_view())?;
                    self.horizontal
                        .as_view_group()
                        .remove_view(env, self.inner_view.as_view())?;
                } else {
                    // V > I
                    self.vertical
                        .as_view_group()
                        .remove_view(env, self.inner_view.as_view())?;
                }
            } else {
                if self.enable_horizontal {
                    // H > I
                    self.parent
                        .as_view_group()
                        .remove_view(env, self.horizontal.as_view())?;
                    self.horizontal
                        .as_view_group()
                        .remove_view(env, self.inner_view.as_view())?;
                } else {
                    // I
                    self.parent
                        .as_view_group()
                        .remove_view(env, self.inner_view.as_view())?;
                }
            }
            Ok(())
        })
    }

    fn attach(&mut self) -> Result<()> {
        vm_exec(|env| {
            if self.enable_vertical {
                self.parent
                    .as_view_group()
                    .add_view(env, self.vertical.as_view())?;
                if self.enable_horizontal {
                    // V > H > I
                    self.vertical
                        .as_view_group()
                        .add_view(env, self.horizontal.as_view())?;
                    self.horizontal
                        .as_view_group()
                        .add_view(env, self.inner_view.as_view())?;
                } else {
                    // V > I
                    self.vertical
                        .as_view_group()
                        .add_view(env, self.inner_view.as_view())?;
                }
            } else {
                if self.enable_horizontal {
                    // H > I
                    self.parent
                        .as_view_group()
                        .add_view(env, self.horizontal.as_view())?;
                    self.horizontal
                        .as_view_group()
                        .add_view(env, self.inner_view.as_view())?;
                } else {
                    // I
                    self.parent
                        .as_view_group()
                        .add_view(env, self.inner_view.as_view())?;
                }
            }
            Ok(())
        })
    }

    pub fn hscroll(&self) -> Result<bool> {
        Ok(self.enable_horizontal)
    }

    pub fn set_hscroll(&mut self, v: bool) -> Result<()> {
        if self.enable_horizontal != v {
            self.detach()?;
            self.enable_horizontal = v;
            self.attach()?;
        }
        Ok(())
    }

    pub fn vscroll(&self) -> Result<bool> {
        Ok(self.enable_vertical)
    }

    pub fn set_vscroll(&mut self, v: bool) -> Result<()> {
        if self.enable_vertical != v {
            self.detach()?;
            self.enable_vertical = v;
            self.attach()?;
        }
        Ok(())
    }

    pub async fn start(&self) -> ! {
        std::future::pending().await
    }
}

winio_handle::impl_as_container!(ScrollView, inner_view);

impl AsWidget for ScrollView {
    fn as_widget(&self) -> BorrowedWidget<'_> {
        if self.enable_vertical {
            self.vertical.as_widget()
        } else if self.enable_horizontal {
            self.horizontal.as_widget()
        } else {
            self.inner_view.as_widget()
        }
    }
}