ui changes
This commit is contained in:
@@ -4,6 +4,7 @@ use tokio::sync::Mutex;
|
||||
use tauri::{AppHandle, Emitter};
|
||||
use irc::client::prelude::*;
|
||||
use futures::stream::StreamExt;
|
||||
use crate::message_formatter::format_message;
|
||||
|
||||
pub struct ConnectionManager {
|
||||
pub client: Option<Arc<Mutex<Client>>>,
|
||||
@@ -57,7 +58,7 @@ impl ConnectionManager {
|
||||
async move {
|
||||
let mut stream = arc_client.lock().await.stream().unwrap(); // <-- .await for Tokio Mutex
|
||||
while let Some(message) = stream.next().await.transpose().unwrap() {
|
||||
let msg_str = format!("{:?}", message);
|
||||
let msg_str = format_message(&message);
|
||||
let _ = app_handle.emit("irc-message", msg_str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod connection_manager;
|
||||
mod command; // now it exists
|
||||
mod message_formatter;
|
||||
|
||||
use connection_manager::ConnectionManager;
|
||||
use command::{
|
||||
|
||||
197
src-tauri/src/message_formatter.rs
Normal file
197
src-tauri/src/message_formatter.rs
Normal file
@@ -0,0 +1,197 @@
|
||||
use irc::client::prelude::*;
|
||||
|
||||
/// Escape HTML special characters
|
||||
fn escape_html(s: &str) -> String {
|
||||
s.replace('&', "&")
|
||||
.replace('<', "<")
|
||||
.replace('>', ">")
|
||||
.replace('"', """)
|
||||
.replace('\'', "'")
|
||||
}
|
||||
|
||||
/// Format an IRC message with HTML colors and beautification
|
||||
pub fn format_message(message: &Message) -> String {
|
||||
// Extract prefix (server or user)
|
||||
let prefix_str = match &message.prefix {
|
||||
Some(Prefix::ServerName(server)) => {
|
||||
format!("<span style='color: #5ddfff;'>{}</span>", escape_html(server))
|
||||
},
|
||||
Some(Prefix::Nickname(nick, user, host)) => {
|
||||
if !host.is_empty() {
|
||||
format!("<span style='color: #5af78e;'>{}</span><span style='color: #666;'>@{}</span>",
|
||||
escape_html(nick), escape_html(host))
|
||||
} else if !user.is_empty() {
|
||||
format!("<span style='color: #5af78e;'>{}</span><span style='color: #666;'>@{}</span>",
|
||||
escape_html(nick), escape_html(user))
|
||||
} else {
|
||||
format!("<span style='color: #5af78e;'>{}</span>", escape_html(nick))
|
||||
}
|
||||
},
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
// Format based on command type
|
||||
match &message.command {
|
||||
Command::NOTICE(target, text) => {
|
||||
format!("<span style='color: #666;'><span style='color: #ffd700;'>[NOTICE]</span> </span>{}<span style='color: #666;'> → </span><span style='color: #666;'>{}</span><span style='color: #666;'>: </span><span style='color: #ffd700;'>{}</span>",
|
||||
prefix_str,
|
||||
escape_html(target),
|
||||
escape_html(text))
|
||||
},
|
||||
Command::PRIVMSG(target, text) => {
|
||||
format!("{}<span style='color: #666;'> → </span><span style='color: #666;'>{}</span><span style='color: #666;'>: </span><span style='color: #fff;'>{}</span>",
|
||||
prefix_str,
|
||||
escape_html(target),
|
||||
escape_html(text))
|
||||
},
|
||||
Command::JOIN(channel, keys, _) => {
|
||||
let keys_str = if let Some(k) = keys {
|
||||
format!(" <span style='color: #666;'>(key: {})</span>", escape_html(k))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!("{}<span style='color: #5af78e;'> joined </span><span style='color: #5ddfff;'>{}</span>{}",
|
||||
prefix_str,
|
||||
escape_html(channel),
|
||||
keys_str)
|
||||
},
|
||||
Command::PART(channel, msg) => {
|
||||
let msg_str = if let Some(m) = msg {
|
||||
format!(" <span style='color: #666;'>({})</span>", escape_html(m))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!("{}<span style='color: #ff5f87;'> left </span><span style='color: #5ddfff;'>{}</span>{}",
|
||||
prefix_str,
|
||||
escape_html(channel),
|
||||
msg_str)
|
||||
},
|
||||
Command::QUIT(msg) => {
|
||||
let msg_str = if let Some(m) = msg {
|
||||
format!(" <span style='color: #666;'>({})</span>", escape_html(m))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!("{}<span style='color: #ff5f87;'> quit</span>{}",
|
||||
prefix_str,
|
||||
msg_str)
|
||||
},
|
||||
Command::NICK(new_nick) => {
|
||||
format!("{}<span style='color: #5af78e;'> is now known as </span><span style='color: #5af78e;'>{}</span>",
|
||||
prefix_str,
|
||||
escape_html(new_nick))
|
||||
},
|
||||
Command::TOPIC(channel, topic) => {
|
||||
if let Some(t) = topic {
|
||||
format!("{}<span style='color: #5ddfff;'>Topic for </span><span style='color: #5ddfff;'>{}</span><span style='color: #666;'>: </span><span style='color: #ffd700;'>{}</span>",
|
||||
prefix_str,
|
||||
escape_html(channel),
|
||||
escape_html(t))
|
||||
} else {
|
||||
format!("{}<span style='color: #5ddfff;'>Topic for </span><span style='color: #5ddfff;'>{}</span><span style='color: #666;'> cleared</span>",
|
||||
prefix_str,
|
||||
escape_html(channel))
|
||||
}
|
||||
},
|
||||
Command::KICK(channel, user, msg) => {
|
||||
let msg_str = if let Some(m) = msg {
|
||||
format!(" <span style='color: #666;'>({})</span>", escape_html(m))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!("{}<span style='color: #ff5f87;'> kicked </span><span style='color: #ff5f87;'>{}</span><span style='color: #666;'> from </span><span style='color: #5ddfff;'>{}</span>{}",
|
||||
prefix_str,
|
||||
escape_html(user),
|
||||
escape_html(channel),
|
||||
msg_str)
|
||||
},
|
||||
Command::Response(code, params) => {
|
||||
// Special handling for RPL_NAMREPLY (353) - format user list nicely
|
||||
if let Response::RPL_NAMREPLY = code {
|
||||
if params.len() >= 4 {
|
||||
let channel = ¶ms[2];
|
||||
let users_str = ¶ms[3];
|
||||
// Split users and format them
|
||||
let users: Vec<&str> = users_str.split_whitespace().collect();
|
||||
let formatted_users: Vec<String> = users.iter()
|
||||
.map(|u| {
|
||||
// Check for channel prefixes (@ for ops, + for voiced)
|
||||
if u.starts_with('@') {
|
||||
format!("<span style='color: #ff5f87; font-weight: bold;'>{}</span>", escape_html(u))
|
||||
} else if u.starts_with('+') {
|
||||
format!("<span style='color: #5af78e;'>{}</span>", escape_html(u))
|
||||
} else {
|
||||
format!("<span style='color: #fff;'>{}</span>", escape_html(u))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
return format!("{}<span style='color: #666;'>[</span><span style='color: #5ddfff;'>NAMES</span><span style='color: #666;'>] </span><span style='color: #5ddfff;'>{}</span><span style='color: #666;'>: </span>{}",
|
||||
prefix_str,
|
||||
escape_html(channel),
|
||||
formatted_users.join(" "));
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for RPL_ENDOFNAMES (366)
|
||||
if let Response::RPL_ENDOFNAMES = code {
|
||||
if params.len() >= 2 {
|
||||
let channel = ¶ms[1];
|
||||
return format!("{}<span style='color: #666;'>[</span><span style='color: #5ddfff;'>ENDOFNAMES</span><span style='color: #666;'>] </span><span style='color: #5ddfff;'>{}</span><span style='color: #666;'>: End of /NAMES list.</span>",
|
||||
prefix_str,
|
||||
escape_html(channel));
|
||||
}
|
||||
}
|
||||
|
||||
let code_str = format!("{:?}", code);
|
||||
let params_str = params.iter()
|
||||
.map(|p| format!("<span style='color: #fff;'>{}</span>", escape_html(p)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
format!("{}<span style='color: #666;'>[</span><span style='color: #5ddfff;'>{}</span><span style='color: #666;'>]</span> {}",
|
||||
prefix_str,
|
||||
escape_html(&code_str),
|
||||
params_str)
|
||||
},
|
||||
Command::PING(server1, server2) => {
|
||||
let servers = if let Some(s2) = server2 {
|
||||
format!("{}, {}", server1, s2)
|
||||
} else {
|
||||
server1.clone()
|
||||
};
|
||||
format!("<span style='color: #666;'><span style='color: #5af78e;'>[PING]</span> </span>{}",
|
||||
escape_html(&servers))
|
||||
},
|
||||
Command::PONG(server1, server2) => {
|
||||
let servers = if let Some(s2) = server2 {
|
||||
format!("{}, {}", server1, s2)
|
||||
} else {
|
||||
server1.clone()
|
||||
};
|
||||
format!("<span style='color: #666;'><span style='color: #5af78e;'>[PONG]</span> </span>{}",
|
||||
escape_html(&servers))
|
||||
},
|
||||
Command::INVITE(user, channel) => {
|
||||
format!("{}<span style='color: #ff87d7;'> invited </span><span style='color: #5af78e;'>{}</span><span style='color: #666;'> to </span><span style='color: #5ddfff;'>{}</span>",
|
||||
prefix_str,
|
||||
escape_html(user),
|
||||
escape_html(channel))
|
||||
},
|
||||
Command::Raw(code, params) => {
|
||||
let params_str = params.iter()
|
||||
.map(|p| format!("<span style='color: #666;'>{}</span>", escape_html(p)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
format!("{}<span style='color: #666;'>[RAW {}]</span> {}",
|
||||
prefix_str,
|
||||
code,
|
||||
params_str)
|
||||
},
|
||||
_ => {
|
||||
// Fallback for unhandled commands
|
||||
format!("{}<span style='color: #666;'>[{:?}]</span>",
|
||||
prefix_str,
|
||||
message.command)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@
|
||||
"windows": [
|
||||
{
|
||||
"title": "ircd",
|
||||
"width": 800,
|
||||
"height": 600
|
||||
"width": 860,
|
||||
"height": 800
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
Reference in New Issue
Block a user