first commit
This commit is contained in:
1
back/.env
Normal file
1
back/.env
Normal file
@@ -0,0 +1 @@
|
||||
DATABASE_URL="mysql://root:root@127.0.0.1:3306/liscord_db"
|
||||
1
back/.gitignore
vendored
Normal file
1
back/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
1062
back/Cargo.lock
generated
Normal file
1062
back/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
back/Cargo.toml
Normal file
12
back/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "back"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.8.4"
|
||||
diesel = { version = "2.2.0", features = ["mysql", "serde_json"] }
|
||||
dotenvy = "0.15"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.143"
|
||||
tokio = { version = "1.47.1", features = ["rt-multi-thread"] }
|
||||
9
back/diesel.toml
Normal file
9
back/diesel.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
# For documentation on how to configure this file,
|
||||
# see https://diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
||||
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
|
||||
|
||||
[migrations_directory]
|
||||
dir = "/home/clement/projects/liscord/back/migrations"
|
||||
13
back/docker/docker-compose.yaml
Normal file
13
back/docker/docker-compose.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:latest
|
||||
volumes:
|
||||
- /liscord:/var/lib/mysql/data
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: liscord_db
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
0
back/migrations/.keep
Normal file
0
back/migrations/.keep
Normal file
6
back/migrations/2025-08-17-115759_create_base/down.sql
Normal file
6
back/migrations/2025-08-17-115759_create_base/down.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
DROP TABLE IF EXISTS user_roles;
|
||||
DROP TABLE IF EXISTS server_members;
|
||||
DROP TABLE IF EXISTS messages;
|
||||
DROP TABLE IF EXISTS channels;
|
||||
DROP TABLE IF EXISTS servers;
|
||||
DROP TABLE IF EXISTS users;
|
||||
73
back/migrations/2025-08-17-115759_create_base/up.sql
Normal file
73
back/migrations/2025-08-17-115759_create_base/up.sql
Normal file
@@ -0,0 +1,73 @@
|
||||
-- Your SQL goes here
|
||||
-- Table des utilisateurs
|
||||
CREATE TABLE users (
|
||||
user_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(100) NOT NULL UNIQUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Table des serveurs
|
||||
CREATE TABLE servers (
|
||||
server_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
server_name VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Table des canaux
|
||||
CREATE TABLE channels (
|
||||
channel_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
server_id INT NOT NULL,
|
||||
channel_name VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (server_id) REFERENCES servers(server_id)
|
||||
);
|
||||
|
||||
-- Table des messages
|
||||
CREATE TABLE messages (
|
||||
message_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
channel_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels(channel_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id)
|
||||
);
|
||||
|
||||
-- Table des membres de serveur
|
||||
CREATE TABLE server_members (
|
||||
server_member_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
server_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (server_id) REFERENCES servers(server_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id)
|
||||
);
|
||||
|
||||
-- Table des membres de canal
|
||||
CREATE TABLE channel_members (
|
||||
channel_member_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
channel_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels(channel_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id)
|
||||
);
|
||||
|
||||
-- Table des rôles
|
||||
CREATE TABLE roles (
|
||||
role_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
server_id INT NOT NULL,
|
||||
role_name VARCHAR(50) NOT NULL,
|
||||
FOREIGN KEY (server_id) REFERENCES servers(server_id)
|
||||
);
|
||||
|
||||
-- Table des relations utilisateur-rôle
|
||||
CREATE TABLE user_roles (
|
||||
user_role_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id),
|
||||
FOREIGN KEY (role_id) REFERENCES roles(role_id)
|
||||
);
|
||||
24
back/src/bin/change_user_email.rs
Normal file
24
back/src/bin/change_user_email.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use back::*;
|
||||
use std::env::args;
|
||||
|
||||
fn main() {
|
||||
let id = args()
|
||||
.nth(1)
|
||||
.expect("This action requires an id")
|
||||
.parse::<i32>()
|
||||
.expect("Invalid id");
|
||||
|
||||
let new_email = args().nth(2).expect("This action requires an email");
|
||||
|
||||
if !new_email.contains("@") {
|
||||
panic!("Email invalid");
|
||||
}
|
||||
|
||||
let connection = &mut establish_connection();
|
||||
|
||||
if let Ok(user) = change_user_email(id, new_email, connection) {
|
||||
debug(format!("Email changed for user {}", user.username));
|
||||
} else {
|
||||
debug("Problem while trying to change email");
|
||||
}
|
||||
}
|
||||
40
back/src/bin/create_user.rs
Normal file
40
back/src/bin/create_user.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use back::{models::NewUser, *};
|
||||
use std::io::stdin;
|
||||
|
||||
fn main() {
|
||||
let connection = &mut establish_connection();
|
||||
|
||||
let mut username = String::new();
|
||||
let mut password = String::new();
|
||||
let mut email = String::new();
|
||||
|
||||
println!("Username: ");
|
||||
stdin().read_line(&mut username).unwrap();
|
||||
let username = username.trim_end();
|
||||
|
||||
println!("Email: ",);
|
||||
stdin().read_line(&mut email).unwrap();
|
||||
let email = email.trim_end();
|
||||
|
||||
println!("Password: ",);
|
||||
stdin().read_line(&mut password).unwrap();
|
||||
let password = password.trim_end();
|
||||
|
||||
let new_user = NewUser {
|
||||
username: username.to_owned(),
|
||||
email: email.to_owned(),
|
||||
password_hash: password.to_owned(),
|
||||
};
|
||||
|
||||
if let Ok(user) = create_user(connection, &new_user) {
|
||||
debug(format!("\nSaved user {username} with id {}", user.user_id));
|
||||
} else {
|
||||
debug("Saving failed");
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(not(windows))]
|
||||
// const EOF: &str = "CTRL+D";
|
||||
|
||||
// #[cfg(windows)]
|
||||
// const EOF: &str = "CTRL+Z";
|
||||
15
back/src/bin/delete_user.rs
Normal file
15
back/src/bin/delete_user.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use std::env::args;
|
||||
|
||||
use back::*;
|
||||
|
||||
fn main() {
|
||||
let target_username = args().nth(1).expect("Expected a username");
|
||||
|
||||
let connection = &mut establish_connection();
|
||||
|
||||
if let Ok(username) = delete_user(target_username, connection) {
|
||||
debug(format!("User {username} deleted"));
|
||||
} else {
|
||||
debug("Deletion failed");
|
||||
}
|
||||
}
|
||||
19
back/src/bin/show_users.rs
Normal file
19
back/src/bin/show_users.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use back::establish_connection;
|
||||
use back::models::*;
|
||||
use diesel::prelude::*;
|
||||
|
||||
fn main() {
|
||||
use back::schema::users::dsl::*;
|
||||
|
||||
let connection = &mut establish_connection();
|
||||
let results = users
|
||||
.limit(5)
|
||||
.select(User::as_select())
|
||||
.load(connection)
|
||||
.expect("Error loading posts");
|
||||
|
||||
println!("Displaying {} posts", results.len());
|
||||
for user in results {
|
||||
println!("{}, {}", user.username, user.email);
|
||||
}
|
||||
}
|
||||
70
back/src/lib.rs
Normal file
70
back/src/lib.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use diesel::prelude::*;
|
||||
use dotenvy::dotenv;
|
||||
use std::{env, fmt::Display};
|
||||
|
||||
use crate::models::{NewUser, User};
|
||||
pub mod models;
|
||||
pub mod schema;
|
||||
// use crate::crud_macros::make_crud;
|
||||
|
||||
type Error = diesel::result::Error;
|
||||
|
||||
pub fn debug(s: impl Display) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
println!("{s}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn establish_connection() -> MysqlConnection {
|
||||
dotenv().ok();
|
||||
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
MysqlConnection::establish(&database_url)
|
||||
.unwrap_or_else(|_| panic!("Error connecting to {database_url}"))
|
||||
}
|
||||
|
||||
pub fn create_user(conn: &mut MysqlConnection, new_user: &NewUser) -> Result<User, Error> {
|
||||
use crate::schema::users;
|
||||
|
||||
conn.transaction(|conn| {
|
||||
diesel::insert_into(users::table)
|
||||
.values(new_user)
|
||||
.execute(conn)?;
|
||||
|
||||
users::table
|
||||
.order(users::user_id.desc())
|
||||
.select(User::as_select())
|
||||
.first(conn)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn delete_user(
|
||||
target_username: String,
|
||||
connection: &mut MysqlConnection,
|
||||
) -> Result<String, Error> {
|
||||
use crate::schema::users::dsl::*;
|
||||
let nb_del = diesel::delete(users.filter(username.eq(&target_username))).execute(connection)?;
|
||||
if nb_del > 0 {
|
||||
Ok(target_username)
|
||||
} else {
|
||||
Err(diesel::result::Error::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_user_email(
|
||||
id: i32,
|
||||
new_email: String,
|
||||
connection: &mut MysqlConnection,
|
||||
) -> Result<User, Error> {
|
||||
use crate::schema::users::dsl::*;
|
||||
connection.transaction(|connection| {
|
||||
let user = users.find(id).select(User::as_select()).first(connection)?;
|
||||
|
||||
diesel::update(users.find(id))
|
||||
.set(email.eq(&new_email))
|
||||
.execute(connection)?;
|
||||
|
||||
Ok(user)
|
||||
})
|
||||
}
|
||||
32
back/src/main.rs
Normal file
32
back/src/main.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use axum::{
|
||||
Json, Router,
|
||||
response::IntoResponse,
|
||||
routing::{get, post},
|
||||
};
|
||||
use back::{create_user, establish_connection, models::NewUser};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let app = Router::new()
|
||||
.route("/", get(hello))
|
||||
.route("/create_user", post(create_user_api));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
async fn hello() -> &'static str {
|
||||
"Hello !"
|
||||
}
|
||||
|
||||
async fn create_user_api(Json(payload): Json<NewUser>) -> impl IntoResponse {
|
||||
let mut conn = establish_connection();
|
||||
match create_user(&mut conn, &payload) {
|
||||
Ok(user) => (axum::http::StatusCode::CREATED, axum::Json(user)).into_response(),
|
||||
Err(e) => (
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Failed to create user: {e}"),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
}
|
||||
50
back/src/models.rs
Normal file
50
back/src/models.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use crate::schema::*;
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Queryable, Selectable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = users)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
pub struct User {
|
||||
pub user_id: i32,
|
||||
pub username: String,
|
||||
pub password_hash: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = users)]
|
||||
pub struct NewUser {
|
||||
pub username: String,
|
||||
pub password_hash: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = servers)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
pub struct Server {
|
||||
pub server_id: i32,
|
||||
pub server_name: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = servers)]
|
||||
pub struct NewServer {
|
||||
pub server_name: String,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = channels)]
|
||||
pub struct Channel {
|
||||
pub channel_id: i32,
|
||||
pub server_id: i32,
|
||||
pub channel_name: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = channels)]
|
||||
pub struct NewChannel {
|
||||
pub server_id: i32,
|
||||
pub channel_name: String,
|
||||
}
|
||||
100
back/src/schema.rs
Normal file
100
back/src/schema.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
channel_members (channel_member_id) {
|
||||
channel_member_id -> Integer,
|
||||
channel_id -> Integer,
|
||||
user_id -> Integer,
|
||||
joined_at -> Nullable<Timestamp>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
channels (channel_id) {
|
||||
channel_id -> Integer,
|
||||
server_id -> Integer,
|
||||
#[max_length = 100]
|
||||
channel_name -> Varchar,
|
||||
created_at -> Nullable<Timestamp>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
messages (message_id) {
|
||||
message_id -> Integer,
|
||||
channel_id -> Integer,
|
||||
user_id -> Integer,
|
||||
content -> Text,
|
||||
created_at -> Nullable<Timestamp>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
roles (role_id) {
|
||||
role_id -> Integer,
|
||||
server_id -> Integer,
|
||||
#[max_length = 50]
|
||||
role_name -> Varchar,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
server_members (server_member_id) {
|
||||
server_member_id -> Integer,
|
||||
server_id -> Integer,
|
||||
user_id -> Integer,
|
||||
joined_at -> Nullable<Timestamp>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
servers (server_id) {
|
||||
server_id -> Integer,
|
||||
#[max_length = 100]
|
||||
server_name -> Varchar,
|
||||
created_at -> Nullable<Timestamp>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
user_roles (user_role_id) {
|
||||
user_role_id -> Integer,
|
||||
user_id -> Integer,
|
||||
role_id -> Integer,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
users (user_id) {
|
||||
user_id -> Integer,
|
||||
#[max_length = 50]
|
||||
username -> Varchar,
|
||||
#[max_length = 255]
|
||||
password_hash -> Varchar,
|
||||
#[max_length = 100]
|
||||
email -> Varchar,
|
||||
created_at -> Nullable<Timestamp>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(channel_members -> channels (channel_id));
|
||||
diesel::joinable!(channel_members -> users (user_id));
|
||||
diesel::joinable!(channels -> servers (server_id));
|
||||
diesel::joinable!(messages -> channels (channel_id));
|
||||
diesel::joinable!(messages -> users (user_id));
|
||||
diesel::joinable!(roles -> servers (server_id));
|
||||
diesel::joinable!(server_members -> servers (server_id));
|
||||
diesel::joinable!(server_members -> users (user_id));
|
||||
diesel::joinable!(user_roles -> roles (role_id));
|
||||
diesel::joinable!(user_roles -> users (user_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
channel_members,
|
||||
channels,
|
||||
messages,
|
||||
roles,
|
||||
server_members,
|
||||
servers,
|
||||
user_roles,
|
||||
users,
|
||||
);
|
||||
1
front/.gitignore
vendored
Normal file
1
front/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
4259
front/Cargo.lock
generated
Normal file
4259
front/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
front/Cargo.toml
Normal file
11
front/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "front"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
iced = { version = "0.13.1", features = ["debug", "image"] }
|
||||
|
||||
[[bin]]
|
||||
name = "liscord"
|
||||
path = "src/main.rs"
|
||||
BIN
front/assets/liscord.png
Normal file
BIN
front/assets/liscord.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 248 KiB |
15
front/src/channels.rs
Normal file
15
front/src/channels.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Channel {
|
||||
pub server_id: i32,
|
||||
pub channel_name: String,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
fn new(server_id: i32, channel_name: &str) -> Self {
|
||||
Channel {
|
||||
server_id,
|
||||
channel_name: channel_name.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
98
front/src/main.rs
Normal file
98
front/src/main.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use iced::Length::{self, Fill, FillPortion};
|
||||
use iced::widget::container;
|
||||
use iced::{
|
||||
Background, Color, Element, Task, Theme,
|
||||
widget::{Image, column, container::Style, row, text},
|
||||
};
|
||||
|
||||
mod channels;
|
||||
mod servers;
|
||||
|
||||
use servers::{User, get_servers_buttons};
|
||||
|
||||
fn main() -> Result<(), iced::Error> {
|
||||
iced::application(Liscord::title, Liscord::update, Liscord::view)
|
||||
.theme(Liscord::theme)
|
||||
.run_with(Liscord::new)
|
||||
}
|
||||
|
||||
struct Liscord {
|
||||
user: Option<User>,
|
||||
selected_server: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Event {
|
||||
ServerPressed(i32),
|
||||
}
|
||||
|
||||
impl Liscord {
|
||||
fn new() -> (Self, Task<Event>) {
|
||||
(
|
||||
Liscord {
|
||||
user: Some(User::default()),
|
||||
selected_server: None,
|
||||
},
|
||||
Task::none(),
|
||||
)
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
"Liscord".to_string()
|
||||
}
|
||||
|
||||
fn update(&mut self, event: Event) -> Task<Event> {
|
||||
match event {
|
||||
Event::ServerPressed(server_id) => {
|
||||
self.selected_server = Some(server_id);
|
||||
// println!("Server Pressed ! Id: {server_id}")
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<'_, Event> {
|
||||
let app_body = {
|
||||
let server_bar = {
|
||||
let mut content = column![text("Servers")];
|
||||
|
||||
if let Some(user) = &self.user {
|
||||
content = content.push(get_servers_buttons(user, self))
|
||||
}
|
||||
|
||||
container(content)
|
||||
.padding(10)
|
||||
.width(iced::Length::Fixed(300.))
|
||||
.height(Fill)
|
||||
.style(|_theme| Style {
|
||||
background: Some(Background::Color(Color::from_rgb(0.0, 0.0, 1.0))),
|
||||
..Default::default()
|
||||
})
|
||||
};
|
||||
|
||||
let message_content = container(text("Messages"))
|
||||
.width(iced::Length::Fill)
|
||||
.height(Fill);
|
||||
row![server_bar, message_content]
|
||||
}
|
||||
.height(FillPortion(19));
|
||||
|
||||
let app_header = {
|
||||
let liscord_logo = Image::new("assets/liscord.png");
|
||||
let liscord_text = text("Liscord");
|
||||
let centered_text = container(liscord_text)
|
||||
.width(Fill)
|
||||
.center_x(Length::Fill)
|
||||
.center_y(Length::Fill);
|
||||
|
||||
row![liscord_logo, centered_text].width(Fill).height(Fill)
|
||||
}
|
||||
.height(FillPortion(1));
|
||||
|
||||
column![app_header, app_body].into()
|
||||
}
|
||||
|
||||
fn theme(&self) -> Theme {
|
||||
Theme::Dark
|
||||
}
|
||||
}
|
||||
93
front/src/servers.rs
Normal file
93
front/src/servers.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use iced::{
|
||||
Border,
|
||||
widget::{Button, Column, container},
|
||||
};
|
||||
use iced::{Length, Shadow};
|
||||
|
||||
use crate::{Event, Liscord};
|
||||
|
||||
mod colors {
|
||||
use iced::Color;
|
||||
|
||||
pub const BUTTON_COLOR: Color = Color::from_rgb(0.2, 0.2, 0.2);
|
||||
pub const SELECTED_BUTTON_COLOR: Color = Color::from_rgb(0.2, 0.2, 1.);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Server {
|
||||
pub server_id: i32,
|
||||
pub server_name: String,
|
||||
is_hovered: bool,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
fn new(id: i32, name: &str) -> Self {
|
||||
Server {
|
||||
server_id: id,
|
||||
server_name: name.to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Server {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.server_id == other.server_id
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Default)]
|
||||
pub struct User {
|
||||
pub user_id: i32,
|
||||
pub username: String,
|
||||
pub password_hash: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
pub fn get_servers(_user: &User) -> Vec<Server> {
|
||||
let friend_serv0 = Server::new(0, "Friends0");
|
||||
let friend_serv1 = Server::new(1, "Friends1");
|
||||
let friend_serv2 = Server::new(2, "Friends2");
|
||||
vec![friend_serv0, friend_serv1, friend_serv2]
|
||||
}
|
||||
|
||||
pub fn get_servers_buttons<'a>(user: &User, instance: &'a Liscord) -> Column<'a, Event> {
|
||||
let servers = get_servers(user);
|
||||
|
||||
let mut col = Column::new();
|
||||
|
||||
for server in servers {
|
||||
col = col.push(server_button(server, instance));
|
||||
}
|
||||
|
||||
col
|
||||
}
|
||||
|
||||
fn server_button<'a>(server: Server, instance: &'a Liscord) -> Button<'a, Event> {
|
||||
Button::new(
|
||||
container(iced::widget::text(server.server_name).size(20))
|
||||
.center_x(Length::Fill)
|
||||
.center_y(Length::Fill),
|
||||
)
|
||||
.padding(10)
|
||||
.width(iced::Length::Fill)
|
||||
.height(Length::Fixed(100.0))
|
||||
.style(move |_theme, _status| iced::widget::button::Style {
|
||||
background: Some(iced::Background::Color(
|
||||
if Some(server.server_id) == instance.selected_server {
|
||||
colors::SELECTED_BUTTON_COLOR
|
||||
} else {
|
||||
colors::BUTTON_COLOR
|
||||
},
|
||||
)),
|
||||
border: Border::default().rounded(10),
|
||||
shadow: Shadow {
|
||||
offset: iced::Vector { x: 3., y: 3. },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.on_press(Event::ServerPressed(server.server_id))
|
||||
}
|
||||
Reference in New Issue
Block a user