new code
This commit is contained in:
parent
0e1100f7d1
commit
111b394b4d
34 changed files with 3523 additions and 83 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
<<<<<<< HEAD
|
||||||
https://192.168.*.*:8000 {
|
https://192.168.*.*:8000 {
|
||||||
|
=======
|
||||||
|
https://192.168.247.197:8000 {
|
||||||
|
>>>>>>> 60db8c0 (new code)
|
||||||
reverse_proxy 127.0.0.1:8010
|
reverse_proxy 127.0.0.1:8010
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ sudo cargo makepad wasm run -p aok_manyatta --release --no-default-features --ta
|
||||||
|
|
||||||
caddy fmt --overwrite /Users/aok/Projects/rustdev/MadeByMakepad/aok_manyatta/Caddyfile
|
caddy fmt --overwrite /Users/aok/Projects/rustdev/MadeByMakepad/aok_manyatta/Caddyfile
|
||||||
caddy reload --config /Users/aok/Projects/rustdev/MadeByMakepad/aok_manyatta/Caddyfile
|
caddy reload --config /Users/aok/Projects/rustdev/MadeByMakepad/aok_manyatta/Caddyfile
|
||||||
|
caddy run --config /Users/aok/Projects/rustdev/MadeByMakepad/aok_manyatta/Caddyfile
|
||||||
|
|
||||||
Creating a new repository on the command line
|
Creating a new repository on the command line
|
||||||
touch README.md
|
touch README.md
|
||||||
|
|
108
command_log.txt
108
command_log.txt
|
@ -646,3 +646,111 @@ Time Taken: 283.93ms
|
||||||
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
Time Taken: 722.92ms
|
Time Taken: 722.92ms
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 361.37s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 464.00ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 42.98s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 17.73s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 847.73ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 6.11s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 26.74s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 350.69ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 12.57s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 480.54s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 267.58ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 5.41s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 334.67s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 439.80ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 7.62s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 650.27s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 674.92ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 66.65s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 430.74s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 329.64ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 3.81s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 146.06s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 247.09ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 638.03ms
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 169.72s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 226.38ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 539.24ms
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 121.63s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 377.13ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 1.65s
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 101.68s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 267.93ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 637.07ms
|
||||||
|
|
||||||
|
Command: rustup run nightly cargo build --target=wasm32-unknown-unknown -Z build-std=panic_abort,std -p aok_manyatta --release
|
||||||
|
Time Taken: 111.87s
|
||||||
|
|
||||||
|
Command: cargo pkgid -p aok_manyatta
|
||||||
|
Time Taken: 230.01ms
|
||||||
|
|
||||||
|
Command: cargo tree -p aok_manyatta --target=wasm32-unknown-unknown
|
||||||
|
Time Taken: 531.42ms
|
||||||
|
|
||||||
|
|
4
resources/back.svg
Executable file
4
resources/back.svg
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#000" d="M11.025 13.25a.748.748 0 0 1-1.281.53l-5.25-5.264a.75.75 0 0 1 0-1.06L9.717 2.22a.75.75 0 1 1 1.062 1.06L6.084 7.986l4.722 4.734a.748.748 0 0 1 .219.53z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 290 B |
7
resources/help_circle.svg
Normal file
7
resources/help_circle.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
||||||
|
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
|
||||||
|
<path d="M12 17h.01"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 326 B |
1
resources/info.svg
Normal file
1
resources/info.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
29
src/app.rs
29
src/app.rs
|
@ -27,8 +27,8 @@ live_design!(
|
||||||
flow: Overlay,
|
flow: Overlay,
|
||||||
|
|
||||||
home_screen_view = <View> {
|
home_screen_view = <View> {
|
||||||
visible: true
|
// visible: true
|
||||||
home_screen = <HomeScreen> {}
|
home_screen = <HomeScreen> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end of body
|
} // end of body
|
||||||
|
@ -46,11 +46,27 @@ struct App {
|
||||||
|
|
||||||
impl MatchEvent for App {
|
impl MatchEvent for App {
|
||||||
fn handle_startup(&mut self, _cx: &mut Cx) {
|
fn handle_startup(&mut self, _cx: &mut Cx) {
|
||||||
|
// self.stack_navigation(id!(view_stack))
|
||||||
|
// .show_view(id!(main_content_view));
|
||||||
// let home = std::env::var("HOME")
|
// let home = std::env::var("HOME")
|
||||||
// .or_else(|_| std::env::var("USERPROFILE"))
|
// .or_else(|_| std::env::var("USERPROFILE"))
|
||||||
// .expect("home not found");
|
// .expect("home not found");
|
||||||
|
|
||||||
// self.state.load_images(&Path::new(&home).join("Downloads"));
|
// self.state.load_images(&Path::new(&home).join("Downloads"));
|
||||||
|
self.state.new();
|
||||||
|
}
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
||||||
|
// for action in actions {
|
||||||
|
// // match action.as_widget_action().cast() {
|
||||||
|
// let widget_uid = self.ui.widget_uid();
|
||||||
|
// // Navigate to the main content view
|
||||||
|
// cx.widget_action(
|
||||||
|
// widget_uid,
|
||||||
|
// &Scope::default().path,
|
||||||
|
// StackNavigationAction::NavigateTo(live_id!(main_content_view)),
|
||||||
|
// );
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,10 +75,14 @@ impl AppMain for App {
|
||||||
// self.ui
|
// self.ui
|
||||||
// .handle_event(cx, event, &mut Scope::with_data(&mut self.state));
|
// .handle_event(cx, event, &mut Scope::with_data(&mut self.state));
|
||||||
// self.match_event(cx, event);
|
// self.match_event(cx, event);
|
||||||
|
if let Event::WindowGeomChange(window_geom_change_event) = event {
|
||||||
|
self.state.window_geom = Some(window_geom_change_event.new_geom.clone());
|
||||||
|
}
|
||||||
|
// Forward events to the MatchEvent trait implementation.
|
||||||
self.match_event(cx, event);
|
self.match_event(cx, event);
|
||||||
let scope = &mut Scope::with_data(&mut self.state);
|
let scope = &mut Scope::with_data(&mut self.state);
|
||||||
self.ui.handle_event(cx, event, scope);
|
self.ui.handle_event(cx, event, scope);
|
||||||
|
|
||||||
// self.match_event(cx, event);
|
// self.match_event(cx, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +92,9 @@ impl LiveRegister for App {
|
||||||
makepad_widgets::live_design(cx);
|
makepad_widgets::live_design(cx);
|
||||||
crate::shared::live_design(cx);
|
crate::shared::live_design(cx);
|
||||||
crate::home::live_design(cx);
|
crate::home::live_design(cx);
|
||||||
|
crate::services::live_design(cx);
|
||||||
|
crate::howitworks::live_design(cx);
|
||||||
|
crate::footer::live_design(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,41 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use makepad_widgets::event;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub images: Vec<PathBuf>,
|
pub images: Vec<PathBuf>,
|
||||||
|
pub select_choices_values: Vec<Vec<String>>,
|
||||||
|
pub window_geom: Option<event::WindowGeom>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
pub fn new(&mut self) {
|
||||||
|
self.select_choices_values = vec![
|
||||||
|
vec![
|
||||||
|
"STP1-Option 1".to_string(),
|
||||||
|
"STP1-Option 2".to_string(),
|
||||||
|
"STP1-Option 3".to_string(),
|
||||||
|
"STP1-Option 4".to_string(),
|
||||||
|
"STP1-Option 5".to_string(),
|
||||||
|
"STP1-Option 6".to_string(),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
"STP2-Option 1".to_string(),
|
||||||
|
"STP2-Option 2".to_string(),
|
||||||
|
"STP2-Option 3".to_string(),
|
||||||
|
"STP2-Option 4".to_string(),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
"STP3-Option 1".to_string(),
|
||||||
|
"STP3-Option 2".to_string(),
|
||||||
|
"STP3-Option 3".to_string(),
|
||||||
|
"STP3-Option 4".to_string(),
|
||||||
|
"STP3-Option 5".to_string(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
pub fn load_images(&mut self, path: &Path) {
|
pub fn load_images(&mut self, path: &Path) {
|
||||||
self.images = fs::read_dir(path)
|
self.images = fs::read_dir(path)
|
||||||
.expect("unable to read directory")
|
.expect("unable to read directory")
|
||||||
|
|
222
src/footer/footer.rs
Normal file
222
src/footer/footer.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
// use event::{FileUploads, SelectedFilesEvent};
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
use crate::shared::widgets::*;
|
||||||
|
|
||||||
|
BG_COLOR = #3
|
||||||
|
|
||||||
|
pub FooterScreen = {{FooterScreen}} {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
<View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
show_bg: true
|
||||||
|
draw_bg: {
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
return #111827;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
padding: 60.0
|
||||||
|
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right
|
||||||
|
spacing: 30
|
||||||
|
padding: {bottom: 40.0}
|
||||||
|
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
<Label> {
|
||||||
|
text: "ProServices"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 18},
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model_name = <Label> {
|
||||||
|
width: Fill
|
||||||
|
text: "Professional services for all your documentation needs"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 13},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
wrap: Word,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
<Label> {
|
||||||
|
text: "Quick Links"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 15},
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 10
|
||||||
|
services = <Label> {
|
||||||
|
text: "Services"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
howitworks = <Label> {
|
||||||
|
text: "How it Works"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contacts = <Label> {
|
||||||
|
text: "Contacts"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
<Label> {
|
||||||
|
text: "Services"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 15},
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 10
|
||||||
|
services = <Label> {
|
||||||
|
text: "Resume Writing"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
howitworks = <Label> {
|
||||||
|
text: "Business Plans"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contacts = <Label> {
|
||||||
|
text: "Tax Services"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
<Label> {
|
||||||
|
text: "Contacts Info"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 15},
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
spacing: 10
|
||||||
|
services = <Label> {
|
||||||
|
text: "contact@infoservices.com"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
howitworks = <Label> {
|
||||||
|
text: "+254 713 521197"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contacts = <Label> {
|
||||||
|
text: "Nairobi, Kenya"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Line> { draw_bg: { color: #x1f2937 }}
|
||||||
|
<Label> {
|
||||||
|
padding: {top: 5.0}
|
||||||
|
text: "© 2025 ProServices. All rights reserved."
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: (TERTIARY_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct FooterScreen {
|
||||||
|
#[deref]
|
||||||
|
deref: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for FooterScreen {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.deref.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
let _state = scope.data.get::<State>().unwrap();
|
||||||
|
|
||||||
|
self.deref.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for FooterScreen {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let _state = scope.data.get_mut::<State>().unwrap();
|
||||||
|
|
||||||
|
// if self.deref.button(id!(file_button)).clicked(&actions) {
|
||||||
|
// cx.open_file_dialog("image/*");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
7
src/footer/mod.rs
Normal file
7
src/footer/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use makepad_widgets::Cx;
|
||||||
|
|
||||||
|
pub mod footer;
|
||||||
|
|
||||||
|
pub fn live_design(cx: &mut Cx) {
|
||||||
|
footer::live_design(cx);
|
||||||
|
}
|
103
src/home/bar.rs
Normal file
103
src/home/bar.rs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
// use crate::shared::search_bar::SearchBarAction;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
use crate::shared::helpers::*;
|
||||||
|
// use crate::shared::search_bar::SearchBar;
|
||||||
|
|
||||||
|
use crate::home::rooms_list::RoomsList;
|
||||||
|
|
||||||
|
RoomsView = {{RoomsView}} {
|
||||||
|
show_bg: true,
|
||||||
|
draw_bg: {
|
||||||
|
instance bg_color: (COLOR_PRIMARY)
|
||||||
|
instance border_color: #f2f2f2
|
||||||
|
instance border_width: 0.003
|
||||||
|
|
||||||
|
// Draws a right-side border
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
if self.pos.x > 1.0 - self.border_width {
|
||||||
|
return self.border_color;
|
||||||
|
} else {
|
||||||
|
return self.bg_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Label> {
|
||||||
|
text: "Rooms"
|
||||||
|
draw_text: {
|
||||||
|
color: #x0
|
||||||
|
text_style: <TITLE_TEXT>{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub RoomsSideBar = <AdaptiveView> {
|
||||||
|
Desktop = <RoomsView> {
|
||||||
|
padding: {top: 20., left: 10., right: 10.}
|
||||||
|
flow: Down, spacing: 10
|
||||||
|
width: Fill, height: Fill
|
||||||
|
},
|
||||||
|
Mobile = <RoomsView> {
|
||||||
|
padding: {top: 17., left: 17., right: 17.}
|
||||||
|
flow: Down, spacing: 7
|
||||||
|
width: Fill, height: Fill
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, DefaultNone)]
|
||||||
|
pub enum RoomsViewAction {
|
||||||
|
/// Search for rooms
|
||||||
|
Search(String),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Widget, Live, LiveHook)]
|
||||||
|
pub struct RoomsView {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for RoomsView {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for RoomsView {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
// let widget_uid = self.widget_uid();
|
||||||
|
// for action in actions {
|
||||||
|
// match action.as_widget_action().cast() {
|
||||||
|
// SearchBarAction::Search(keywords) => {
|
||||||
|
// cx.widget_action(
|
||||||
|
// widget_uid,
|
||||||
|
// &scope.path,
|
||||||
|
// RoomsViewAction::Search(keywords.clone()),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// SearchBarAction::ResetSearch => {
|
||||||
|
// cx.widget_action(
|
||||||
|
// widget_uid,
|
||||||
|
// &scope.path,
|
||||||
|
// RoomsViewAction::Search("".to_string()),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// _ => {}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
349
src/home/hero.rs
Normal file
349
src/home/hero.rs
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::{data::state::State, shared::choose::choose::NextBackAction};
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::shared::widgets::SmallCard;
|
||||||
|
use crate::shared::choose::choose::Choose;
|
||||||
|
use crate::shared::choose::final_choose::FinalChoose;
|
||||||
|
// use crate::home::choose::Choose;
|
||||||
|
use crate::shared::html_or_plaintext::*;
|
||||||
|
|
||||||
|
BG_COLOR = #3
|
||||||
|
ICON_HELP_CIRCLE = dep("crate://self/resources/help_circle.svg")
|
||||||
|
|
||||||
|
pub HeroScreen = {{HeroScreen}} {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
show_bg: true
|
||||||
|
flow: Right
|
||||||
|
// debug: A
|
||||||
|
|
||||||
|
align: {x: 0.5, y: 0.0},
|
||||||
|
draw_bg: {
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
return (COLOR_SECONDARY);
|
||||||
|
// return #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
padding: 50.0
|
||||||
|
// spacing: -20,
|
||||||
|
|
||||||
|
// debug: A
|
||||||
|
<View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
// padding: {top: -50.0}
|
||||||
|
// spacing: 40,
|
||||||
|
// align: {x: 0.0, y: 0.5},
|
||||||
|
// debug: B
|
||||||
|
|
||||||
|
|
||||||
|
<MessageHtml> {
|
||||||
|
padding: {top: 12, left: 0.}
|
||||||
|
// spacing: -40.
|
||||||
|
font_size: 60.
|
||||||
|
font_color: #x4B5563
|
||||||
|
draw_normal: {
|
||||||
|
color: #000
|
||||||
|
}
|
||||||
|
// a = {
|
||||||
|
// padding: {left: 8., right: 8., top: 4., bottom: 5.},
|
||||||
|
// // draw_text: {
|
||||||
|
// // text_style: <THEME_FONT_BOLD> {top_drop: 1.2, font_size: 11. },
|
||||||
|
// // color: #f,
|
||||||
|
// // color_pressed: #f00,
|
||||||
|
// // color_hover: #0f0,
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// span = {
|
||||||
|
// // padding: {left: 8., right: 8., top: 4., bottom: 5.},
|
||||||
|
// // draw_text: {
|
||||||
|
// // text_style: <THEME_FONT_BOLD> {top_drop: 1.2, font_size: 12. },
|
||||||
|
// // color: #x2563EB,
|
||||||
|
// // // color_pressed: #f00,
|
||||||
|
// // // color_hover: #0f0,
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
body:"<h4>Building, Dreams <span color: x2563EB>Delivering Excellence<span/><h4/>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Here
|
||||||
|
<h1/>
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right
|
||||||
|
// align: {x: 0.5, y: 0.5},
|
||||||
|
// debug: B
|
||||||
|
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fill,
|
||||||
|
flow: Down
|
||||||
|
spacing: 40,
|
||||||
|
// padding: {bottom: 0.}
|
||||||
|
align: {x: 0.0, y: 1.0},
|
||||||
|
// debug: B
|
||||||
|
|
||||||
|
<View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: RightWrap
|
||||||
|
|
||||||
|
// <Label> {
|
||||||
|
// width: Fit
|
||||||
|
// text: "Building, and "
|
||||||
|
// draw_text: {
|
||||||
|
// text_style: <TITLE_TEXT>{font_size: 60},
|
||||||
|
// color: #x4B5563
|
||||||
|
// wrap: Word,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// <Label> {
|
||||||
|
// width: Fit
|
||||||
|
// text: "Delivering Excellence"
|
||||||
|
// draw_text: {
|
||||||
|
// text_style: <TITLE_TEXT>{font_size: 60},
|
||||||
|
// color: #x2563EB
|
||||||
|
// // wrap: Word,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
<P> {
|
||||||
|
width: 650
|
||||||
|
text: "From architectural masterpieces to regulatory compliance, we're your one-stop solution for all construction and design needs."
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 16},
|
||||||
|
color: #4B5563
|
||||||
|
wrap: Word,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View> {
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right
|
||||||
|
spacing: 20
|
||||||
|
// debug: B
|
||||||
|
explore = <MolyButton> {
|
||||||
|
width: 220,
|
||||||
|
height: 60,
|
||||||
|
text: "Explore Services →"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
// color: #x2563EB
|
||||||
|
}
|
||||||
|
draw_bg: { color: #x2563EB, border_color: #x2563EB }
|
||||||
|
}
|
||||||
|
requests = <MolyButton> {
|
||||||
|
width: 220,
|
||||||
|
height: 60,
|
||||||
|
text: "View My Requests >"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
// color: #x2563EB
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_bg: { color: #1a365d, border_color: #x2563EB }
|
||||||
|
}
|
||||||
|
choose = <MolyButton> {
|
||||||
|
width: 220,
|
||||||
|
height: 60,
|
||||||
|
text: "Help Me Choose ⓘ"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
// color: #x2563EB
|
||||||
|
}
|
||||||
|
// draw_icon: {
|
||||||
|
// svg_file: (ICON_HELP_CIRCLE),
|
||||||
|
// fn get_color(self) -> vec4 {
|
||||||
|
// return #B42318;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
draw_bg: { color: #x2563EB, border_color: #x2563EB }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View> {
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right
|
||||||
|
spacing: 20
|
||||||
|
align: {x: 0.0, y: -0.5},
|
||||||
|
// debug: B
|
||||||
|
|
||||||
|
<SmallCard> {
|
||||||
|
width: 220,
|
||||||
|
content = {
|
||||||
|
title ={
|
||||||
|
text: "Expert Team"
|
||||||
|
}
|
||||||
|
description ={
|
||||||
|
text: "Professional architects, engineers, and consultants at your service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<SmallCard> {
|
||||||
|
width: 220,
|
||||||
|
content = {
|
||||||
|
title = {
|
||||||
|
text: "Fast Turnaround"
|
||||||
|
}
|
||||||
|
description ={
|
||||||
|
text: "Quick response times and efficient project completion"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<SmallCard> {
|
||||||
|
width: 220,
|
||||||
|
content = {
|
||||||
|
title ={
|
||||||
|
text: "Quality Assured"
|
||||||
|
}
|
||||||
|
description ={
|
||||||
|
text: "Committed to delivering excellence in every project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Choose = <FinalChoose>{
|
||||||
|
Choose = <Choose>{
|
||||||
|
choices = {
|
||||||
|
indicators = {
|
||||||
|
ind = {
|
||||||
|
// indicator_titles: [
|
||||||
|
// "Step Four",
|
||||||
|
// "Step Five",
|
||||||
|
// "Step Six"
|
||||||
|
// ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
back = {
|
||||||
|
back_left_button = {
|
||||||
|
text: "Back"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps = {}
|
||||||
|
next_button = {
|
||||||
|
next = {
|
||||||
|
text: "Next"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct HeroScreen {
|
||||||
|
#[deref]
|
||||||
|
deref: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, DefaultNone, Debug)]
|
||||||
|
pub enum ButtonClickAction {
|
||||||
|
None,
|
||||||
|
Click,
|
||||||
|
}
|
||||||
|
impl Widget for HeroScreen {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.deref.handle_event(cx, event, scope);
|
||||||
|
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
// if let Event::Actions(actions) = event {
|
||||||
|
// for action in actions {
|
||||||
|
// if self.deref.button(id!(next)).clicked(&actions) {
|
||||||
|
// log!("Hero - Next Button Clicked");
|
||||||
|
|
||||||
|
// let widget_uid = self.deref.widget_uid();
|
||||||
|
// // Navigate to the main content view
|
||||||
|
// cx.widget_action(
|
||||||
|
// widget_uid,
|
||||||
|
// &scope.path,
|
||||||
|
// NextBackAction::NextButton {
|
||||||
|
// clicked: true,
|
||||||
|
// page_no: 0, // You can pass the current page number if needed
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// log!("Hero - Action dispatched: {:?}", widget_uid);
|
||||||
|
// self.redraw(cx);
|
||||||
|
// }
|
||||||
|
// if self.deref.button(id!(back_left_button)).clicked(&actions) {
|
||||||
|
// log!("Hero - Next Button Clicked");
|
||||||
|
|
||||||
|
// let widget_uid = self.deref.widget_uid();
|
||||||
|
// // Navigate to the main content view
|
||||||
|
// cx.widget_action(
|
||||||
|
// widget_uid,
|
||||||
|
// &scope.path,
|
||||||
|
// NextBackAction::BackButton {
|
||||||
|
// clicked: true,
|
||||||
|
// page_no: 0, // You can pass the current page number if needed
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// log!("Hero - Action dispatched: {:?}", widget_uid);
|
||||||
|
// self.redraw(cx);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
let _state = scope.data.get::<State>().unwrap();
|
||||||
|
|
||||||
|
self.deref.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for HeroScreen {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let _state = scope.data.get_mut::<State>().unwrap();
|
||||||
|
if self.deref.button(id!(next)).clicked(&actions) {
|
||||||
|
// log!("Hero - Next Button Clicked");
|
||||||
|
|
||||||
|
let widget_uid = self.deref.widget_uid();
|
||||||
|
// Navigate to the main content view
|
||||||
|
cx.widget_action(
|
||||||
|
widget_uid,
|
||||||
|
&scope.path,
|
||||||
|
NextBackAction::NextButton {
|
||||||
|
clicked: true,
|
||||||
|
page_no: 0, // You can pass the current page number if needed
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// log!("Hero - Action dispatched: {:?}", widget_uid);
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
if self.deref.button(id!(back_left_button)).clicked(&actions) {
|
||||||
|
// log!("Hero - Next Button Clicked");
|
||||||
|
|
||||||
|
let widget_uid = self.deref.widget_uid();
|
||||||
|
// Navigate to the main content view
|
||||||
|
cx.widget_action(
|
||||||
|
widget_uid,
|
||||||
|
&scope.path,
|
||||||
|
NextBackAction::BackButton {
|
||||||
|
clicked: true,
|
||||||
|
page_no: 0, // You can pass the current page number if needed
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// log!("Hero - Action dispatched: {:?}", widget_uid);
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
// if self.deref.button(id!(file_button)).clicked(&actions) {
|
||||||
|
// cx.open_file_dialog("image/*");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ live_design! {
|
||||||
use crate::shared::styles::*;
|
use crate::shared::styles::*;
|
||||||
use crate::home::main_desktop_ui::MainDesktopUI;
|
use crate::home::main_desktop_ui::MainDesktopUI;
|
||||||
use crate::home::main_web_ui::MainWebUI;
|
use crate::home::main_web_ui::MainWebUI;
|
||||||
|
use crate::home::bar::RoomsSideBar;
|
||||||
|
|
||||||
NavigationWrapper = {{NavigationWrapper}} {
|
NavigationWrapper = {{NavigationWrapper}} {
|
||||||
view_stack = <StackNavigation> {}
|
view_stack = <StackNavigation> {}
|
||||||
|
@ -46,6 +47,8 @@ live_design! {
|
||||||
padding: {top: 40.}
|
padding: {top: 40.}
|
||||||
flow: Down
|
flow: Down
|
||||||
width: Fill, height: Fill
|
width: Fill, height: Fill
|
||||||
|
sidebar = <RoomsSideBar> {}
|
||||||
|
// spaces = <SpacesDock> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
main_content_view = <StackNavigationView> {
|
main_content_view = <StackNavigationView> {
|
||||||
|
@ -136,5 +139,7 @@ impl MatchEvent for NavigationWrapper {
|
||||||
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
|
||||||
self.stack_navigation(id!(view_stack))
|
self.stack_navigation(id!(view_stack))
|
||||||
.handle_stack_view_actions(cx, actions);
|
.handle_stack_view_actions(cx, actions);
|
||||||
|
// self.stack_navigation(id!(view_stack))
|
||||||
|
// .show_view(id!(main_content_view));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,61 +5,88 @@ use crate::data::state::State;
|
||||||
|
|
||||||
live_design! {
|
live_design! {
|
||||||
use link::theme::*;
|
use link::theme::*;
|
||||||
use link::shaders::*;
|
// use link::shaders::*;
|
||||||
use link::widgets::*;
|
use link::widgets::*;
|
||||||
|
|
||||||
use crate::shared::styles::*;
|
use crate::shared::styles::*;
|
||||||
BG_COLOR = #3
|
// use crate::shared::widgets::*;
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::services::services::ServicesScreen;
|
||||||
|
use crate::howitworks::howitworks::HowItWorksScreen;
|
||||||
|
use crate::footer::footer::FooterScreen;
|
||||||
|
use crate::home::hero::HeroScreen;
|
||||||
|
|
||||||
|
BG_COLOR = #f9fafb
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub LandingScreen = {{LandingScreen}} {
|
pub LandingScreen = {{LandingScreen}} {
|
||||||
flow: Down
|
flow: Down
|
||||||
padding: { top: 30 }
|
// padding: { top: 30 }
|
||||||
show_bg: true
|
show_bg: true
|
||||||
draw_bg: {
|
draw_bg: {
|
||||||
fn pixel(self) -> vec4 {
|
fn pixel(self) -> vec4 {
|
||||||
return (BG_COLOR);
|
return (BG_COLOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body = <View> { width: 0, height: 0 }
|
// body = <View> { width: 0, height: 0 }
|
||||||
<View>{
|
|
||||||
flow: Right
|
|
||||||
height: Fit
|
|
||||||
file_button = <Button> {
|
|
||||||
text: "Select Images"
|
|
||||||
draw_text: { color: #fff }
|
|
||||||
}
|
|
||||||
jump_to_2= <Button> {
|
|
||||||
text: "Jump to 2"
|
|
||||||
draw_text:{color:#fff}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<View>{
|
|
||||||
flow: Right
|
|
||||||
|
|
||||||
img_list = <PortalList> {
|
<ScrollYView> {
|
||||||
img_btn = <Button> {
|
width: Fill,
|
||||||
width: Fill
|
height: Fill,
|
||||||
|
flow: Down
|
||||||
|
// spacing: 10,
|
||||||
|
// align: {x: 0.5, y: 0.5},
|
||||||
|
|
||||||
|
<HeroScreen>{}
|
||||||
|
<ServicesScreen>{}
|
||||||
|
<HowItWorksScreen>{}
|
||||||
|
<FooterScreen>{}
|
||||||
|
<View>{
|
||||||
|
flow: Right
|
||||||
|
height: Fit
|
||||||
|
file_button = <MolyButton> {
|
||||||
|
width: 140,
|
||||||
|
height: 32,
|
||||||
|
text: "Select Images"
|
||||||
|
draw_bg: { color: #099250, border_color: #099250 }
|
||||||
}
|
}
|
||||||
img_text = <Label> {
|
jump_to_2= <MolyButton> {
|
||||||
width: Fill
|
width: 140,
|
||||||
draw_text: {
|
height: 32,
|
||||||
// text_style: <TEXT_BOLD> {},
|
text: "Jump to 2"
|
||||||
instance hover: 0.0
|
draw_bg: { color: #099250, border_color: #099250 }
|
||||||
instance down: 0.0
|
|
||||||
fn get_color(self) -> vec4 {
|
|
||||||
return mix(mix(#xFFFA, #xFFFF, self.hover), #xFFF8, self.down);
|
|
||||||
}
|
|
||||||
wrap: Word,
|
|
||||||
}
|
|
||||||
text: "Hello World"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
img = <Image> {
|
<View>{
|
||||||
width: Fill
|
flow: Right
|
||||||
height: Fill
|
|
||||||
fit: Smallest
|
img_list = <PortalList> {
|
||||||
|
img_btn = <Button> {
|
||||||
|
width: Fill
|
||||||
|
}
|
||||||
|
img_text = <Label> {
|
||||||
|
width: Fill
|
||||||
|
draw_text: {
|
||||||
|
// text_style: <TEXT_BOLD> {},
|
||||||
|
instance hover: 0.0
|
||||||
|
instance down: 0.0
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return mix(mix(#xFFFA, #xFFFF, self.hover), #xFFF8, self.down);
|
||||||
|
}
|
||||||
|
wrap: Word,
|
||||||
|
}
|
||||||
|
text: "Hello World"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img = <Image> {
|
||||||
|
width: Fill
|
||||||
|
height: Fill
|
||||||
|
fit: Smallest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,23 +12,11 @@ live_design!(
|
||||||
|
|
||||||
|
|
||||||
pub MainDesktopUI = {{MainDesktopUI}} {
|
pub MainDesktopUI = {{MainDesktopUI}} {
|
||||||
align: {x: 0.5, y: 0.5}
|
// align: {x: 0.5, y: 0.5}
|
||||||
|
|
||||||
body = <View>{
|
body = <View>{
|
||||||
flow: Down
|
flow: Down
|
||||||
width: Fit
|
// padding: {top: 20., left: 10., right: 10.}
|
||||||
<Label> {
|
|
||||||
text: "HEY, MY NAME IS ODEKI KEGODE ANDREW (DESKTOP)"
|
|
||||||
draw_text: {
|
|
||||||
text_style: <TEXT_BOLD> {},
|
|
||||||
instance hover: 0.0
|
|
||||||
instance down: 0.0
|
|
||||||
fn get_color(self) -> vec4 {
|
|
||||||
return mix(mix(#x06060E, #x5C0B11, self.hover), #x76AEAA, self.down);
|
|
||||||
}
|
|
||||||
wrap: Word,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<LandingScreen>{}
|
<LandingScreen>{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,20 +13,6 @@ live_design!(
|
||||||
|
|
||||||
body = <View>{
|
body = <View>{
|
||||||
flow: Down
|
flow: Down
|
||||||
width: Fit
|
|
||||||
|
|
||||||
<Label> {
|
|
||||||
text: "HEY, MY NAME IS ODEKI KEGODE ANDREW (MOBILE)"
|
|
||||||
draw_text: {
|
|
||||||
text_style: <TEXT_BOLD> {},
|
|
||||||
instance hover: 0.0
|
|
||||||
instance down: 0.0
|
|
||||||
fn get_color(self) -> vec4 {
|
|
||||||
return mix(mix(#x06060E, #x5C0B11, self.hover), #x76AEAA, self.down);
|
|
||||||
}
|
|
||||||
wrap: Word,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<LandingScreen>{}
|
<LandingScreen>{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,20 +13,6 @@ live_design!(
|
||||||
|
|
||||||
body = <View>{
|
body = <View>{
|
||||||
flow: Down
|
flow: Down
|
||||||
width: Fit
|
|
||||||
|
|
||||||
<Label> {
|
|
||||||
text: "HEY, MY NAME IS ODEKI KEGODE ANDREW (WEB)"
|
|
||||||
draw_text: {
|
|
||||||
text_style: <TEXT_BOLD> {},
|
|
||||||
instance hover: 0.0
|
|
||||||
instance down: 0.0
|
|
||||||
fn get_color(self) -> vec4 {
|
|
||||||
return mix(mix(#x06060E, #x5C0B11, self.hover), #x76AEAA, self.down);
|
|
||||||
}
|
|
||||||
wrap: Word,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<LandingScreen>{}
|
<LandingScreen>{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use makepad_widgets::Cx;
|
use makepad_widgets::Cx;
|
||||||
|
|
||||||
|
pub mod bar;
|
||||||
|
pub mod choose;
|
||||||
|
pub mod hero;
|
||||||
pub mod home_screen;
|
pub mod home_screen;
|
||||||
pub mod landing_screen;
|
pub mod landing_screen;
|
||||||
pub mod main_desktop_ui;
|
pub mod main_desktop_ui;
|
||||||
|
@ -15,6 +18,9 @@ pub fn live_design(cx: &mut Cx) {
|
||||||
main_mobile_ui::live_design(cx);
|
main_mobile_ui::live_design(cx);
|
||||||
main_desktop_ui::live_design(cx);
|
main_desktop_ui::live_design(cx);
|
||||||
main_web_ui::live_design(cx);
|
main_web_ui::live_design(cx);
|
||||||
|
hero::live_design(cx);
|
||||||
|
bar::live_design(cx);
|
||||||
|
choose::live_design(cx);
|
||||||
// ////
|
// ////
|
||||||
// ui::live_design(cx);
|
// ui::live_design(cx);
|
||||||
// welcome_screen::live_design(cx);
|
// welcome_screen::live_design(cx);
|
||||||
|
|
197
src/howitworks/howitworks.rs
Normal file
197
src/howitworks/howitworks.rs
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
// use event::{FileUploads, SelectedFilesEvent};
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::shared::widgets::Avatar;
|
||||||
|
|
||||||
|
BG_COLOR = #f9fafb
|
||||||
|
|
||||||
|
pub HowItWorksScreen = {{HowItWorksScreen}} {
|
||||||
|
padding: { top: 30 }
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
|
||||||
|
<View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
show_bg: true
|
||||||
|
draw_bg: {
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
return #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
padding: 40.0
|
||||||
|
|
||||||
|
<Label> {
|
||||||
|
text: "How It Works"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 30},
|
||||||
|
color: #111827
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right
|
||||||
|
one = <View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
avatar = <Avatar> {
|
||||||
|
width: 70
|
||||||
|
height: 70
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
radius: 18.0
|
||||||
|
color: #xdbeafe
|
||||||
|
}
|
||||||
|
avatar_label = {
|
||||||
|
text: "1"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 20},
|
||||||
|
color: #x2563eb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<Label> {
|
||||||
|
text: "Choose Your Service"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
color: #111827
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Label> {
|
||||||
|
text: "Select from our wide range of professional services"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: #x4b5563
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
two = <View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
avatar = <Avatar> {
|
||||||
|
width: 70
|
||||||
|
height: 70
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
radius: 18.0
|
||||||
|
color: #xdbeafe
|
||||||
|
}
|
||||||
|
avatar_label = {
|
||||||
|
text: "2"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 20},
|
||||||
|
color: #x2563eb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Label> {
|
||||||
|
text: "Submit Requirements"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
color: #111827
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Label> {
|
||||||
|
text: "Provide necessary information and documents"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: #x4b5563
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
three = <View>{
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
flow: Down
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
avatar = <Avatar> {
|
||||||
|
width: 70
|
||||||
|
height: 70
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
radius: 18.0
|
||||||
|
color: #xdbeafe
|
||||||
|
}
|
||||||
|
avatar_label = {
|
||||||
|
text: "3"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 20},
|
||||||
|
color: #x2563eb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Label> {
|
||||||
|
text: "Get Results"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
color: #111827
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<Label> {
|
||||||
|
width: Fill
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
text: "Receive your completed service within the promised timeline"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TITLE_TEXT>{font_size: 12},
|
||||||
|
color: #x4b5563
|
||||||
|
wrap: Word,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct HowItWorksScreen {
|
||||||
|
#[deref]
|
||||||
|
deref: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for HowItWorksScreen {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.deref.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
let _state = scope.data.get::<State>().unwrap();
|
||||||
|
|
||||||
|
self.deref.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for HowItWorksScreen {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let _state = scope.data.get_mut::<State>().unwrap();
|
||||||
|
|
||||||
|
// if self.deref.button(id!(file_button)).clicked(&actions) {
|
||||||
|
// cx.open_file_dialog("image/*");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
7
src/howitworks/mod.rs
Normal file
7
src/howitworks/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use makepad_widgets::Cx;
|
||||||
|
|
||||||
|
pub mod howitworks;
|
||||||
|
|
||||||
|
pub fn live_design(cx: &mut Cx) {
|
||||||
|
howitworks::live_design(cx);
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
pub mod app;
|
pub mod app;
|
||||||
mod data;
|
mod data;
|
||||||
mod home;
|
mod home;
|
||||||
|
mod howitworks;
|
||||||
|
mod services;
|
||||||
mod shared;
|
mod shared;
|
||||||
|
mod footer;
|
||||||
|
|
525
src/services/chat_history_card.rs
Normal file
525
src/services/chat_history_card.rs
Normal file
|
@ -0,0 +1,525 @@
|
||||||
|
use crate::{
|
||||||
|
data::{chats::chat::ChatID, store::Store},
|
||||||
|
shared::modal::ModalWidgetExt,
|
||||||
|
};
|
||||||
|
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
chat_history_card_options::ChatHistoryCardOptionsWidgetExt,
|
||||||
|
// delete_chat_modal::DeleteChatModalAction,
|
||||||
|
};
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
use crate::shared::widgets::*;
|
||||||
|
use crate::shared::modal::*;
|
||||||
|
use crate::chat::shared::Avatar;
|
||||||
|
use crate::chat::chat_history_card_options::ChatHistoryCardOptions;
|
||||||
|
// use crate::chat::delete_chat_modal::DeleteChatModal;
|
||||||
|
|
||||||
|
ICON_DELETE = dep("crate://self/resources/icons/delete.svg")
|
||||||
|
|
||||||
|
EditTextInput = <MolyTextInput> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
padding: 0,
|
||||||
|
empty_message: ""
|
||||||
|
|
||||||
|
draw_text: {
|
||||||
|
text_style:<REGULAR_FONT>{font_size: 10},
|
||||||
|
word: Wrap,
|
||||||
|
|
||||||
|
instance prompt_enabled: 0.0
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditActionButton = <MolyButton> {
|
||||||
|
width: 56,
|
||||||
|
height: 31,
|
||||||
|
spacing: 6,
|
||||||
|
|
||||||
|
draw_bg: { color: #099250 }
|
||||||
|
|
||||||
|
draw_text: {
|
||||||
|
text_style: <REGULAR_FONT>{font_size: 9},
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveButton = <EditActionButton> {
|
||||||
|
text: "Save"
|
||||||
|
}
|
||||||
|
|
||||||
|
CancelButton = <EditActionButton> {
|
||||||
|
draw_bg: { border_color: #D0D5DD, border_width: 1.0, color: #fff }
|
||||||
|
|
||||||
|
draw_text: {
|
||||||
|
text_style: <REGULAR_FONT>{font_size: 9},
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text: "Cancel"
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatHistoryCard = {{ChatHistoryCard}} {
|
||||||
|
flow: Overlay,
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
|
||||||
|
content = <RoundedView> {
|
||||||
|
flow: Down
|
||||||
|
width: 248
|
||||||
|
height: Fit
|
||||||
|
padding: 20
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
cursor: Hand
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
color: #fff
|
||||||
|
border_width: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
<View> {
|
||||||
|
width: Fill
|
||||||
|
height: Fit
|
||||||
|
flow: Right
|
||||||
|
spacing: 10
|
||||||
|
padding: { top: 4, bottom: 4 }
|
||||||
|
margin: 0
|
||||||
|
|
||||||
|
title_wrapper = <RoundedView> {
|
||||||
|
show_bg: true,
|
||||||
|
draw_bg: {
|
||||||
|
radius: 12.0,
|
||||||
|
},
|
||||||
|
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down,
|
||||||
|
align: {x: 0.5, y: 0.0},
|
||||||
|
|
||||||
|
title_input_container = <View> {
|
||||||
|
visible: false,
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
title_input = <EditTextInput> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
title_label_container = <View> {
|
||||||
|
visible: false,
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
|
||||||
|
title_label = <Label> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
draw_text:{
|
||||||
|
text_style: <BOLD_FONT>{font_size: 10},
|
||||||
|
color: #000,
|
||||||
|
}
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edit_buttons = <View> {
|
||||||
|
visible: false,
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
margin: {top: 10},
|
||||||
|
spacing: 6,
|
||||||
|
save = <SaveButton> {}
|
||||||
|
cancel = <CancelButton> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is horrible, find a way of getting the position of the button.
|
||||||
|
chat_options_wrapper = <View> {
|
||||||
|
width: Fit
|
||||||
|
height: Fit
|
||||||
|
padding: 4
|
||||||
|
|
||||||
|
chat_options = <MolyButton> {
|
||||||
|
width: Fit
|
||||||
|
height: Fit
|
||||||
|
padding: {top: 0, right: 4, bottom: 6, left: 4}
|
||||||
|
margin: { top: -4}
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
radius: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_text:{
|
||||||
|
text_style: <BOLD_FONT>{font_size: 14},
|
||||||
|
color: #667085,
|
||||||
|
}
|
||||||
|
text: "..."
|
||||||
|
|
||||||
|
reset_hover_on_click: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<View> {
|
||||||
|
width: Fill
|
||||||
|
height: Fit
|
||||||
|
align: {y: 1}
|
||||||
|
|
||||||
|
avatar = <ChatAgentAvatar> {
|
||||||
|
width: 30
|
||||||
|
height: 30
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
radius: 8
|
||||||
|
}
|
||||||
|
avatar_label = {
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filler = <View> {width: Fill}
|
||||||
|
|
||||||
|
date = <Label> {
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
draw_text:{
|
||||||
|
text_style: <REGULAR_FONT>{font_size: 10},
|
||||||
|
color: #667085,
|
||||||
|
}
|
||||||
|
text: "5:29 PM, 5/12/24"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chat_history_card_options_modal = <Modal> {
|
||||||
|
align: {x: 0.0, y: 0.0}
|
||||||
|
bg_view: {
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
chat_history_card_options = <ChatHistoryCardOptions> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_chat_modal = <Modal> {
|
||||||
|
content: {
|
||||||
|
delete_chat_modal_inner = <DeleteChatModal> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, PartialEq)]
|
||||||
|
enum TitleState {
|
||||||
|
OnEdit,
|
||||||
|
#[default]
|
||||||
|
Editable,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct ChatHistoryCard {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
#[rust]
|
||||||
|
chat_id: ChatID,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
title_edition_state: TitleState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for ChatHistoryCard {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
let store = scope.data.get_mut::<Store>().unwrap();
|
||||||
|
let chat = store
|
||||||
|
.chats
|
||||||
|
.saved_chats
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.borrow().id == self.chat_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(current_chat_id) = store.chats.get_current_chat_id() {
|
||||||
|
let content_view = self.view(id!(content));
|
||||||
|
|
||||||
|
if current_chat_id == self.chat_id {
|
||||||
|
let active_border_color = vec3(0.082, 0.522, 0.604);
|
||||||
|
content_view.apply_over(
|
||||||
|
cx,
|
||||||
|
live! {
|
||||||
|
draw_bg: {border_color: (active_border_color)}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let border_color = vec3(0.918, 0.925, 0.941);
|
||||||
|
content_view.apply_over(
|
||||||
|
cx,
|
||||||
|
live! {
|
||||||
|
draw_bg: {border_color: (border_color)}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_title_text(chat.borrow_mut().get_title());
|
||||||
|
self.update_title_visibility(cx);
|
||||||
|
|
||||||
|
let initial_letter = store
|
||||||
|
.get_last_used_file_initial_letter(self.chat_id)
|
||||||
|
.unwrap_or('A')
|
||||||
|
.to_uppercase()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let avatar_label = self.view.label(id!(avatar.avatar_label));
|
||||||
|
avatar_label.set_text(&initial_letter);
|
||||||
|
|
||||||
|
let date_label = self.view.label(id!(date));
|
||||||
|
|
||||||
|
// Format date.
|
||||||
|
// TODO: Feels wrong to asume the id will always be the date, do smth about this.
|
||||||
|
let datetime =
|
||||||
|
DateTime::from_timestamp_millis(chat.borrow().id as i64).expect("Invalid timestamp");
|
||||||
|
let local_datetime: DateTime<Local> = Local.from_utc_datetime(&datetime.naive_utc());
|
||||||
|
if let Some(formatted_date) = relative_format(local_datetime) {
|
||||||
|
date_label.set_text(&formatted_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for ChatHistoryCard {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
// let widget_uid = self.widget_uid();
|
||||||
|
|
||||||
|
match self.title_edition_state {
|
||||||
|
TitleState::Editable => self.handle_title_editable_actions(cx, actions, scope),
|
||||||
|
TitleState::OnEdit => self.handle_title_on_edit_actions(cx, actions, scope),
|
||||||
|
}
|
||||||
|
|
||||||
|
let chat_options_wrapper_rect = self.view(id!(chat_options_wrapper)).area().rect(cx);
|
||||||
|
if self.button(id!(chat_options)).clicked(actions) {
|
||||||
|
let wrapper_coords = chat_options_wrapper_rect.pos;
|
||||||
|
let coords = dvec2(
|
||||||
|
wrapper_coords.x,
|
||||||
|
wrapper_coords.y + chat_options_wrapper_rect.size.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.chat_history_card_options(id!(chat_history_card_options))
|
||||||
|
.selected(cx, self.chat_id);
|
||||||
|
|
||||||
|
let modal = self.modal(id!(chat_history_card_options_modal));
|
||||||
|
modal.apply_over(
|
||||||
|
cx,
|
||||||
|
live! {
|
||||||
|
content: { margin: { left: (coords.x), top: (coords.y) } }
|
||||||
|
},
|
||||||
|
);
|
||||||
|
modal.open(cx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fe) = self.view(id!(content)).finger_down(actions) {
|
||||||
|
if fe.tap_count == 1 {
|
||||||
|
cx.action(ChatHistoryCardAction::ChatSelected);
|
||||||
|
let store = scope.data.get_mut::<Store>().unwrap();
|
||||||
|
store.chats.set_current_chat(self.chat_id);
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for action in actions {
|
||||||
|
if matches!(
|
||||||
|
action.cast(),
|
||||||
|
DeleteChatModalAction::Cancelled
|
||||||
|
| DeleteChatModalAction::CloseButtonClicked
|
||||||
|
| DeleteChatModalAction::ChatDeleted
|
||||||
|
) {
|
||||||
|
self.modal(id!(delete_chat_modal)).close(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChatHistoryCard {
|
||||||
|
pub fn set_chat_id(&mut self, id: ChatID) {
|
||||||
|
if id != self.chat_id {
|
||||||
|
self.chat_id = id;
|
||||||
|
self.title_edition_state = TitleState::Editable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_title_text(&mut self, text: &str) {
|
||||||
|
self.view.label(id!(title_label)).set_text(text.trim());
|
||||||
|
if let TitleState::Editable = self.title_edition_state {
|
||||||
|
self.view.text_input(id!(title_input)).set_text(text.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_title_visibility(&mut self, cx: &mut Cx) {
|
||||||
|
let on_edit = matches!(self.title_edition_state, TitleState::OnEdit);
|
||||||
|
self.view(id!(edit_buttons)).set_visible(on_edit);
|
||||||
|
self.view(id!(title_input_container)).set_visible(on_edit);
|
||||||
|
self.button(id!(chat_options)).set_visible(!on_edit);
|
||||||
|
|
||||||
|
let editable = matches!(self.title_edition_state, TitleState::Editable);
|
||||||
|
self.view(id!(title_label_container)).set_visible(editable);
|
||||||
|
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition_title_state(&mut self, cx: &mut Cx) {
|
||||||
|
self.title_edition_state = match self.title_edition_state {
|
||||||
|
TitleState::OnEdit => TitleState::Editable,
|
||||||
|
TitleState::Editable => TitleState::OnEdit,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.update_title_visibility(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_title_editable_actions(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut Cx,
|
||||||
|
actions: &Actions,
|
||||||
|
_scope: &mut Scope,
|
||||||
|
) {
|
||||||
|
for action in actions {
|
||||||
|
match action.cast() {
|
||||||
|
ChatHistoryCardAction::MenuClosed(chat_id) => {
|
||||||
|
if chat_id == self.chat_id {
|
||||||
|
self.button(id!(chat_options)).reset_hover(cx);
|
||||||
|
self.modal(id!(chat_history_card_options_modal)).close(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChatHistoryCardAction::ActivateTitleEdition(chat_id) => {
|
||||||
|
if chat_id == self.chat_id {
|
||||||
|
self.transition_title_state(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChatHistoryCardAction::DeleteChatOptionSelected(chat_id) => {
|
||||||
|
if chat_id == self.chat_id {
|
||||||
|
let mut delete_modal_inner =
|
||||||
|
self.delete_chat_modal(id!(delete_chat_modal_inner));
|
||||||
|
delete_modal_inner.set_chat_id(self.chat_id);
|
||||||
|
|
||||||
|
self.modal(id!(delete_chat_modal)).open(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the modal is dissmised (such as, clicking outside) we need to reset the hover state
|
||||||
|
// of the open chat options button.
|
||||||
|
if self
|
||||||
|
.modal(id!(chat_history_card_options_modal))
|
||||||
|
.dismissed(actions)
|
||||||
|
{
|
||||||
|
self.button(id!(chat_options)).reset_hover(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_title_on_edit_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let store = scope.data.get_mut::<Store>().unwrap();
|
||||||
|
|
||||||
|
if self.button(id!(save)).clicked(actions) {
|
||||||
|
let updated_title = self.text_input(id!(title_input)).text();
|
||||||
|
let chat = store
|
||||||
|
.chats
|
||||||
|
.saved_chats
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.borrow().id == self.chat_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !updated_title.trim().is_empty() && chat.borrow().get_title() != updated_title {
|
||||||
|
chat.borrow_mut().set_title(updated_title.clone());
|
||||||
|
chat.borrow().save();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.transition_title_state(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(val) = self.text_input(id!(title_input)).returned(actions) {
|
||||||
|
let chat = store
|
||||||
|
.chats
|
||||||
|
.saved_chats
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.borrow().id == self.chat_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !val.trim().is_empty() && chat.borrow().get_title() != val {
|
||||||
|
chat.borrow_mut().set_title(val.clone());
|
||||||
|
chat.borrow().save();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.transition_title_state(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.button(id!(cancel)).clicked(actions) {
|
||||||
|
self.transition_title_state(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChatHistoryCardRef {
|
||||||
|
pub fn set_chat_id(&mut self, id: ChatID) -> Result<(), &'static str> {
|
||||||
|
let Some(mut inner) = self.borrow_mut() else {
|
||||||
|
return Err("Widget not found in the document");
|
||||||
|
};
|
||||||
|
|
||||||
|
inner.set_chat_id(id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, DefaultNone, Eq, Hash, PartialEq, Debug)]
|
||||||
|
pub enum ChatHistoryCardAction {
|
||||||
|
None,
|
||||||
|
ChatSelected,
|
||||||
|
ActivateTitleEdition(ChatID),
|
||||||
|
MenuClosed(ChatID),
|
||||||
|
DeleteChatOptionSelected(ChatID),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn relative_format(datetime: DateTime<Local>) -> Option<String> {
|
||||||
|
|
||||||
|
// Calculate the time difference between now and the given timestamp
|
||||||
|
let now = Local::now();
|
||||||
|
let duration = now - datetime;
|
||||||
|
|
||||||
|
// Handle different time ranges and format accordingly
|
||||||
|
if duration < Duration::seconds(60) {
|
||||||
|
Some("Now".to_string())
|
||||||
|
} else if duration < Duration::minutes(60) {
|
||||||
|
let minutes_text = if duration.num_minutes() == 1 { "min" } else { "mins" };
|
||||||
|
Some(format!("{} {} ago", duration.num_minutes(), minutes_text))
|
||||||
|
} else if duration < Duration::hours(24) && now.date_naive() == datetime.date_naive() {
|
||||||
|
Some(format!("{}", datetime.format("%H:%M"))) // "HH:MM" format for today
|
||||||
|
} else if duration < Duration::hours(48) {
|
||||||
|
if let Some(yesterday) = now.date_naive().succ_opt() {
|
||||||
|
if yesterday == datetime.date_naive() {
|
||||||
|
return Some(format!("Yesterday at {}", datetime.format("%H:%M")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(format!("{}", datetime.format("%A"))) // Fallback to day of the week if not yesterday
|
||||||
|
} else if duration < Duration::weeks(1) {
|
||||||
|
Some(format!("{}", datetime.format("%A"))) // Day of the week (e.g., "Tuesday")
|
||||||
|
} else {
|
||||||
|
Some(format!("{}", datetime.format("%F"))) // "YYYY-MM-DD" format for older messages
|
||||||
|
}
|
||||||
|
}
|
7
src/services/mod.rs
Normal file
7
src/services/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use makepad_widgets::Cx;
|
||||||
|
|
||||||
|
pub mod services;
|
||||||
|
|
||||||
|
pub fn live_design(cx: &mut Cx) {
|
||||||
|
services::live_design(cx);
|
||||||
|
}
|
103
src/services/services.rs
Normal file
103
src/services/services.rs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// use event::{FileUploads, SelectedFilesEvent};
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
|
||||||
|
BG_COLOR = #3
|
||||||
|
|
||||||
|
pub ServicesScreen = {{ServicesScreen}} {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
<View> {
|
||||||
|
width: Fill,
|
||||||
|
height: Fit,
|
||||||
|
flow: Down
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
|
||||||
|
<Label> {
|
||||||
|
text: "Our Services"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <BOLD_FONT>{font_size: 30},
|
||||||
|
color: #111827
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, LiveHook, Widget)]
|
||||||
|
pub struct ServicesScreen {
|
||||||
|
#[deref]
|
||||||
|
deref: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for ServicesScreen {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.deref.handle_event(cx, event, scope);
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
let _state = scope.data.get::<State>().unwrap();
|
||||||
|
|
||||||
|
self.deref.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for ServicesScreen {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
let _state = scope.data.get_mut::<State>().unwrap();
|
||||||
|
|
||||||
|
// if self.deref.button(id!(file_button)).clicked(&actions) {
|
||||||
|
// cx.open_file_dialog("image/*");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn handle_file_uploads(&mut self, cx: &mut Cx, e: &SelectedFilesEvent, scope: &mut Scope) {
|
||||||
|
// for event in e {
|
||||||
|
// match &event.file {
|
||||||
|
// FileUploads::SelectedFile(file) => {
|
||||||
|
// // if let Some(data) = file.get_file_upload_data() {
|
||||||
|
// // log!("File size: {:?} bytes", data);
|
||||||
|
// // }
|
||||||
|
// log!("File size: {:?} bytes", file.get_file_name());
|
||||||
|
// // alright we got an image back
|
||||||
|
// // match event.request_id {
|
||||||
|
// // live_id!(llm)=>if let Some(res) = file.get.get_string_body() {
|
||||||
|
// // // lets parse it as json
|
||||||
|
// // // if let Ok(val) = JsonValue::deserialize_json(&res){
|
||||||
|
// // // if let Some(val) = val.key("content"){
|
||||||
|
// // // if let Some(val) = val.string(){
|
||||||
|
// // // if let Some((LLMMsg::Progress,_)) = self.llm_chat.last(){
|
||||||
|
// // // self.llm_chat.pop();
|
||||||
|
// // // }
|
||||||
|
// // // let val = val.strip_prefix("assistant").unwrap_or(val);
|
||||||
|
// // // let val = val.to_string().replace("\"","");
|
||||||
|
// // // let val = val.trim();
|
||||||
|
// // // self.ui.text_input(id!(prompt_input)).set_text(cx, &val);
|
||||||
|
// // // self.llm_chat.push((LLMMsg::AI,val.into()));
|
||||||
|
// // // self.ui.widget(id!(llm_chat)).redraw(cx);
|
||||||
|
// // // }
|
||||||
|
// // // }
|
||||||
|
// // // else{
|
||||||
|
// // // log!("{}", res);
|
||||||
|
// // // }
|
||||||
|
// // // }
|
||||||
|
// // // else{
|
||||||
|
// // // log!("{}", res);
|
||||||
|
// // // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// _ => (),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
226
src/shared/choose/choose.rs
Normal file
226
src/shared/choose/choose.rs
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::choose::steps::Steps;
|
||||||
|
use crate::shared::choose::selectoptions::ButChoices;
|
||||||
|
use crate::shared::choose::steps::StepsScreen;
|
||||||
|
use crate::shared::choose::indicator::Indicators;
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
|
||||||
|
|
||||||
|
pub Choose = {{Choose}}{
|
||||||
|
// debug: A
|
||||||
|
width: Fit,
|
||||||
|
// height: Fill,
|
||||||
|
height: 488,
|
||||||
|
// height: Fit,
|
||||||
|
padding: {left: 50.}, spacing: 20
|
||||||
|
// align: {x: 0.5, y: 0.5}
|
||||||
|
choices = <View>{
|
||||||
|
// debug: A
|
||||||
|
flow: Down,
|
||||||
|
width: Fit,
|
||||||
|
// height: Fill,
|
||||||
|
// spacing: 20
|
||||||
|
align: {y: 0.5}
|
||||||
|
indicators = <View>{
|
||||||
|
// debug: A
|
||||||
|
height: Fit,
|
||||||
|
width: Fit,
|
||||||
|
margin: {bottom: 20.0}
|
||||||
|
ind = <Indicators>{
|
||||||
|
indicator_titles: [
|
||||||
|
"Step One",
|
||||||
|
"Step Two",
|
||||||
|
"Step Three"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
back = <View> {
|
||||||
|
// debug: A
|
||||||
|
width: Fit, height: Fit,
|
||||||
|
back_left_button = <Button> {
|
||||||
|
width: Fit, height: Fit,
|
||||||
|
icon_walk: {width: 10, height: Fit}
|
||||||
|
text: "Back"
|
||||||
|
draw_text: {
|
||||||
|
text_style: <REGULAR_TEXT>{font_size: 10.},
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return #016def
|
||||||
|
return mix(mix(#000, #000, self.hover), #000, self.pressed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_bg: {
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
let sdf = Sdf2d::viewport(self.pos * self.rect_size);
|
||||||
|
return sdf.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_icon: {
|
||||||
|
svg_file: dep("crate://self/resources/back.svg"),
|
||||||
|
// color: (THEME_COLOR_TEXT_DEFAULT);
|
||||||
|
color: #016def;
|
||||||
|
brightness: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps = <Steps>{
|
||||||
|
page_template: <StepsScreen> {}
|
||||||
|
selects_template: <ButChoices> {}
|
||||||
|
page_titles: ["What stage is your project in?", "What type of property is it?", "What's your primary concern?" ]
|
||||||
|
choices_values: [
|
||||||
|
["STP1-Option 1"],
|
||||||
|
["STP2-Option 1", "STP2-Option 2", "STP2-Option 3"],
|
||||||
|
["STP3-Option 1", "STP3-Option 2"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
next_button = <View> {
|
||||||
|
// debug: A
|
||||||
|
height: Fit
|
||||||
|
align: {x: 0.5, y: 0.5}
|
||||||
|
next = <MolyButton> {
|
||||||
|
// debug: A
|
||||||
|
width: 300, height: 50,
|
||||||
|
// margin: 0, padding: 0
|
||||||
|
text: "Next"
|
||||||
|
draw_text: {
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
// return #016def // 0160C0
|
||||||
|
return mix(mix(#f0, #016def, self.hover), #f0, self.pressed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_bg: {
|
||||||
|
border_radius: 2.
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
let border_color = #0157c0;
|
||||||
|
// let border_color = #016def; //#0157c0
|
||||||
|
let border_width = 0.5;
|
||||||
|
let sdf = Sdf2d::viewport(self.pos * self.rect_size);
|
||||||
|
let body = mix(mix(#0157c0, #f, self.hover), #0157c0, self.pressed);
|
||||||
|
|
||||||
|
sdf.box(
|
||||||
|
1.,
|
||||||
|
1.,
|
||||||
|
self.rect_size.x - 2.0,
|
||||||
|
self.rect_size.y - 2.0,
|
||||||
|
self.border_radius
|
||||||
|
)
|
||||||
|
sdf.fill_keep(body)
|
||||||
|
|
||||||
|
sdf.stroke(
|
||||||
|
border_color,
|
||||||
|
border_width
|
||||||
|
)
|
||||||
|
return sdf.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#[derive(Live, Widget)]
|
||||||
|
pub struct Choose {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
#[animator]
|
||||||
|
animator: Animator,
|
||||||
|
#[rust]
|
||||||
|
screen_width: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum AllPages {
|
||||||
|
Pages {
|
||||||
|
content: Vec<Vec<String>>,
|
||||||
|
page_no: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
#[derive(Clone, DefaultNone, Debug)]
|
||||||
|
pub enum NextBackAction {
|
||||||
|
/// The user clicked the "react" button on a message
|
||||||
|
/// and wants to send the given `reaction` to that message.
|
||||||
|
NextButton {
|
||||||
|
clicked: bool,
|
||||||
|
page_no: u8,
|
||||||
|
},
|
||||||
|
BackButton {
|
||||||
|
clicked: bool,
|
||||||
|
page_no: u8,
|
||||||
|
},
|
||||||
|
SetIndicator {
|
||||||
|
set: bool,
|
||||||
|
page_no: u8,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LiveHook for Choose {
|
||||||
|
fn after_new_from_doc(&mut self, cx: &mut Cx) {}
|
||||||
|
}
|
||||||
|
impl Widget for Choose {
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk_all(cx, scope, walk);
|
||||||
|
// log!("Choose: draw_walk");
|
||||||
|
|
||||||
|
DrawStep::done()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetMatchEvent for Choose {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, scope: &mut Scope) {
|
||||||
|
if self.button(id!(next)).clicked(&actions) {
|
||||||
|
// Emit an action to increment the page number
|
||||||
|
log!("Choose - Next Button Clicked");
|
||||||
|
cx.action(NextBackAction::NextButton {
|
||||||
|
clicked: true,
|
||||||
|
page_no: 0, // You can pass the current page number if needed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for action in actions {
|
||||||
|
if let WindowAction::WindowGeomChange(ce) = action.as_widget_action().cast() {
|
||||||
|
self.screen_width = ce.new_geom.inner_size.x * ce.new_geom.dpi_factor;
|
||||||
|
|
||||||
|
log!("SCREEN_WIDTH ===> {}", self.screen_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Choose {
|
||||||
|
fn back_left_view(&mut self, cx: &mut Cx) {
|
||||||
|
// // Fire the "show" animation when the "restart" animation is done
|
||||||
|
// if self.animator.animator_in_state(cx, id!(choice.restart)) {
|
||||||
|
// self.animator_play(cx, id!(choice.show));
|
||||||
|
// }
|
||||||
|
self.animator_play(cx, id!(choice.show));
|
||||||
|
// cx.widget_action(
|
||||||
|
// self.widget_uid(),
|
||||||
|
// &HeapLiveIdPath::default(),
|
||||||
|
// StackNavigationTransitionAction::HideBegin,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
fn next_page_view(&mut self, cx: &mut Cx) {
|
||||||
|
// // Fire the "show" animation when the "restart" animation is done
|
||||||
|
// if self.animator.animator_in_state(cx, id!(choice.restart)) {
|
||||||
|
// self.animator_play(cx, id!(choice.show));
|
||||||
|
// }
|
||||||
|
self.animator_play(cx, id!(choice.show));
|
||||||
|
// cx.widget_action(
|
||||||
|
// self.widget_uid(),
|
||||||
|
// &HeapLiveIdPath::default(),
|
||||||
|
// StackNavigationTransitionAction::HideBegin,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
267
src/shared/choose/indicator.rs
Normal file
267
src/shared/choose/indicator.rs
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
use super::choose::NextBackAction;
|
||||||
|
const SELECTED: bool = false;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
|
||||||
|
IndicatorCheckBox = <CheckBox> {
|
||||||
|
width: Fill,
|
||||||
|
height: 35,
|
||||||
|
margin: {left: 1},
|
||||||
|
label_walk: {margin: {top: 15, bottom: 10}}
|
||||||
|
draw_check: {
|
||||||
|
uniform size: 3.5;
|
||||||
|
instance open: 0.0
|
||||||
|
uniform length: 3.0
|
||||||
|
uniform width: 1.0
|
||||||
|
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
let sdf = Sdf2d::viewport(self.pos * self.rect_size)
|
||||||
|
match self.check_type {
|
||||||
|
CheckType::Check => {
|
||||||
|
let sz = self.size;
|
||||||
|
let left = sz + 1.;
|
||||||
|
let up = sz + 7;
|
||||||
|
let c = self.rect_size * vec2(0.5, 0.5);
|
||||||
|
sdf.box(
|
||||||
|
left,
|
||||||
|
c.y - up,
|
||||||
|
25. * sz + 5,
|
||||||
|
1.8 * sz,
|
||||||
|
1.8
|
||||||
|
);
|
||||||
|
|
||||||
|
sdf.fill(#232323);
|
||||||
|
sdf.stroke(#000, 0.5 + 0.5 * self.dpi_dilate);
|
||||||
|
|
||||||
|
let isz = sz * 0.5;
|
||||||
|
let ileft = isz + 3;
|
||||||
|
let iup = sz + 7;
|
||||||
|
sdf.box(
|
||||||
|
ileft,
|
||||||
|
c.y - iup,
|
||||||
|
25. * sz + 5,
|
||||||
|
1.8 * sz,
|
||||||
|
1.8
|
||||||
|
);
|
||||||
|
sdf.fill(mix(#000, #016def, self.selected));
|
||||||
|
sdf.stroke(mix(
|
||||||
|
#000, #016def,
|
||||||
|
self.selected), 1.25
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sdf.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_text: {text_style: <THEME_FONT_LABEL> {}}
|
||||||
|
|
||||||
|
}
|
||||||
|
pub Indicators = {{Indicators}} {
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
flow: Right,
|
||||||
|
// flow: Down,
|
||||||
|
spacing: 5,
|
||||||
|
// align: {x: 0.5, y: 0.5},
|
||||||
|
indicator_titles: []
|
||||||
|
template: <IndicatorCheckBox> {
|
||||||
|
width: 100, height: 20,
|
||||||
|
margin: 0, padding: 0
|
||||||
|
// flow: Right,
|
||||||
|
// flow: Down,
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
text: "Here",
|
||||||
|
draw_text: {
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return #f60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_check: {
|
||||||
|
check_type: Check,
|
||||||
|
}
|
||||||
|
animator: {
|
||||||
|
selected = {
|
||||||
|
default: on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, Widget)]
|
||||||
|
pub struct Indicators {
|
||||||
|
#[redraw]
|
||||||
|
#[rust]
|
||||||
|
area: Area,
|
||||||
|
|
||||||
|
#[walk]
|
||||||
|
walk: Walk,
|
||||||
|
|
||||||
|
#[layout]
|
||||||
|
layout: Layout,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
indicator_titles: Vec<String>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
template: Option<LivePtr>,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
items: ComponentMap<LiveId, WidgetRef>,
|
||||||
|
|
||||||
|
#[rust(0)]
|
||||||
|
page_no: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LiveHook for Indicators {
|
||||||
|
fn after_apply(&mut self, cx: &mut Cx, _apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
|
||||||
|
// fn after_new_from_doc(&mut self, cx: &mut Cx) {
|
||||||
|
// let tags = ["test1", "test2", "test3"];
|
||||||
|
// log!("Indicators: after_apply");
|
||||||
|
|
||||||
|
self.items.clear();
|
||||||
|
self.page_no = 0; // Assign initial page
|
||||||
|
if self.page_no < self.indicator_titles.len() as u8 {
|
||||||
|
for (i, title_text) in self.indicator_titles.iter().enumerate() {
|
||||||
|
let item_id = LiveId::from_str(&format!("items{}", i));
|
||||||
|
let item_widget = WidgetRef::new_from_ptr(cx, self.template);
|
||||||
|
item_widget.apply_over(cx, live! {text: (title_text)});
|
||||||
|
|
||||||
|
let indicator = item_widget.check_box(&[item_id]);
|
||||||
|
if usize::from(self.page_no) == i {
|
||||||
|
if indicator.selected(cx) != SELECTED {
|
||||||
|
indicator.set_selected(cx, SELECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.items.insert(item_id, item_widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetMatchEvent for Indicators {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
|
||||||
|
// if (self.page_no as usize) < arr.len() {
|
||||||
|
// // Iterate over the selected page's choices
|
||||||
|
let mut arr: Vec<WidgetRef> = Vec::new();
|
||||||
|
for (_idx, inner_vec) in self.items.iter_mut() {
|
||||||
|
// Append the inner vector to the new variable
|
||||||
|
arr.push(inner_vec.clone());
|
||||||
|
}
|
||||||
|
if (self.page_no as usize) < arr.len() {
|
||||||
|
for (inneridx, indicator_arr) in arr.iter().enumerate() {
|
||||||
|
let index: u8 = inneridx as u8;
|
||||||
|
let widget_id = LiveId::from_str(&format!("items{}", index));
|
||||||
|
let item = self.items.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.template)
|
||||||
|
});
|
||||||
|
let indicator = item.check_box(&[widget_id]);
|
||||||
|
|
||||||
|
// if usize::from(self.page_no) == inneridx {
|
||||||
|
if indicator.selected(cx) != SELECTED {
|
||||||
|
indicator.set_selected(cx, SELECTED);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// item.check_box(&[widget_id]).set_selected(cx, SELECTED);
|
||||||
|
// let _ = item.draw_all(cx, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// log!("Invalid page_no: {}", self.page_no);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for action in actions {
|
||||||
|
if let NextBackAction::NextButton { clicked, page_no } =
|
||||||
|
action.as_widget_action().cast()
|
||||||
|
{
|
||||||
|
if clicked {
|
||||||
|
self.increment_page_no(cx); // Increment the page number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let NextBackAction::BackButton { clicked, page_no } =
|
||||||
|
action.as_widget_action().cast()
|
||||||
|
{
|
||||||
|
if clicked {
|
||||||
|
self.decrement_page_no(cx); // Increment the page number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Widget for Indicators {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
for (_id, item) in self.items.iter_mut() {
|
||||||
|
item.handle_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
// let state = scope.data.get_mut::<State>().unwrap();
|
||||||
|
// state.select_choices_values.len();
|
||||||
|
self.draw_walkd(cx, scope, walk);
|
||||||
|
DrawStep::done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Indicators {
|
||||||
|
fn draw_walkd(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) {
|
||||||
|
cx.begin_turtle(walk, Layout::default());
|
||||||
|
let mut arr: Vec<WidgetRef> = Vec::new();
|
||||||
|
for (_idx, inner_vec) in self.items.iter_mut() {
|
||||||
|
// Append the inner vector to the new variable
|
||||||
|
arr.push(inner_vec.clone());
|
||||||
|
}
|
||||||
|
if (self.page_no as usize) < arr.len() {
|
||||||
|
for (inneridx, indicator_arr) in arr.iter().enumerate() {
|
||||||
|
let index: u8 = inneridx as u8;
|
||||||
|
let widget_id = LiveId::from_str(&format!("items{}", index));
|
||||||
|
let item = self.items.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.template)
|
||||||
|
});
|
||||||
|
let indicator = item.check_box(&[widget_id]);
|
||||||
|
|
||||||
|
// if usize::from(self.page_no) == inneridx {
|
||||||
|
if indicator.selected(cx) != SELECTED {
|
||||||
|
indicator.set_selected(cx, SELECTED);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
let _ = item.draw_all(cx, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cx.end_turtle_with_area(&mut self.area);
|
||||||
|
// cx.end_turtle_with_area(&mut self.custom_button.area());
|
||||||
|
}
|
||||||
|
pub fn increment_page_no(&mut self, cx: &mut Cx) {
|
||||||
|
self.page_no = (self.page_no + 1).min(2); // Ensure page_no doesn't exceed max value
|
||||||
|
log!("SelectOption - Navigated to page: {}", self.page_no);
|
||||||
|
self.update_view(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrement_page_no(&mut self, cx: &mut Cx) {
|
||||||
|
if self.page_no > 0 {
|
||||||
|
self.page_no -= 1;
|
||||||
|
log!("SelectOption - Navigated to page: {}", self.page_no);
|
||||||
|
self.update_view(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_view(&mut self, cx: &mut Cx) {
|
||||||
|
match self.page_no {
|
||||||
|
0 => log!("SelectOption - Showing Step One"),
|
||||||
|
1 => log!("SelectOption - Showing Step Two"),
|
||||||
|
2 => log!("SelectOption - Showing Step Three"),
|
||||||
|
_ => log!("SelectOption - Unknown Page"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/shared/choose/mod.rs
Normal file
15
src/shared/choose/mod.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use makepad_widgets::Cx;
|
||||||
|
|
||||||
|
pub mod choose;
|
||||||
|
// pub mod final_choose;
|
||||||
|
pub mod indicator;
|
||||||
|
pub mod selectoptions;
|
||||||
|
pub mod steps;
|
||||||
|
|
||||||
|
pub fn live_design(cx: &mut Cx) {
|
||||||
|
selectoptions::live_design(cx);
|
||||||
|
indicator::live_design(cx);
|
||||||
|
choose::live_design(cx);
|
||||||
|
steps::live_design(cx);
|
||||||
|
// final_choose::live_design(cx);
|
||||||
|
}
|
471
src/shared/choose/selectoptions.rs
Normal file
471
src/shared/choose/selectoptions.rs
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
use super::choose::NextBackAction;
|
||||||
|
const CHOICE_MAX_OFFSET: f64 = 700.0;
|
||||||
|
const SELECT_MAX_OFFSET: f64 = 500.0;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
|
||||||
|
COLOR_DOWN_6 = #x000000CC
|
||||||
|
SIDEBAR_FONT_COLOR = #344054
|
||||||
|
SIDEBAR_FONT_COLOR_HOVER = #344054
|
||||||
|
SIDEBAR_FONT_COLOR_SELECTED = #127487
|
||||||
|
|
||||||
|
SIDEBAR_BG_COLOR = #f
|
||||||
|
SIDEBAR_BG_COLOR_HOVER = #E2F1F199
|
||||||
|
SIDEBAR_BG_COLOR_SELECTED = #E2F1F199
|
||||||
|
|
||||||
|
pub ButChoices = <ButtonGroup>{
|
||||||
|
// debug: A
|
||||||
|
flow: Down,
|
||||||
|
show_bg: false
|
||||||
|
draw_bg: {
|
||||||
|
color: #000
|
||||||
|
}
|
||||||
|
align: {x: 0.5, y: 0.5}
|
||||||
|
but = <View> {
|
||||||
|
// debug: A
|
||||||
|
width: 300, height: 45,
|
||||||
|
butchoice = <RadioButtonTab> {
|
||||||
|
width: Fill,
|
||||||
|
height: 70,
|
||||||
|
align: {x: 0.5, y: 0.5}
|
||||||
|
|
||||||
|
text: "Option 1"
|
||||||
|
label_walk: { width: Fit, height: 34.0 }
|
||||||
|
icon_walk: {width: 80, height: 80}
|
||||||
|
|
||||||
|
draw_radio: {
|
||||||
|
radio_type: Tab,
|
||||||
|
|
||||||
|
instance border_width: 0.0
|
||||||
|
instance border_color: #344054
|
||||||
|
instance inset: vec4(0.0, 0.0, 0.0, 0.0)
|
||||||
|
instance radius: 2.5
|
||||||
|
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return mix(
|
||||||
|
mix(
|
||||||
|
(SIDEBAR_BG_COLOR),
|
||||||
|
(SIDEBAR_BG_COLOR_HOVER),
|
||||||
|
self.hover
|
||||||
|
),
|
||||||
|
(SIDEBAR_BG_COLOR_SELECTED),
|
||||||
|
self.selected
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_border_color(self) -> vec4 {
|
||||||
|
return self.border_color
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pixel(self) -> vec4 {
|
||||||
|
let border_color = #0157c0;
|
||||||
|
let border_width = 0.0;
|
||||||
|
|
||||||
|
let sdf = Sdf2d::viewport(self.pos * self.rect_size)
|
||||||
|
sdf.box(
|
||||||
|
self.inset.x + self.border_width,
|
||||||
|
self.inset.y + self.border_width,
|
||||||
|
self.rect_size.x - (self.inset.x + self.inset.z + self.border_width * 2.0),
|
||||||
|
self.rect_size.y - (self.inset.y + self.inset.w + self.border_width * 2.0),
|
||||||
|
max(1.0, self.radius)
|
||||||
|
)
|
||||||
|
sdf.fill_keep(self.get_color())
|
||||||
|
if self.border_width > 0.0 {
|
||||||
|
sdf.stroke(self.get_border_color(), self.border_width)
|
||||||
|
}
|
||||||
|
sdf.stroke(
|
||||||
|
border_color,
|
||||||
|
border_width
|
||||||
|
)
|
||||||
|
return sdf.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_text: {
|
||||||
|
color_unselected: (SIDEBAR_FONT_COLOR)
|
||||||
|
color_unselected_hover: (SIDEBAR_FONT_COLOR_HOVER)
|
||||||
|
color_selected: (SIDEBAR_FONT_COLOR_SELECTED)
|
||||||
|
|
||||||
|
fn get_color(self) -> vec4 {
|
||||||
|
return mix(
|
||||||
|
mix(
|
||||||
|
self.color_unselected,
|
||||||
|
self.color_unselected_hover,
|
||||||
|
self.hover
|
||||||
|
),
|
||||||
|
self.color_selected,
|
||||||
|
self.selected
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub SelectOptions = {{SelectOptions}} {
|
||||||
|
// page_titles: []
|
||||||
|
width: Fit, height: Fit,
|
||||||
|
// indicator_titles: []
|
||||||
|
flow: Down,
|
||||||
|
spacing: 10,
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
select_choices_values: []
|
||||||
|
selects_template: <ButChoices> {
|
||||||
|
flow: Down,
|
||||||
|
}
|
||||||
|
choice_page_offset: 0.0
|
||||||
|
animator: {
|
||||||
|
selectopt = {
|
||||||
|
default: restart,
|
||||||
|
restart = {
|
||||||
|
ease: ExpDecay {d1: 0.80, d2: 0.97}
|
||||||
|
from: {all: Snap}
|
||||||
|
apply: {choice_page_offset: 500.0}
|
||||||
|
}
|
||||||
|
show = {
|
||||||
|
redraw: true,
|
||||||
|
ease: ExpDecay {d1: 0.80, d2: 0.97}
|
||||||
|
// from: {all: Forward {duration: 0}}
|
||||||
|
from: {all: Snap}
|
||||||
|
apply: {choice_page_offset: 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Live, Widget)]
|
||||||
|
pub struct SelectOptions {
|
||||||
|
#[redraw]
|
||||||
|
#[rust]
|
||||||
|
area: Area,
|
||||||
|
|
||||||
|
#[walk]
|
||||||
|
walk: Walk,
|
||||||
|
|
||||||
|
#[layout]
|
||||||
|
layout: Layout,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
page_titles: Vec<String>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
select_choices_values: Vec<Vec<String>>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
selects_template: Option<LivePtr>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
options_template: Option<LivePtr>,
|
||||||
|
|
||||||
|
#[rust(0)]
|
||||||
|
current_page: u8,
|
||||||
|
|
||||||
|
#[rust(0)]
|
||||||
|
page_no: u8,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
pages: ComponentMap<LiveId, WidgetRef>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
choice_page_offset: f64,
|
||||||
|
|
||||||
|
#[animator]
|
||||||
|
animator: Animator,
|
||||||
|
/// The persistent UI-relevant states for the selecte options that this widget is currently displaying.
|
||||||
|
#[rust]
|
||||||
|
select_options_state: Option<SelectOptionUiState>,
|
||||||
|
}
|
||||||
|
struct SelectOptionUiState {
|
||||||
|
prev_first_index: Option<usize>,
|
||||||
|
}
|
||||||
|
impl LiveHook for SelectOptions {
|
||||||
|
fn after_apply(&mut self, cx: &mut Cx, _apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
|
||||||
|
// fn after_new_from_doc(&mut self, cx: &mut Cx) {
|
||||||
|
// log!(
|
||||||
|
// "============SelectOptions::after_new_from_doc============, {:?}",
|
||||||
|
// self.page_no
|
||||||
|
// );
|
||||||
|
|
||||||
|
// fn after_apply(&mut self, cx: &mut Cx, _apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
|
||||||
|
// log!("SelectOptions: after_apply");
|
||||||
|
|
||||||
|
self.select_choices_values = vec![
|
||||||
|
vec![
|
||||||
|
"Planning Phase".to_string(),
|
||||||
|
"Ready to Start".to_string(),
|
||||||
|
"In Progress".to_string(),
|
||||||
|
"Needs Approval".to_string(),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
"Residential".to_string(),
|
||||||
|
"Commercial".to_string(),
|
||||||
|
"Industrial".to_string(),
|
||||||
|
"Mixed Use".to_string(),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
"Design".to_string(),
|
||||||
|
"Construction".to_string(),
|
||||||
|
"Approvals".to_string(),
|
||||||
|
"Cost Management".to_string(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
self.page_no = 0; // Assign initial page
|
||||||
|
if self.page_no < self.select_choices_values.len() as u8 {
|
||||||
|
for (idx, title_text) in self.select_choices_values[self.page_no as usize]
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", idx));
|
||||||
|
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.selects_template)
|
||||||
|
});
|
||||||
|
page.radio_button(id!(butchoice))
|
||||||
|
.set_text(cx, &format!("{}", title_text.as_str()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!("Warning: page_no is out of bounds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for SelectOptions {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
for (_id, page) in self.pages.iter_mut() {
|
||||||
|
page.handle_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if let Event::Actions(actions) = event {
|
||||||
|
// for action in actions {
|
||||||
|
// if let NextBackAction::NextButton { clicked, page_no } =
|
||||||
|
// action.as_widget_action().cast()
|
||||||
|
// {
|
||||||
|
// log!(
|
||||||
|
// "SelectOption - handle_event - Navigated to page: {}",
|
||||||
|
// page_no
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if clicked {
|
||||||
|
// self.increment_page_no(cx); // Increment the page number
|
||||||
|
// // self.redraw(cx);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if let NextBackAction::BackButton { clicked, page_no } =
|
||||||
|
// action.as_widget_action().cast()
|
||||||
|
// {
|
||||||
|
// log!(
|
||||||
|
// "SelectOption - handle_event - Navigated to page: {}",
|
||||||
|
// page_no
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if clicked {
|
||||||
|
// self.decrement_page_no(cx); // Increment the page number
|
||||||
|
// // let walk = self.walk(cx);
|
||||||
|
// // self.draw_walkd(cx, scope, walk);
|
||||||
|
// // self.redraw(cx);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.draw_walkd(cx, scope, walk);
|
||||||
|
DrawStep::done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetMatchEvent for SelectOptions {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
|
||||||
|
let mut arr: Vec<Vec<String>> = self.select_choices_values.clone();
|
||||||
|
let mut widget_id_vec: Vec<LiveId> = Vec::new();
|
||||||
|
let mut pagec: Vec<WidgetRef> = Vec::new();
|
||||||
|
if (self.page_no as usize) < arr.len() {
|
||||||
|
// Iterate over the selected page's choices
|
||||||
|
for (inneridx, choices_arr) in arr[self.page_no as usize].iter().enumerate() {
|
||||||
|
let offset: f64 = self.choice_page_offset - SELECT_MAX_OFFSET;
|
||||||
|
let index: u8 = inneridx as u8;
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", index));
|
||||||
|
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.selects_template)
|
||||||
|
});
|
||||||
|
|
||||||
|
widget_id_vec.push(widget_id.clone());
|
||||||
|
pagec.push(page.clone());
|
||||||
|
|
||||||
|
// Handle any actions with the `page` widget if needed
|
||||||
|
page.radio_button(id!(butchoice))
|
||||||
|
.set_text(cx, choices_arr.as_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!("Invalid page_no: {}", self.page_no);
|
||||||
|
}
|
||||||
|
// page.radio_button_set(&[&[widget_id]]).selected_to_visible(
|
||||||
|
// cx,
|
||||||
|
// &pagec,
|
||||||
|
// actions,
|
||||||
|
// &[&[widget_id]],
|
||||||
|
// );
|
||||||
|
|
||||||
|
for action in actions {
|
||||||
|
if let NextBackAction::NextButton { clicked, page_no } =
|
||||||
|
action.as_widget_action().cast()
|
||||||
|
{
|
||||||
|
if clicked {
|
||||||
|
self.increment_page_no(cx); // Increment the page number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let NextBackAction::BackButton { clicked, page_no } =
|
||||||
|
action.as_widget_action().cast()
|
||||||
|
{
|
||||||
|
if clicked {
|
||||||
|
self.decrement_page_no(cx); // Increment the page number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl SelectOptions {
|
||||||
|
fn draw_walkd(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) {
|
||||||
|
cx.begin_turtle(walk, self.layout);
|
||||||
|
|
||||||
|
// Ensure page_no is within the bounds of select_choices_values
|
||||||
|
|
||||||
|
if (self.page_no as usize) < self.select_choices_values.len() {
|
||||||
|
let offset: f64 = self.choice_page_offset - SELECT_MAX_OFFSET;
|
||||||
|
// Iterate over the current page's choices
|
||||||
|
for (inneridx, choices_arr) in self.select_choices_values[self.page_no as usize]
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let index: u8 = inneridx as u8;
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", index));
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.selects_template)
|
||||||
|
});
|
||||||
|
|
||||||
|
page.radio_button(id!(butchoice))
|
||||||
|
.set_text(cx, &format!("{}", choices_arr.as_str()));
|
||||||
|
|
||||||
|
// Draw each widget with margin adjustment
|
||||||
|
let _ = page.draw_walk(cx, scope, walk.with_margin_left(offset));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!("Invalid page_no: {}", self.page_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.end_turtle_with_area(&mut self.area);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_page_no(&mut self, cx: &mut Cx) {
|
||||||
|
self.page_no = (self.page_no + 1).min(2); // Ensure page_no doesn't exceed max value
|
||||||
|
log!("SelectOption - Navigated to page: {}", self.page_no);
|
||||||
|
self.update_view(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrement_page_no(&mut self, cx: &mut Cx) {
|
||||||
|
if self.page_no > 0 {
|
||||||
|
self.page_no -= 1;
|
||||||
|
log!("SelectOption - Navigated to page: {}", self.page_no);
|
||||||
|
self.update_view(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_view(&mut self, cx: &mut Cx) {
|
||||||
|
match self.page_no {
|
||||||
|
0 => log!("SelectOption - Showing Step One"),
|
||||||
|
1 => log!("SelectOption - Showing Step Two"),
|
||||||
|
2 => log!("SelectOption - Showing Step Three"),
|
||||||
|
_ => log!("SelectOption - Unknown Page"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_page_with_offset(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut Cx2d,
|
||||||
|
scope: &mut Scope,
|
||||||
|
index: u8,
|
||||||
|
offset: f64,
|
||||||
|
walk: Walk,
|
||||||
|
) {
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", index));
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.selects_template)
|
||||||
|
});
|
||||||
|
|
||||||
|
// let _ = page.draw_all(cx, scope);
|
||||||
|
let _ = page.draw_walk(cx, scope, walk.with_margin_left(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_current_page(&mut self) {
|
||||||
|
self.current_page = (self.current_page + 1) % self.select_choices_values[0].len() as u8;
|
||||||
|
log!(
|
||||||
|
"SelectOptions::update_current_page: {:?}",
|
||||||
|
&self.current_page
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectOptions {
|
||||||
|
/// Handles any [`NextBackAction`]s received by this SelectOptions.
|
||||||
|
fn handle_message_actions(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut Cx,
|
||||||
|
actions: &ActionsBuf,
|
||||||
|
// portal_list: &PortalListRef,
|
||||||
|
// loading_pane: &LoadingPaneRef,
|
||||||
|
) {
|
||||||
|
let room_screen_widget_uid = self.widget_uid();
|
||||||
|
// for action in actions {
|
||||||
|
// match action
|
||||||
|
// .as_widget_action()
|
||||||
|
// .widget_uid_eq(room_screen_widget_uid)
|
||||||
|
// .cast()
|
||||||
|
// {
|
||||||
|
// NextBackAction::NextButton { clicked, page_no } => {
|
||||||
|
// // let Some(tl) = self.tl_state.as_mut() else {
|
||||||
|
// // return;
|
||||||
|
// // };
|
||||||
|
// // let mut success = false;
|
||||||
|
// // if let Some(timeline_item) = tl.items.get(details.item_id) {
|
||||||
|
// // if let Some(event_tl_item) = timeline_item.as_event() {
|
||||||
|
// // if event_tl_item.event_id() == details.event_id.as_deref() {
|
||||||
|
// // let timeline_event_id = event_tl_item.identifier();
|
||||||
|
// // // submit_async_request(MatrixRequest::ToggleReaction {
|
||||||
|
// // // room_id: tl.room_id.clone(),
|
||||||
|
// // // timeline_event_id,
|
||||||
|
// // // reaction,
|
||||||
|
// // // });
|
||||||
|
// // success = true;
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// if !success {
|
||||||
|
// // enqueue_popup_notification(
|
||||||
|
// // "Couldn't find message in timeline to react to.".to_string(),
|
||||||
|
// // );
|
||||||
|
// // error!("MessageAction::React: couldn't find event [{}] {:?} to react to in room {}",
|
||||||
|
// // details.item_id,
|
||||||
|
// // details.event_id.as_deref(),
|
||||||
|
// // tl.room_id,
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// NextBackAction::None => {}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
292
src/shared/choose/steps.rs
Normal file
292
src/shared/choose/steps.rs
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
use crate::data::state::State;
|
||||||
|
|
||||||
|
use super::choose::NextBackAction;
|
||||||
|
const CHOICE_MAX_OFFSET: f64 = 700.0;
|
||||||
|
const SELECT_MAX_OFFSET: f64 = 0.0;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::widgets::MolyButton;
|
||||||
|
use crate::shared::choose::selectoptions::ButChoices;
|
||||||
|
use crate::shared::choose::selectoptions::SelectOptions;
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
|
||||||
|
COLOR_DOWN_6 = #x000000CC
|
||||||
|
SIDEBAR_FONT_COLOR = #344054
|
||||||
|
SIDEBAR_FONT_COLOR_HOVER = #344054
|
||||||
|
SIDEBAR_FONT_COLOR_SELECTED = #127487
|
||||||
|
|
||||||
|
SIDEBAR_BG_COLOR = #f
|
||||||
|
SIDEBAR_BG_COLOR_HOVER = #E2F1F199
|
||||||
|
SIDEBAR_BG_COLOR_SELECTED = #E2F1F199
|
||||||
|
pub StepsScreen = <View> {
|
||||||
|
height: Fit,
|
||||||
|
flow: Down,
|
||||||
|
align: {y: 0.}
|
||||||
|
spacing: 20.,
|
||||||
|
title = <View> {
|
||||||
|
padding: {left: 0.0},
|
||||||
|
height: Fit
|
||||||
|
spacing: 0,
|
||||||
|
step_title = <Label> {
|
||||||
|
width: Fill
|
||||||
|
draw_text: {
|
||||||
|
text_style: <TEXT_BOLD>{font_size: 20.},
|
||||||
|
color: (COLOR_DOWN_6)
|
||||||
|
wrap: Word,
|
||||||
|
}
|
||||||
|
text: "Step One"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
avail_options = <View> {
|
||||||
|
// debug: A
|
||||||
|
align: {x: 0.5, y: 0.5}
|
||||||
|
height: Fit
|
||||||
|
<SelectOptions> {
|
||||||
|
|
||||||
|
select_choices_values: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
pub Steps = {{Steps}} {
|
||||||
|
// debug: A
|
||||||
|
page_titles: []
|
||||||
|
choices_values: []
|
||||||
|
|
||||||
|
page_template: <StepsScreen> {}
|
||||||
|
selects_template: <ButChoices> {}
|
||||||
|
|
||||||
|
step_page_offset: 0.0
|
||||||
|
animator: {
|
||||||
|
step_choice = {
|
||||||
|
default: restart,
|
||||||
|
restart = {
|
||||||
|
from: {all: Snap}
|
||||||
|
apply: {step_page_offset: 400.0}
|
||||||
|
}
|
||||||
|
show = {
|
||||||
|
redraw: true,
|
||||||
|
from: {all: Forward {duration: 0.5}}
|
||||||
|
apply: {step_page_offset: 0.0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Live, Widget)]
|
||||||
|
pub struct Steps {
|
||||||
|
#[redraw]
|
||||||
|
#[rust]
|
||||||
|
area: Area,
|
||||||
|
|
||||||
|
#[walk]
|
||||||
|
walk: Walk,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
page_titles: Vec<String>,
|
||||||
|
#[live]
|
||||||
|
choices_values: Vec<Vec<String>>,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
items: ComponentMap<LiveId, WidgetRef>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
pub page_template: Option<LivePtr>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
selects_template: Option<LivePtr>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
options_template: Option<LivePtr>,
|
||||||
|
|
||||||
|
#[rust(0)]
|
||||||
|
current_page: u8,
|
||||||
|
#[rust(0)]
|
||||||
|
page_no: u8,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
pages: ComponentMap<LiveId, WidgetRef>,
|
||||||
|
|
||||||
|
#[live]
|
||||||
|
step_page_offset: f64,
|
||||||
|
|
||||||
|
#[animator]
|
||||||
|
animator: Animator,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LiveHook for Steps {
|
||||||
|
fn after_new_from_doc(&mut self, cx: &mut Cx) {
|
||||||
|
// log!("Steps::after_new_from_doc");
|
||||||
|
|
||||||
|
self.page_no = 0; // Assign initial page
|
||||||
|
if self.page_no < self.page_titles.len() as u8 {
|
||||||
|
for (idx, title_text) in self.page_titles.iter().enumerate() {
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", idx));
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.page_template)
|
||||||
|
});
|
||||||
|
|
||||||
|
if usize::from(self.page_no) == idx {
|
||||||
|
page.label(id!(step_title))
|
||||||
|
.set_text(cx, &format!("{}", &title_text.as_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for Steps {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
for (_id, page) in self.pages.iter_mut() {
|
||||||
|
page.handle_event(cx, event, scope);
|
||||||
|
}
|
||||||
|
self.widget_match_event(cx, event, scope);
|
||||||
|
|
||||||
|
if self.animator_handle_event(cx, event).must_redraw() {
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire the "show" animation when the "restart" animation is done
|
||||||
|
if self
|
||||||
|
.animator
|
||||||
|
.animator_in_state(cx, id!(step_choice.restart))
|
||||||
|
{
|
||||||
|
self.animator_play(cx, id!(step_choice.show));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.draw_walkd(cx, scope, walk);
|
||||||
|
DrawStep::done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetMatchEvent for Steps {
|
||||||
|
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions, _scope: &mut Scope) {
|
||||||
|
for action in actions {
|
||||||
|
if let WindowAction::WindowGeomChange(ce) = action.as_widget_action().cast() {
|
||||||
|
let screen_width = ce.new_geom.inner_size.x * ce.new_geom.dpi_factor;
|
||||||
|
|
||||||
|
log!("SCREEN_WIDTH ===> {}", screen_width);
|
||||||
|
}
|
||||||
|
if let NextBackAction::NextButton { clicked, page_no } =
|
||||||
|
action.as_widget_action().cast()
|
||||||
|
{
|
||||||
|
if clicked {
|
||||||
|
self.increment_page_no(cx); // Increment the page number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let NextBackAction::BackButton { clicked, page_no } =
|
||||||
|
action.as_widget_action().cast()
|
||||||
|
{
|
||||||
|
if clicked {
|
||||||
|
self.decrement_page_no(cx); // Increment the page number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut arr: Vec<String> = self.page_titles.clone();
|
||||||
|
if (self.page_no as usize) < arr.len() {
|
||||||
|
// Iterate over the selected page's choices
|
||||||
|
for (inneridx, choices_arr) in arr.iter().enumerate() {
|
||||||
|
let offset: f64 = self.step_page_offset - SELECT_MAX_OFFSET;
|
||||||
|
let index: u8 = inneridx as u8;
|
||||||
|
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", index));
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.page_template)
|
||||||
|
});
|
||||||
|
if usize::from(self.page_no) == inneridx {
|
||||||
|
page.label(id!(step_title))
|
||||||
|
.set_text(cx, &format!("{}", &choices_arr.as_str()));
|
||||||
|
}
|
||||||
|
// page.label(id!(step_title))
|
||||||
|
// .set_text(cx, &format!("{}", &choices_arr.as_str()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!("Invalid page_no: {}", self.page_no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Steps {
|
||||||
|
fn draw_walkd(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) {
|
||||||
|
cx.begin_turtle(walk, Layout::default());
|
||||||
|
// Steps
|
||||||
|
{
|
||||||
|
// Ensure page_no is within the bounds of select_choices_values
|
||||||
|
if (self.page_no as usize) < self.page_titles.len() {
|
||||||
|
let offset: f64 = self.step_page_offset - SELECT_MAX_OFFSET;
|
||||||
|
log!("Steps::draw_walkd-{:?}", self.page_no as usize);
|
||||||
|
|
||||||
|
// Iterate over the current page's choices
|
||||||
|
for (inneridx, choices_arr) in self.page_titles.iter().enumerate() {
|
||||||
|
let index: u8 = inneridx as u8;
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", index));
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.page_template)
|
||||||
|
});
|
||||||
|
if usize::from(self.page_no) == inneridx {
|
||||||
|
page.label(id!(step_title))
|
||||||
|
.set_text(cx, &format!("{}", &choices_arr.as_str()));
|
||||||
|
let _ = page.draw_walk(cx, scope, walk.with_margin_left(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw each widget with margin adjustment
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!("Invalid page_no: {}", self.page_no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cx.end_turtle_with_area(&mut self.area);
|
||||||
|
// cx.end_turtle_with_area(&mut self.custom_button.area());
|
||||||
|
}
|
||||||
|
pub fn increment_page_no(&mut self, cx: &mut Cx) {
|
||||||
|
self.page_no = (self.page_no + 1).min(2); // Ensure page_no doesn't exceed max value
|
||||||
|
log!("SelectOption - Navigated to page: {}", self.page_no);
|
||||||
|
self.update_view(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrement_page_no(&mut self, cx: &mut Cx) {
|
||||||
|
if self.page_no > 0 {
|
||||||
|
self.page_no -= 1;
|
||||||
|
log!("SelectOption - Navigated to page: {}", self.page_no);
|
||||||
|
self.update_view(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_view(&mut self, cx: &mut Cx) {
|
||||||
|
match self.page_no {
|
||||||
|
0 => log!("SelectOption - Showing Step One"),
|
||||||
|
1 => log!("SelectOption - Showing Step Two"),
|
||||||
|
2 => log!("SelectOption - Showing Step Three"),
|
||||||
|
_ => log!("SelectOption - Unknown Page"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_page_with_offset(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut Cx2d,
|
||||||
|
scope: &mut Scope,
|
||||||
|
index: u8,
|
||||||
|
offset: f64,
|
||||||
|
walk: Walk,
|
||||||
|
) {
|
||||||
|
let widget_id = LiveId::from_str(&format!("page{}", index));
|
||||||
|
let page = self.pages.get_or_insert(cx, widget_id, |cx| {
|
||||||
|
WidgetRef::new_from_ptr(cx, self.page_template)
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = page.draw_walk(cx, scope, walk.with_margin_left(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_current_page(&mut self) {
|
||||||
|
self.current_page = (self.current_page + 1) % self.page_titles.len() as u8;
|
||||||
|
log!("Steps::update_current_page: {:?}", &self.current_page);
|
||||||
|
// self.current_page = (self.current_page + 1) % self.choices_values.len() as u8;
|
||||||
|
}
|
||||||
|
}
|
31
src/shared/helpers.rs
Normal file
31
src/shared/helpers.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use makepad_widgets::*;
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
|
||||||
|
pub Divider = <View> {
|
||||||
|
width: Fill, height: Fit
|
||||||
|
flow: Down
|
||||||
|
<RoundedView> {
|
||||||
|
width: Fill,
|
||||||
|
height: 1.,
|
||||||
|
draw_bg: {color: (#ddd)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub LineH = <RoundedView> {
|
||||||
|
width: Fill,
|
||||||
|
height: 2.0,
|
||||||
|
margin: 0.0,
|
||||||
|
padding: 0.0, spacing: 0.0
|
||||||
|
show_bg: true
|
||||||
|
draw_bg: {color: (COLOR_DIVIDER)}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub FillerX = <View> { width: Fill, height: Fit }
|
||||||
|
pub FillerY = <View> { width: Fit, height: Fill }
|
||||||
|
}
|
377
src/shared/html_or_plaintext.rs
Normal file
377
src/shared/html_or_plaintext.rs
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
//! A `HtmlOrPlaintext` view can display either plaintext or rich HTML content.
|
||||||
|
|
||||||
|
use makepad_widgets::{makepad_html::HtmlDoc, *};
|
||||||
|
|
||||||
|
/// The color of the text used to print the spoiler reason before the hidden text.
|
||||||
|
const COLOR_SPOILER_REASON: Vec4 = vec4(0.6, 0.6, 0.6, 1.0);
|
||||||
|
|
||||||
|
live_design! {
|
||||||
|
use link::theme::*;
|
||||||
|
use link::shaders::*;
|
||||||
|
use link::widgets::*;
|
||||||
|
|
||||||
|
use crate::shared::styles::*;
|
||||||
|
|
||||||
|
// These match the `MESSAGE_*` styles defined in `styles.rs`.
|
||||||
|
// For some reason, they're not the same. That's TBD.
|
||||||
|
// HTML_LINE_SPACING = 6.0
|
||||||
|
// HTML_TEXT_HEIGHT_FACTOR = 1.1
|
||||||
|
|
||||||
|
// This is an HTML subwidget used to handle `<font>` and `<span>` tags,
|
||||||
|
// specifically: foreground text color, background color, and spoilers.
|
||||||
|
pub MatrixHtmlSpan = {{MatrixHtmlSpan}} {
|
||||||
|
width: Fit, height: Fit,
|
||||||
|
align: {x: 0., y: 0.}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A centralized widget where we define styles and custom elements for HTML
|
||||||
|
// message content. This is a wrapper around Makepad's built-in `Html` widget.
|
||||||
|
pub MessageHtml = <Html> {
|
||||||
|
padding: 0.0,
|
||||||
|
width: Fill, height: Fit, // see comment in `HtmlOrPlaintext`
|
||||||
|
font_size: (MESSAGE_FONT_SIZE),
|
||||||
|
font_color: (MESSAGE_TEXT_COLOR),
|
||||||
|
draw_normal: { color: (MESSAGE_TEXT_COLOR), } // text_style: { height_factor: (HTML_TEXT_HEIGHT_FACTOR), line_spacing: (HTML_LINE_SPACING) } }
|
||||||
|
draw_italic: { color: (MESSAGE_TEXT_COLOR), } // text_style: { height_factor: (HTML_TEXT_HEIGHT_FACTOR), line_spacing: (HTML_LINE_SPACING) } }
|
||||||
|
draw_bold: { color: (MESSAGE_TEXT_COLOR), } // text_style: { height_factor: (HTML_TEXT_HEIGHT_FACTOR), line_spacing: (HTML_LINE_SPACING) } }
|
||||||
|
draw_bold_italic: { color: (MESSAGE_TEXT_COLOR), } // text_style: { height_factor: (HTML_TEXT_HEIGHT_FACTOR), line_spacing: (HTML_LINE_SPACING) } }
|
||||||
|
draw_fixed: { color: (MESSAGE_TEXT_COLOR), } // text_style: { height_factor: (HTML_TEXT_HEIGHT_FACTOR), line_spacing: (HTML_LINE_SPACING) } }
|
||||||
|
draw_block: {
|
||||||
|
line_color: (MESSAGE_TEXT_COLOR)
|
||||||
|
sep_color: (MESSAGE_TEXT_COLOR)
|
||||||
|
code_color: (#EDEDED)
|
||||||
|
quote_bg_color: (#EDEDED)
|
||||||
|
quote_fg_color: (MESSAGE_TEXT_COLOR)
|
||||||
|
}
|
||||||
|
// list_item_layout: { padding: {left: 5.0, top: 1.0, bottom: 1.0}, }
|
||||||
|
// code_layout: { padding: {left: 7.0, right: 7.0, top: 8.0, bottom: 0.0}, }
|
||||||
|
// quote_layout: { padding: {top: 0.0, bottom: 0.0}, }
|
||||||
|
// inline_code_padding: { left: 5.0, right: 5.0, top: 7.0, bottom: 0.0 }
|
||||||
|
|
||||||
|
font = <MatrixHtmlSpan> { }
|
||||||
|
span = <MatrixHtmlSpan> { }
|
||||||
|
|
||||||
|
a = {
|
||||||
|
hover_color: #21b070
|
||||||
|
grab_key_focus: false,
|
||||||
|
padding: {left: 1.0, right: 1.5},
|
||||||
|
}
|
||||||
|
|
||||||
|
body: "[<i> HTML message placeholder</i>]",
|
||||||
|
}
|
||||||
|
|
||||||
|
// A view container that displays either plaintext s(a simple `Label`)
|
||||||
|
// or rich HTML content (an instance of `MessageHtml`).
|
||||||
|
//
|
||||||
|
// Key Usage Notes:
|
||||||
|
// * Labels need their width to be Fill *and* all of their parent views
|
||||||
|
// also need to have their width set to Fill. Otherwise, the label
|
||||||
|
// won't wrap text properly.
|
||||||
|
// * They also need their height to be Fit along with all of their parent views,
|
||||||
|
// otherwise their total height will be zero (when a Fit is inside of a Fill),
|
||||||
|
// resulting in nothing being displayed.
|
||||||
|
pub HtmlOrPlaintext = {{HtmlOrPlaintext}} {
|
||||||
|
width: Fill, height: Fit, // see above comment
|
||||||
|
flow: Overlay
|
||||||
|
|
||||||
|
plaintext_view = <View> {
|
||||||
|
visible: true,
|
||||||
|
width: Fill, height: Fit, // see above comment
|
||||||
|
pt_label = <Label> {
|
||||||
|
width: Fill, height: Fit, // see above comment
|
||||||
|
draw_text: {
|
||||||
|
wrap: Word,
|
||||||
|
color: (MESSAGE_TEXT_COLOR),
|
||||||
|
text_style: <MESSAGE_TEXT_STYLE> { font_size: (MESSAGE_FONT_SIZE) },
|
||||||
|
}
|
||||||
|
text: "[plaintext message placeholder]",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html_view = <View> {
|
||||||
|
visible: false,
|
||||||
|
width: Fill, height: Fit, // see above comment
|
||||||
|
html = <MessageHtml> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A widget used to display a single HTML `<span>` tag or a `<font>` tag.
|
||||||
|
#[derive(Live, Widget)]
|
||||||
|
struct MatrixHtmlSpan {
|
||||||
|
// TODO: this is unused; just here to invalidly satisfy the area provider.
|
||||||
|
// I'm not sure how to implement `fn area()` given that it has multiple area rects.
|
||||||
|
#[redraw]
|
||||||
|
#[area]
|
||||||
|
area: Area,
|
||||||
|
|
||||||
|
// TODO: remove these if they're unneeded
|
||||||
|
#[walk]
|
||||||
|
walk: Walk,
|
||||||
|
#[layout]
|
||||||
|
layout: Layout,
|
||||||
|
|
||||||
|
#[rust]
|
||||||
|
drawn_areas: SmallVec<[Area; 2]>,
|
||||||
|
|
||||||
|
/// Whether to grab key focus when pressed.
|
||||||
|
#[live(true)]
|
||||||
|
grab_key_focus: bool,
|
||||||
|
|
||||||
|
/// The text content within the `<span>` tag.
|
||||||
|
#[live]
|
||||||
|
text: ArcStringMut,
|
||||||
|
/// The current display state of the spoiler.
|
||||||
|
#[rust]
|
||||||
|
spoiler: SpoilerDisplay,
|
||||||
|
/// Foreground (text) color: the `data-mx-color` or `color` attributes.
|
||||||
|
#[rust]
|
||||||
|
fg_color: Option<Vec4>,
|
||||||
|
/// Background color: the `data-mx-bg-color` attribute.
|
||||||
|
#[rust]
|
||||||
|
bg_color: Option<Vec4>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The possible states that a spoiler can be in: hidden or revealed.
|
||||||
|
///
|
||||||
|
/// The enclosed `reason` string is an optional reason given for why
|
||||||
|
/// the text is hidden; if empty, then no reason was given.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
enum SpoilerDisplay {
|
||||||
|
/// There is no spoiler at all.
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
/// The spoiler text is hidden, with an optional reason given.
|
||||||
|
Hidden { reason: String },
|
||||||
|
/// The spoiler text is revealed, with an optional reason given.
|
||||||
|
Revealed { reason: String },
|
||||||
|
}
|
||||||
|
impl SpoilerDisplay {
|
||||||
|
/// Toggles the spoiler's display state.
|
||||||
|
fn toggle(&mut self) {
|
||||||
|
match self {
|
||||||
|
SpoilerDisplay::Hidden { reason } => {
|
||||||
|
let s = std::mem::take(reason);
|
||||||
|
*self = SpoilerDisplay::Revealed { reason: s };
|
||||||
|
}
|
||||||
|
SpoilerDisplay::Revealed { reason } => {
|
||||||
|
let s = std::mem::take(reason);
|
||||||
|
*self = SpoilerDisplay::Hidden { reason: s };
|
||||||
|
}
|
||||||
|
SpoilerDisplay::None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this spoiler is not `None`, i.e., if it's `Hidden` or `Revealed`.
|
||||||
|
fn is_some(&self) -> bool {
|
||||||
|
!matches!(self, SpoilerDisplay::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LiveHook for MatrixHtmlSpan {
|
||||||
|
// After an MatrixHtmlSpan instance has been instantiated ("applied"),
|
||||||
|
// populate its struct fields from the `<span>` or `<font>` tag's attributes.
|
||||||
|
fn after_apply(&mut self, _cx: &mut Cx, apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
|
||||||
|
// The attributes we care about (we allow all attributes in both tags):
|
||||||
|
// * in `<font>` tags: `color`
|
||||||
|
// * in `<span>` tags: `data-mx-color`, `data-mx-bg-color`, `data-mx-spoiler`
|
||||||
|
|
||||||
|
if let ApplyFrom::NewFromDoc { .. } = apply.from {
|
||||||
|
if let Some(scope) = apply.scope.as_ref() {
|
||||||
|
if let Some(doc) = scope.props.get::<HtmlDoc>() {
|
||||||
|
let mut walker = doc.new_walker_with_index(scope.index + 1);
|
||||||
|
while let Some((lc, attr)) = walker.while_attr_lc() {
|
||||||
|
let attr = attr.trim_matches(['"', '\'']);
|
||||||
|
match lc {
|
||||||
|
live_id!(color) | live_id!(data - mx - color) => {
|
||||||
|
self.fg_color = Vec4::from_hex_str(attr).ok()
|
||||||
|
}
|
||||||
|
live_id!(data - mx - bg - color) => {
|
||||||
|
self.bg_color = Vec4::from_hex_str(attr).ok()
|
||||||
|
}
|
||||||
|
live_id!(data - mx - spoiler) => {
|
||||||
|
self.spoiler = SpoilerDisplay::Hidden {
|
||||||
|
reason: attr.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"BUG: MatrixHtmlSpan::after_apply(): scope not found, cannot set attributes."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for MatrixHtmlSpan {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {
|
||||||
|
let mut needs_redraw = false;
|
||||||
|
for area in self.drawn_areas.clone().into_iter() {
|
||||||
|
match event.hits(cx, area) {
|
||||||
|
Hit::FingerDown(_fe) if self.grab_key_focus => {
|
||||||
|
cx.set_key_focus(self.area());
|
||||||
|
}
|
||||||
|
Hit::FingerHoverIn(_) if self.spoiler.is_some() => {
|
||||||
|
cx.set_cursor(MouseCursor::Hand);
|
||||||
|
}
|
||||||
|
Hit::FingerUp(fe) if fe.is_over => {
|
||||||
|
self.spoiler.toggle();
|
||||||
|
needs_redraw = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needs_redraw {
|
||||||
|
for area in &self.drawn_areas {
|
||||||
|
cx.redraw_area(*area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, _walk: Walk) -> DrawStep {
|
||||||
|
let Some(tf) = scope.data.get_mut::<TextFlow>() else {
|
||||||
|
return DrawStep::done();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Here: the text flow has already began drawing,
|
||||||
|
// so we just need to tweak the formatting and draw the text.
|
||||||
|
tf.areas_tracker.push_tracker();
|
||||||
|
let mut pushed_color = false;
|
||||||
|
let mut pushed_inline_code = false;
|
||||||
|
let mut old_code_color = None;
|
||||||
|
|
||||||
|
if let Some(fg_color) = self.fg_color {
|
||||||
|
tf.font_colors.push(fg_color);
|
||||||
|
pushed_color = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(bg_color) = self.bg_color {
|
||||||
|
// Reuse the inline code drawblock to set the background color.
|
||||||
|
tf.inline_code.push();
|
||||||
|
pushed_inline_code = true;
|
||||||
|
old_code_color = Some(tf.draw_block.code_color);
|
||||||
|
tf.draw_block.code_color = bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &self.spoiler {
|
||||||
|
SpoilerDisplay::Hidden { reason } | SpoilerDisplay::Revealed { reason } => {
|
||||||
|
// Draw the spoiler reason text in an italic gray font.
|
||||||
|
tf.font_colors.push(COLOR_SPOILER_REASON);
|
||||||
|
tf.italic.push();
|
||||||
|
// tf.push_size_rel_scale(0.8);
|
||||||
|
if reason.is_empty() {
|
||||||
|
tf.draw_text(cx, " [Spoiler] ");
|
||||||
|
} else {
|
||||||
|
tf.draw_text(cx, &format!(" [Spoiler: {}] ", reason));
|
||||||
|
}
|
||||||
|
// tf.font_sizes.pop();
|
||||||
|
tf.italic.pop();
|
||||||
|
tf.font_colors.pop();
|
||||||
|
|
||||||
|
// Now, draw the spoiler context text itself, either hidden or revealed.
|
||||||
|
if matches!(self.spoiler, SpoilerDisplay::Hidden { .. }) {
|
||||||
|
// Use a background color that is the same as the foreground color,
|
||||||
|
// which is a hacky way to make the spoiled text non-readable.
|
||||||
|
// In the future, we should use a proper blur effect.
|
||||||
|
let spoiler_bg_color = self
|
||||||
|
.fg_color
|
||||||
|
.or_else(|| tf.font_colors.last().copied())
|
||||||
|
.unwrap_or(tf.font_color);
|
||||||
|
|
||||||
|
tf.inline_code.push();
|
||||||
|
let old_bg_color = tf.draw_block.code_color;
|
||||||
|
tf.draw_block.code_color = spoiler_bg_color;
|
||||||
|
|
||||||
|
tf.draw_text(cx, self.text.as_ref());
|
||||||
|
|
||||||
|
tf.draw_block.code_color = old_bg_color;
|
||||||
|
tf.inline_code.pop();
|
||||||
|
} else {
|
||||||
|
tf.draw_text(cx, self.text.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpoilerDisplay::None => {
|
||||||
|
tf.draw_text(cx, self.text.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pushed_color {
|
||||||
|
tf.font_colors.pop();
|
||||||
|
}
|
||||||
|
if pushed_inline_code {
|
||||||
|
tf.inline_code.pop();
|
||||||
|
}
|
||||||
|
if let Some(old_code_color) = old_code_color {
|
||||||
|
tf.draw_block.code_color = old_code_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (start, end) = tf.areas_tracker.pop_tracker();
|
||||||
|
self.drawn_areas = SmallVec::from(&tf.areas_tracker.areas[start..end]);
|
||||||
|
|
||||||
|
DrawStep::done()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text(&self) -> String {
|
||||||
|
self.text.as_ref().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_text(&mut self, cx: &mut Cx, v: &str) {
|
||||||
|
self.text.as_mut_empty().push_str(v);
|
||||||
|
self.redraw(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LiveHook, Live, Widget)]
|
||||||
|
pub struct HtmlOrPlaintext {
|
||||||
|
#[deref]
|
||||||
|
view: View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for HtmlOrPlaintext {
|
||||||
|
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
|
||||||
|
self.view.handle_event(cx, event, scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
|
||||||
|
self.view.draw_walk(cx, scope, walk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HtmlOrPlaintext {
|
||||||
|
/// Sets the plaintext content and makes it visible, hiding the rich HTML content.
|
||||||
|
pub fn show_plaintext<T: AsRef<str>>(&mut self, cx: &mut Cx, text: T) {
|
||||||
|
self.view(id!(html_view)).set_visible(cx, false);
|
||||||
|
self.view(id!(plaintext_view)).set_visible(cx, true);
|
||||||
|
self.label(id!(plaintext_view.pt_label))
|
||||||
|
.set_text(cx, text.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the HTML content, making the HTML visible and the plaintext invisible.
|
||||||
|
pub fn show_html<T: AsRef<str>>(&mut self, cx: &mut Cx, html_body: T) {
|
||||||
|
self.html(id!(html_view.html))
|
||||||
|
.set_text(cx, html_body.as_ref());
|
||||||
|
self.view(id!(html_view)).set_visible(cx, true);
|
||||||
|
self.view(id!(plaintext_view)).set_visible(cx, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HtmlOrPlaintextRef {
|
||||||
|
/// See [`HtmlOrPlaintext::show_plaintext()`].
|
||||||
|
pub fn show_plaintext<T: AsRef<str>>(&self, cx: &mut Cx, text: T) {
|
||||||
|
if let Some(mut inner) = self.borrow_mut() {
|
||||||
|
inner.show_plaintext(cx, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`HtmlOrPlaintext::show_html()`].
|
||||||
|
pub fn show_html<T: AsRef<str>>(&self, cx: &mut Cx, html_body: T) {
|
||||||
|
if let Some(mut inner) = self.borrow_mut() {
|
||||||
|
inner.show_html(cx, html_body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,15 @@
|
||||||
use makepad_widgets::Cx;
|
use makepad_widgets::Cx;
|
||||||
|
|
||||||
|
pub mod choose;
|
||||||
|
pub mod helpers;
|
||||||
|
pub mod html_or_plaintext;
|
||||||
pub mod styles;
|
pub mod styles;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
|
||||||
pub fn live_design(cx: &mut Cx) {
|
pub fn live_design(cx: &mut Cx) {
|
||||||
styles::live_design(cx);
|
styles::live_design(cx);
|
||||||
|
html_or_plaintext::live_design(cx);
|
||||||
|
helpers::live_design(cx);
|
||||||
|
choose::live_design(cx);
|
||||||
widgets::live_design(cx);
|
widgets::live_design(cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ live_design! {
|
||||||
pub ROOM_NAME_TEXT_COLOR = #x0
|
pub ROOM_NAME_TEXT_COLOR = #x0
|
||||||
|
|
||||||
pub COLOR_META = #xccc
|
pub COLOR_META = #xccc
|
||||||
|
pub TERTIARY_TEXT_COLOR = #x9ca3af
|
||||||
|
|
||||||
pub COLOR_PROFILE_CIRCLE = #xfff8ee
|
pub COLOR_PROFILE_CIRCLE = #xfff8ee
|
||||||
pub COLOR_DIVIDER = #x00000018
|
pub COLOR_DIVIDER = #x00000018
|
||||||
|
@ -88,7 +89,7 @@ live_design! {
|
||||||
|
|
||||||
pub COLOR_PRIMARY = #ffffff
|
pub COLOR_PRIMARY = #ffffff
|
||||||
pub COLOR_PRIMARY_DARKER = #fefefe
|
pub COLOR_PRIMARY_DARKER = #fefefe
|
||||||
pub COLOR_SECONDARY = #eef2f4
|
pub COLOR_SECONDARY = #eef2ff
|
||||||
|
|
||||||
pub COLOR_SELECTED_PRIMARY = #0f88fe
|
pub COLOR_SELECTED_PRIMARY = #0f88fe
|
||||||
pub COLOR_SELECTED_PRIMARY_DARKER = #106fcc
|
pub COLOR_SELECTED_PRIMARY_DARKER = #106fcc
|
||||||
|
|
|
@ -55,6 +55,62 @@ live_design! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub SmallCard = <RoundedView> {
|
||||||
|
width: Fit,
|
||||||
|
height: 200,
|
||||||
|
padding: {top: 30, bottom: 30, left: 20, right: 40}
|
||||||
|
// padding: 20
|
||||||
|
|
||||||
|
draw_bg: {
|
||||||
|
instance radius: 4.0,
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
content = <View>{
|
||||||
|
width: Fit,
|
||||||
|
height: Fill,
|
||||||
|
flow: Down
|
||||||
|
spacing: 20,
|
||||||
|
|
||||||
|
title = <Label> {
|
||||||
|
draw_text: {
|
||||||
|
wrap: Word
|
||||||
|
text_style: <BOLD_FONT>{font_size: 13},
|
||||||
|
color: #x0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description = <Label> {
|
||||||
|
width: 200
|
||||||
|
draw_text: {
|
||||||
|
wrap: Word
|
||||||
|
text_style: <REGULAR_FONT>{font_size: 13},
|
||||||
|
color: #x0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub Avatar = <RoundedView> {
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
|
||||||
|
show_bg: true,
|
||||||
|
draw_bg: {
|
||||||
|
color: #444D9A,
|
||||||
|
radius: 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
align: {x: 0.5, y: 0.5},
|
||||||
|
|
||||||
|
avatar_label = <Label> {
|
||||||
|
width: Fit,
|
||||||
|
height: Fit,
|
||||||
|
draw_text:{
|
||||||
|
text_style: <BOLD_FONT>{font_size: 10},
|
||||||
|
color: #fff,
|
||||||
|
}
|
||||||
|
text: "P"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub SIDEBAR_FONT_COLOR = #344054
|
pub SIDEBAR_FONT_COLOR = #344054
|
||||||
pub SIDEBAR_FONT_COLOR_HOVER = #344054
|
pub SIDEBAR_FONT_COLOR_HOVER = #344054
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue