2021-10-05 00:30:11 +00:00
|
|
|
use client::{
|
2021-08-24 10:23:50 +00:00
|
|
|
channel::{Channel, ChannelEvent, ChannelList, ChannelMessage},
|
2021-10-05 00:30:11 +00:00
|
|
|
Client,
|
2021-08-24 10:23:50 +00:00
|
|
|
};
|
2022-02-24 23:27:11 +00:00
|
|
|
use editor::Editor;
|
2021-08-24 12:17:15 +00:00
|
|
|
use gpui::{
|
2021-08-31 00:59:13 +00:00
|
|
|
action,
|
|
|
|
elements::*,
|
|
|
|
keymap::Binding,
|
2021-09-07 10:27:43 +00:00
|
|
|
platform::CursorStyle,
|
2021-08-31 00:59:13 +00:00
|
|
|
views::{ItemType, Select, SelectStyle},
|
2021-09-08 13:58:16 +00:00
|
|
|
AppContext, Entity, ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View,
|
2021-08-31 00:59:13 +00:00
|
|
|
ViewContext, ViewHandle,
|
2021-08-24 12:17:15 +00:00
|
|
|
};
|
2022-03-11 22:59:05 +00:00
|
|
|
use postage::prelude::Stream;
|
2021-12-17 00:36:33 +00:00
|
|
|
use std::sync::Arc;
|
2021-08-25 22:22:14 +00:00
|
|
|
use time::{OffsetDateTime, UtcOffset};
|
2021-10-04 19:07:35 +00:00
|
|
|
use util::{ResultExt, TryFutureExt};
|
2022-02-24 23:27:11 +00:00
|
|
|
use workspace::{settings::SoftWrap, Settings};
|
2021-08-20 21:28:45 +00:00
|
|
|
|
2021-09-02 14:05:34 +00:00
|
|
|
const MESSAGE_LOADING_THRESHOLD: usize = 50;
|
|
|
|
|
2021-08-20 21:28:45 +00:00
|
|
|
pub struct ChatPanel {
|
2021-10-05 00:14:21 +00:00
|
|
|
rpc: Arc<Client>,
|
2021-08-23 22:02:42 +00:00
|
|
|
channel_list: ModelHandle<ChannelList>,
|
2021-08-24 00:21:06 +00:00
|
|
|
active_channel: Option<(ModelHandle<Channel>, Subscription)>,
|
2021-08-26 14:36:56 +00:00
|
|
|
message_list: ListState,
|
2021-08-24 12:17:15 +00:00
|
|
|
input_editor: ViewHandle<Editor>,
|
2021-08-31 00:59:13 +00:00
|
|
|
channel_select: ViewHandle<Select>,
|
2021-09-02 17:15:05 +00:00
|
|
|
local_timezone: UtcOffset,
|
2021-09-08 15:09:02 +00:00
|
|
|
_observe_status: Task<()>,
|
2021-08-20 21:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Event {}
|
|
|
|
|
2021-08-24 14:15:46 +00:00
|
|
|
action!(Send);
|
2021-08-27 21:58:28 +00:00
|
|
|
action!(LoadMoreMessages);
|
2021-08-24 14:15:46 +00:00
|
|
|
|
|
|
|
pub fn init(cx: &mut MutableAppContext) {
|
|
|
|
cx.add_action(ChatPanel::send);
|
2021-08-27 21:58:28 +00:00
|
|
|
cx.add_action(ChatPanel::load_more_messages);
|
2021-08-24 15:29:14 +00:00
|
|
|
|
|
|
|
cx.add_bindings(vec![Binding::new("enter", Send, Some("ChatPanel"))]);
|
2021-08-24 14:15:46 +00:00
|
|
|
}
|
|
|
|
|
2021-08-23 15:29:46 +00:00
|
|
|
impl ChatPanel {
|
2021-08-24 10:23:50 +00:00
|
|
|
pub fn new(
|
2021-10-05 00:14:21 +00:00
|
|
|
rpc: Arc<Client>,
|
2021-08-24 10:23:50 +00:00
|
|
|
channel_list: ModelHandle<ChannelList>,
|
|
|
|
cx: &mut ViewContext<Self>,
|
|
|
|
) -> Self {
|
2021-09-02 18:20:30 +00:00
|
|
|
let input_editor = cx.add_view(|cx| {
|
2022-03-11 22:59:05 +00:00
|
|
|
let mut editor =
|
|
|
|
Editor::auto_height(4, Some(|theme| theme.chat_panel.input_editor.clone()), cx);
|
2022-02-24 23:27:11 +00:00
|
|
|
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
|
|
|
|
editor
|
2021-09-02 18:20:30 +00:00
|
|
|
});
|
2021-08-31 00:59:13 +00:00
|
|
|
let channel_select = cx.add_view(|cx| {
|
|
|
|
let channel_list = channel_list.clone();
|
|
|
|
Select::new(0, cx, {
|
|
|
|
move |ix, item_type, is_hovered, cx| {
|
|
|
|
Self::render_channel_name(
|
|
|
|
&channel_list,
|
|
|
|
ix,
|
|
|
|
item_type,
|
|
|
|
is_hovered,
|
2022-03-17 13:33:01 +00:00
|
|
|
&cx.global::<Settings>().theme.chat_panel.channel_select,
|
2021-08-31 00:59:13 +00:00
|
|
|
cx,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
})
|
2022-03-11 22:59:05 +00:00
|
|
|
.with_style(move |cx| {
|
2022-03-17 13:33:01 +00:00
|
|
|
let theme = &cx.global::<Settings>().theme.chat_panel.channel_select;
|
2022-03-11 22:59:05 +00:00
|
|
|
SelectStyle {
|
|
|
|
header: theme.header.container.clone(),
|
|
|
|
menu: theme.menu.clone(),
|
2021-08-31 12:41:59 +00:00
|
|
|
}
|
2021-08-31 00:59:13 +00:00
|
|
|
})
|
|
|
|
});
|
2021-09-01 04:57:56 +00:00
|
|
|
|
2021-09-01 14:18:44 +00:00
|
|
|
let mut message_list = ListState::new(0, Orientation::Bottom, 1000., {
|
2021-11-29 22:12:53 +00:00
|
|
|
let this = cx.weak_handle();
|
2021-09-01 04:57:56 +00:00
|
|
|
move |ix, cx| {
|
|
|
|
let this = this.upgrade(cx).unwrap().read(cx);
|
|
|
|
let message = this.active_channel.as_ref().unwrap().0.read(cx).message(ix);
|
2022-03-11 22:59:05 +00:00
|
|
|
this.render_message(message, cx)
|
2021-09-01 04:57:56 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
message_list.set_scroll_handler(|visible_range, cx| {
|
2021-09-02 14:05:34 +00:00
|
|
|
if visible_range.start < MESSAGE_LOADING_THRESHOLD {
|
2021-09-01 04:57:56 +00:00
|
|
|
cx.dispatch_action(LoadMoreMessages);
|
|
|
|
}
|
|
|
|
});
|
2022-03-01 17:50:05 +00:00
|
|
|
let _observe_status = cx.spawn_weak(|this, mut cx| {
|
2021-09-08 13:58:16 +00:00
|
|
|
let mut status = rpc.status();
|
|
|
|
async move {
|
|
|
|
while let Some(_) = status.recv().await {
|
2022-03-01 17:50:05 +00:00
|
|
|
if let Some(this) = this.upgrade(&cx) {
|
|
|
|
this.update(&mut cx, |_, cx| cx.notify());
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2021-09-08 13:58:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2021-09-01 04:57:56 +00:00
|
|
|
|
2021-08-23 22:02:42 +00:00
|
|
|
let mut this = Self {
|
2021-09-07 10:27:43 +00:00
|
|
|
rpc,
|
2021-08-23 22:02:42 +00:00
|
|
|
channel_list,
|
2021-08-26 14:36:56 +00:00
|
|
|
active_channel: Default::default(),
|
2021-09-01 04:57:56 +00:00
|
|
|
message_list,
|
2021-08-24 12:17:15 +00:00
|
|
|
input_editor,
|
2021-08-31 00:59:13 +00:00
|
|
|
channel_select,
|
2021-09-02 17:15:05 +00:00
|
|
|
local_timezone: cx.platform().local_timezone(),
|
2021-09-08 15:09:02 +00:00
|
|
|
_observe_status,
|
2021-08-23 22:02:42 +00:00
|
|
|
};
|
2021-08-24 00:21:06 +00:00
|
|
|
|
2021-08-24 15:29:14 +00:00
|
|
|
this.init_active_channel(cx);
|
2021-08-24 00:21:06 +00:00
|
|
|
cx.observe(&this.channel_list, |this, _, cx| {
|
2021-08-24 15:29:14 +00:00
|
|
|
this.init_active_channel(cx);
|
2021-08-24 00:21:06 +00:00
|
|
|
})
|
|
|
|
.detach();
|
2021-09-02 08:16:20 +00:00
|
|
|
cx.observe(&this.channel_select, |this, channel_select, cx| {
|
|
|
|
let selected_ix = channel_select.read(cx).selected_index();
|
|
|
|
let selected_channel = this.channel_list.update(cx, |channel_list, cx| {
|
|
|
|
let available_channels = channel_list.available_channels()?;
|
|
|
|
let channel_id = available_channels.get(selected_ix)?.id;
|
|
|
|
channel_list.get_channel(channel_id, cx)
|
|
|
|
});
|
|
|
|
if let Some(selected_channel) = selected_channel {
|
|
|
|
this.set_active_channel(selected_channel, cx);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.detach();
|
2021-08-24 00:21:06 +00:00
|
|
|
|
|
|
|
this
|
|
|
|
}
|
|
|
|
|
2021-08-24 15:29:14 +00:00
|
|
|
fn init_active_channel(&mut self, cx: &mut ViewContext<Self>) {
|
2021-08-31 00:59:13 +00:00
|
|
|
let (active_channel, channel_count) = self.channel_list.update(cx, |list, cx| {
|
|
|
|
let channel_count;
|
|
|
|
let mut active_channel = None;
|
|
|
|
|
|
|
|
if let Some(available_channels) = list.available_channels() {
|
|
|
|
channel_count = available_channels.len();
|
|
|
|
if self.active_channel.is_none() {
|
|
|
|
if let Some(channel_id) = available_channels.first().map(|channel| channel.id) {
|
|
|
|
active_channel = list.get_channel(channel_id, cx);
|
|
|
|
}
|
2021-08-24 15:29:14 +00:00
|
|
|
}
|
2021-08-31 00:59:13 +00:00
|
|
|
} else {
|
|
|
|
channel_count = 0;
|
2021-08-24 00:21:06 +00:00
|
|
|
}
|
2021-08-31 00:59:13 +00:00
|
|
|
|
|
|
|
(active_channel, channel_count)
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(active_channel) = active_channel {
|
|
|
|
self.set_active_channel(active_channel, cx);
|
|
|
|
} else {
|
2021-09-08 13:58:16 +00:00
|
|
|
self.message_list.reset(0);
|
2021-08-24 00:21:06 +00:00
|
|
|
self.active_channel = None;
|
2021-08-23 15:29:46 +00:00
|
|
|
}
|
2021-08-31 00:59:13 +00:00
|
|
|
|
|
|
|
self.channel_select.update(cx, |select, cx| {
|
|
|
|
select.set_item_count(channel_count, cx);
|
|
|
|
});
|
2021-08-23 22:02:42 +00:00
|
|
|
}
|
|
|
|
|
2021-08-24 15:29:14 +00:00
|
|
|
fn set_active_channel(&mut self, channel: ModelHandle<Channel>, cx: &mut ViewContext<Self>) {
|
|
|
|
if self.active_channel.as_ref().map(|e| &e.0) != Some(&channel) {
|
2021-09-03 00:36:56 +00:00
|
|
|
{
|
|
|
|
let channel = channel.read(cx);
|
|
|
|
self.message_list.reset(channel.message_count());
|
|
|
|
let placeholder = format!("Message #{}", channel.name());
|
|
|
|
self.input_editor.update(cx, move |editor, cx| {
|
|
|
|
editor.set_placeholder_text(placeholder, cx);
|
|
|
|
});
|
|
|
|
}
|
2021-08-24 15:29:14 +00:00
|
|
|
let subscription = cx.subscribe(&channel, Self::channel_did_change);
|
|
|
|
self.active_channel = Some((channel, subscription));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-24 10:23:50 +00:00
|
|
|
fn channel_did_change(
|
|
|
|
&mut self,
|
2021-08-26 14:36:56 +00:00
|
|
|
_: ModelHandle<Channel>,
|
2021-08-24 10:23:50 +00:00
|
|
|
event: &ChannelEvent,
|
|
|
|
cx: &mut ViewContext<Self>,
|
|
|
|
) {
|
|
|
|
match event {
|
2021-09-09 13:34:46 +00:00
|
|
|
ChannelEvent::MessagesUpdated {
|
2021-08-24 20:12:02 +00:00
|
|
|
old_range,
|
|
|
|
new_count,
|
|
|
|
} => {
|
2021-08-26 14:36:56 +00:00
|
|
|
self.message_list.splice(old_range.clone(), *new_count);
|
2021-08-24 10:23:50 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-24 00:21:06 +00:00
|
|
|
cx.notify();
|
2021-08-23 15:29:46 +00:00
|
|
|
}
|
2021-08-24 10:23:50 +00:00
|
|
|
|
2022-03-11 22:59:05 +00:00
|
|
|
fn render_channel(&self, cx: &mut RenderContext<Self>) -> ElementBox {
|
2022-03-17 13:33:01 +00:00
|
|
|
let theme = &cx.global::<Settings>().theme;
|
2021-09-07 11:57:30 +00:00
|
|
|
Flex::column()
|
|
|
|
.with_child(
|
2022-01-27 16:52:36 +00:00
|
|
|
Container::new(ChildView::new(&self.channel_select).boxed())
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.chat_panel.channel_select.container)
|
2021-09-07 11:57:30 +00:00
|
|
|
.boxed(),
|
|
|
|
)
|
|
|
|
.with_child(self.render_active_channel_messages())
|
2022-03-11 22:59:05 +00:00
|
|
|
.with_child(self.render_input_box(cx))
|
2021-09-07 11:57:30 +00:00
|
|
|
.boxed()
|
|
|
|
}
|
|
|
|
|
2021-09-01 04:57:56 +00:00
|
|
|
fn render_active_channel_messages(&self) -> ElementBox {
|
|
|
|
let messages = if self.active_channel.is_some() {
|
|
|
|
List::new(self.message_list.clone()).boxed()
|
2021-08-26 14:36:56 +00:00
|
|
|
} else {
|
|
|
|
Empty::new().boxed()
|
|
|
|
};
|
|
|
|
|
2022-01-07 01:29:34 +00:00
|
|
|
Flexible::new(1., true, messages).boxed()
|
2021-08-24 10:23:50 +00:00
|
|
|
}
|
|
|
|
|
2022-03-11 22:59:05 +00:00
|
|
|
fn render_message(&self, message: &ChannelMessage, cx: &AppContext) -> ElementBox {
|
2021-09-01 04:57:56 +00:00
|
|
|
let now = OffsetDateTime::now_utc();
|
2022-03-17 13:33:01 +00:00
|
|
|
let settings = cx.global::<Settings>();
|
2021-09-15 13:12:16 +00:00
|
|
|
let theme = if message.is_pending() {
|
|
|
|
&settings.theme.chat_panel.pending_message
|
|
|
|
} else {
|
|
|
|
&settings.theme.chat_panel.message
|
|
|
|
};
|
|
|
|
|
2021-09-01 23:14:51 +00:00
|
|
|
Container::new(
|
|
|
|
Flex::column()
|
|
|
|
.with_child(
|
|
|
|
Flex::row()
|
|
|
|
.with_child(
|
|
|
|
Container::new(
|
|
|
|
Label::new(
|
|
|
|
message.sender.github_login.clone(),
|
|
|
|
theme.sender.text.clone(),
|
|
|
|
)
|
|
|
|
.boxed(),
|
2021-08-25 22:22:14 +00:00
|
|
|
)
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.sender.container)
|
2021-08-25 22:22:14 +00:00
|
|
|
.boxed(),
|
|
|
|
)
|
2021-09-01 23:14:51 +00:00
|
|
|
.with_child(
|
|
|
|
Container::new(
|
|
|
|
Label::new(
|
2021-09-02 17:15:05 +00:00
|
|
|
format_timestamp(message.timestamp, now, self.local_timezone),
|
2021-09-01 23:14:51 +00:00
|
|
|
theme.timestamp.text.clone(),
|
|
|
|
)
|
|
|
|
.boxed(),
|
2021-08-25 22:22:14 +00:00
|
|
|
)
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.timestamp.container)
|
2021-08-25 22:22:14 +00:00
|
|
|
.boxed(),
|
|
|
|
)
|
|
|
|
.boxed(),
|
2021-09-01 23:14:51 +00:00
|
|
|
)
|
|
|
|
.with_child(Text::new(message.body.clone(), theme.body.clone()).boxed())
|
|
|
|
.boxed(),
|
|
|
|
)
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.container)
|
2021-09-01 23:14:51 +00:00
|
|
|
.boxed()
|
2021-08-24 10:23:50 +00:00
|
|
|
}
|
|
|
|
|
2022-03-11 22:59:05 +00:00
|
|
|
fn render_input_box(&self, cx: &AppContext) -> ElementBox {
|
2022-03-17 13:33:01 +00:00
|
|
|
let theme = &cx.global::<Settings>().theme;
|
2022-01-27 16:52:36 +00:00
|
|
|
Container::new(ChildView::new(&self.input_editor).boxed())
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.chat_panel.input_editor.container)
|
2021-09-06 10:50:04 +00:00
|
|
|
.boxed()
|
2021-08-24 10:23:50 +00:00
|
|
|
}
|
2021-08-24 14:15:46 +00:00
|
|
|
|
2021-08-31 00:59:13 +00:00
|
|
|
fn render_channel_name(
|
|
|
|
channel_list: &ModelHandle<ChannelList>,
|
|
|
|
ix: usize,
|
|
|
|
item_type: ItemType,
|
|
|
|
is_hovered: bool,
|
|
|
|
theme: &theme::ChannelSelect,
|
|
|
|
cx: &AppContext,
|
|
|
|
) -> ElementBox {
|
|
|
|
let channel = &channel_list.read(cx).available_channels().unwrap()[ix];
|
|
|
|
let theme = match (item_type, is_hovered) {
|
|
|
|
(ItemType::Header, _) => &theme.header,
|
|
|
|
(ItemType::Selected, false) => &theme.active_item,
|
|
|
|
(ItemType::Selected, true) => &theme.hovered_active_item,
|
|
|
|
(ItemType::Unselected, false) => &theme.item,
|
|
|
|
(ItemType::Unselected, true) => &theme.hovered_item,
|
|
|
|
};
|
|
|
|
Container::new(
|
|
|
|
Flex::row()
|
|
|
|
.with_child(
|
|
|
|
Container::new(Label::new("#".to_string(), theme.hash.text.clone()).boxed())
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.hash.container)
|
2021-08-31 00:59:13 +00:00
|
|
|
.boxed(),
|
|
|
|
)
|
|
|
|
.with_child(Label::new(channel.name.clone(), theme.name.clone()).boxed())
|
|
|
|
.boxed(),
|
|
|
|
)
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.container)
|
2021-08-31 00:59:13 +00:00
|
|
|
.boxed()
|
|
|
|
}
|
|
|
|
|
2021-09-07 11:57:30 +00:00
|
|
|
fn render_sign_in_prompt(&self, cx: &mut RenderContext<Self>) -> ElementBox {
|
2022-03-17 13:33:01 +00:00
|
|
|
let theme = cx.global::<Settings>().theme.clone();
|
2021-09-07 11:57:30 +00:00
|
|
|
let rpc = self.rpc.clone();
|
|
|
|
let this = cx.handle();
|
|
|
|
|
|
|
|
enum SignInPromptLabel {}
|
|
|
|
|
|
|
|
Align::new(
|
2022-02-17 21:43:58 +00:00
|
|
|
MouseEventHandler::new::<SignInPromptLabel, _, _>(0, cx, |mouse_state, _| {
|
|
|
|
Label::new(
|
|
|
|
"Sign in to use chat".to_string(),
|
|
|
|
if mouse_state.hovered {
|
|
|
|
theme.chat_panel.hovered_sign_in_prompt.clone()
|
|
|
|
} else {
|
|
|
|
theme.chat_panel.sign_in_prompt.clone()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.boxed()
|
|
|
|
})
|
2021-09-07 11:57:30 +00:00
|
|
|
.with_cursor_style(CursorStyle::PointingHand)
|
|
|
|
.on_click(move |cx| {
|
|
|
|
let rpc = rpc.clone();
|
|
|
|
let this = this.clone();
|
|
|
|
cx.spawn(|mut cx| async move {
|
2022-03-23 18:15:36 +00:00
|
|
|
if rpc
|
|
|
|
.authenticate_and_connect(true, &cx)
|
|
|
|
.log_err()
|
|
|
|
.await
|
|
|
|
.is_some()
|
|
|
|
{
|
2021-09-07 11:57:30 +00:00
|
|
|
cx.update(|cx| {
|
|
|
|
if let Some(this) = this.upgrade(cx) {
|
|
|
|
if this.is_focused(cx) {
|
|
|
|
this.update(cx, |this, cx| cx.focus(&this.input_editor));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.detach();
|
|
|
|
})
|
|
|
|
.boxed(),
|
|
|
|
)
|
|
|
|
.boxed()
|
|
|
|
}
|
|
|
|
|
2021-08-24 14:15:46 +00:00
|
|
|
fn send(&mut self, _: &Send, cx: &mut ViewContext<Self>) {
|
|
|
|
if let Some((channel, _)) = self.active_channel.as_ref() {
|
|
|
|
let body = self.input_editor.update(cx, |editor, cx| {
|
|
|
|
let body = editor.text(cx);
|
|
|
|
editor.clear(cx);
|
|
|
|
body
|
|
|
|
});
|
|
|
|
|
2021-08-27 23:53:23 +00:00
|
|
|
if let Some(task) = channel
|
2021-08-24 14:15:46 +00:00
|
|
|
.update(cx, |channel, cx| channel.send_message(body, cx))
|
2021-08-27 23:53:23 +00:00
|
|
|
.log_err()
|
|
|
|
{
|
|
|
|
task.detach();
|
|
|
|
}
|
2021-08-24 14:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-27 21:58:28 +00:00
|
|
|
|
|
|
|
fn load_more_messages(&mut self, _: &LoadMoreMessages, cx: &mut ViewContext<Self>) {
|
|
|
|
if let Some((channel, _)) = self.active_channel.as_ref() {
|
|
|
|
channel.update(cx, |channel, cx| {
|
|
|
|
channel.load_more_messages(cx);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-08-23 15:29:46 +00:00
|
|
|
}
|
|
|
|
|
2021-08-20 21:28:45 +00:00
|
|
|
impl Entity for ChatPanel {
|
|
|
|
type Event = Event;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl View for ChatPanel {
|
|
|
|
fn ui_name() -> &'static str {
|
|
|
|
"ChatPanel"
|
|
|
|
}
|
|
|
|
|
2021-09-07 10:27:43 +00:00
|
|
|
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
2021-09-15 11:18:13 +00:00
|
|
|
let element = if self.rpc.user_id().is_some() {
|
2022-03-11 22:59:05 +00:00
|
|
|
self.render_channel(cx)
|
2021-09-15 11:18:13 +00:00
|
|
|
} else {
|
|
|
|
self.render_sign_in_prompt(cx)
|
2021-09-07 10:27:43 +00:00
|
|
|
};
|
2022-03-17 13:33:01 +00:00
|
|
|
let theme = &cx.global::<Settings>().theme;
|
2021-09-07 11:57:30 +00:00
|
|
|
ConstrainedBox::new(
|
|
|
|
Container::new(element)
|
2021-09-14 23:47:43 +00:00
|
|
|
.with_style(theme.chat_panel.container)
|
2021-09-07 11:57:30 +00:00
|
|
|
.boxed(),
|
|
|
|
)
|
|
|
|
.with_min_width(150.)
|
|
|
|
.boxed()
|
2021-08-25 22:22:14 +00:00
|
|
|
}
|
2021-08-27 08:01:44 +00:00
|
|
|
|
|
|
|
fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
|
2021-10-05 00:14:21 +00:00
|
|
|
if matches!(
|
|
|
|
*self.rpc.status().borrow(),
|
|
|
|
client::Status::Connected { .. }
|
|
|
|
) {
|
2021-09-07 11:57:30 +00:00
|
|
|
cx.focus(&self.input_editor);
|
|
|
|
}
|
2021-08-27 08:01:44 +00:00
|
|
|
}
|
2021-08-25 22:22:14 +00:00
|
|
|
}
|
|
|
|
|
2021-09-02 17:15:05 +00:00
|
|
|
fn format_timestamp(
|
|
|
|
mut timestamp: OffsetDateTime,
|
|
|
|
mut now: OffsetDateTime,
|
|
|
|
local_timezone: UtcOffset,
|
|
|
|
) -> String {
|
|
|
|
timestamp = timestamp.to_offset(local_timezone);
|
|
|
|
now = now.to_offset(local_timezone);
|
2021-08-25 22:22:14 +00:00
|
|
|
|
|
|
|
let today = now.date();
|
|
|
|
let date = timestamp.date();
|
|
|
|
let mut hour = timestamp.hour();
|
|
|
|
let mut part = "am";
|
|
|
|
if hour > 12 {
|
|
|
|
hour -= 12;
|
|
|
|
part = "pm";
|
|
|
|
}
|
|
|
|
if date == today {
|
2021-08-26 22:09:26 +00:00
|
|
|
format!("{:02}:{:02}{}", hour, timestamp.minute(), part)
|
2021-08-25 22:22:14 +00:00
|
|
|
} else if date.next_day() == Some(today) {
|
2021-08-26 22:09:26 +00:00
|
|
|
format!("yesterday at {:02}:{:02}{}", hour, timestamp.minute(), part)
|
2021-08-25 22:22:14 +00:00
|
|
|
} else {
|
2021-08-26 22:09:26 +00:00
|
|
|
format!("{:02}/{}/{}", date.month() as u32, date.day(), date.year())
|
2021-08-20 21:28:45 +00:00
|
|
|
}
|
|
|
|
}
|