diff --git a/assets/brand/coop-dark.png b/assets/brand/coop-dark.png
deleted file mode 100644
index cb69627..0000000
Binary files a/assets/brand/coop-dark.png and /dev/null differ
diff --git a/assets/brand/coop-light.png b/assets/brand/coop-light.png
deleted file mode 100644
index c7f31c2..0000000
Binary files a/assets/brand/coop-light.png and /dev/null differ
diff --git a/assets/brand/coop.svg b/assets/brand/coop.svg
new file mode 100644
index 0000000..c463b0c
--- /dev/null
+++ b/assets/brand/coop.svg
@@ -0,0 +1,4 @@
+
diff --git a/crates/app/src/states/chat/room.rs b/crates/app/src/states/chat/room.rs
index 9925d81..b88991c 100644
--- a/crates/app/src/states/chat/room.rs
+++ b/crates/app/src/states/chat/room.rs
@@ -31,7 +31,7 @@ impl Member {
IMAGE_SERVICE, picture
)
} else {
- "brands/avatar.png".into()
+ "brand/avatar.png".into()
}
}
diff --git a/crates/app/src/utils.rs b/crates/app/src/utils.rs
index 6adf7ef..39f55b1 100644
--- a/crates/app/src/utils.rs
+++ b/crates/app/src/utils.rs
@@ -1,12 +1,11 @@
-use chrono::{Duration, Local, TimeZone};
+use crate::{constants::NIP96_SERVER, get_client};
+use chrono::{Datelike, Local, TimeZone};
use nostr_sdk::prelude::*;
use std::{
collections::HashSet,
hash::{DefaultHasher, Hash, Hasher},
};
-use crate::{constants::NIP96_SERVER, get_client};
-
pub async fn nip96_upload(file: Vec) -> anyhow::Result {
let client = get_client();
let signer = client.signer().await?;
@@ -42,50 +41,47 @@ pub fn shorted_public_key(public_key: PublicKey) -> String {
format!("{}:{}", &pk[0..4], &pk[pk.len() - 4..])
}
-pub fn show_npub(public_key: PublicKey, len: usize) -> String {
- let bech32 = public_key.to_bech32().unwrap_or_default();
- let separator = " ... ";
-
- let sep_len = separator.len();
- let chars_to_show = len - sep_len;
- let front_chars = (chars_to_show + 1) / 2; // ceil
- let back_chars = chars_to_show / 2; // floor
-
- format!(
- "{}{}{}",
- &bech32[..front_chars],
- separator,
- &bech32[bech32.len() - back_chars..]
- )
-}
-
-pub fn ago(time: Timestamp) -> String {
+pub fn message_ago(time: Timestamp) -> String {
let now = Local::now();
let input_time = Local.timestamp_opt(time.as_u64() as i64, 0).unwrap();
let diff = (now - input_time).num_hours();
if diff < 24 {
let duration = now.signed_duration_since(input_time);
- format_duration(duration)
+
+ if duration.num_seconds() < 60 {
+ "now".to_string()
+ } else if duration.num_minutes() == 1 {
+ "1m".to_string()
+ } else if duration.num_minutes() < 60 {
+ format!("{}m", duration.num_minutes())
+ } else if duration.num_hours() == 1 {
+ "1h".to_string()
+ } else if duration.num_hours() < 24 {
+ format!("{}h", duration.num_hours())
+ } else if duration.num_days() == 1 {
+ "1d".to_string()
+ } else {
+ format!("{}d", duration.num_days())
+ }
} else {
input_time.format("%b %d").to_string()
}
}
-pub fn format_duration(duration: Duration) -> String {
- if duration.num_seconds() < 60 {
- "now".to_string()
- } else if duration.num_minutes() == 1 {
- "1m".to_string()
- } else if duration.num_minutes() < 60 {
- format!("{}m", duration.num_minutes())
- } else if duration.num_hours() == 1 {
- "1h".to_string()
- } else if duration.num_hours() < 24 {
- format!("{}h", duration.num_hours())
- } else if duration.num_days() == 1 {
- "1d".to_string()
+pub fn message_time(time: Timestamp) -> String {
+ let now = Local::now();
+ let input_time = Local.timestamp_opt(time.as_u64() as i64, 0).unwrap();
+
+ if input_time.day() == now.day() {
+ format!("Today at {}", input_time.format("%H:%M %p"))
+ } else if input_time.day() == now.day() - 1 {
+ format!("Yesterday at {}", input_time.format("%H:%M %p"))
} else {
- format!("{}d", duration.num_days())
+ format!(
+ "{}, {}",
+ input_time.format("%d/%m/%y"),
+ input_time.format("%H:%M %p")
+ )
}
}
diff --git a/crates/app/src/views/chat/mod.rs b/crates/app/src/views/chat/mod.rs
index d434157..e9837ca 100644
--- a/crates/app/src/views/chat/mod.rs
+++ b/crates/app/src/views/chat/mod.rs
@@ -2,7 +2,7 @@ use crate::{
constants::IMAGE_SERVICE,
get_client,
states::chat::room::Room,
- utils::{ago, compare, nip96_upload},
+ utils::{compare, message_time, nip96_upload},
};
use async_utility::task::spawn;
use gpui::{
@@ -197,7 +197,7 @@ impl ChatPanel {
Some(Message::new(
member,
ev.content.into(),
- ago(ev.created_at).into(),
+ message_time(ev.created_at).into(),
))
} else {
None
@@ -228,7 +228,7 @@ impl ChatPanel {
Message::new(
member,
event.content.clone().into(),
- ago(event.created_at).into(),
+ message_time(event.created_at).into(),
)
})
})
@@ -298,7 +298,7 @@ impl ChatPanel {
let message = Message::new(
owner,
content.to_string().into(),
- ago(Timestamp::now()).into(),
+ message_time(Timestamp::now()).into(),
);
model.items.extend(vec![message]);
diff --git a/crates/app/src/views/sidebar/compose.rs b/crates/app/src/views/sidebar/compose.rs
new file mode 100644
index 0000000..90f05ca
--- /dev/null
+++ b/crates/app/src/views/sidebar/compose.rs
@@ -0,0 +1,222 @@
+use crate::{get_client, states::chat::room::Member};
+use gpui::{
+ div, img, impl_internal_actions, px, uniform_list, Context, FocusHandle, InteractiveElement,
+ IntoElement, Model, ParentElement, Render, StatefulInteractiveElement, Styled, View,
+ ViewContext, VisualContext, WindowContext,
+};
+use nostr_sdk::prelude::*;
+use serde::Deserialize;
+use std::collections::HashSet;
+use ui::{
+ indicator::Indicator,
+ input::TextInput,
+ prelude::FluentBuilder,
+ theme::{scale::ColorScaleStep, ActiveTheme},
+ Icon, IconName, Sizable, StyledExt,
+};
+
+#[derive(Clone, PartialEq, Eq, Deserialize)]
+struct SelectContact(PublicKey);
+
+impl_internal_actions!(contacts, [SelectContact]);
+
+pub struct Compose {
+ input: View,
+ contacts: Model