Skip to main content

repose_material/material3/
scaffold.rs

1#![allow(non_snake_case)]
2
3
4use repose_core::*;
5use repose_ui::{
6    Box, Column,
7    ViewExt,
8};
9
10use super::*;
11
12/// Position of the floating action button within a Scaffold.
13#[derive(Clone, Copy, Debug, PartialEq)]
14pub enum FabPosition {
15    End,
16    Center,
17}
18
19impl Default for FabPosition {
20    fn default() -> Self {
21        Self::End
22    }
23}
24
25#[derive(Clone)]
26pub struct ScaffoldConfig {
27    pub modifier: Modifier,
28    pub top_bar: Option<View>,
29    pub bottom_bar: Option<View>,
30    pub floating_action_button: Option<View>,
31    pub snackbar_host: Option<View>,
32    pub container_color: Color,
33    pub content_color: Color,
34    pub fab_position: FabPosition,
35}
36
37impl Default for ScaffoldConfig {
38    fn default() -> Self {
39        Self {
40            modifier: Modifier::new(),
41            top_bar: None,
42            bottom_bar: None,
43            floating_action_button: None,
44            snackbar_host: None,
45            container_color: ScaffoldDefaults::container_color(),
46            content_color: ScaffoldDefaults::content_color(),
47            fab_position: FabPosition::End,
48        }
49    }
50}
51
52pub fn Scaffold(content: impl Fn(PaddingValues) -> View, config: ScaffoldConfig) -> View {
53    let insets = window_insets();
54    let itop = px_to_dp(insets.top);
55    let ibottom = px_to_dp(insets.bottom);
56    let iime = px_to_dp(insets.ime_bottom);
57    let ileft = px_to_dp(insets.left);
58    let iright = px_to_dp(insets.right);
59
60    let content_padding = PaddingValues {
61        top: if config.top_bar.is_some() {
62            64.0
63        } else {
64            itop
65        },
66        bottom: if config.bottom_bar.is_some() {
67            80.0 + ibottom + iime
68        } else {
69            ibottom + iime
70        },
71        left: ileft,
72        right: iright,
73    };
74
75    Column(
76        config
77            .modifier
78            .fill_max_size()
79            .background(config.container_color),
80    )
81    .child((
82        Box(Modifier::new()
83            .fill_max_size()
84            .padding_values(PaddingValues {
85                top: if config.top_bar.is_some() {
86                    64.0 + itop
87                } else {
88                    0.0
89                },
90                bottom: if config.bottom_bar.is_some() {
91                    80.0 + ibottom + iime
92                } else {
93                    ibottom + iime
94                },
95                ..Default::default()
96            }))
97        .child(content(content_padding)),
98        if let Some(bar) = config.top_bar {
99            Box(Modifier::new()
100                .absolute()
101                .offset(Some(0.0), Some(itop), Some(0.0), None))
102            .child(bar)
103        } else {
104            Box(Modifier::new())
105        },
106        if let Some(bar) = config.bottom_bar {
107            Box(Modifier::new().absolute().offset(
108                Some(0.0),
109                None,
110                Some(ibottom + iime),
111                Some(0.0),
112            ))
113            .child(bar)
114        } else {
115            Box(Modifier::new())
116        },
117        if let Some(fab) = config.floating_action_button {
118            let mut fab_m = Modifier::new().absolute();
119            match config.fab_position {
120                FabPosition::End => {
121                    fab_m = fab_m.offset(
122                        None,
123                        None,
124                        Some(16.0 + ibottom + iime),
125                        Some(16.0),
126                    );
127                }
128                FabPosition::Center => {
129                    fab_m = fab_m.fill_max_width().align_self(AlignSelf::CENTER).offset(
130                        None,
131                        None,
132                        Some(16.0 + ibottom + iime),
133                        None,
134                    );
135                }
136            }
137            Box(fab_m).child(fab)
138        } else {
139            Box(Modifier::new())
140        },
141        config.snackbar_host.unwrap_or_else(|| Box(Modifier::new())),
142    ))
143}