|
|
@ -1,16 +1,16 @@ |
|
|
|
use crate::chat::Chat; |
|
|
|
use crate::chat::Chat; |
|
|
|
|
|
|
|
use crate::chat::RenderableChat; |
|
|
|
use crate::degeon_worker::{Degeon, DegeonContainer}; |
|
|
|
use crate::degeon_worker::{Degeon, DegeonContainer}; |
|
|
|
use crate::gui_events::GuiEvent; |
|
|
|
use crate::gui_events::GuiEvent; |
|
|
|
use crate::message::{DegMessage, DegMessageContent, ProtocolMsg}; |
|
|
|
use crate::message::{DegMessage, DegMessageContent, ProtocolMsg}; |
|
|
|
use crate::styles::style; |
|
|
|
use crate::styles::style; |
|
|
|
use core::default::Default; |
|
|
|
use core::default::Default; |
|
|
|
|
|
|
|
use degeon_core::AppScreen; |
|
|
|
use iced::{ |
|
|
|
use iced::{ |
|
|
|
button, Align, Application, Button, Column, Element, HorizontalAlignment, Length, Row, |
|
|
|
button, Align, Application, Button, Column, Element, HorizontalAlignment, Length, Row, Text, |
|
|
|
Text, TextInput, VerticalAlignment, |
|
|
|
TextInput, VerticalAlignment, |
|
|
|
}; |
|
|
|
}; |
|
|
|
use ironforce::PublicKey; |
|
|
|
use ironforce::PublicKey; |
|
|
|
use degeon_core::AppScreen; |
|
|
|
|
|
|
|
use crate::chat::RenderableChat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Render a message into an iced `Element`
|
|
|
|
/// Render a message into an iced `Element`
|
|
|
|
pub fn view_message(msg: &DegMessage, pkey: PublicKey) -> Option<Element<GuiEvent>> { |
|
|
|
pub fn view_message(msg: &DegMessage, pkey: PublicKey) -> Option<Element<GuiEvent>> { |
|
|
@ -41,7 +41,6 @@ pub fn view_message(msg: &DegMessage, pkey: PublicKey) -> Option<Element<GuiEven |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// The main application struct (for iced)
|
|
|
|
/// The main application struct (for iced)
|
|
|
|
#[derive(Default)] |
|
|
|
#[derive(Default)] |
|
|
|
pub struct DegeonApp { |
|
|
|
pub struct DegeonApp { |
|
|
@ -59,10 +58,14 @@ pub struct DegeonApp { |
|
|
|
preview_button_states: Vec<button::State>, |
|
|
|
preview_button_states: Vec<button::State>, |
|
|
|
/// Name input on profile screen
|
|
|
|
/// Name input on profile screen
|
|
|
|
name_input_state: iced::text_input::State, |
|
|
|
name_input_state: iced::text_input::State, |
|
|
|
|
|
|
|
/// Bio input on profile screen
|
|
|
|
|
|
|
|
bio_input_state: iced::text_input::State, |
|
|
|
/// Button on the profile screen
|
|
|
|
/// Button on the profile screen
|
|
|
|
profile_done_button_state: iced::button::State, |
|
|
|
profile_done_button_state: iced::button::State, |
|
|
|
/// Scroll state
|
|
|
|
/// Scroll state
|
|
|
|
scroll: iced::scrollable::State, |
|
|
|
scroll: iced::scrollable::State, |
|
|
|
|
|
|
|
/// The button at the left-upper corner of the screen
|
|
|
|
|
|
|
|
profile_logo_state: iced::button::State, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl DegeonApp { |
|
|
|
impl DegeonApp { |
|
|
@ -71,10 +74,23 @@ impl DegeonApp { |
|
|
|
chats: &'a [Chat], |
|
|
|
chats: &'a [Chat], |
|
|
|
preview_button_states: &'a mut Vec<button::State>, |
|
|
|
preview_button_states: &'a mut Vec<button::State>, |
|
|
|
selected: usize, |
|
|
|
selected: usize, |
|
|
|
|
|
|
|
profile_logo_state: &'a mut button::State, |
|
|
|
) -> Element<'a, GuiEvent> { |
|
|
|
) -> Element<'a, GuiEvent> { |
|
|
|
while preview_button_states.len() < chats.len() { |
|
|
|
while preview_button_states.len() < chats.len() { |
|
|
|
preview_button_states.push(Default::default()) |
|
|
|
preview_button_states.push(Default::default()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Column::new() |
|
|
|
|
|
|
|
.push( |
|
|
|
|
|
|
|
iced::Button::new( |
|
|
|
|
|
|
|
profile_logo_state, |
|
|
|
|
|
|
|
iced::Container::new(iced::Image::new(iced::image::Handle::from_memory( |
|
|
|
|
|
|
|
include_bytes!("profile_logo.png").to_vec(), |
|
|
|
|
|
|
|
))) |
|
|
|
|
|
|
|
.width(Length::Units(25)), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.on_press(GuiEvent::ChangeScreen(AppScreen::ProfileEditor)), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.push( |
|
|
|
Column::with_children( |
|
|
|
Column::with_children( |
|
|
|
chats |
|
|
|
chats |
|
|
|
.iter() |
|
|
|
.iter() |
|
|
@ -85,7 +101,8 @@ impl DegeonApp { |
|
|
|
) |
|
|
|
) |
|
|
|
.padding(20) |
|
|
|
.padding(20) |
|
|
|
.spacing(10) |
|
|
|
.spacing(10) |
|
|
|
.align_items(Align::Start) |
|
|
|
.align_items(Align::Start), |
|
|
|
|
|
|
|
) |
|
|
|
.width(Length::FillPortion(1)) |
|
|
|
.width(Length::FillPortion(1)) |
|
|
|
.into() |
|
|
|
.into() |
|
|
|
} |
|
|
|
} |
|
|
@ -119,6 +136,7 @@ impl DegeonApp { |
|
|
|
text_input_state, |
|
|
|
text_input_state, |
|
|
|
preview_button_states, |
|
|
|
preview_button_states, |
|
|
|
scroll: scroll_state, |
|
|
|
scroll: scroll_state, |
|
|
|
|
|
|
|
profile_logo_state, |
|
|
|
.. |
|
|
|
.. |
|
|
|
} = self; |
|
|
|
} = self; |
|
|
|
Row::new() |
|
|
|
Row::new() |
|
|
@ -127,6 +145,7 @@ impl DegeonApp { |
|
|
|
chats, |
|
|
|
chats, |
|
|
|
preview_button_states, |
|
|
|
preview_button_states, |
|
|
|
*selected_chat, |
|
|
|
*selected_chat, |
|
|
|
|
|
|
|
profile_logo_state, |
|
|
|
)) |
|
|
|
)) |
|
|
|
.push(Self::active_chat( |
|
|
|
.push(Self::active_chat( |
|
|
|
chats, |
|
|
|
chats, |
|
|
@ -143,11 +162,12 @@ impl DegeonApp { |
|
|
|
let Self { |
|
|
|
let Self { |
|
|
|
data: |
|
|
|
data: |
|
|
|
Degeon { |
|
|
|
Degeon { |
|
|
|
profile: crate::message::Profile { name }, |
|
|
|
profile: crate::message::Profile { name, bio }, |
|
|
|
.. |
|
|
|
.. |
|
|
|
}, |
|
|
|
}, |
|
|
|
profile_done_button_state, |
|
|
|
profile_done_button_state, |
|
|
|
name_input_state, |
|
|
|
name_input_state, |
|
|
|
|
|
|
|
bio_input_state, |
|
|
|
.. |
|
|
|
.. |
|
|
|
} = self; |
|
|
|
} = self; |
|
|
|
iced::Container::new( |
|
|
|
iced::Container::new( |
|
|
@ -155,16 +175,42 @@ impl DegeonApp { |
|
|
|
.align_items(Align::Center) |
|
|
|
.align_items(Align::Center) |
|
|
|
.width(Length::Fill) |
|
|
|
.width(Length::Fill) |
|
|
|
.spacing(60) |
|
|
|
.spacing(60) |
|
|
|
.push(Text::new("Profile")) |
|
|
|
.padding(40) |
|
|
|
|
|
|
|
.push(Text::new("Profile").size(40)) |
|
|
|
|
|
|
|
// Name input
|
|
|
|
.push( |
|
|
|
.push( |
|
|
|
iced::Container::new(Row::with_children(vec![ |
|
|
|
iced::Container::new( |
|
|
|
|
|
|
|
Row::with_children(vec![ |
|
|
|
Text::new("Name").into(), |
|
|
|
Text::new("Name").into(), |
|
|
|
TextInput::new(name_input_state, "Name", name.as_str(), |name| { |
|
|
|
TextInput::new(name_input_state, "Name", name.as_str(), |name| { |
|
|
|
GuiEvent::ChangeName(name) |
|
|
|
GuiEvent::ChangeName(name) |
|
|
|
}) |
|
|
|
}) |
|
|
|
.padding(5) |
|
|
|
.padding(5) |
|
|
|
.into(), |
|
|
|
.into(), |
|
|
|
]).max_width(250).align_items(Align::Center)) |
|
|
|
]) |
|
|
|
|
|
|
|
.spacing(10) |
|
|
|
|
|
|
|
.max_width(250) |
|
|
|
|
|
|
|
.align_items(Align::Center), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.align_x(Align::Center) |
|
|
|
|
|
|
|
.padding(40) |
|
|
|
|
|
|
|
.style(style::Container::Field), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
// Bio input
|
|
|
|
|
|
|
|
.push( |
|
|
|
|
|
|
|
iced::Container::new( |
|
|
|
|
|
|
|
Row::with_children(vec![ |
|
|
|
|
|
|
|
Text::new("Bio").into(), |
|
|
|
|
|
|
|
TextInput::new(bio_input_state, "Bio", bio.as_str(), |bio| { |
|
|
|
|
|
|
|
GuiEvent::ChangeBio(bio) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.padding(5) |
|
|
|
|
|
|
|
.into(), |
|
|
|
|
|
|
|
]) |
|
|
|
|
|
|
|
.spacing(10) |
|
|
|
|
|
|
|
.max_width(250) |
|
|
|
|
|
|
|
.align_items(Align::Center), |
|
|
|
|
|
|
|
) |
|
|
|
.align_x(Align::Center) |
|
|
|
.align_x(Align::Center) |
|
|
|
.padding(40) |
|
|
|
.padding(40) |
|
|
|
.style(style::Container::Field), |
|
|
|
.style(style::Container::Field), |
|
|
@ -176,6 +222,7 @@ impl DegeonApp { |
|
|
|
), |
|
|
|
), |
|
|
|
) |
|
|
|
) |
|
|
|
.align_x(Align::Center) |
|
|
|
.align_x(Align::Center) |
|
|
|
|
|
|
|
.width(Length::Fill) |
|
|
|
.into() |
|
|
|
.into() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -192,7 +239,11 @@ impl Application for DegeonApp { |
|
|
|
} |
|
|
|
} |
|
|
|
data.send_multicast(ProtocolMsg::Ping).unwrap(); |
|
|
|
data.send_multicast(ProtocolMsg::Ping).unwrap(); |
|
|
|
let mut scroll: iced::scrollable::State = Default::default(); |
|
|
|
let mut scroll: iced::scrollable::State = Default::default(); |
|
|
|
scroll.scroll_to(1., iced::Rectangle::with_size(iced::Size::ZERO), iced::Rectangle::with_size(iced::Size::UNIT)); |
|
|
|
scroll.scroll_to( |
|
|
|
|
|
|
|
1., |
|
|
|
|
|
|
|
iced::Rectangle::with_size(iced::Size::ZERO), |
|
|
|
|
|
|
|
iced::Rectangle::with_size(iced::Size::UNIT), |
|
|
|
|
|
|
|
); |
|
|
|
let st = DegeonApp { |
|
|
|
let st = DegeonApp { |
|
|
|
screen: if data.profile.name.is_empty() { |
|
|
|
screen: if data.profile.name.is_empty() { |
|
|
|
AppScreen::ProfileEditor |
|
|
|
AppScreen::ProfileEditor |
|
|
@ -205,8 +256,10 @@ impl Application for DegeonApp { |
|
|
|
text_input_state: Default::default(), |
|
|
|
text_input_state: Default::default(), |
|
|
|
preview_button_states: vec![Default::default(), Default::default()], |
|
|
|
preview_button_states: vec![Default::default(), Default::default()], |
|
|
|
name_input_state: Default::default(), |
|
|
|
name_input_state: Default::default(), |
|
|
|
|
|
|
|
bio_input_state: Default::default(), |
|
|
|
profile_done_button_state: Default::default(), |
|
|
|
profile_done_button_state: Default::default(), |
|
|
|
scroll, |
|
|
|
scroll, |
|
|
|
|
|
|
|
profile_logo_state: Default::default(), |
|
|
|
}; |
|
|
|
}; |
|
|
|
(st, iced::Command::none()) |
|
|
|
(st, iced::Command::none()) |
|
|
|
} |
|
|
|
} |
|
|
@ -246,13 +299,15 @@ impl Application for DegeonApp { |
|
|
|
self.screen = sc; |
|
|
|
self.screen = sc; |
|
|
|
self.data.save_to_file("".to_string()).unwrap(); |
|
|
|
self.data.save_to_file("".to_string()).unwrap(); |
|
|
|
if prev_screen == AppScreen::ProfileEditor { |
|
|
|
if prev_screen == AppScreen::ProfileEditor { |
|
|
|
return self.data.get_send_command( |
|
|
|
return self |
|
|
|
ProtocolMsg::ProfileResponse(self.data.get_profile()), |
|
|
|
.data |
|
|
|
&target, |
|
|
|
.get_broadcast_send_command(ProtocolMsg::ProfileResponse( |
|
|
|
); |
|
|
|
self.data.get_profile(), |
|
|
|
|
|
|
|
)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
GuiEvent::ChangeName(name) => self.data.profile.name = name, |
|
|
|
GuiEvent::ChangeName(name) => self.data.profile.name = name, |
|
|
|
|
|
|
|
GuiEvent::ChangeBio(bio) => self.data.profile.bio = bio, |
|
|
|
// The following events are already handled in Degeon::process_event
|
|
|
|
// The following events are already handled in Degeon::process_event
|
|
|
|
GuiEvent::NewMessageInChat(_pkey, _msg) => {} |
|
|
|
GuiEvent::NewMessageInChat(_pkey, _msg) => {} |
|
|
|
GuiEvent::SetProfile(_pkey, _profile) => {} |
|
|
|
GuiEvent::SetProfile(_pkey, _profile) => {} |
|
|
|