mirror of
https://gitea.mizah.xyz/mizah/dergchat
synced 2024-11-21 13:35:01 -05:00
More refactoring; fixes to non-compiling parts.
This commit is contained in:
parent
b9639ad85c
commit
f8bb6f1fbd
76
src/configuration.rs
Normal file
76
src/configuration.rs
Normal file
@ -0,0 +1,76 @@
|
||||
// Dergchat, a free XMPP client.
|
||||
// Copyright (C) 2023 Werner Kroneman
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use keyring::Entry;
|
||||
use log::error;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::widgets::login_screen::LoginAttempt;
|
||||
|
||||
/// The configuration struct containing all the configuration options.
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
pub struct Configuration {
|
||||
pub stored_username: String,
|
||||
pub stored_default_nick: String,
|
||||
}
|
||||
|
||||
/// Cache the login attempt into the config and keyring.
|
||||
///
|
||||
/// Specifically, we store the username and default nick in the config file, and the password in the keyring.
|
||||
///
|
||||
/// Note: we do NOT store the password in the config file, because the latter is stored in plaintext.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `attempt` - The login attempt to store.
|
||||
/// * `config` - The current app configuration; UseState should prevent race conditions in writing.
|
||||
pub fn store_login_details(attempt: LoginAttempt, config: &mut UseRef<Configuration>) {
|
||||
|
||||
// Extract the fields from the login attempt.
|
||||
let LoginAttempt {
|
||||
username,
|
||||
default_nick,
|
||||
password,
|
||||
} = attempt;
|
||||
|
||||
// Open the config state and store the username and default nick.
|
||||
config.with_mut(|c| {
|
||||
|
||||
// Open the keyring and store the password.
|
||||
let entry = Entry::new("dergchat", &username).expect("Failed to create keyring entry.");
|
||||
entry.set_password(&password).expect("Failed to set password in keyring.");
|
||||
|
||||
// Store the username and default nick in the config.
|
||||
c.stored_username = username;
|
||||
c.stored_default_nick = default_nick;
|
||||
|
||||
if let Err(e) = confy::store("dergchat", None, c) {
|
||||
error!("Failed to store the config file: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Load the configuration from the config file.
|
||||
///
|
||||
/// On failure, log the error and return the default configuration.
|
||||
pub fn load_config() -> Configuration {
|
||||
match confy::load("dergchat", None) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
error!("Failed to load config file: {}", e);
|
||||
Configuration::default()
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
mod types;
|
||||
mod widgets;
|
||||
mod xmpp_interface;
|
||||
mod configuration;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_desktop::Config;
|
||||
|
@ -18,6 +18,7 @@ use crate::types::LoginCredentials;
|
||||
use crate::widgets::login_screen::LoginAttempt;
|
||||
use crate::widgets::login_screen::{LoginScreen, LoginStatus};
|
||||
use crate::widgets::room_view::RoomView;
|
||||
use crate::widgets::no_room_open::NoRoomPlaceholder;
|
||||
use crate::widgets::sidebar::SideBar;
|
||||
use crate::xmpp_interface::NetworkCommand;
|
||||
use dioxus::core::{Element, Scope};
|
||||
@ -31,7 +32,7 @@ use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::string::String;
|
||||
use keyring::Entry;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::configuration::load_config;
|
||||
use crate::xmpp_interface;
|
||||
|
||||
pub mod login_screen;
|
||||
@ -40,14 +41,10 @@ pub mod room_list;
|
||||
pub mod room_view;
|
||||
pub mod send_message;
|
||||
pub mod sidebar;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
struct Configuration {
|
||||
stored_username: String,
|
||||
stored_default_nick: String,
|
||||
}
|
||||
mod no_room_open;
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
|
||||
let messages = use_ref(cx, || HashMap::new());
|
||||
let current_room = use_state(cx, || None::<BareJid>);
|
||||
let connection_status = use_state(cx, || LoginStatus::LoggedOut);
|
||||
@ -56,13 +53,7 @@ pub fn App(cx: Scope) -> Element {
|
||||
xmpp_interface::run_xmpp_toplevel(connection_status.to_owned(), messages.to_owned(), rx)
|
||||
});
|
||||
|
||||
let config = use_ref(cx, || match confy::load("dergchat", None) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
error!("Failed to load config file: {}", e);
|
||||
Configuration::default()
|
||||
}
|
||||
});
|
||||
let config = use_ref(cx, load_config);
|
||||
|
||||
{
|
||||
let config = config.to_owned();
|
||||
@ -157,6 +148,9 @@ pub fn App(cx: Scope) -> Element {
|
||||
current_room.set(None);
|
||||
coroutine.send(NetworkCommand::LeaveRoom { room: x });
|
||||
},
|
||||
on_join_room: move |x: BareJid| {
|
||||
coroutine.send(NetworkCommand::JoinRoom { room: x });
|
||||
},
|
||||
}
|
||||
|
||||
// The current room.
|
||||
@ -173,21 +167,11 @@ pub fn App(cx: Scope) -> Element {
|
||||
}
|
||||
} else {
|
||||
// No room selected
|
||||
NoRoomPlaceholder {}
|
||||
rsx! {
|
||||
NoRoomPlaceholder {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn NoRoomPlaceholder(cx: Scope) -> Element {
|
||||
render! {
|
||||
div {
|
||||
padding: "5mm",
|
||||
flex_grow: 1,
|
||||
display: "flex",
|
||||
background_color: "#166322",
|
||||
"No room selected. Pick one from the list on the left."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
src/widgets/no_room_open.rs
Normal file
31
src/widgets/no_room_open.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Dergchat, a free XMPP client.
|
||||
// Copyright (C) 2023 Werner Kroneman
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use dioxus::core::{Element, Scope};
|
||||
use dioxus::prelude::*;
|
||||
|
||||
/// A placeholder widget for when no room is open.
|
||||
pub fn NoRoomPlaceholder(cx: Scope) -> Element {
|
||||
render! {
|
||||
div {
|
||||
padding: "5mm",
|
||||
flex_grow: 1,
|
||||
display: "flex",
|
||||
background_color: "#166322",
|
||||
"No room selected. Pick one from the list on the left."
|
||||
}
|
||||
}
|
||||
}
|
@ -18,18 +18,25 @@ use dioxus::core::{Element, Scope};
|
||||
use dioxus::core_macro::Props;
|
||||
use dioxus::hooks::use_state;
|
||||
use dioxus::prelude::*;
|
||||
use jid::BareJid;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// The props for the room join widget, including:
|
||||
/// * The event handler for when the user clicks the join button, passing in a room name. This name is not validated in any way.
|
||||
#[derive(Props)]
|
||||
pub struct RoomJoinProps<'a> {
|
||||
on_join_room: EventHandler<'a, String>,
|
||||
on_join_room: EventHandler<'a, BareJid>,
|
||||
}
|
||||
|
||||
/// A simple widget that allows the user to join a room by typing
|
||||
/// its name into a text field and clicking a button.
|
||||
///
|
||||
/// Also validates the room name, and displays an error message if the room name is invalid.
|
||||
pub fn RoomJoinWidget<'a>(cx: Scope<'a, RoomJoinProps>) -> Element<'a> {
|
||||
|
||||
// Store the current room name and error message in state.
|
||||
let room = use_state(cx, || "".to_owned());
|
||||
let error = use_state(cx, || "".to_owned());
|
||||
|
||||
render! {
|
||||
div {
|
||||
@ -39,11 +46,19 @@ pub fn RoomJoinWidget<'a>(cx: Scope<'a, RoomJoinProps>) -> Element<'a> {
|
||||
flex_grow: 1,
|
||||
display: "block",
|
||||
oninput: |evt| {
|
||||
room.set(evt.value.clone());
|
||||
room.set(evt.value.to_string());
|
||||
error.set("".to_owned());
|
||||
}
|
||||
}
|
||||
button {
|
||||
onclick: move |_| cx.props.on_join_room.call(room.current().to_string()),
|
||||
onclick: move |_| {
|
||||
// Validate the room name. If it's a valid Jid, try to join it.
|
||||
// Otherwise, display an error message.
|
||||
match BareJid::from_str(room.current().as_str()) {
|
||||
Ok(jid) => {error.set("".to_string()); cx.props.on_join_room.call(jid);},
|
||||
Err(e) => {error.set(e.to_string());},
|
||||
}
|
||||
},
|
||||
"Join"
|
||||
}
|
||||
}
|
||||
|
@ -22,14 +22,15 @@ use crate::widgets::room_list::RoomList;
|
||||
use crate::widgets::room_join_widget::RoomJoinWidget;
|
||||
|
||||
#[derive(Props)]
|
||||
pub struct SideBarProps {
|
||||
pub struct SideBarProps<'a> {
|
||||
pub rooms: Vec<BareJid>,
|
||||
pub on_room_picked: EventHandler<'static, BareJid>,
|
||||
pub on_room_left: EventHandler<'static, BareJid>,
|
||||
pub on_room_picked: EventHandler<'a, BareJid>,
|
||||
pub on_room_left: EventHandler<'a, BareJid>,
|
||||
pub on_join_room: EventHandler<'a, BareJid>,
|
||||
}
|
||||
|
||||
/// A widget that combines the RoomList, RoomJoinWidget, and current user info into a sidebar.
|
||||
pub fn SideBar(cx: Scope<SideBarProps>) -> Element {
|
||||
pub fn SideBar<'a>(cx: Scope<'a, SideBarProps>) -> Element<'a> {
|
||||
render! {
|
||||
div {
|
||||
padding: "5mm",
|
||||
@ -46,15 +47,13 @@ pub fn SideBar(cx: Scope<SideBarProps>) -> Element {
|
||||
// The list of rooms.
|
||||
RoomList {
|
||||
rooms: cx.props.rooms.clone(),
|
||||
on_room_picked: cx.props.on_room_picked.clone(),
|
||||
on_room_left: cx.props.on_room_left.clone(),
|
||||
on_room_picked: |e| cx.props.on_room_picked.call(e),
|
||||
on_room_left: |e| cx.props.on_room_left.call(e),
|
||||
}
|
||||
|
||||
// The widget to join a room.
|
||||
RoomJoinWidget {
|
||||
on_join_room: |x: String| {
|
||||
println!("Joining room: {:?}", x);
|
||||
},
|
||||
on_join_room: |x| cx.props.on_join_room.call(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user