use anyhow::Result;
use eframe::egui::*;
use serde::{Deserialize, Serialize};
use freezeout_cards::egui::Textures;
use freezeout_core::{
crypto::{PeerId, SigningKey},
message::{Message, SignedMessage},
};
use crate::{ConnectView, Connection, ConnectionEvent};
#[derive(Debug)]
pub struct Config {
pub server_url: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct AppData {
pub passphrase: String,
pub nickname: String,
}
pub struct App {
pub config: Config,
pub textures: Textures,
sk: SigningKey,
player_id: PeerId,
nickname: String,
connection: Option<Connection>,
}
impl App {
const STORAGE_KEY: &str = "appdata";
fn new(config: Config, textures: Textures) -> Self {
let sk = SigningKey::default();
Self {
config,
textures,
player_id: sk.verifying_key().peer_id(),
sk,
nickname: String::default(),
connection: None,
}
}
pub fn connect(&mut self, sk: SigningKey, nickname: &str, ctx: &Context) -> Result<()> {
let con = Connection::connect(&self.config.server_url, ctx.clone())?;
if let Some(mut c) = self.connection.take() {
c.close();
}
self.connection = Some(con);
self.player_id = sk.verifying_key().peer_id();
self.sk = sk;
self.nickname = nickname.to_string();
Ok(())
}
pub fn is_connected(&self) -> bool {
self.connection.is_some()
}
pub fn poll_network(&mut self) -> Option<ConnectionEvent> {
if let Some(c) = self.connection.as_mut() {
c.poll()
} else {
None
}
}
pub fn player_id(&self) -> &PeerId {
&self.player_id
}
pub fn nickname(&self) -> &str {
&self.nickname
}
pub fn send_message(&mut self, msg: Message) {
if let Some(c) = self.connection.as_mut() {
let msg = SignedMessage::new(&self.sk, msg);
c.send(&msg);
}
}
pub fn close_connection(&mut self) {
if let Some(c) = self.connection.as_mut() {
c.close();
}
}
pub fn get_storage(&self, storage: Option<&dyn eframe::Storage>) -> Option<AppData> {
storage.and_then(|s| eframe::get_value::<AppData>(s, Self::STORAGE_KEY))
}
pub fn set_storage(
&self,
storage: Option<&mut (dyn eframe::Storage + 'static)>,
data: &AppData,
) {
if let Some(s) = storage {
eframe::set_value::<AppData>(s, Self::STORAGE_KEY, data);
s.flush();
}
}
}
pub trait View {
fn update(&mut self, ctx: &Context, frame: &mut eframe::Frame, app: &mut App);
fn next(
&mut self,
ctx: &Context,
frame: &mut eframe::Frame,
app: &mut App,
) -> Option<Box<dyn View>>;
}
pub struct AppFrame {
app: App,
panel: Box<dyn View>,
}
impl AppFrame {
pub fn new(config: Config, cc: &eframe::CreationContext<'_>) -> Self {
cc.egui_ctx.set_theme(Theme::Dark);
log::info!("Creating new app with config: {config:?}");
let app = App::new(config, Textures::new(&cc.egui_ctx));
let panel = Box::new(ConnectView::new(cc.storage, &app));
AppFrame { app, panel }
}
}
impl eframe::App for AppFrame {
fn update(&mut self, ctx: &Context, frame: &mut eframe::Frame) {
self.panel.update(ctx, frame, &mut self.app);
if let Some(panel) = self.panel.next(ctx, frame, &mut self.app) {
self.panel = panel;
self.panel.update(ctx, frame, &mut self.app);
}
}
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
self.app.close_connection();
}
}