repose_material/material3/
scaffold.rs1#![allow(non_snake_case)]
2
3
4use repose_core::*;
5use repose_ui::{
6 Box, Column,
7 ViewExt,
8};
9
10use super::*;
11
12#[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}