Fix messages scrolling up on re-render
This commit is contained in:
parent
26b07d6c57
commit
a97c838474
2 changed files with 31 additions and 30 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
//! Intermediate representation of chat history as blocks of things.
|
//! Intermediate representation of chat history as blocks of things.
|
||||||
|
|
||||||
use std::collections::{vec_deque, VecDeque};
|
use std::collections::{vec_deque, VecDeque};
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use toss::styled::Styled;
|
use toss::styled::Styled;
|
||||||
|
|
@ -55,9 +56,9 @@ pub struct Block<I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Block<I> {
|
impl<I> Block<I> {
|
||||||
pub fn bottom() -> Self {
|
pub fn bottom(line: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
line: 0,
|
line,
|
||||||
time: None,
|
time: None,
|
||||||
indent: 0,
|
indent: 0,
|
||||||
body: BlockBody::Marker(MarkerBlock::Bottom),
|
body: BlockBody::Marker(MarkerBlock::Bottom),
|
||||||
|
|
@ -143,16 +144,19 @@ pub struct Blocks<I> {
|
||||||
|
|
||||||
impl<I> Blocks<I> {
|
impl<I> Blocks<I> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::new_below(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new [`Blocks`] such that prepending a single line will result
|
|
||||||
/// in `top_line = bottom_line = line`.
|
|
||||||
pub fn new_below(line: i32) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
blocks: VecDeque::new(),
|
blocks: VecDeque::new(),
|
||||||
top_line: line + 1,
|
top_line: 1,
|
||||||
bottom_line: line,
|
bottom_line: 0,
|
||||||
|
roots: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_bottom(line: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
blocks: iter::once(Block::bottom(line)).collect(),
|
||||||
|
top_line: line,
|
||||||
|
bottom_line: line - 1,
|
||||||
roots: None,
|
roots: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
if let Some(block) = last_blocks.find(|b| cursor.matches_block(b)) {
|
if let Some(block) = last_blocks.find(|b| cursor.matches_block(b)) {
|
||||||
block.line
|
block.line
|
||||||
} else if last_cursor_path < cursor_path {
|
} else if last_cursor_path < cursor_path {
|
||||||
// Not using size.height - 1 because markers like
|
// If the cursor is bottom, the bottom marker needs to be located at
|
||||||
// MarkerBlock::Bottom in the line below the last visible line are
|
// the line below the last visible line. If it is a normal message
|
||||||
// still relevant to us.
|
// cursor, it will be made visible again one way or another later.
|
||||||
size.height.into()
|
size.height.into()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
|
@ -133,13 +133,17 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
});
|
});
|
||||||
blocks
|
blocks
|
||||||
} else {
|
} else {
|
||||||
let mut blocks = Blocks::new_below(cursor_line);
|
Blocks::new_bottom(cursor_line)
|
||||||
blocks.push_front(Block::bottom());
|
|
||||||
blocks
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll_so_cursor_is_visible(blocks: &mut Blocks<M::Id>, cursor: &Cursor<M::Id>, size: Size) {
|
fn scroll_so_cursor_is_visible(blocks: &mut Blocks<M::Id>, cursor: &Cursor<M::Id>, size: Size) {
|
||||||
|
if !matches!(cursor, Cursor::Msg(_)) {
|
||||||
|
// In all other cases, there is special scrolling behaviour, so
|
||||||
|
// let's not interfere.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(block) = blocks.find(|b| cursor.matches_block(b)) {
|
if let Some(block) = blocks.find(|b| cursor.matches_block(b)) {
|
||||||
let min_line = 0;
|
let min_line = 0;
|
||||||
let max_line = size.height as i32 - block.height();
|
let max_line = size.height as i32 - block.height();
|
||||||
|
|
@ -155,11 +159,9 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to obtain a normal cursor (i.e. no composing or placeholder cursor)
|
/// Try to obtain a [`Cursor::Msg`] pointing to the block.
|
||||||
/// pointing to the block.
|
fn as_msg_cursor(block: &Block<M::Id>) -> Option<Cursor<M::Id>> {
|
||||||
fn as_direct_cursor(block: &Block<M::Id>) -> Option<Cursor<M::Id>> {
|
|
||||||
match &block.body {
|
match &block.body {
|
||||||
BlockBody::Marker(MarkerBlock::Bottom) => Some(Cursor::Bottom),
|
|
||||||
BlockBody::Msg(MsgBlock { id, .. }) => Some(Cursor::Msg(id.clone())),
|
BlockBody::Msg(MsgBlock { id, .. }) => Some(Cursor::Msg(id.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -170,14 +172,9 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
cursor: &mut Cursor<M::Id>,
|
cursor: &mut Cursor<M::Id>,
|
||||||
size: Size,
|
size: Size,
|
||||||
) {
|
) {
|
||||||
if matches!(cursor, Cursor::Compose(_) | Cursor::Placeholder(_)) {
|
if !matches!(cursor, Cursor::Msg(_)) {
|
||||||
// In this case, we can't easily move the cursor since moving it
|
// In all other cases, there is special scrolling behaviour, so
|
||||||
// would change how the entire layout is rendered in
|
// let's not interfere.
|
||||||
// difficult-to-predict ways.
|
|
||||||
//
|
|
||||||
// Also, the user has initiated a reply to get into this state. This
|
|
||||||
// confirms that they want their cursor in precisely its current
|
|
||||||
// place. Moving it might lead to mis-replies and frustration.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,14 +187,14 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
blocks
|
blocks
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|b| b.line >= min_line)
|
.filter(|b| b.line >= min_line)
|
||||||
.find_map(Self::as_direct_cursor)
|
.find_map(Self::as_msg_cursor)
|
||||||
} else if block.line > max_line {
|
} else if block.line > max_line {
|
||||||
// Move cursor to last possible visible block
|
// Move cursor to last possible visible block
|
||||||
blocks
|
blocks
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.filter(|b| b.line <= max_line)
|
.filter(|b| b.line <= max_line)
|
||||||
.find_map(Self::as_direct_cursor)
|
.find_map(Self::as_msg_cursor)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue