fix: always reserve space for selection marker to prevent text shift #23

Merged
killingdruid merged 1 commits from refactor into main 2026-02-24 12:59:04 +00:00
22 changed files with 54 additions and 58 deletions
Showing only changes of commit a095fe277b - Show all commits

View File

@@ -221,9 +221,9 @@ pub fn render_message_bubble(
let mut lines = Vec::new(); let mut lines = Vec::new();
let is_selected = selected_msg_id == Some(msg.id()); let is_selected = selected_msg_id == Some(msg.id());
// Маркер выбора // Маркер выбора (всегда резервируем место для ▶, чтобы текст не сдвигался)
let selection_marker = if is_selected { "" } else { " " }; let selection_marker = if is_selected { "" } else { " " };
let marker_len = selection_marker.chars().count(); let marker_len = 2;
// Цвет сообщения // Цвет сообщения
let msg_color = if is_selected { let msg_color = if is_selected {
@@ -306,16 +306,16 @@ pub fn render_message_bubble(
let full_len = line_len + time_mark_len + marker_len; let full_len = line_len + time_mark_len + marker_len;
let padding = content_width.saturating_sub(full_len + 1); let padding = content_width.saturating_sub(full_len + 1);
let mut line_spans = vec![Span::raw(" ".repeat(padding))]; let mut line_spans = vec![Span::raw(" ".repeat(padding))];
if is_selected && i == 0 { if i == 0 {
// Одна строка — маркер на ней // Первая (или единственная) строка — маркер
line_spans.push(Span::styled( line_spans.push(Span::styled(
selection_marker, selection_marker,
Style::default() Style::default()
.fg(Color::Yellow) .fg(Color::Yellow)
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
)); ));
} else if is_selected { } else {
// Последняя строка multi-line — пробелы вместо маркера // Остальные строки multi-line — пробелы вместо маркера
line_spans.push(Span::raw(" ".repeat(marker_len))); line_spans.push(Span::raw(" ".repeat(marker_len)));
} }
line_spans.extend(formatted_spans); line_spans.extend(formatted_spans);
@@ -327,14 +327,14 @@ pub fn render_message_bubble(
} else { } else {
let padding = content_width.saturating_sub(line_len + marker_len + 1); let padding = content_width.saturating_sub(line_len + marker_len + 1);
let mut line_spans = vec![Span::raw(" ".repeat(padding))]; let mut line_spans = vec![Span::raw(" ".repeat(padding))];
if i == 0 && is_selected { if i == 0 {
line_spans.push(Span::styled( line_spans.push(Span::styled(
selection_marker, selection_marker,
Style::default() Style::default()
.fg(Color::Yellow) .fg(Color::Yellow)
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
)); ));
} else if is_selected { } else {
// Средние строки multi-line — пробелы вместо маркера // Средние строки multi-line — пробелы вместо маркера
line_spans.push(Span::raw(" ".repeat(marker_len))); line_spans.push(Span::raw(" ".repeat(marker_len)));
} }
@@ -364,14 +364,12 @@ pub fn render_message_bubble(
if i == 0 { if i == 0 {
let mut line_spans = vec![]; let mut line_spans = vec![];
if is_selected {
line_spans.push(Span::styled( line_spans.push(Span::styled(
selection_marker, selection_marker,
Style::default() Style::default()
.fg(Color::Yellow) .fg(Color::Yellow)
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
)); ));
}
line_spans line_spans
.push(Span::styled(format!(" {}", time_str), Style::default().fg(Color::Gray))); .push(Span::styled(format!(" {}", time_str), Style::default().fg(Color::Gray)));
line_spans.push(Span::raw(" ")); line_spans.push(Span::raw(" "));
@@ -548,7 +546,7 @@ pub fn render_album_bubble(
let is_selected = messages.iter().any(|m| selected_msg_id == Some(m.id())); let is_selected = messages.iter().any(|m| selected_msg_id == Some(m.id()));
let is_outgoing = messages.first().is_some_and(|m| m.is_outgoing()); let is_outgoing = messages.first().is_some_and(|m| m.is_outgoing());
// Selection marker // Selection marker (всегда резервируем место)
let selection_marker = if is_selected { "" } else { " " }; let selection_marker = if is_selected { "" } else { " " };
// Фильтруем фото // Фильтруем фото
@@ -567,15 +565,13 @@ pub fn render_album_bubble(
let cols = photo_count.min(ALBUM_GRID_MAX_COLS); let cols = photo_count.min(ALBUM_GRID_MAX_COLS);
let rows = photo_count.div_ceil(cols); let rows = photo_count.div_ceil(cols);
// Добавляем маркер выбора на первую строку // Добавляем маркер выбора на первую строку (всегда — для постоянного отступа)
if is_selected {
lines.push(Line::from(vec![Span::styled( lines.push(Line::from(vec![Span::styled(
selection_marker, selection_marker,
Style::default() Style::default()
.fg(Color::Yellow) .fg(Color::Yellow)
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
)])); )]));
}
let grid_start_line = lines.len(); let grid_start_line = lines.len();