update ui

This commit is contained in:
2026-10-27 12:36:45 +07:00
parent 589c43b982
commit f486075099
7 changed files with 139 additions and 41 deletions
+1
View File
@@ -17,6 +17,7 @@ gpui-kit = { workspace = true, features = ["speech"] }
ui = { path = "../ui" }
gpui.workspace = true
instant.workspace = true
nostr-sdk.workspace = true
anyhow.workspace = true
log.workspace = true
+45 -17
View File
@@ -316,6 +316,8 @@ pub struct GroupPanel {
input: Entity<TextareaState>,
/// Dictation session for the composer input
speech: Entity<SpeechState>,
/// When the running dictation started, for the elapsed counter
speech_started: Option<instant::Instant>,
/// Uploaded, non-encrypted attachments waiting to be sent.
attachments: Vec<Url>,
/// Whether an upload is in flight.
@@ -367,14 +369,26 @@ impl GroupPanel {
subscriptions.push(
cx.subscribe_in(&speech, window, |this, _, event, window, cx| {
match event {
SpeechEvent::Final(text) if !text.is_empty() => {
this.input.update(cx, |input, cx| {
input.insert(text.clone(), window, cx);
});
SpeechEvent::Started => {
this.speech_started = Some(instant::Instant::now());
cx.notify();
}
SpeechEvent::Final(text) => {
this.speech_started = None;
if !text.is_empty() {
this.input.update(cx, |input, cx| {
input.insert(text.clone(), window, cx);
});
}
}
SpeechEvent::Error(error) => {
this.speech_started = None;
window.push_notification(Notification::error(error.to_string()), cx);
}
SpeechEvent::Cancelled => {
this.speech_started = None;
}
_ => {}
};
}),
@@ -416,6 +430,7 @@ impl GroupPanel {
rendered_texts_by_id: BTreeMap::new(),
input,
speech,
speech_started: None,
attachments: Vec::new(),
uploading: false,
tasks: smallvec![],
@@ -1073,6 +1088,8 @@ impl GroupPanel {
return self.render_notice(&notice, cx);
}
let dictating = self.speech.read(cx).status().is_active();
v_flex()
.flex_shrink_0()
.w_full()
@@ -1091,23 +1108,34 @@ impl GroupPanel {
.icon(ui::IconName::Paperclip)
.tooltip("Upload media")
.loading(self.uploading)
.disabled(self.uploading)
.disabled(dictating || self.uploading)
.ghost()
.on_click(cx.listener(|this, _event, window, cx| {
this.upload(window, cx);
})),
)
.child(
Textarea::new(&self.input)
.appearance(false)
.bg(cx.theme().input)
.small()
.min_h_8()
.py_1()
.flex_1(),
)
.when(self.speech.read(cx).status().is_capturing(), |this| {
this.child(SpeechWaveform::new(&self.speech).xsmall().w_12())
.when(dictating, |this| {
this.child(
h_flex()
.h_8()
.flex_1()
.gap_2()
.child(SpeechWaveform::new(&self.speech).small().flex_1())
.when_some(self.speech_started, |this, started| {
this.child(speech::elapsed(started, cx))
}),
)
})
.when(!dictating, |this| {
this.child(
Textarea::new(&self.input)
.appearance(false)
.bg(cx.theme().input)
.small()
.min_h_8()
.py_1()
.flex_1(),
)
})
.child(SpeechButton::new(&self.speech))
.child(
@@ -1115,7 +1143,7 @@ impl GroupPanel {
.icon(ui::IconName::PaperPlaneFill)
.tooltip("Send")
.ghost()
.disabled(self.uploading)
.disabled(dictating || self.uploading)
.on_click(cx.listener(|this, _event, window, cx| {
this.send(window, cx);
})),