mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Use terminal window focus to determine when a message has actually been seen (#94)
This commit is contained in:
parent
430c601ff2
commit
885b56038f
5 changed files with 51 additions and 13 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2137,7 +2137,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "modalkit"
|
name = "modalkit"
|
||||||
version = "0.0.15"
|
version = "0.0.15"
|
||||||
source = "git+https://github.com/ulyssa/modalkit?rev=7979680#797968002c53287d907ca3ae823e3482265c94bb"
|
source = "git+https://github.com/ulyssa/modalkit?rev=f641162#f6411625caa1ddb764c91a3fc47e052cfdc405b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anymap2",
|
"anymap2",
|
||||||
"arboard",
|
"arboard",
|
||||||
|
|
|
@ -52,7 +52,7 @@ url = {version = "^2.2.2", features = ["serde"]}
|
||||||
|
|
||||||
[dependencies.modalkit]
|
[dependencies.modalkit]
|
||||||
git = "https://github.com/ulyssa/modalkit"
|
git = "https://github.com/ulyssa/modalkit"
|
||||||
rev = "7979680"
|
rev = "f641162"
|
||||||
|
|
||||||
[dependencies.matrix-sdk]
|
[dependencies.matrix-sdk]
|
||||||
version = "0.6"
|
version = "0.6"
|
||||||
|
|
41
src/main.rs
41
src/main.rs
|
@ -22,7 +22,15 @@ use matrix_sdk::ruma::OwnedUserId;
|
||||||
use modalkit::crossterm::{
|
use modalkit::crossterm::{
|
||||||
self,
|
self,
|
||||||
cursor::Show as CursorShow,
|
cursor::Show as CursorShow,
|
||||||
event::{poll, read, DisableBracketedPaste, EnableBracketedPaste, Event},
|
event::{
|
||||||
|
poll,
|
||||||
|
read,
|
||||||
|
DisableBracketedPaste,
|
||||||
|
DisableFocusChange,
|
||||||
|
EnableBracketedPaste,
|
||||||
|
EnableFocusChange,
|
||||||
|
Event,
|
||||||
|
},
|
||||||
execute,
|
execute,
|
||||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen, SetTitle},
|
terminal::{EnterAlternateScreen, LeaveAlternateScreen, SetTitle},
|
||||||
};
|
};
|
||||||
|
@ -109,6 +117,7 @@ struct Application {
|
||||||
bindings: KeyManager<TerminalKey, ProgramAction, RepeatType, ProgramContext>,
|
bindings: KeyManager<TerminalKey, ProgramAction, RepeatType, ProgramContext>,
|
||||||
actstack: VecDeque<(ProgramAction, ProgramContext)>,
|
actstack: VecDeque<(ProgramAction, ProgramContext)>,
|
||||||
screen: ScreenState<IambWindow, IambInfo>,
|
screen: ScreenState<IambWindow, IambInfo>,
|
||||||
|
focused: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
|
@ -120,6 +129,7 @@ impl Application {
|
||||||
crossterm::terminal::enable_raw_mode()?;
|
crossterm::terminal::enable_raw_mode()?;
|
||||||
crossterm::execute!(stdout, EnterAlternateScreen)?;
|
crossterm::execute!(stdout, EnterAlternateScreen)?;
|
||||||
crossterm::execute!(stdout, EnableBracketedPaste)?;
|
crossterm::execute!(stdout, EnableBracketedPaste)?;
|
||||||
|
crossterm::execute!(stdout, EnableFocusChange)?;
|
||||||
|
|
||||||
let title = format!("iamb ({})", settings.profile.user_id);
|
let title = format!("iamb ({})", settings.profile.user_id);
|
||||||
crossterm::execute!(stdout, SetTitle(title))?;
|
crossterm::execute!(stdout, SetTitle(title))?;
|
||||||
|
@ -154,11 +164,13 @@ impl Application {
|
||||||
bindings,
|
bindings,
|
||||||
actstack,
|
actstack,
|
||||||
screen,
|
screen,
|
||||||
|
focused: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redraw(&mut self, full: bool, store: &mut ProgramStore) -> Result<(), std::io::Error> {
|
fn redraw(&mut self, full: bool, store: &mut ProgramStore) -> Result<(), std::io::Error> {
|
||||||
let bindings = &mut self.bindings;
|
let bindings = &mut self.bindings;
|
||||||
|
let focused = self.focused;
|
||||||
let sstate = &mut self.screen;
|
let sstate = &mut self.screen;
|
||||||
let term = &mut self.terminal;
|
let term = &mut self.terminal;
|
||||||
|
|
||||||
|
@ -176,7 +188,11 @@ impl Application {
|
||||||
// Don't show terminal cursor when we show a dialog.
|
// Don't show terminal cursor when we show a dialog.
|
||||||
let hide_cursor = !dialogstr.is_empty();
|
let hide_cursor = !dialogstr.is_empty();
|
||||||
|
|
||||||
let screen = Screen::new(store).show_dialog(dialogstr).show_mode(modestr).borders(true);
|
let screen = Screen::new(store)
|
||||||
|
.show_dialog(dialogstr)
|
||||||
|
.show_mode(modestr)
|
||||||
|
.borders(true)
|
||||||
|
.focus(focused);
|
||||||
f.render_stateful_widget(screen, area, sstate);
|
f.render_stateful_widget(screen, area, sstate);
|
||||||
|
|
||||||
if hide_cursor {
|
if hide_cursor {
|
||||||
|
@ -212,8 +228,11 @@ impl Application {
|
||||||
Event::Mouse(_) => {
|
Event::Mouse(_) => {
|
||||||
// Do nothing for now.
|
// Do nothing for now.
|
||||||
},
|
},
|
||||||
Event::FocusGained | Event::FocusLost => {
|
Event::FocusGained => {
|
||||||
// Do nothing for now.
|
self.focused = true;
|
||||||
|
},
|
||||||
|
Event::FocusLost => {
|
||||||
|
self.focused = false;
|
||||||
},
|
},
|
||||||
Event::Resize(_, _) => {
|
Event::Resize(_, _) => {
|
||||||
// We'll redraw for the new size next time step() is called.
|
// We'll redraw for the new size next time step() is called.
|
||||||
|
@ -532,13 +551,18 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> {
|
||||||
|
|
||||||
login(worker, &settings).await.unwrap_or_else(print_exit);
|
login(worker, &settings).await.unwrap_or_else(print_exit);
|
||||||
|
|
||||||
|
fn restore_tty() {
|
||||||
|
let _ = crossterm::terminal::disable_raw_mode();
|
||||||
|
let _ = crossterm::execute!(stdout(), DisableBracketedPaste);
|
||||||
|
let _ = crossterm::execute!(stdout(), DisableFocusChange);
|
||||||
|
let _ = crossterm::execute!(stdout(), LeaveAlternateScreen);
|
||||||
|
let _ = crossterm::execute!(stdout(), CursorShow);
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure panics clean up the terminal properly.
|
// Make sure panics clean up the terminal properly.
|
||||||
let orig_hook = std::panic::take_hook();
|
let orig_hook = std::panic::take_hook();
|
||||||
std::panic::set_hook(Box::new(move |panic_info| {
|
std::panic::set_hook(Box::new(move |panic_info| {
|
||||||
let _ = crossterm::terminal::disable_raw_mode();
|
restore_tty();
|
||||||
let _ = crossterm::execute!(stdout(), DisableBracketedPaste);
|
|
||||||
let _ = crossterm::execute!(stdout(), LeaveAlternateScreen);
|
|
||||||
let _ = crossterm::execute!(stdout(), CursorShow);
|
|
||||||
orig_hook(panic_info);
|
orig_hook(panic_info);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}));
|
}));
|
||||||
|
@ -547,6 +571,7 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> {
|
||||||
|
|
||||||
// We can now run the application.
|
// We can now run the application.
|
||||||
application.run().await?;
|
application.run().await?;
|
||||||
|
restore_tty();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -848,7 +848,9 @@ impl<'a> StatefulWidget for Chat<'a> {
|
||||||
|
|
||||||
// Render the message scrollback.
|
// Render the message scrollback.
|
||||||
let scrollback_focused = state.focus.is_scrollback() && self.focused;
|
let scrollback_focused = state.focus.is_scrollback() && self.focused;
|
||||||
let scrollback = Scrollback::new(self.store).focus(scrollback_focused);
|
let scrollback = Scrollback::new(self.store)
|
||||||
|
.focus(scrollback_focused)
|
||||||
|
.room_focus(self.focused);
|
||||||
scrollback.render(scrollarea, buf, &mut state.scrollback);
|
scrollback.render(scrollarea, buf, &mut state.scrollback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1206,13 +1206,21 @@ impl TerminalCursor for ScrollbackState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Scrollback<'a> {
|
pub struct Scrollback<'a> {
|
||||||
|
room_focused: bool,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
store: &'a mut ProgramStore,
|
store: &'a mut ProgramStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Scrollback<'a> {
|
impl<'a> Scrollback<'a> {
|
||||||
pub fn new(store: &'a mut ProgramStore) -> Self {
|
pub fn new(store: &'a mut ProgramStore) -> Self {
|
||||||
Scrollback { focused: false, store }
|
Scrollback { room_focused: false, focused: false, store }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicate whether the room window is currently focused, regardless of whether the scrollback
|
||||||
|
/// also is.
|
||||||
|
pub fn room_focus(mut self, focused: bool) -> Self {
|
||||||
|
self.room_focused = focused;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicate whether the scrollback is currently focused.
|
/// Indicate whether the scrollback is currently focused.
|
||||||
|
@ -1307,7 +1315,10 @@ impl<'a> StatefulWidget for Scrollback<'a> {
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.tunables.read_receipt_send && state.cursor.timestamp.is_none() {
|
if self.room_focused &&
|
||||||
|
settings.tunables.read_receipt_send &&
|
||||||
|
state.cursor.timestamp.is_none()
|
||||||
|
{
|
||||||
// If the cursor is at the last message, then update the read marker.
|
// If the cursor is at the last message, then update the read marker.
|
||||||
info.read_till = info.messages.last_key_value().map(|(k, _)| k.1.clone());
|
info.read_till = info.messages.last_key_value().map(|(k, _)| k.1.clone());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue