record, and transfer you to the error-log viewer with a beep, just the
way Mono did it.
-## Tracking what you've read
+## LDB checkpointing
-When you restart Mastodonochrome and open a feed, it ought to put in
-view the first thing you haven't yet read in that feed. This means
-tracking what _is_ read during run time, and saving it to a file in
-the config directory.
-
-Similarly, when the client automatically moves you into the Read
-Mentions field because a new mention has arrived, it should
-automatically jump the position to the first unread one.
+It would be nice to checkpoint the LDB to disk every few minutes, if
+it's changed, as a precaution against data loss if the client crashes
+after sitting in the same `File` for a long time.
## Reading
You should be able to post polls, again via some kind of internal
editor markup that inserts magic delimiter characters.
+### Mentions arriving while you're editing
+
+If you got a beep for an incoming mention while you were writing a
+post of your own, then in real Mono, finishing up your post causes you
+to be belatedly thrown into your mentions. Perhaps we should replicate
+that.
+
+### Saving a draft
+
+If you ESC out of the editor, your draft should be saved to come back
+to.
+
## Editor improvements
### Block cut and paste
FilePosition::item_top(latest_read_index + 1)
} else {
FilePosition::item_bottom(latest_read_index)
- }
+ };
}
}
// But if we have an actual FilePosition in our SavedFilePos,
- // it's even better to use that.
- if let Some(file_pos) = saved_pos.and_then(|sp| sp.file_pos) {
- initial_pos = file_pos;
+ // it's even better to use that ... unless we're supposed to
+ // be showing a new thing eagerly.
+ if !show_new {
+ if let Some(file_pos) = saved_pos.and_then(|sp| sp.file_pos) {
+ initial_pos = file_pos;
+ }
}
// Now clip initial_pos at the top and bottom of the data we have
}
pub fn mentions(file_positions: &HashMap<FeedId, SavedFilePos>,
- client: &mut Client) ->
+ client: &mut Client, is_interrupt: bool) ->
Result<Box<dyn ActivityState>, ClientError>
{
let feed = FeedId::Mentions;
let file = File::new(
client, FeedSource::new(feed), ColouredString::general(
"Mentions [ESC][R]",
- "HHHHHHHHHHHHKKKHHKH"), desc, pos, false)?;
+ "HHHHHHHHHHHHKKKHHKH"), desc, pos, is_interrupt)?;
Ok(Box::new(file))
}
LogicalAction::Nothing => break PhysicalAction::Nothing,
LogicalAction::Goto(activity) => {
self.activity_stack.goto(activity);
- self.changed_activity(client, None);
+ self.changed_activity(client, None, false);
break PhysicalAction::Nothing
}
LogicalAction::Pop => {
self.activity_stack.pop();
- self.changed_activity(client, None);
+ self.changed_activity(client, None, false);
break PhysicalAction::Nothing
}
LogicalAction::PopOverlaySilent => {
act => panic!("can't postcompose {act:?}"),
};
self.activity_stack.chain_to(newact);
- self.changed_activity(client, Some(post));
+ self.changed_activity(client, Some(post), false);
break PhysicalAction::Nothing
}
LogicalAction::PostReEdit(post) => {
act => panic!("can't reedit {act:?}"),
};
self.activity_stack.chain_to(newact);
- self.changed_activity(client, Some(post));
+ self.changed_activity(client, Some(post), false);
break PhysicalAction::Nothing
}
};
if feeds_updated.contains(&FeedId::Mentions) {
if self.activity_stack.top().throw_into_mentions() {
self.activity_stack.goto(UtilityActivity::ReadMentions.into());
- self.changed_activity(client, None);
+ self.changed_activity(client, None, true);
}
// FIXME: we'd quite like a double-beep if you're in the composer
}
}
- fn changed_activity(&mut self, client: &mut Client, post: Option<Post>) {
+ fn changed_activity(&mut self, client: &mut Client, post: Option<Post>,
+ is_interrupt: bool) {
if let Some((feed_id, saved_pos)) =
self.activity_state.save_file_position()
{
}
}
self.activity_state = self.new_activity_state(
- self.activity_stack.top(), client, post);
+ self.activity_stack.top(), client, post, is_interrupt);
self.overlay_activity_state = match self.activity_stack.overlay() {
Some(activity) =>
- Some(self.new_activity_state(activity, client, None)),
+ Some(self.new_activity_state(activity, client, None, false)),
None => None,
};
if let Some(area) = self.last_area {
}
fn new_activity_state(&self, activity: Activity, client: &mut Client,
- post: Option<Post>) -> Box<dyn ActivityState>
+ post: Option<Post>, is_interrupt: bool)
+ -> Box<dyn ActivityState>
{
let result = match activity {
Activity::NonUtil(NonUtilityActivity::MainMenu) =>
Activity::NonUtil(NonUtilityActivity::HashtagTimeline(ref id)) =>
hashtag_timeline(client, id),
Activity::Util(UtilityActivity::ReadMentions) =>
- mentions(&self.file_positions, client),
+ mentions(&self.file_positions, client, is_interrupt),
Activity::Util(UtilityActivity::EgoLog) =>
ego_log(&self.file_positions, client),
Activity::Overlay(OverlayActivity::GetUserToExamine) =>