Switch to unified timeline cache via TimelineKinds
This is a fairly large rewrite which unifies our threads, timelines and profiles. Now all timelines have a MultiSubscriber, and can be added and removed to columns just like Threads and Profiles. Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -143,32 +143,39 @@ impl AddColumnOption {
|
||||
ndb: &Ndb,
|
||||
cur_account: Option<&UserAccount>,
|
||||
) -> Option<AddColumnResponse> {
|
||||
let txn = Transaction::new(ndb).unwrap();
|
||||
match self {
|
||||
AddColumnOption::Algo(algo_option) => Some(AddColumnResponse::Algo(algo_option)),
|
||||
AddColumnOption::Universe => TimelineKind::Universe
|
||||
.into_timeline(ndb, None)
|
||||
.map(AddColumnResponse::Timeline),
|
||||
AddColumnOption::Notification(pubkey) => TimelineKind::Notifications(pubkey)
|
||||
.into_timeline(ndb, cur_account.map(|a| a.pubkey.bytes()))
|
||||
.into_timeline(&txn, ndb)
|
||||
.map(AddColumnResponse::Timeline),
|
||||
AddColumnOption::Notification(pubkey) => {
|
||||
TimelineKind::Notifications(*pubkey.to_pubkey(&cur_account.map(|kp| kp.pubkey)?))
|
||||
.into_timeline(&txn, ndb)
|
||||
.map(AddColumnResponse::Timeline)
|
||||
}
|
||||
AddColumnOption::UndecidedNotification => {
|
||||
Some(AddColumnResponse::UndecidedNotification)
|
||||
}
|
||||
AddColumnOption::Contacts(pubkey) => {
|
||||
let tlk = TimelineKind::contact_list(pubkey);
|
||||
tlk.into_timeline(ndb, cur_account.map(|a| a.pubkey.bytes()))
|
||||
AddColumnOption::Contacts(pk_src) => {
|
||||
let tlk = TimelineKind::contact_list(
|
||||
*pk_src.to_pubkey(&cur_account.map(|kp| kp.pubkey)?),
|
||||
);
|
||||
tlk.into_timeline(&txn, ndb)
|
||||
.map(AddColumnResponse::Timeline)
|
||||
}
|
||||
AddColumnOption::ExternalNotification => Some(AddColumnResponse::ExternalNotification),
|
||||
AddColumnOption::UndecidedHashtag => Some(AddColumnResponse::Hashtag),
|
||||
AddColumnOption::Hashtag(hashtag) => TimelineKind::Hashtag(hashtag)
|
||||
.into_timeline(ndb, None)
|
||||
.into_timeline(&txn, ndb)
|
||||
.map(AddColumnResponse::Timeline),
|
||||
AddColumnOption::UndecidedIndividual => Some(AddColumnResponse::UndecidedIndividual),
|
||||
AddColumnOption::ExternalIndividual => Some(AddColumnResponse::ExternalIndividual),
|
||||
AddColumnOption::Individual(pubkey_source) => {
|
||||
let tlk = TimelineKind::profile(pubkey_source);
|
||||
tlk.into_timeline(ndb, cur_account.map(|a| a.pubkey.bytes()))
|
||||
let tlk = TimelineKind::profile(
|
||||
*pubkey_source.to_pubkey(&cur_account.map(|kp| kp.pubkey)?),
|
||||
);
|
||||
tlk.into_timeline(&txn, ndb)
|
||||
.map(AddColumnResponse::Timeline)
|
||||
}
|
||||
}
|
||||
@@ -232,13 +239,17 @@ impl<'a> AddColumnView<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn algo_last_per_pk_ui(&mut self, ui: &mut Ui) -> Option<AddColumnResponse> {
|
||||
fn algo_last_per_pk_ui(
|
||||
&mut self,
|
||||
ui: &mut Ui,
|
||||
deck_author: Pubkey,
|
||||
) -> Option<AddColumnResponse> {
|
||||
let algo_option = ColumnOptionData {
|
||||
title: "Contact List",
|
||||
description: "Source the last note for each user in your contact list",
|
||||
icon: egui::include_image!("../../../../assets/icons/home_icon_dark_4x.png"),
|
||||
option: AddColumnOption::Algo(AlgoOption::LastPerPubkey(Decision::Decided(
|
||||
ListKind::contact_list(PubkeySource::DeckAuthor),
|
||||
ListKind::contact_list(deck_author),
|
||||
))),
|
||||
};
|
||||
|
||||
@@ -319,18 +330,22 @@ impl<'a> AddColumnView<'a> {
|
||||
}
|
||||
|
||||
let resp = if let Some(keypair) = key_state.get_login_keypair() {
|
||||
let txn = Transaction::new(self.ndb).expect("txn");
|
||||
if let Ok(profile) = self.ndb.get_profile_by_pubkey(&txn, keypair.pubkey.bytes()) {
|
||||
egui::Frame::window(ui.style())
|
||||
.outer_margin(Margin {
|
||||
left: 4.0,
|
||||
right: 4.0,
|
||||
top: 12.0,
|
||||
bottom: 32.0,
|
||||
})
|
||||
.show(ui, |ui| {
|
||||
ProfilePreview::new(&profile, self.img_cache).ui(ui);
|
||||
});
|
||||
{
|
||||
let txn = Transaction::new(self.ndb).expect("txn");
|
||||
if let Ok(profile) =
|
||||
self.ndb.get_profile_by_pubkey(&txn, keypair.pubkey.bytes())
|
||||
{
|
||||
egui::Frame::window(ui.style())
|
||||
.outer_margin(Margin {
|
||||
left: 4.0,
|
||||
right: 4.0,
|
||||
top: 12.0,
|
||||
bottom: 32.0,
|
||||
})
|
||||
.show(ui, |ui| {
|
||||
ProfilePreview::new(&profile, self.img_cache).ui(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ui.add(add_column_button()).clicked() {
|
||||
@@ -470,7 +485,7 @@ impl<'a> AddColumnView<'a> {
|
||||
title: "Contacts",
|
||||
description: "See notes from your contacts",
|
||||
icon: egui::include_image!("../../../../assets/icons/home_icon_dark_4x.png"),
|
||||
option: AddColumnOption::Contacts(source.clone()),
|
||||
option: AddColumnOption::Contacts(source),
|
||||
});
|
||||
}
|
||||
vec.push(ColumnOptionData {
|
||||
@@ -609,7 +624,13 @@ pub fn render_add_column_routes(
|
||||
AddColumnRoute::Base => add_column_view.ui(ui),
|
||||
AddColumnRoute::Algo(r) => match r {
|
||||
AddAlgoRoute::Base => add_column_view.algo_ui(ui),
|
||||
AddAlgoRoute::LastPerPubkey => add_column_view.algo_last_per_pk_ui(ui),
|
||||
AddAlgoRoute::LastPerPubkey => {
|
||||
if let Some(deck_author) = ctx.accounts.get_selected_account() {
|
||||
add_column_view.algo_last_per_pk_ui(ui, deck_author.pubkey)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
AddColumnRoute::UndecidedNotification => add_column_view.notifications_ui(ui),
|
||||
AddColumnRoute::ExternalNotification => add_column_view.external_notification_ui(ui),
|
||||
@@ -628,13 +649,16 @@ pub fn render_add_column_routes(
|
||||
ctx.pool,
|
||||
ctx.note_cache,
|
||||
app.since_optimize,
|
||||
ctx.accounts
|
||||
.get_selected_account()
|
||||
.as_ref()
|
||||
.map(|sa| &sa.pubkey),
|
||||
);
|
||||
|
||||
app.columns_mut(ctx.accounts)
|
||||
.add_timeline_to_column(col, timeline);
|
||||
.column_mut(col)
|
||||
.router_mut()
|
||||
.route_to_replaced(Route::timeline(timeline.kind.clone()));
|
||||
|
||||
app.timeline_cache
|
||||
.timelines
|
||||
.insert(timeline.kind.clone(), timeline);
|
||||
}
|
||||
|
||||
AddColumnResponse::Algo(algo_option) => match algo_option {
|
||||
@@ -654,14 +678,8 @@ pub fn render_add_column_routes(
|
||||
// add it to our list of timelines
|
||||
AlgoOption::LastPerPubkey(Decision::Decided(list_kind)) => {
|
||||
let maybe_timeline = {
|
||||
let default_user = ctx
|
||||
.accounts
|
||||
.get_selected_account()
|
||||
.as_ref()
|
||||
.map(|sa| sa.pubkey.bytes());
|
||||
|
||||
TimelineKind::last_per_pubkey(list_kind.clone())
|
||||
.into_timeline(ctx.ndb, default_user)
|
||||
let txn = Transaction::new(ctx.ndb).unwrap();
|
||||
TimelineKind::last_per_pubkey(list_kind).into_timeline(&txn, ctx.ndb)
|
||||
};
|
||||
|
||||
if let Some(mut timeline) = maybe_timeline {
|
||||
@@ -672,14 +690,16 @@ pub fn render_add_column_routes(
|
||||
ctx.pool,
|
||||
ctx.note_cache,
|
||||
app.since_optimize,
|
||||
ctx.accounts
|
||||
.get_selected_account()
|
||||
.as_ref()
|
||||
.map(|sa| &sa.pubkey),
|
||||
);
|
||||
|
||||
app.columns_mut(ctx.accounts)
|
||||
.add_timeline_to_column(col, timeline);
|
||||
.column_mut(col)
|
||||
.router_mut()
|
||||
.route_to_replaced(Route::timeline(timeline.kind.clone()));
|
||||
|
||||
app.timeline_cache
|
||||
.timelines
|
||||
.insert(timeline.kind.clone(), timeline);
|
||||
} else {
|
||||
// we couldn't fetch the timeline yet... let's let
|
||||
// the user know ?
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::nav::SwitchingAction;
|
||||
use crate::{
|
||||
column::Columns,
|
||||
route::Route,
|
||||
timeline::{ColumnTitle, TimelineId, TimelineKind, TimelineRoute},
|
||||
timeline::{ColumnTitle, TimelineKind},
|
||||
ui::{
|
||||
self,
|
||||
anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE},
|
||||
@@ -22,7 +22,6 @@ pub struct NavTitle<'a> {
|
||||
ndb: &'a Ndb,
|
||||
img_cache: &'a mut ImageCache,
|
||||
columns: &'a Columns,
|
||||
deck_author: Option<&'a Pubkey>,
|
||||
routes: &'a [Route],
|
||||
col_id: usize,
|
||||
}
|
||||
@@ -32,7 +31,6 @@ impl<'a> NavTitle<'a> {
|
||||
ndb: &'a Ndb,
|
||||
img_cache: &'a mut ImageCache,
|
||||
columns: &'a Columns,
|
||||
deck_author: Option<&'a Pubkey>,
|
||||
routes: &'a [Route],
|
||||
col_id: usize,
|
||||
) -> Self {
|
||||
@@ -40,7 +38,6 @@ impl<'a> NavTitle<'a> {
|
||||
ndb,
|
||||
img_cache,
|
||||
columns,
|
||||
deck_author,
|
||||
routes,
|
||||
col_id,
|
||||
}
|
||||
@@ -123,14 +120,14 @@ impl<'a> NavTitle<'a> {
|
||||
// not it looks cool
|
||||
self.title_pfp(ui, prev, 32.0);
|
||||
|
||||
let column_title = prev.title(self.columns);
|
||||
let column_title = prev.title();
|
||||
|
||||
let back_resp = match &column_title {
|
||||
ColumnTitle::Simple(title) => ui.add(Self::back_label(title, color)),
|
||||
|
||||
ColumnTitle::NeedsDb(need_db) => {
|
||||
let txn = Transaction::new(self.ndb).unwrap();
|
||||
let title = need_db.title(&txn, self.ndb, self.deck_author);
|
||||
let title = need_db.title(&txn, self.ndb);
|
||||
ui.add(Self::back_label(title, color))
|
||||
}
|
||||
};
|
||||
@@ -402,14 +399,11 @@ impl<'a> NavTitle<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn timeline_pfp(&mut self, ui: &mut egui::Ui, id: TimelineId, pfp_size: f32) {
|
||||
fn timeline_pfp(&mut self, ui: &mut egui::Ui, id: &TimelineKind, pfp_size: f32) {
|
||||
let txn = Transaction::new(self.ndb).unwrap();
|
||||
|
||||
if let Some(pfp) = self
|
||||
.columns
|
||||
.find_timeline(id)
|
||||
.and_then(|tl| tl.kind.pubkey_source())
|
||||
.and_then(|pksrc| self.deck_author.map(|da| pksrc.to_pubkey(da)))
|
||||
if let Some(pfp) = id
|
||||
.pubkey()
|
||||
.and_then(|pk| self.pubkey_pfp(&txn, pk.bytes(), pfp_size))
|
||||
{
|
||||
ui.add(pfp);
|
||||
@@ -422,34 +416,35 @@ impl<'a> NavTitle<'a> {
|
||||
|
||||
fn title_pfp(&mut self, ui: &mut egui::Ui, top: &Route, pfp_size: f32) {
|
||||
match top {
|
||||
Route::Timeline(tlr) => match tlr {
|
||||
TimelineRoute::Timeline(tlid) => {
|
||||
let is_hashtag = self
|
||||
.columns
|
||||
.find_timeline(*tlid)
|
||||
.is_some_and(|tl| matches!(tl.kind, TimelineKind::Hashtag(_)));
|
||||
|
||||
if is_hashtag {
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!(
|
||||
"../../../../../assets/icons/hashtag_icon_4x.png"
|
||||
))
|
||||
.fit_to_exact_size(egui::vec2(pfp_size, pfp_size)),
|
||||
);
|
||||
} else {
|
||||
self.timeline_pfp(ui, *tlid, pfp_size);
|
||||
}
|
||||
Route::Timeline(kind) => match kind {
|
||||
TimelineKind::Hashtag(_ht) => {
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!(
|
||||
"../../../../../assets/icons/hashtag_icon_4x.png"
|
||||
))
|
||||
.fit_to_exact_size(egui::vec2(pfp_size, pfp_size)),
|
||||
);
|
||||
}
|
||||
|
||||
TimelineRoute::Thread(_note_id) => {}
|
||||
TimelineRoute::Reply(_note_id) => {}
|
||||
TimelineRoute::Quote(_note_id) => {}
|
||||
|
||||
TimelineRoute::Profile(pubkey) => {
|
||||
TimelineKind::Profile(pubkey) => {
|
||||
self.show_profile(ui, pubkey, pfp_size);
|
||||
}
|
||||
|
||||
TimelineKind::Thread(_) => {
|
||||
// no pfp for threads
|
||||
}
|
||||
|
||||
TimelineKind::Universe
|
||||
| TimelineKind::Algo(_)
|
||||
| TimelineKind::Notifications(_)
|
||||
| TimelineKind::Generic(_)
|
||||
| TimelineKind::List(_) => {
|
||||
self.timeline_pfp(ui, kind, pfp_size);
|
||||
}
|
||||
},
|
||||
|
||||
Route::Reply(_) => {}
|
||||
Route::Quote(_) => {}
|
||||
Route::Accounts(_as) => {}
|
||||
Route::ComposeNote => {}
|
||||
Route::AddColumn(_add_col_route) => {}
|
||||
@@ -480,7 +475,7 @@ impl<'a> NavTitle<'a> {
|
||||
}
|
||||
|
||||
fn title_label(&self, ui: &mut egui::Ui, top: &Route) {
|
||||
let column_title = top.title(self.columns);
|
||||
let column_title = top.title();
|
||||
|
||||
match &column_title {
|
||||
ColumnTitle::Simple(title) => {
|
||||
@@ -489,7 +484,7 @@ impl<'a> NavTitle<'a> {
|
||||
|
||||
ColumnTitle::NeedsDb(need_db) => {
|
||||
let txn = Transaction::new(self.ndb).unwrap();
|
||||
let title = need_db.title(&txn, self.ndb, self.deck_author);
|
||||
let title = need_db.title(&txn, self.ndb);
|
||||
ui.add(Self::title_label_value(title));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ pub mod preview;
|
||||
pub use edit::EditProfileView;
|
||||
use egui::load::TexturePoll;
|
||||
use egui::{vec2, Color32, Label, Layout, Rect, RichText, Rounding, ScrollArea, Sense, Stroke};
|
||||
use enostr::{Pubkey, PubkeyRef};
|
||||
use enostr::Pubkey;
|
||||
use nostrdb::{Ndb, ProfileRecord, Transaction};
|
||||
pub use picture::ProfilePic;
|
||||
pub use preview::ProfilePreview;
|
||||
@@ -15,7 +15,7 @@ use crate::{
|
||||
actionbar::NoteAction,
|
||||
colors, images,
|
||||
profile::get_display_name,
|
||||
timeline::{TimelineCache, TimelineCacheKey},
|
||||
timeline::{TimelineCache, TimelineKind},
|
||||
ui::{
|
||||
note::NoteOptions,
|
||||
timeline::{tabs_ui, TimelineTabView},
|
||||
@@ -90,7 +90,7 @@ impl<'a> ProfileView<'a> {
|
||||
self.ndb,
|
||||
self.note_cache,
|
||||
&txn,
|
||||
TimelineCacheKey::Profile(PubkeyRef::new(self.pubkey.bytes())),
|
||||
&TimelineKind::Profile(*self.pubkey),
|
||||
)
|
||||
.get_ptr();
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
if router
|
||||
.routes()
|
||||
.iter()
|
||||
.any(|&r| r == Route::Accounts(AccountsRoute::Accounts))
|
||||
.any(|r| r == &Route::Accounts(AccountsRoute::Accounts))
|
||||
{
|
||||
// return if we are already routing to accounts
|
||||
router.go_back();
|
||||
@@ -297,7 +297,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
}
|
||||
}
|
||||
SidePanelAction::Settings => {
|
||||
if router.routes().iter().any(|&r| r == Route::Relays) {
|
||||
if router.routes().iter().any(|r| r == &Route::Relays) {
|
||||
// return if we are already routing to accounts
|
||||
router.go_back();
|
||||
} else {
|
||||
@@ -308,7 +308,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
if router
|
||||
.routes()
|
||||
.iter()
|
||||
.any(|&r| matches!(r, Route::AddColumn(_)))
|
||||
.any(|r| matches!(r, Route::AddColumn(_)))
|
||||
{
|
||||
router.go_back();
|
||||
} else {
|
||||
@@ -316,7 +316,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
}
|
||||
}
|
||||
SidePanelAction::ComposeNote => {
|
||||
if router.routes().iter().any(|&r| r == Route::ComposeNote) {
|
||||
if router.routes().iter().any(|r| r == &Route::ComposeNote) {
|
||||
router.go_back();
|
||||
} else {
|
||||
router.route_to(Route::ComposeNote);
|
||||
@@ -331,7 +331,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
info!("Clicked expand side panel button");
|
||||
}
|
||||
SidePanelAction::Support => {
|
||||
if router.routes().iter().any(|&r| r == Route::Support) {
|
||||
if router.routes().iter().any(|r| r == &Route::Support) {
|
||||
router.go_back();
|
||||
} else {
|
||||
support.refresh();
|
||||
@@ -339,7 +339,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
}
|
||||
}
|
||||
SidePanelAction::NewDeck => {
|
||||
if router.routes().iter().any(|&r| r == Route::NewDeck) {
|
||||
if router.routes().iter().any(|r| r == &Route::NewDeck) {
|
||||
router.go_back();
|
||||
} else {
|
||||
router.route_to(Route::NewDeck);
|
||||
@@ -351,7 +351,7 @@ impl<'a> DesktopSidePanel<'a> {
|
||||
)))
|
||||
}
|
||||
SidePanelAction::EditDeck(index) => {
|
||||
if router.routes().iter().any(|&r| r == Route::EditDeck(index)) {
|
||||
if router.routes().iter().any(|r| r == &Route::EditDeck(index)) {
|
||||
router.go_back();
|
||||
} else {
|
||||
switching_response = Some(crate::nav::SwitchingAction::Decks(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
actionbar::NoteAction,
|
||||
timeline::{TimelineCache, TimelineCacheKey},
|
||||
timeline::{ThreadSelection, TimelineCache, TimelineKind},
|
||||
ui::note::NoteOptions,
|
||||
};
|
||||
|
||||
@@ -83,7 +83,7 @@ impl<'a> ThreadView<'a> {
|
||||
self.ndb,
|
||||
self.note_cache,
|
||||
&txn,
|
||||
TimelineCacheKey::Thread(root_id),
|
||||
&TimelineKind::Thread(ThreadSelection::from_root_id(root_id.to_owned())),
|
||||
)
|
||||
.get_ptr();
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ use std::f32::consts::PI;
|
||||
use crate::actionbar::NoteAction;
|
||||
use crate::timeline::TimelineTab;
|
||||
use crate::{
|
||||
column::Columns,
|
||||
timeline::{TimelineId, ViewFilter},
|
||||
timeline::{TimelineCache, TimelineKind, ViewFilter},
|
||||
ui,
|
||||
ui::note::NoteOptions,
|
||||
};
|
||||
@@ -19,8 +18,8 @@ use tracing::{error, warn};
|
||||
use super::anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE};
|
||||
|
||||
pub struct TimelineView<'a> {
|
||||
timeline_id: TimelineId,
|
||||
columns: &'a mut Columns,
|
||||
timeline_id: &'a TimelineKind,
|
||||
timeline_cache: &'a mut TimelineCache,
|
||||
ndb: &'a Ndb,
|
||||
note_cache: &'a mut NoteCache,
|
||||
img_cache: &'a mut ImageCache,
|
||||
@@ -31,8 +30,8 @@ pub struct TimelineView<'a> {
|
||||
|
||||
impl<'a> TimelineView<'a> {
|
||||
pub fn new(
|
||||
timeline_id: TimelineId,
|
||||
columns: &'a mut Columns,
|
||||
timeline_id: &'a TimelineKind,
|
||||
timeline_cache: &'a mut TimelineCache,
|
||||
ndb: &'a Ndb,
|
||||
note_cache: &'a mut NoteCache,
|
||||
img_cache: &'a mut ImageCache,
|
||||
@@ -43,7 +42,7 @@ impl<'a> TimelineView<'a> {
|
||||
TimelineView {
|
||||
ndb,
|
||||
timeline_id,
|
||||
columns,
|
||||
timeline_cache,
|
||||
note_cache,
|
||||
img_cache,
|
||||
reverse,
|
||||
@@ -57,7 +56,7 @@ impl<'a> TimelineView<'a> {
|
||||
ui,
|
||||
self.ndb,
|
||||
self.timeline_id,
|
||||
self.columns,
|
||||
self.timeline_cache,
|
||||
self.note_cache,
|
||||
self.img_cache,
|
||||
self.reverse,
|
||||
@@ -76,8 +75,8 @@ impl<'a> TimelineView<'a> {
|
||||
fn timeline_ui(
|
||||
ui: &mut egui::Ui,
|
||||
ndb: &Ndb,
|
||||
timeline_id: TimelineId,
|
||||
columns: &mut Columns,
|
||||
timeline_id: &TimelineKind,
|
||||
timeline_cache: &mut TimelineCache,
|
||||
note_cache: &mut NoteCache,
|
||||
img_cache: &mut ImageCache,
|
||||
reversed: bool,
|
||||
@@ -92,7 +91,7 @@ fn timeline_ui(
|
||||
*/
|
||||
|
||||
let scroll_id = {
|
||||
let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) {
|
||||
let timeline = if let Some(timeline) = timeline_cache.timelines.get_mut(timeline_id) {
|
||||
timeline
|
||||
} else {
|
||||
error!("tried to render timeline in column, but timeline was missing");
|
||||
@@ -142,7 +141,7 @@ fn timeline_ui(
|
||||
}
|
||||
|
||||
let scroll_output = scroll_area.show(ui, |ui| {
|
||||
let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) {
|
||||
let timeline = if let Some(timeline) = timeline_cache.timelines.get(timeline_id) {
|
||||
timeline
|
||||
} else {
|
||||
error!("tried to render timeline in column, but timeline was missing");
|
||||
|
||||
Reference in New Issue
Block a user