Skip to content

Commit

Permalink
Merge profiling editing #625
Browse files Browse the repository at this point in the history
Changelog-Added: Added profile editing
  • Loading branch information
jb55 committed Jan 4, 2025
2 parents 5f21d32 + 05ab117 commit e1187c3
Show file tree
Hide file tree
Showing 24 changed files with 894 additions and 210 deletions.
Binary file added assets/icons/edit_icon_4x_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/key_4x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/links_4x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/verified_4x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/zap_4x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions crates/notedeck/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ impl Accounts {
None
}

pub fn contains_full_kp(&self, pubkey: &enostr::Pubkey) -> bool {
if let Some(contains) = self.contains_account(pubkey.bytes()) {
contains.has_nsec
} else {
false
}
}

#[must_use = "UnknownIdAction's must be handled. Use .process_unknown_id_action()"]
pub fn add_account(&mut self, account: Keypair) -> AddAccountAction {
let pubkey = account.pubkey;
Expand Down Expand Up @@ -567,6 +575,18 @@ impl Accounts {
self.needs_relay_config = false;
}
}

pub fn get_full<'a>(&'a self, pubkey: &[u8; 32]) -> Option<FilledKeypair<'a>> {
if let Some(contains) = self.contains_account(pubkey) {
if contains.has_nsec {
if let Some(kp) = self.get_account(contains.index) {
return kp.to_full();
}
}
}

None
}
}

fn get_selected_index(accounts: &[UserAccount], keystore: &KeyStorageType) -> Option<usize> {
Expand Down
7 changes: 7 additions & 0 deletions crates/notedeck/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,11 @@ impl NotedeckTextStyle {
pub fn get_font_id(&self, ctx: &Context) -> FontId {
FontId::new(get_font_size(ctx, self), self.font_family())
}

pub fn get_bolded_font(&self, ctx: &Context) -> FontId {
FontId::new(
get_font_size(ctx, self),
egui::FontFamily::Name(crate::NamedFontFamily::Bold.as_str().into()),
)
}
}
2 changes: 2 additions & 0 deletions crates/notedeck_chrome/src/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use notedeck_chrome::setup::generate_native_options;
use notedeck_chrome::Notedeck;
use notedeck_columns::ui::configure_deck::ConfigureDeckView;
use notedeck_columns::ui::edit_deck::EditDeckView;
use notedeck_columns::ui::profile::EditProfileView;
use notedeck_columns::ui::{
account_login_view::AccountLoginView, PostView, Preview, PreviewApp, PreviewConfig, ProfilePic,
ProfilePreview, RelayView,
Expand Down Expand Up @@ -95,5 +96,6 @@ async fn main() {
PostView,
ConfigureDeckView,
EditDeckView,
EditProfileView,
);
}
1 change: 1 addition & 0 deletions crates/notedeck_columns/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ use egui::Color32;
pub const ALMOST_WHITE: Color32 = Color32::from_rgb(0xFA, 0xFA, 0xFA);
pub const MID_GRAY: Color32 = Color32::from_rgb(0xbd, 0xbd, 0xbd);
pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
pub const TEAL: Color32 = Color32::from_rgb(0x77, 0xDC, 0xE1);
3 changes: 2 additions & 1 deletion crates/notedeck_columns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod nav;
mod notes_holder;
mod post;
mod profile;
mod profile_state;
pub mod relay_pool_manager;
mod route;
mod subscriptions;
Expand All @@ -42,6 +43,6 @@ pub mod storage;

pub use app::Damus;
pub use error::Error;
pub use profile::DisplayName;
pub use profile::NostrName;

pub type Result<T> = std::result::Result<T, error::Error>;
44 changes: 43 additions & 1 deletion crates/notedeck_columns/src/nav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::{
deck_state::DeckState,
decks::{Deck, DecksAction, DecksCache},
notes_holder::NotesHolder,
profile::Profile,
profile::{Profile, ProfileAction, SaveProfileChanges},
profile_state::ProfileState,
relay_pool_manager::RelayPoolManager,
route::Route,
thread::Thread,
Expand All @@ -21,6 +22,7 @@ use crate::{
configure_deck::ConfigureDeckView,
edit_deck::{EditDeckResponse, EditDeckView},
note::{PostAction, PostType},
profile::EditProfileView,
support::SupportView,
RelayView, View,
},
Expand All @@ -39,6 +41,7 @@ pub enum RenderNavAction {
RemoveColumn,
PostAction(PostAction),
NoteAction(NoteAction),
ProfileAction(ProfileAction),
SwitchingAction(SwitchingAction),
}

Expand Down Expand Up @@ -168,6 +171,16 @@ impl RenderNavResponse {
RenderNavAction::SwitchingAction(switching_action) => {
switching_occured = switching_action.process(&mut app.decks_cache, ctx);
}
RenderNavAction::ProfileAction(profile_action) => {
profile_action.process(
&mut app.view_state.pubkey_to_profile_state,
ctx.ndb,
ctx.pool,
get_active_columns_mut(ctx.accounts, &mut app.decks_cache)
.column_mut(col)
.router_mut(),
);
}
}
}

Expand Down Expand Up @@ -368,6 +381,35 @@ fn render_nav_body(

action
}
Route::EditProfile(pubkey) => {
let mut action = None;
if let Some(kp) = ctx.accounts.get_full(pubkey.bytes()) {
let state = app
.view_state
.pubkey_to_profile_state
.entry(*kp.pubkey)
.or_insert_with(|| {
let txn = Transaction::new(ctx.ndb).expect("txn");
if let Ok(record) = ctx.ndb.get_profile_by_pubkey(&txn, kp.pubkey.bytes()) {
ProfileState::from_profile(&record)
} else {
ProfileState::default()
}
});
if EditProfileView::new(state, ctx.img_cache).ui(ui) {
if let Some(taken_state) =
app.view_state.pubkey_to_profile_state.remove(kp.pubkey)
{
action = Some(RenderNavAction::ProfileAction(ProfileAction::SaveChanges(
SaveProfileChanges::new(kp.to_full(), taken_state),
)))
}
}
} else {
error!("Pubkey in EditProfile route did not have an nsec attached in Accounts");
}
action
}
}
}

Expand Down
144 changes: 117 additions & 27 deletions crates/notedeck_columns/src/profile.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
use enostr::{Filter, Pubkey};
use nostrdb::{FilterBuilder, Ndb, ProfileRecord, Transaction};
use std::collections::HashMap;

use enostr::{Filter, FullKeypair, Pubkey, RelayPool};
use nostrdb::{
FilterBuilder, Ndb, Note, NoteBuildOptions, NoteBuilder, ProfileRecord, Transaction,
};

use notedeck::{filter::default_limit, FilterState, MuteFun, NoteCache, NoteRef};
use tracing::info;

use crate::{
multi_subscriber::MultiSubscriber,
notes_holder::NotesHolder,
profile_state::ProfileState,
route::{Route, Router},
timeline::{copy_notes_into_timeline, PubkeySource, Timeline, TimelineKind, TimelineTab},
};

pub enum DisplayName<'a> {
One(&'a str),

Both {
username: &'a str,
display_name: &'a str,
},
pub struct NostrName<'a> {
pub username: Option<&'a str>,
pub display_name: Option<&'a str>,
pub nip05: Option<&'a str>,
}

impl<'a> DisplayName<'a> {
pub fn username(&self) -> &'a str {
match self {
Self::One(n) => n,
Self::Both { username, .. } => username,
impl<'a> NostrName<'a> {
pub fn name(&self) -> &'a str {
if let Some(name) = self.username {
name
} else if let Some(name) = self.display_name {
name
} else {
self.nip05.unwrap_or("??")
}
}

pub fn unknown() -> Self {
Self {
username: None,
display_name: None,
nip05: None,
}
}
}
Expand All @@ -31,19 +46,35 @@ fn is_empty(s: &str) -> bool {
s.chars().all(|c| c.is_whitespace())
}

pub fn get_profile_name<'a>(record: &ProfileRecord<'a>) -> Option<DisplayName<'a>> {
let profile = record.record().profile()?;
let display_name = profile.display_name().filter(|n| !is_empty(n));
let name = profile.name().filter(|n| !is_empty(n));

match (display_name, name) {
(None, None) => None,
(Some(disp), None) => Some(DisplayName::One(disp)),
(None, Some(username)) => Some(DisplayName::One(username)),
(Some(display_name), Some(username)) => Some(DisplayName::Both {
display_name,
username,
}),
pub fn get_display_name<'a>(record: Option<&ProfileRecord<'a>>) -> NostrName<'a> {
if let Some(record) = record {
if let Some(profile) = record.record().profile() {
let display_name = profile.display_name().filter(|n| !is_empty(n));
let username = profile.name().filter(|n| !is_empty(n));
let nip05 = if let Some(raw_nip05) = profile.nip05() {
if let Some(at_pos) = raw_nip05.find('@') {
if raw_nip05.starts_with('_') {
raw_nip05.get(at_pos + 1..)
} else {
Some(raw_nip05)
}
} else {
None
}
} else {
None
};

NostrName {
username,
display_name,
nip05,
}
} else {
NostrName::unknown()
}
} else {
NostrName::unknown()
}
}

Expand Down Expand Up @@ -131,3 +162,62 @@ impl NotesHolder for Profile {
self.multi_subscriber = Some(subscriber);
}
}

pub struct SaveProfileChanges {
pub kp: FullKeypair,
pub state: ProfileState,
}

impl SaveProfileChanges {
pub fn new(kp: FullKeypair, state: ProfileState) -> Self {
Self { kp, state }
}
pub fn to_note(&self) -> Note {
let sec = &self.kp.secret_key.to_secret_bytes();
add_client_tag(NoteBuilder::new())
.kind(0)
.content(&self.state.to_json())
.options(NoteBuildOptions::default().created_at(true).sign(sec))
.build()
.expect("should build")
}
}

fn add_client_tag(builder: NoteBuilder<'_>) -> NoteBuilder<'_> {
builder
.start_tag()
.tag_str("client")
.tag_str("Damus Notedeck")
}

pub enum ProfileAction {
Edit(FullKeypair),
SaveChanges(SaveProfileChanges),
}

impl ProfileAction {
pub fn process(
&self,
state_map: &mut HashMap<Pubkey, ProfileState>,
ndb: &Ndb,
pool: &mut RelayPool,
router: &mut Router<Route>,
) {
match self {
ProfileAction::Edit(kp) => {
router.route_to(Route::EditProfile(kp.pubkey));
}
ProfileAction::SaveChanges(changes) => {
let raw_msg = format!("[\"EVENT\",{}]", changes.to_note().json().unwrap());

let _ = ndb.process_client_event(raw_msg.as_str());
let _ = state_map.remove_entry(&changes.kp.pubkey);

info!("sending {}", raw_msg);
pool.send(&enostr::ClientMessage::raw(raw_msg));

router.go_back();
}
}
}
}
Loading

0 comments on commit e1187c3

Please sign in to comment.