#[cfg_attr(not(test), expect(clippy::wildcard_imports, reason = "shared"))]
use super::*;
impl App {
pub(crate) fn tick(&mut self, now: Instant) -> (Vec<AppEffect>, bool) {
let toast_expired = self
.toast
.as_ref()
.is_some_and(|toast| now >= toast.expires_at);
let mut changed = toast_expired;
if toast_expired {
self.toast = None;
}
if self
.pending_g
.is_some_and(|pressed| now.duration_since(pressed) >= Duration::from_millis(500))
{
self.pending_g = None;
}
let mut effects = Vec::new();
if self.preview_due.is_some_and(|due| now >= due) {
self.preview_due = None;
self.request_preview(&mut effects);
changed = true;
}
if self.pull_request_poll_due.is_some_and(|due| now >= due) {
self.refresh_pull_request_live(now, false, &mut effects);
changed = true;
}
if self.busy.is_some() {
self.operation_frame = self.operation_frame.wrapping_add(1) % OPERATION_SPINNER.len();
changed = true;
}
(effects, changed)
}
pub(crate) fn operation_spinner(&self) -> &'static str {
OPERATION_SPINNER
.get(self.operation_frame % OPERATION_SPINNER.len())
.copied()
.unwrap_or("◐")
}
pub(crate) fn webhook_delivered(&mut self, now: Instant) -> Vec<AppEffect> {
let mut effects = Vec::new();
if self.pull_request.is_some() {
self.refresh_pull_request_live(now, true, &mut effects);
}
effects
}
pub(crate) const fn pull_request_refreshing(&self) -> bool {
self.pull_request_loading
|| self.pull_request_checks_loading
|| self.pull_request_conversation_loading
|| self.pull_request_review_loading
|| self.pull_request_check_log_loading
}
pub(crate) const fn pull_request_served_from_cache(&self) -> bool {
self.pull_request.is_some()
&& self.pull_request_from_cache
&& self.pull_request_conversation.from_cache
&& !self.pull_request_refreshing()
}
pub(super) fn pull_request_poll_interval(&self) -> Duration {
if self.view != View::PullRequests {
return PULL_REQUEST_BACKGROUND_POLL;
}
if self
.pull_request_checks
.iter()
.any(|check| check.status.is_running())
{
PULL_REQUEST_ACTIVE_POLL
} else {
PULL_REQUEST_IDLE_POLL
}
}
pub(super) fn schedule_pull_request_poll(&mut self, now: Instant) {
self.pull_request_poll_due = self
.pull_request
.is_some()
.then(|| now + self.pull_request_poll_interval());
}
pub(super) fn refresh_pull_request_live(
&mut self,
now: Instant,
force: bool,
effects: &mut Vec<AppEffect>,
) {
self.schedule_pull_request_poll(now);
let Some(number) = self.pull_request_exact_number else {
return;
};
if self.pull_request.is_none() {
return;
}
let due = |last: Option<Instant>, interval: Duration| {
force || last.is_none_or(|last| now.duration_since(last) >= interval)
};
if due(
self.pull_request_checks_read_at,
self.pull_request_poll_interval(),
) {
let issued = effects.len();
self.request_pull_request_checks(true, effects);
if effects.len() > issued {
self.pull_request_checks_read_at = Some(now);
}
}
let settled = self
.pull_request
.as_ref()
.is_some_and(|pull_request| matches!(pull_request.state.as_str(), "MERGED" | "CLOSED"));
if settled && !force {
return;
}
if due(self.pull_request_detail_read_at, PULL_REQUEST_DETAIL_POLL) {
let issued = effects.len();
self.request_pull_request_lookup(number, true, true, effects);
self.request_pull_request_conversation(true, effects);
self.request_pull_request_review(true, effects);
if effects.len() > issued {
self.pull_request_detail_read_at = Some(now);
}
}
let running = self
.selected_pull_request_check()
.is_some_and(|check| check.status.is_running());
if running && due(self.pull_request_log_read_at, PULL_REQUEST_LOG_POLL) {
let issued = effects.len();
self.request_check_run_log(true, effects);
if effects.len() > issued {
self.pull_request_log_read_at = Some(now);
}
}
}
pub(crate) fn filesystem_changed(&mut self, effects: &mut Vec<AppEffect>) {
self.changes_diff_version = self.changes_diff_version.wrapping_add(1);
if self.view == View::Changes && self.auxiliary_preview.is_none() {
self.invalidate_preview();
self.local_diff_loading_path = None;
self.local_diff_pending_paths.clear();
}
self.request_refresh(effects);
}
pub(crate) fn periodic_refresh(&mut self, effects: &mut Vec<AppEffect>) {
self.request_refresh(effects);
}
}