feat: Redesign New Chat (#31)
* make subject is optional * redesign * search * fix * adjust
This commit is contained in:
@@ -13,6 +13,7 @@ anyhow.workspace = true
|
||||
itertools.workspace = true
|
||||
chrono.workspace = true
|
||||
smallvec.workspace = true
|
||||
smol.workspace = true
|
||||
futures.workspace = true
|
||||
|
||||
random_name_generator = "0.3.6"
|
||||
qrcode-generator = "5.0.0"
|
||||
|
||||
55
crates/common/src/debounced_delay.rs
Normal file
55
crates/common/src/debounced_delay.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use futures::{channel::oneshot, FutureExt};
|
||||
use gpui::{Context, Task};
|
||||
use std::{marker::PhantomData, time::Duration};
|
||||
|
||||
pub struct DebouncedDelay<E: 'static> {
|
||||
task: Option<Task<()>>,
|
||||
cancel_channel: Option<oneshot::Sender<()>>,
|
||||
_phantom_data: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E: 'static> Default for DebouncedDelay<E> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: 'static> DebouncedDelay<E> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
task: None,
|
||||
cancel_channel: None,
|
||||
_phantom_data: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fire_new<F>(&mut self, delay: Duration, cx: &mut Context<E>, func: F)
|
||||
where
|
||||
F: 'static + Send + FnOnce(&mut E, &mut Context<E>) -> Task<()>,
|
||||
{
|
||||
if let Some(channel) = self.cancel_channel.take() {
|
||||
_ = channel.send(());
|
||||
}
|
||||
|
||||
let (sender, mut receiver) = oneshot::channel::<()>();
|
||||
self.cancel_channel = Some(sender);
|
||||
|
||||
let previous_task = self.task.take();
|
||||
self.task = Some(cx.spawn(async move |entity, cx| {
|
||||
let mut timer = cx.background_executor().timer(delay).fuse();
|
||||
|
||||
if let Some(previous_task) = previous_task {
|
||||
previous_task.await;
|
||||
}
|
||||
|
||||
futures::select_biased! {
|
||||
_ = receiver => return,
|
||||
_ = timer => {}
|
||||
}
|
||||
|
||||
if let Ok(task) = entity.update(cx, |project, cx| (func)(project, cx)) {
|
||||
task.await;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,13 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use global::constants::NIP96_SERVER;
|
||||
use gpui::Image;
|
||||
use itertools::Itertools;
|
||||
use nostr_sdk::prelude::*;
|
||||
use qrcode_generator::QrCodeEcc;
|
||||
use rnglib::{Language, RNG};
|
||||
|
||||
pub mod debounced_delay;
|
||||
pub mod profile;
|
||||
|
||||
pub async fn nip96_upload(client: &Client, file: Vec<u8>) -> anyhow::Result<Url, anyhow::Error> {
|
||||
@@ -43,19 +42,6 @@ pub fn room_hash(event: &Event) -> u64 {
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
pub fn device_pubkey(event: &Event) -> Result<PublicKey, anyhow::Error> {
|
||||
let n_tag = event.tags.find(TagKind::custom("n")).context("Invalid")?;
|
||||
let hex = n_tag.content().context("Invalid")?;
|
||||
let pubkey = PublicKey::parse(hex)?;
|
||||
|
||||
Ok(pubkey)
|
||||
}
|
||||
|
||||
pub fn random_name(length: usize) -> String {
|
||||
let rng = RNG::from(&Language::Roman);
|
||||
rng.generate_names(length, true).join("-").to_lowercase()
|
||||
}
|
||||
|
||||
pub fn create_qr(data: &str) -> Result<Arc<Image>, anyhow::Error> {
|
||||
let qr = qrcode_generator::to_png_to_vec_from_str(data, QrCodeEcc::Medium, 256)?;
|
||||
let img = Arc::new(Image {
|
||||
|
||||
Reference in New Issue
Block a user