Skip to content
This repository has been archived by the owner on Sep 6, 2024. It is now read-only.

Commit

Permalink
[+] address book add item function
Browse files Browse the repository at this point in the history
  • Loading branch information
heng30 committed Dec 27, 2023
1 parent d835ac7 commit b5ddcd3
Show file tree
Hide file tree
Showing 15 changed files with 410 additions and 29 deletions.
158 changes: 158 additions & 0 deletions bitbox/src/db/address_book.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use super::pool;
use anyhow::Result;

#[derive(Serialize, Deserialize, Debug, Clone, sqlx::FromRow)]
pub struct AddressBook {
pub uuid: String,
pub data: String,
}

pub async fn new() -> Result<()> {
sqlx::query(
"CREATE TABLE IF NOT EXISTS address_book (
id INTEGER PRIMARY KEY,
uuid TEXT NOT NULL UNIQUE,
data TEXT NOT NULL)",
)
.execute(&pool())
.await?;

Ok(())
}

pub async fn delete(uuid: &str) -> Result<()> {
sqlx::query("DELETE FROM address_book WHERE uuid=?")
.bind(uuid)
.execute(&pool())
.await?;
Ok(())
}

pub async fn delete_all() -> Result<()> {

Check warning on line 31 in bitbox/src/db/address_book.rs

View workflow job for this annotation

GitHub Actions / action-run

function `delete_all` is never used
sqlx::query("DELETE FROM address_book").execute(&pool()).await?;
Ok(())
}

pub async fn insert(uuid: &str, data: &str) -> Result<()> {
sqlx::query("INSERT INTO address_book (uuid, data) VALUES (?, ?)")
.bind(uuid)
.bind(data)
.execute(&pool())
.await?;
Ok(())
}
pub async fn update(uuid: &str, data: &str) -> Result<()> {

Check warning on line 44 in bitbox/src/db/address_book.rs

View workflow job for this annotation

GitHub Actions / action-run

function `update` is never used
sqlx::query("UPDATE address_book SET data=? WHERE uuid=?")
.bind(data)
.bind(uuid)
.execute(&pool())
.await?;

Ok(())
}

pub async fn select(uuid: &str) -> Result<AddressBook> {
let pool = pool();
let stream = sqlx::query_as::<_, AddressBook>("SELECT * FROM address_book WHERE uuid=?")
.bind(uuid)
.fetch_one(&pool);

Ok(stream.await?)
}

pub async fn select_all() -> Result<Vec<AddressBook>> {
Ok(sqlx::query_as::<_, AddressBook>("SELECT * FROM address_book")
.fetch_all(&pool())
.await?)
}

#[allow(dead_code)]
pub async fn is_exist(uuid: &str) -> Result<()> {
select(uuid).await?;
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::db;

#[tokio::test]
async fn test_address_book_table_new() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await
}

#[tokio::test]
async fn test_address_book_table_delete_one() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await?;
insert("uuid-1", "data-1").await?;
delete("uuid-1").await
}

#[tokio::test]
async fn test_address_book_table_delete_all() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await
}

#[tokio::test]
async fn test_address_book_table_insert() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await?;
insert("uuid-1", "data-1").await?;
insert("uuid-2", "data-2").await
}

#[tokio::test]
async fn test_address_book_table_update() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await?;
insert("uuid-1", "data-1").await?;
update("uuid-1", "data-1.1").await
}

#[tokio::test]
async fn test_address_book_table_select_one() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await?;
assert!(select("uuid-1").await.is_err());

insert("uuid-1", "data-1").await?;
assert_eq!(select("uuid-1").await?.data, "data-1");
Ok(())
}

#[tokio::test]
async fn test_address_book_table_select_all() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await?;
insert("uuid-1", "data-1").await?;
insert("uuid-2", "data-2").await?;
let address_books = select_all().await?;

assert_eq!(address_books.len(), 2);
assert_eq!(address_books[0].uuid, "uuid-1");
assert_eq!(address_books[1].uuid, "uuid-2");
Ok(())
}

#[tokio::test]
async fn test_address_book_table_is_exist() -> Result<()> {
db::init("/tmp/bitbox-test.db").await;
new().await?;
delete_all().await?;
insert("uuid-1", "data-1").await?;

assert!(is_exist("uuid-0").await.is_err());
assert!(is_exist("uuid-1").await.is_ok());
Ok(())
}
}
2 changes: 2 additions & 0 deletions bitbox/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use sqlx::{
use std::sync::Mutex;

pub mod account;
pub mod address_book;

const MAX_CONNECTIONS: u32 = 3;

Expand Down Expand Up @@ -34,6 +35,7 @@ async fn create_db(db_path: &str) -> Result<(), sqlx::Error> {
pub async fn init(db_path: &str) {
create_db(db_path).await.expect("create db");
account::new().await.expect("account new");
address_book::new().await.expect("address_book new");
}

#[allow(dead_code)]
Expand Down
96 changes: 94 additions & 2 deletions bitbox/src/logic/address_book.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use crate::db;
use crate::message::{async_message_success, async_message_warn};
use crate::slint_generatedAppWindow::{AddressBookItem, AppWindow, Logic, Store};
use slint::{ComponentHandle, Model, VecModel};
use crate::util::translator::tr;
use serde_json::{json, Value};
use slint::{ComponentHandle, Model, VecModel, Weak};
use tokio::task::spawn;
use uuid::Uuid;

pub fn init(ui: &AppWindow) {
load_items(ui.as_weak());

let ui_handle = ui.as_weak();
ui.global::<Logic>()
.on_address_book_delete_item(move |uuid| {
Expand All @@ -21,7 +29,16 @@ pub fn init(ui: &AppWindow) {
.expect("We know we set a VecModel earlier")
.remove(index);

// TODO: remove data from the database
let (ui, uuid) = (ui.as_weak(), uuid.to_string());
spawn(async move {
match db::address_book::delete(&uuid).await {
Ok(_) => async_message_success(ui.clone(), tr("删除成功")),
Err(e) => async_message_warn(
ui.clone(),
format!("{}. {}: {}", tr("删除失败"), tr("原因"), e),
),
}
});
return;
}
}
Expand All @@ -40,4 +57,79 @@ pub fn init(ui: &AppWindow) {

slint::SharedString::default()
});

let ui_handle = ui.as_weak();
ui.global::<Logic>()
.on_address_book_add_item(move |name, address| {
let ui = ui_handle.unwrap();
let uuid = Uuid::new_v4().to_string();

let item = AddressBookItem {
uuid: uuid.clone().into(),
name: name,
address: address,
};

let json_item = json!({
"uuid": uuid.clone(),
"name": item.name.to_string(),
"address": item.address.to_string()
});
let json = serde_json::to_string(&json_item).unwrap();

ui.global::<Store>()
.get_address_book_datas()
.as_any()
.downcast_ref::<VecModel<AddressBookItem>>()
.expect("We know we set a VecModel earlier")
.push(item);

let ui = ui.as_weak();
spawn(async move {
match db::address_book::insert(&uuid, &json).await {
Ok(_) => async_message_success(ui.clone(), tr("添加成功")),
Err(e) => async_message_warn(
ui.clone(),
format!("{}. {}: {}", tr("添加失败"), tr("原因"), e),
),
}
});
});
}

fn load_items(ui: Weak<AppWindow>) {
spawn(async move {
match db::address_book::select_all().await {
Ok(items) => {
let mut address_items = vec![];
for item in items.iter() {
match serde_json::from_str::<Value>(&item.data) {
Err(e) => log::warn!("Error: {e:?}"),
Ok(value) => {
address_items.push(AddressBookItem {
uuid: value["uuid"].as_str().unwrap().into(),
name: value["name"].as_str().unwrap().into(),
address: value["address"].as_str().unwrap().into(),
});
}
}
}

let _ = slint::invoke_from_event_loop(move || {
ui.clone()
.unwrap()
.global::<Store>()
.get_address_book_datas()
.as_any()
.downcast_ref::<VecModel<AddressBookItem>>()
.expect("We know we set a VecModel earlier")
.set_vec(address_items);
});
}
Err(e) => async_message_warn(
ui.clone(),
format!("{}. {}: {}", tr("加载失败"), tr("原因"), e),
),
}
});
}
18 changes: 17 additions & 1 deletion bitbox/src/logic/message.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::slint_generatedAppWindow::{AppWindow, Logic, MessageItem, Store};
use slint::ComponentHandle;
use slint::{Timer, TimerMode};
use slint::{Timer, TimerMode, Weak};

#[macro_export]
macro_rules! message_warn {
Expand All @@ -18,6 +18,22 @@ macro_rules! message_success {
};
}

pub fn async_message_warn(ui: Weak<AppWindow>, msg: String) {
let _ = slint::invoke_from_event_loop(move || {
ui.unwrap()
.global::<Logic>()
.invoke_show_message(slint::format!("{}", msg), "warning".into());
});
}

pub fn async_message_success(ui: Weak<AppWindow>, msg: String) {
let _ = slint::invoke_from_event_loop(move || {
ui.unwrap()
.global::<Logic>()
.invoke_show_message(slint::format!("{}", msg), "success".into());
});
}

pub fn init(ui: &AppWindow) {
let timer = Timer::default();
let ui_handle = ui.as_weak();
Expand Down
34 changes: 20 additions & 14 deletions bitbox/src/logic/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,24 @@ pub fn init(ui: &AppWindow) {
.parse()
.unwrap_or(18);
config.ui.font_family = setting_config.ui.font_family.to_string();
config.ui.win_width = setting_config
.ui
.win_width
.to_string()
.parse()
.unwrap_or(600);
config.ui.win_height = setting_config
.ui
.win_height
.to_string()
.parse()
.unwrap_or(800);
config.ui.win_width = u32::max(
setting_config
.ui
.win_width
.to_string()
.parse()
.unwrap_or(600),
600,
);
config.ui.win_height = u32::max(
setting_config
.ui
.win_height
.to_string()
.parse()
.unwrap_or(800),
800,
);

config.ui.language = setting_config.ui.language.to_string();

Expand Down Expand Up @@ -81,8 +87,8 @@ fn init_setting_dialog(ui: Weak<AppWindow>) {
let mut setting_dialog = ui.global::<Store>().get_setting_dialog_config();
setting_dialog.ui.font_size = slint::format!("{}", ui_config.font_size);
setting_dialog.ui.font_family = ui_config.font_family.into();
setting_dialog.ui.win_width = slint::format!("{}", ui_config.win_width);
setting_dialog.ui.win_height = slint::format!("{}", ui_config.win_height);
setting_dialog.ui.win_width = slint::format!("{}", u32::max(ui_config.win_width, 600));
setting_dialog.ui.win_height = slint::format!("{}", u32::max(ui_config.win_height, 800));
setting_dialog.ui.language = ui_config.language.into();

setting_dialog.proxy.enabled = socks5_config.enabled;
Expand Down
3 changes: 3 additions & 0 deletions bitbox/src/util/translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub fn tr(text: &str) -> String {
items.insert("原因", "Reason");
items.insert("删除成功", "Delete success");
items.insert("删除失败", "Delete failed");
items.insert("添加成功", "Add success");
items.insert("添加失败", "Add failed");
items.insert("复制失败", "Copy failed");
items.insert("复制成功", "Copy success");
items.insert("清空失败", "Delete failed");
Expand All @@ -22,6 +24,7 @@ pub fn tr(text: &str) -> String {
items.insert("发送失败", "Send failed");
items.insert("下载成功", "Download success");
items.insert("下载失败", "Download failed");
items.insert("加载失败", "Load failed");
items.insert("正在重试...", "Retrying...");
items.insert("正在下载...", "Downloading...");
items.insert("刷新...", "Flush...");
Expand Down
Loading

0 comments on commit b5ddcd3

Please sign in to comment.