T21b and T21c round 1 fixes
- a page centers only while it fits the view; a wider one starts in reach - the reveal runs after the pages' prepaint and keys on the hit itself, so a new hit at the same index and a hit current from the first frame come into view - the chapter list scrolls - zen takes focus when turned on from outside, so Escape leaves it, and hands focus back - the gallery keeps a page's due date and tags
This commit is contained in:
1 parent
9854cfa460
commit
444a95a854
8 files changed
+196
-42
No files matched your search
+126
-16
@@ -1,23 +1,33 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use gpui::{
|
||||
AppContext as _, Bounds, Context, Entity, IntoElement, Modifiers, ParentElement, Pixels, Point,
|
||||
Render, ScrollDelta, ScrollWheelEvent, Styled, TestAppContext, TouchPhase, VisualTestContext,
|
||||
Window, div, point, px, size,
|
||||
AppContext as _, Bounds, Context, Entity, Focusable, IntoElement, Modifiers, ParentElement,
|
||||
Pixels, Point, Render, ScrollDelta, ScrollWheelEvent, Styled, TestAppContext, TouchPhase,
|
||||
VisualTestContext, Window, div, point, px, size,
|
||||
};
|
||||
|
||||
use super::{DocPage, DocumentViewer, PageHit};
|
||||
use super::{DocPage, DocumentViewer, PageHit, ZenMode};
|
||||
use crate::{
|
||||
editor::FindWidget,
|
||||
forms::TextInput,
|
||||
forms::{Input, TextInput},
|
||||
theme::{ActiveTheme, ControlSize, Theme},
|
||||
};
|
||||
|
||||
type Noted = Rc<RefCell<Option<(usize, Point<f32>)>>>;
|
||||
|
||||
/// Three tall pages with one hit on the second; a press while pinning records the note asked.
|
||||
/// A hit on `page`, 400 points down.
|
||||
fn hit(page: usize) -> PageHit {
|
||||
PageHit {
|
||||
page,
|
||||
bounds: Bounds::new(point(40.0, 400.0), size(60.0, 12.0)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Three tall pages and the hits found; a press while pinning records the note asked.
|
||||
struct Reader {
|
||||
query: Entity<TextInput>,
|
||||
width: f32,
|
||||
hits: Vec<PageHit>,
|
||||
current: Option<usize>,
|
||||
noted: Noted,
|
||||
}
|
||||
@@ -27,20 +37,16 @@ impl Render for Reader {
|
||||
let pages: Vec<DocPage> = (0..3)
|
||||
.map(|ix| DocPage {
|
||||
source: format!("page-{ix}.png").into(),
|
||||
width: 400.0,
|
||||
width: self.width,
|
||||
height: 1000.0,
|
||||
})
|
||||
.collect();
|
||||
let hit = PageHit {
|
||||
page: 1,
|
||||
bounds: Bounds::new(point(40.0, 400.0), size(60.0, 12.0)),
|
||||
};
|
||||
let noted = self.noted.clone();
|
||||
div().size_full().child(
|
||||
DocumentViewer::new("viewer", "lift.pdf", pages)
|
||||
.find(
|
||||
FindWidget::new("find", &self.query, self.current, 1),
|
||||
vec![hit],
|
||||
FindWidget::new("find", &self.query, self.current, self.hits.len()),
|
||||
self.hits.clone(),
|
||||
self.current,
|
||||
)
|
||||
.notes(Vec::new(), move |page, at, _, _| {
|
||||
@@ -51,12 +57,23 @@ impl Render for Reader {
|
||||
}
|
||||
|
||||
fn open(cx: &mut TestAppContext) -> (Entity<Reader>, Noted, &mut VisualTestContext) {
|
||||
open_with(400.0, None, cx)
|
||||
}
|
||||
|
||||
/// Pages `width` points wide, with a hit on the second, current from the first frame when `current` says.
|
||||
fn open_with(
|
||||
width: f32,
|
||||
current: Option<usize>,
|
||||
cx: &mut TestAppContext,
|
||||
) -> (Entity<Reader>, Noted, &mut VisualTestContext) {
|
||||
cx.update(Theme::init);
|
||||
let noted = Noted::default();
|
||||
let seen = noted.clone();
|
||||
let (reader, cx) = cx.add_window_view(move |window, cx| Reader {
|
||||
query: cx.new(|cx| TextInput::new(window, cx)),
|
||||
current: None,
|
||||
width,
|
||||
hits: vec![hit(1)],
|
||||
current,
|
||||
noted: seen,
|
||||
});
|
||||
settle(cx);
|
||||
@@ -85,8 +102,13 @@ fn wheel(down: f32, cx: &mut VisualTestContext) {
|
||||
settle(cx);
|
||||
}
|
||||
|
||||
/// Turns pinning on with the header's last button, then presses the pages; returns the note asked.
|
||||
/// Turns pinning on with the header's last button, then presses the pages at their middle; returns the note asked.
|
||||
fn pin(cx: &mut VisualTestContext, noted: &Noted) -> (usize, Point<f32>) {
|
||||
let at = on_pages(cx);
|
||||
pin_at(at, cx, noted)
|
||||
}
|
||||
|
||||
fn pin_at(at: Point<Pixels>, cx: &mut VisualTestContext, noted: &Noted) -> (usize, Point<f32>) {
|
||||
let toggle = cx.update(|window, cx| {
|
||||
let header = cx
|
||||
.theme()
|
||||
@@ -99,7 +121,6 @@ fn pin(cx: &mut VisualTestContext, noted: &Noted) -> (usize, Point<f32>) {
|
||||
});
|
||||
cx.simulate_click(toggle, Modifiers::none());
|
||||
settle(cx);
|
||||
let at = on_pages(cx);
|
||||
cx.simulate_click(at, Modifiers::none());
|
||||
settle(cx);
|
||||
noted
|
||||
@@ -143,3 +164,92 @@ fn a_current_hit_comes_to_one_place_from_any_scroll(cx: &mut TestAppContext) {
|
||||
assert_eq!(from_top.0, 1, "the hit's page comes into view");
|
||||
assert_eq!(from_top, from_below);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_page_wider_than_the_view_starts_at_its_left_edge(cx: &mut TestAppContext) {
|
||||
let (_, noted, cx) = open_with(3000.0, None, cx);
|
||||
let (page, at) = pin_at(point(px(60.0), px(300.0)), cx, ¬ed);
|
||||
assert_eq!(page, 0);
|
||||
assert!(
|
||||
at.x < 100.0,
|
||||
"the page's left edge is in reach, not at {}",
|
||||
at.x
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_new_hit_at_the_same_index_moves_the_view(cx: &mut TestAppContext) {
|
||||
let (reader, noted, cx) = open(cx);
|
||||
reader.update(cx, |reader, cx| {
|
||||
reader.current = Some(0);
|
||||
cx.notify();
|
||||
});
|
||||
settle(cx);
|
||||
reader.update(cx, |reader, cx| {
|
||||
reader.hits = vec![hit(2)];
|
||||
cx.notify();
|
||||
});
|
||||
settle(cx);
|
||||
assert_eq!(pin(cx, ¬ed).0, 2, "the view follows the new hit");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_hit_current_from_the_first_frame_comes_into_view(cx: &mut TestAppContext) {
|
||||
let (_, noted, first) = open_with(400.0, Some(0), cx);
|
||||
let at_once = pin(first, ¬ed);
|
||||
let later = revealed(0.0, cx);
|
||||
assert_eq!(at_once, later);
|
||||
}
|
||||
|
||||
/// A field outside a zen view, and how often Escape left zen.
|
||||
struct Zen {
|
||||
outside: Entity<TextInput>,
|
||||
on: bool,
|
||||
left: usize,
|
||||
}
|
||||
|
||||
impl Render for Zen {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let me = cx.entity();
|
||||
div().size_full().child(Input::new(&self.outside)).child(
|
||||
ZenMode::new("zen", self.on)
|
||||
.on_exit(move |_, cx| {
|
||||
me.update(cx, |zen, cx| {
|
||||
zen.on = false;
|
||||
zen.left += 1;
|
||||
cx.notify();
|
||||
})
|
||||
})
|
||||
.child(div().child("A quiet page")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn escape_leaves_zen_turned_on_from_outside_and_hands_focus_back(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
Theme::init(cx);
|
||||
crate::forms::bind_keys(cx);
|
||||
});
|
||||
let (zen, cx) = cx.add_window_view(|window, cx| Zen {
|
||||
outside: cx.new(|cx| TextInput::new(window, cx)),
|
||||
on: false,
|
||||
left: 0,
|
||||
});
|
||||
cx.update(|window, cx| {
|
||||
window.activate_window();
|
||||
let outside = zen.read(cx).outside.focus_handle(cx);
|
||||
window.focus(&outside);
|
||||
});
|
||||
settle(cx);
|
||||
zen.update(cx, |zen, cx| {
|
||||
zen.on = true;
|
||||
cx.notify();
|
||||
});
|
||||
settle(cx);
|
||||
cx.simulate_keystrokes("escape");
|
||||
settle(cx);
|
||||
assert_eq!(zen.read_with(cx, |zen, _| zen.left), 1);
|
||||
let back = cx.update(|window, cx| zen.read(cx).outside.focus_handle(cx).is_focused(window));
|
||||
assert!(back, "focus returns to where it was");
|
||||
}
|
||||
Reference in new issue
Block a user