dave: bubble note actions to chrome
This allows chrome to pass note actions to other apps
This commit is contained in:
@@ -3,7 +3,8 @@ use crate::wallet::GlobalWallet;
|
|||||||
use crate::zaps::Zaps;
|
use crate::zaps::Zaps;
|
||||||
use crate::{
|
use crate::{
|
||||||
frame_history::FrameHistory, AccountStorage, Accounts, AppContext, Args, DataPath,
|
frame_history::FrameHistory, AccountStorage, Accounts, AppContext, Args, DataPath,
|
||||||
DataPathType, Directory, Images, NoteCache, RelayDebugView, ThemeHandler, UnknownIds,
|
DataPathType, Directory, Images, NoteAction, NoteCache, RelayDebugView, ThemeHandler,
|
||||||
|
UnknownIds,
|
||||||
};
|
};
|
||||||
use egui::ThemePreference;
|
use egui::ThemePreference;
|
||||||
use egui_winit::clipboard::Clipboard;
|
use egui_winit::clipboard::Clipboard;
|
||||||
@@ -15,8 +16,12 @@ use std::path::Path;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
pub enum AppAction {
|
||||||
|
Note(NoteAction),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait App {
|
pub trait App {
|
||||||
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui);
|
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main notedeck app framework
|
/// Main notedeck app framework
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ mod wallet;
|
|||||||
mod zaps;
|
mod zaps;
|
||||||
|
|
||||||
pub use accounts::{AccountData, Accounts, AccountsAction, AddAccountAction, SwitchAccountAction};
|
pub use accounts::{AccountData, Accounts, AccountsAction, AddAccountAction, SwitchAccountAction};
|
||||||
pub use app::{App, Notedeck};
|
pub use app::{App, AppAction, Notedeck};
|
||||||
pub use args::Args;
|
pub use args::Args;
|
||||||
pub use context::AppContext;
|
pub use context::AppContext;
|
||||||
pub use error::{Error, FilterError, ZapError};
|
pub use error::{Error, FilterError, ZapError};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use notedeck::AppContext;
|
use notedeck::{AppAction, AppContext};
|
||||||
use notedeck_columns::Damus;
|
use notedeck_columns::Damus;
|
||||||
use notedeck_dave::Dave;
|
use notedeck_dave::Dave;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ pub enum NotedeckApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl notedeck::App for NotedeckApp {
|
impl notedeck::App for NotedeckApp {
|
||||||
fn update(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) {
|
fn update(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option<AppAction> {
|
||||||
match self {
|
match self {
|
||||||
NotedeckApp::Dave(dave) => dave.update(ctx, ui),
|
NotedeckApp::Dave(dave) => dave.update(ctx, ui),
|
||||||
NotedeckApp::Columns(columns) => columns.update(ctx, ui),
|
NotedeckApp::Columns(columns) => columns.update(ctx, ui),
|
||||||
|
|||||||
@@ -6,9 +6,13 @@ use egui::{vec2, Button, Label, Layout, RichText, ThemePreference, Widget};
|
|||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use nostrdb::{ProfileRecord, Transaction};
|
use nostrdb::{ProfileRecord, Transaction};
|
||||||
use notedeck::{
|
use notedeck::{
|
||||||
profile::get_profile_url, App, AppContext, NotedeckTextStyle, UserAccount, WalletType,
|
profile::get_profile_url, App, AppAction, AppContext, NoteAction, NotedeckTextStyle,
|
||||||
|
UserAccount, WalletType,
|
||||||
|
};
|
||||||
|
use notedeck_columns::{
|
||||||
|
timeline::{ThreadSelection, TimelineKind},
|
||||||
|
Damus, Route,
|
||||||
};
|
};
|
||||||
use notedeck_columns::Damus;
|
|
||||||
use notedeck_dave::{Dave, DaveAvatar};
|
use notedeck_dave::{Dave, DaveAvatar};
|
||||||
use notedeck_ui::{AnimationHelper, ProfilePic};
|
use notedeck_ui::{AnimationHelper, ProfilePic};
|
||||||
|
|
||||||
@@ -179,7 +183,9 @@ impl Chrome {
|
|||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
self.apps[self.active as usize].update(ctx, ui);
|
if let Some(action) = self.apps[self.active as usize].update(ctx, ui) {
|
||||||
|
chrome_handle_app_action(self, ctx, action, ui);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -297,11 +303,12 @@ impl Chrome {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl notedeck::App for Chrome {
|
impl notedeck::App for Chrome {
|
||||||
fn update(&mut self, ctx: &mut notedeck::AppContext, ui: &mut egui::Ui) {
|
fn update(&mut self, ctx: &mut notedeck::AppContext, ui: &mut egui::Ui) -> Option<AppAction> {
|
||||||
if let Some(action) = self.show(ctx, ui) {
|
if let Some(action) = self.show(ctx, ui) {
|
||||||
action.process(ctx, self, ui);
|
action.process(ctx, self, ui);
|
||||||
}
|
}
|
||||||
// TODO: unify this constant with the columns side panel width. ui crate?
|
// TODO: unify this constant with the columns side panel width. ui crate?
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,3 +460,62 @@ fn wallet_button() -> impl Widget {
|
|||||||
helper.take_animation_response()
|
helper.take_animation_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chrome_handle_app_action(
|
||||||
|
chrome: &mut Chrome,
|
||||||
|
ctx: &mut AppContext,
|
||||||
|
action: AppAction,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) {
|
||||||
|
match action {
|
||||||
|
AppAction::Note(note_action) => match note_action {
|
||||||
|
NoteAction::Hashtag(hashtag) => {
|
||||||
|
ChromePanelAction::columns_navigate(
|
||||||
|
ctx,
|
||||||
|
chrome,
|
||||||
|
Route::Timeline(TimelineKind::Hashtag(hashtag)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteAction::Reply(note_id) => {
|
||||||
|
ChromePanelAction::columns_navigate(ctx, chrome, Route::Reply(note_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteAction::Zap(_) => {
|
||||||
|
todo!("implement note zaps in chrome");
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteAction::Context(context) => 'brk: {
|
||||||
|
let txn = Transaction::new(ctx.ndb).unwrap();
|
||||||
|
let Some(note) = ctx.ndb.get_note_by_key(&txn, context.note_key).ok() else {
|
||||||
|
break 'brk;
|
||||||
|
};
|
||||||
|
|
||||||
|
context.action.process(ui, ¬e, ctx.pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteAction::Quote(note_id) => {
|
||||||
|
ChromePanelAction::columns_navigate(ctx, chrome, Route::Quote(note_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteAction::Profile(pubkey) => {
|
||||||
|
ChromePanelAction::columns_navigate(
|
||||||
|
ctx,
|
||||||
|
chrome,
|
||||||
|
Route::Timeline(TimelineKind::Profile(pubkey)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteAction::Note(note_id) => {
|
||||||
|
let txn = Transaction::new(ctx.ndb).unwrap();
|
||||||
|
let thread = ThreadSelection::from_note_id(ctx.ndb, ctx.note_cache, &txn, note_id);
|
||||||
|
|
||||||
|
match thread {
|
||||||
|
Ok(t) => ChromePanelAction::columns_navigate(ctx, chrome, Route::thread(t)),
|
||||||
|
|
||||||
|
Err(err) => tracing::error!("{:?}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::{
|
|||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
use notedeck::{Accounts, AppContext, DataPath, DataPathType, FilterState, UnknownIds};
|
use notedeck::{Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState, UnknownIds};
|
||||||
use notedeck_ui::NoteOptions;
|
use notedeck_ui::NoteOptions;
|
||||||
|
|
||||||
use enostr::{ClientMessage, Keypair, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
use enostr::{ClientMessage, Keypair, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
||||||
@@ -639,7 +639,7 @@ fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, ctx: &mut App
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl notedeck::App for Damus {
|
impl notedeck::App for Damus {
|
||||||
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> {
|
||||||
/*
|
/*
|
||||||
self.app
|
self.app
|
||||||
.frame_history
|
.frame_history
|
||||||
@@ -648,6 +648,8 @@ impl notedeck::App for Damus {
|
|||||||
|
|
||||||
update_damus(self, ctx, ui.ctx());
|
update_damus(self, ctx, ui.ctx());
|
||||||
render_damus(self, ctx, ui);
|
render_damus(self, ctx, ui);
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ mod search;
|
|||||||
mod subscriptions;
|
mod subscriptions;
|
||||||
mod support;
|
mod support;
|
||||||
mod test_data;
|
mod test_data;
|
||||||
mod timeline;
|
pub mod timeline;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
mod unknowns;
|
mod unknowns;
|
||||||
mod view_state;
|
mod view_state;
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use egui::{
|
|||||||
};
|
};
|
||||||
use egui::{Layout, TextEdit};
|
use egui::{Layout, TextEdit};
|
||||||
use enostr::Keypair;
|
use enostr::Keypair;
|
||||||
use notedeck::fonts::get_font_size;
|
use notedeck::{fonts::get_font_size, AppAction, NotedeckTextStyle};
|
||||||
use notedeck::NotedeckTextStyle;
|
|
||||||
|
|
||||||
pub struct AccountLoginView<'a> {
|
pub struct AccountLoginView<'a> {
|
||||||
manager: &'a mut AcquireKeyState,
|
manager: &'a mut AcquireKeyState,
|
||||||
@@ -155,8 +154,14 @@ mod preview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App for AccountLoginPreview {
|
impl App for AccountLoginPreview {
|
||||||
fn update(&mut self, _app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_app_ctx: &mut AppContext<'_>,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<AppAction> {
|
||||||
AccountLoginView::new(&mut self.manager).ui(ui);
|
AccountLoginView::new(&mut self.manager).ui(ui);
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ mod preview {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::ConfigureDeckView;
|
use super::ConfigureDeckView;
|
||||||
use notedeck::{App, AppContext};
|
use notedeck::{App, AppAction, AppContext};
|
||||||
|
|
||||||
pub struct ConfigureDeckPreview {
|
pub struct ConfigureDeckPreview {
|
||||||
state: DeckState,
|
state: DeckState,
|
||||||
@@ -316,8 +316,14 @@ mod preview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App for ConfigureDeckPreview {
|
impl App for ConfigureDeckPreview {
|
||||||
fn update(&mut self, _app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_app_ctx: &mut AppContext<'_>,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<AppAction> {
|
||||||
ConfigureDeckView::new(&mut self.state).ui(ui);
|
ConfigureDeckView::new(&mut self.state).ui(ui);
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ mod preview {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::EditDeckView;
|
use super::EditDeckView;
|
||||||
use notedeck::{App, AppContext};
|
use notedeck::{App, AppAction, AppContext};
|
||||||
|
|
||||||
pub struct EditDeckPreview {
|
pub struct EditDeckPreview {
|
||||||
state: DeckState,
|
state: DeckState,
|
||||||
@@ -75,8 +75,13 @@ mod preview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App for EditDeckPreview {
|
impl App for EditDeckPreview {
|
||||||
fn update(&mut self, _app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
_app_ctx: &mut AppContext<'_>,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<AppAction> {
|
||||||
EditDeckView::new(&mut self.state).ui(ui);
|
EditDeckView::new(&mut self.state).ui(ui);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -691,7 +691,7 @@ mod preview {
|
|||||||
use crate::media_upload::Nip94Event;
|
use crate::media_upload::Nip94Event;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use notedeck::{App, AppContext};
|
use notedeck::{App, AppAction, AppContext};
|
||||||
|
|
||||||
pub struct PostPreview {
|
pub struct PostPreview {
|
||||||
draft: Draft,
|
draft: Draft,
|
||||||
@@ -730,7 +730,7 @@ mod preview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App for PostPreview {
|
impl App for PostPreview {
|
||||||
fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> {
|
||||||
let txn = Transaction::new(app.ndb).expect("txn");
|
let txn = Transaction::new(app.ndb).expect("txn");
|
||||||
let mut note_context = NoteContext {
|
let mut note_context = NoteContext {
|
||||||
ndb: app.ndb,
|
ndb: app.ndb,
|
||||||
@@ -749,6 +749,8 @@ mod preview {
|
|||||||
NoteOptions::default(),
|
NoteOptions::default(),
|
||||||
)
|
)
|
||||||
.ui(&txn, ui);
|
.ui(&txn, ui);
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use notedeck::AppAction;
|
||||||
|
|
||||||
pub struct PreviewConfig {
|
pub struct PreviewConfig {
|
||||||
pub is_mobile: bool,
|
pub is_mobile: bool,
|
||||||
}
|
}
|
||||||
@@ -20,7 +22,12 @@ impl PreviewApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl notedeck::App for PreviewApp {
|
impl notedeck::App for PreviewApp {
|
||||||
fn update(&mut self, app_ctx: &mut notedeck::AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
app_ctx: &mut notedeck::AppContext<'_>,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<AppAction> {
|
||||||
self.view.update(app_ctx, ui);
|
self.view.update(app_ctx, ui);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ fn button(text: &str, width: f32) -> egui::Button<'static> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod preview {
|
mod preview {
|
||||||
use notedeck::App;
|
use notedeck::{App, AppAction};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
profile_state::ProfileState,
|
profile_state::ProfileState,
|
||||||
@@ -190,8 +190,13 @@ mod preview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App for EditProfilePreivew {
|
impl App for EditProfilePreivew {
|
||||||
fn update(&mut self, ctx: &mut notedeck::AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut notedeck::AppContext<'_>,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<AppAction> {
|
||||||
EditProfileView::new(&mut self.state, ctx.img_cache).ui(ui);
|
EditProfileView::new(&mut self.state, ctx.img_cache).ui(ui);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ fn get_connection_icon(status: RelayStatus) -> egui::Image<'static> {
|
|||||||
mod preview {
|
mod preview {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_data::sample_pool;
|
use crate::test_data::sample_pool;
|
||||||
use notedeck::{App, AppContext};
|
use notedeck::{App, AppAction, AppContext};
|
||||||
|
|
||||||
pub struct RelayViewPreview {
|
pub struct RelayViewPreview {
|
||||||
pool: RelayPool,
|
pool: RelayPool,
|
||||||
@@ -289,7 +289,7 @@ mod preview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App for RelayViewPreview {
|
impl App for RelayViewPreview {
|
||||||
fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> {
|
||||||
self.pool.try_recv();
|
self.pool.try_recv();
|
||||||
let mut id_string_map = HashMap::new();
|
let mut id_string_map = HashMap::new();
|
||||||
RelayView::new(
|
RelayView::new(
|
||||||
@@ -298,6 +298,7 @@ mod preview {
|
|||||||
&mut id_string_map,
|
&mut id_string_map,
|
||||||
)
|
)
|
||||||
.ui(ui);
|
.ui(ui);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use chrono::{Duration, Local};
|
|||||||
use egui_wgpu::RenderState;
|
use egui_wgpu::RenderState;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use nostrdb::Transaction;
|
use nostrdb::Transaction;
|
||||||
use notedeck::AppContext;
|
use notedeck::{AppAction, AppContext};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use std::sync::mpsc::{self, Receiver};
|
use std::sync::mpsc::{self, Receiver};
|
||||||
@@ -313,17 +313,21 @@ You are an AI agent for the nostr protocol called Dave, created by Damus. nostr
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl notedeck::App for Dave {
|
impl notedeck::App for Dave {
|
||||||
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
|
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> {
|
||||||
/*
|
/*
|
||||||
self.app
|
self.app
|
||||||
.frame_history
|
.frame_history
|
||||||
.on_new_frame(ctx.input(|i| i.time), frame.info().cpu_usage);
|
.on_new_frame(ctx.input(|i| i.time), frame.info().cpu_usage);
|
||||||
*/
|
*/
|
||||||
|
let mut app_action: Option<AppAction> = None;
|
||||||
|
|
||||||
//update_dave(self, ctx, ui.ctx());
|
//update_dave(self, ctx, ui.ctx());
|
||||||
let should_send = self.process_events(ctx);
|
let should_send = self.process_events(ctx);
|
||||||
if let Some(action) = self.ui(ctx, ui).action {
|
if let Some(action) = self.ui(ctx, ui).action {
|
||||||
match action {
|
match action {
|
||||||
|
DaveAction::Note(n) => {
|
||||||
|
app_action = Some(AppAction::Note(n));
|
||||||
|
}
|
||||||
DaveAction::NewChat => {
|
DaveAction::NewChat => {
|
||||||
self.handle_new_chat();
|
self.handle_new_chat();
|
||||||
}
|
}
|
||||||
@@ -332,8 +336,11 @@ impl notedeck::App for Dave {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_send {
|
if should_send {
|
||||||
self.send_user_message(ctx, ui.ctx());
|
self.send_user_message(ctx, ui.ctx());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app_action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use egui::{Align, Key, KeyboardShortcut, Layout, Modifiers};
|
use egui::{Align, Key, KeyboardShortcut, Layout, Modifiers};
|
||||||
use nostrdb::{Ndb, Transaction};
|
use nostrdb::{Ndb, Transaction};
|
||||||
use notedeck::{AppContext, NoteContext};
|
use notedeck::{AppContext, NoteAction, NoteContext};
|
||||||
use notedeck_ui::{icons::search_icon, NoteOptions, ProfilePic};
|
use notedeck_ui::{icons::search_icon, NoteOptions, ProfilePic};
|
||||||
|
|
||||||
/// DaveUi holds all of the data it needs to render itself
|
/// DaveUi holds all of the data it needs to render itself
|
||||||
@@ -27,6 +27,10 @@ impl DaveResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn note(action: NoteAction) -> DaveResponse {
|
||||||
|
Self::new(DaveAction::Note(action))
|
||||||
|
}
|
||||||
|
|
||||||
fn or(self, r: DaveResponse) -> DaveResponse {
|
fn or(self, r: DaveResponse) -> DaveResponse {
|
||||||
DaveResponse {
|
DaveResponse {
|
||||||
action: self.action.or(r.action),
|
action: self.action.or(r.action),
|
||||||
@@ -51,6 +55,7 @@ pub enum DaveAction {
|
|||||||
/// The action generated when the user sends a message to dave
|
/// The action generated when the user sends a message to dave
|
||||||
Send,
|
Send,
|
||||||
NewChat,
|
NewChat,
|
||||||
|
Note(NoteAction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DaveUi<'a> {
|
impl<'a> DaveUi<'a> {
|
||||||
@@ -112,18 +117,23 @@ impl<'a> DaveUi<'a> {
|
|||||||
.show(ui, |ui| self.inputbox(ui))
|
.show(ui, |ui| self.inputbox(ui))
|
||||||
.inner;
|
.inner;
|
||||||
|
|
||||||
egui::ScrollArea::vertical()
|
let note_action = egui::ScrollArea::vertical()
|
||||||
.stick_to_bottom(true)
|
.stick_to_bottom(true)
|
||||||
.auto_shrink([false; 2])
|
.auto_shrink([false; 2])
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
Self::chat_frame(ui.ctx()).show(ui, |ui| {
|
Self::chat_frame(ui.ctx())
|
||||||
ui.vertical(|ui| {
|
.show(ui, |ui| {
|
||||||
self.render_chat(app_ctx, ui);
|
ui.vertical(|ui| self.render_chat(app_ctx, ui)).inner
|
||||||
});
|
})
|
||||||
});
|
.inner
|
||||||
});
|
})
|
||||||
|
.inner;
|
||||||
|
|
||||||
r
|
if let Some(action) = note_action {
|
||||||
|
DaveResponse::note(action)
|
||||||
|
} else {
|
||||||
|
r
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.inner
|
.inner
|
||||||
})
|
})
|
||||||
@@ -132,21 +142,36 @@ impl<'a> DaveUi<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render a chat message (user, assistant, tool call/response, etc)
|
/// Render a chat message (user, assistant, tool call/response, etc)
|
||||||
fn render_chat(&self, ctx: &mut AppContext, ui: &mut egui::Ui) {
|
fn render_chat(&self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option<NoteAction> {
|
||||||
|
let mut action: Option<NoteAction> = None;
|
||||||
for message in self.chat {
|
for message in self.chat {
|
||||||
match message {
|
let r = match message {
|
||||||
Message::User(msg) => self.user_chat(msg, ui),
|
Message::User(msg) => {
|
||||||
Message::Assistant(msg) => self.assistant_chat(msg, ui),
|
self.user_chat(msg, ui);
|
||||||
Message::ToolResponse(msg) => Self::tool_response_ui(msg, ui),
|
None
|
||||||
|
}
|
||||||
|
Message::Assistant(msg) => {
|
||||||
|
self.assistant_chat(msg, ui);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Message::ToolResponse(msg) => {
|
||||||
|
Self::tool_response_ui(msg, ui);
|
||||||
|
None
|
||||||
|
}
|
||||||
Message::System(_msg) => {
|
Message::System(_msg) => {
|
||||||
// system prompt is not rendered. Maybe we could
|
// system prompt is not rendered. Maybe we could
|
||||||
// have a debug option to show this
|
// have a debug option to show this
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Message::ToolCalls(toolcalls) => {
|
Message::ToolCalls(toolcalls) => Self::tool_calls_ui(ctx, toolcalls, ui),
|
||||||
Self::tool_calls_ui(ctx, toolcalls, ui);
|
};
|
||||||
}
|
|
||||||
|
if r.is_some() {
|
||||||
|
action = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tool_response_ui(_tool_response: &ToolResponse, _ui: &mut egui::Ui) {
|
fn tool_response_ui(_tool_response: &ToolResponse, _ui: &mut egui::Ui) {
|
||||||
@@ -161,7 +186,11 @@ impl<'a> DaveUi<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The ai has asked us to render some notes, so we do that here
|
/// The ai has asked us to render some notes, so we do that here
|
||||||
fn present_notes_ui(ctx: &mut AppContext, call: &PresentNotesCall, ui: &mut egui::Ui) {
|
fn present_notes_ui(
|
||||||
|
ctx: &mut AppContext,
|
||||||
|
call: &PresentNotesCall,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<NoteAction> {
|
||||||
let mut note_context = NoteContext {
|
let mut note_context = NoteContext {
|
||||||
ndb: ctx.ndb,
|
ndb: ctx.ndb,
|
||||||
img_cache: ctx.img_cache,
|
img_cache: ctx.img_cache,
|
||||||
@@ -177,6 +206,7 @@ impl<'a> DaveUi<'a> {
|
|||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
|
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
|
||||||
ui.spacing_mut().item_spacing.x = 10.0;
|
ui.spacing_mut().item_spacing.x = 10.0;
|
||||||
|
let mut action: Option<NoteAction> = None;
|
||||||
|
|
||||||
for note_id in &call.note_ids {
|
for note_id in &call.note_ids {
|
||||||
let Ok(note) = note_context.ndb.get_note_by_id(&txn, note_id.bytes())
|
let Ok(note) = note_context.ndb.get_note_by_id(&txn, note_id.bytes())
|
||||||
@@ -184,26 +214,51 @@ impl<'a> DaveUi<'a> {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut note_view = notedeck_ui::NoteView::new(
|
let r = ui
|
||||||
&mut note_context,
|
.allocate_ui_with_layout(
|
||||||
&None,
|
[400.0, 400.0].into(),
|
||||||
¬e,
|
Layout::centered_and_justified(ui.layout().main_dir()),
|
||||||
NoteOptions::default(),
|
|ui| {
|
||||||
)
|
notedeck_ui::NoteView::new(
|
||||||
.preview_style();
|
&mut note_context,
|
||||||
|
&None,
|
||||||
|
¬e,
|
||||||
|
NoteOptions::default(),
|
||||||
|
)
|
||||||
|
.preview_style()
|
||||||
|
.show(ui)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.inner;
|
||||||
|
|
||||||
// TODO: remove current account thing, just add to note context
|
if r.action.is_some() {
|
||||||
ui.add_sized([400.0, 400.0], &mut note_view);
|
action = r.action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
action
|
||||||
|
})
|
||||||
|
.inner
|
||||||
|
})
|
||||||
|
.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tool_calls_ui(ctx: &mut AppContext, toolcalls: &[ToolCall], ui: &mut egui::Ui) {
|
fn tool_calls_ui(
|
||||||
|
ctx: &mut AppContext,
|
||||||
|
toolcalls: &[ToolCall],
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
) -> Option<NoteAction> {
|
||||||
|
let mut note_action: Option<NoteAction> = None;
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
for call in toolcalls {
|
for call in toolcalls {
|
||||||
match call.calls() {
|
match call.calls() {
|
||||||
ToolCalls::PresentNotes(call) => Self::present_notes_ui(ctx, call, ui),
|
ToolCalls::PresentNotes(call) => {
|
||||||
|
let r = Self::present_notes_ui(ctx, call, ui);
|
||||||
|
if r.is_some() {
|
||||||
|
note_action = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
ToolCalls::Invalid(err) => {
|
ToolCalls::Invalid(err) => {
|
||||||
ui.label(format!("invalid tool call: {:?}", err));
|
ui.label(format!("invalid tool call: {:?}", err));
|
||||||
}
|
}
|
||||||
@@ -219,6 +274,8 @@ impl<'a> DaveUi<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
note_action
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inputbox(&mut self, ui: &mut egui::Ui) -> DaveResponse {
|
fn inputbox(&mut self, ui: &mut egui::Ui) -> DaveResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user