web: more accurate reading progress bar
This commit is contained in:
parent
baba720749
commit
4b8923d852
@ -41,7 +41,9 @@ wasm-opt = ['-Os']
|
|||||||
version = "0.3.58"
|
version = "0.3.58"
|
||||||
features = [
|
features = [
|
||||||
"Clipboard",
|
"Clipboard",
|
||||||
|
"DomRect",
|
||||||
|
"Element",
|
||||||
"MediaQueryList",
|
"MediaQueryList",
|
||||||
"Navigator",
|
"Navigator",
|
||||||
"Window"
|
"Window",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use graphql_client::GraphQLQuery;
|
|||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use web_sys::HtmlElement;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api,
|
api,
|
||||||
@ -39,9 +40,7 @@ pub fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
|||||||
// 'notmuch new' on the server periodically?
|
// 'notmuch new' on the server periodically?
|
||||||
orders.stream(streams::interval(30_000, || Msg::RefreshStart));
|
orders.stream(streams::interval(30_000, || Msg::RefreshStart));
|
||||||
orders.subscribe(on_url_changed);
|
orders.subscribe(on_url_changed);
|
||||||
orders.stream(streams::window_event(Ev::Scroll, |_| {
|
orders.stream(streams::window_event(Ev::Scroll, |_| Msg::WindowScrolled));
|
||||||
compute_scroll_ratio()
|
|
||||||
}));
|
|
||||||
|
|
||||||
build_info::build_info!(fn bi);
|
build_info::build_info!(fn bi);
|
||||||
Model {
|
Model {
|
||||||
@ -50,6 +49,7 @@ pub fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
|||||||
refreshing_state: RefreshingState::None,
|
refreshing_state: RefreshingState::None,
|
||||||
tags: None,
|
tags: None,
|
||||||
read_completion_ratio: 0.,
|
read_completion_ratio: 0.,
|
||||||
|
content_el: ElRef::<HtmlElement>::default(),
|
||||||
versions: Version {
|
versions: Version {
|
||||||
client: version,
|
client: version,
|
||||||
server: None,
|
server: None,
|
||||||
@ -521,6 +521,27 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
.expect("failed to copy to clipboard");
|
.expect("failed to copy to clipboard");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Msg::WindowScrolled => {
|
||||||
|
if let Some(el) = model.content_el.get() {
|
||||||
|
let ih = window()
|
||||||
|
.inner_height()
|
||||||
|
.expect("window height")
|
||||||
|
.unchecked_into::<js_sys::Number>()
|
||||||
|
.value_of();
|
||||||
|
|
||||||
|
let r = el.get_bounding_client_rect();
|
||||||
|
info!(
|
||||||
|
"window scrolled {}x{}@{},{}",
|
||||||
|
r.width(),
|
||||||
|
r.height(),
|
||||||
|
r.x(),
|
||||||
|
r.y(),
|
||||||
|
);
|
||||||
|
let end = r.height() - ih;
|
||||||
|
let y = -r.y();
|
||||||
|
orders.send_msg(Msg::SetProgress((y / end).max(0.)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Msg::SetProgress(ratio) => {
|
Msg::SetProgress(ratio) => {
|
||||||
model.read_completion_ratio = ratio;
|
model.read_completion_ratio = ratio;
|
||||||
}
|
}
|
||||||
@ -543,6 +564,7 @@ pub struct Model {
|
|||||||
pub refreshing_state: RefreshingState,
|
pub refreshing_state: RefreshingState,
|
||||||
pub tags: Option<Vec<Tag>>,
|
pub tags: Option<Vec<Tag>>,
|
||||||
pub read_completion_ratio: f64,
|
pub read_completion_ratio: f64,
|
||||||
|
pub content_el: ElRef<HtmlElement>,
|
||||||
pub versions: Version,
|
pub versions: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,6 +669,7 @@ pub enum Msg {
|
|||||||
|
|
||||||
CopyToClipboard(String),
|
CopyToClipboard(String),
|
||||||
|
|
||||||
|
WindowScrolled,
|
||||||
SetProgress(f64),
|
SetProgress(f64),
|
||||||
UpdateServerVersion(String),
|
UpdateServerVersion(String),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,11 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
|
|||||||
Context::ThreadResult {
|
Context::ThreadResult {
|
||||||
thread: ShowThreadQueryThread::EmailThread(thread),
|
thread: ShowThreadQueryThread::EmailThread(thread),
|
||||||
open_messages,
|
open_messages,
|
||||||
} => view::thread(thread, open_messages, show_icon_text),
|
} => view::thread(thread, open_messages, show_icon_text, &model.content_el),
|
||||||
Context::ThreadResult {
|
Context::ThreadResult {
|
||||||
thread: ShowThreadQueryThread::NewsPost(post),
|
thread: ShowThreadQueryThread::NewsPost(post),
|
||||||
..
|
..
|
||||||
} => view::news_post(post, show_icon_text),
|
} => view::news_post(post, show_icon_text, &model.content_el),
|
||||||
Context::SearchResult {
|
Context::SearchResult {
|
||||||
query,
|
query,
|
||||||
results,
|
results,
|
||||||
|
|||||||
@ -19,11 +19,11 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
|
|||||||
Context::ThreadResult {
|
Context::ThreadResult {
|
||||||
thread: ShowThreadQueryThread::EmailThread(thread),
|
thread: ShowThreadQueryThread::EmailThread(thread),
|
||||||
open_messages,
|
open_messages,
|
||||||
} => view::thread(thread, open_messages, show_icon_text),
|
} => view::thread(thread, open_messages, show_icon_text, &model.content_el),
|
||||||
Context::ThreadResult {
|
Context::ThreadResult {
|
||||||
thread: ShowThreadQueryThread::NewsPost(post),
|
thread: ShowThreadQueryThread::NewsPost(post),
|
||||||
..
|
..
|
||||||
} => view::news_post(post, show_icon_text),
|
} => view::news_post(post, show_icon_text, &model.content_el),
|
||||||
Context::SearchResult {
|
Context::SearchResult {
|
||||||
query,
|
query,
|
||||||
results,
|
results,
|
||||||
|
|||||||
@ -6,9 +6,10 @@ use std::{
|
|||||||
use chrono::{DateTime, Datelike, Duration, Local, Utc};
|
use chrono::{DateTime, Datelike, Duration, Local, Utc};
|
||||||
use human_format::{Formatter, Scales};
|
use human_format::{Formatter, Scales};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::{error, info};
|
use log::{debug, error, info};
|
||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
use seed_hooks::{state_access::CloneState, topo, use_state};
|
use seed_hooks::{state_access::CloneState, topo, use_state};
|
||||||
|
use web_sys::HtmlElement;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api::urls,
|
api::urls,
|
||||||
@ -795,6 +796,7 @@ fn thread(
|
|||||||
thread: &ShowThreadQueryThreadOnEmailThread,
|
thread: &ShowThreadQueryThreadOnEmailThread,
|
||||||
open_messages: &HashSet<String>,
|
open_messages: &HashSet<String>,
|
||||||
show_icon_text: bool,
|
show_icon_text: bool,
|
||||||
|
content_el: &ElRef<HtmlElement>,
|
||||||
) -> Node<Msg> {
|
) -> Node<Msg> {
|
||||||
// TODO(wathiede): show per-message subject if it changes significantly from top-level subject
|
// TODO(wathiede): show per-message subject if it changes significantly from top-level subject
|
||||||
let subject = if thread.subject.is_empty() {
|
let subject = if thread.subject.is_empty() {
|
||||||
@ -867,8 +869,7 @@ fn thread(
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
messages,
|
div![el_ref(content_el), messages] /* TODO(wathiede): plumb in orignal id
|
||||||
/* TODO(wathiede): plumb in orignal id
|
|
||||||
a![
|
a![
|
||||||
attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)},
|
attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)},
|
||||||
"Original"
|
"Original"
|
||||||
@ -1074,7 +1075,11 @@ pub fn tags(model: &Model) -> Node<Msg> {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
fn news_post(post: &ShowThreadQueryThreadOnNewsPost, show_icon_text: bool) -> Node<Msg> {
|
fn news_post(
|
||||||
|
post: &ShowThreadQueryThreadOnNewsPost,
|
||||||
|
show_icon_text: bool,
|
||||||
|
content_el: &ElRef<HtmlElement>,
|
||||||
|
) -> Node<Msg> {
|
||||||
// TODO(wathiede): show per-message subject if it changes significantly from top-level subject
|
// TODO(wathiede): show per-message subject if it changes significantly from top-level subject
|
||||||
let subject = &post.title;
|
let subject = &post.title;
|
||||||
set_title(subject);
|
set_title(subject);
|
||||||
@ -1114,6 +1119,7 @@ fn news_post(post: &ShowThreadQueryThreadOnNewsPost, show_icon_text: bool) -> No
|
|||||||
div![C!["header"], render_news_post_header(&post)],
|
div![C!["header"], render_news_post_header(&post)],
|
||||||
div![
|
div![
|
||||||
C!["body", "news-post", format!("site-{}", post.slug)],
|
C!["body", "news-post", format!("site-{}", post.slug)],
|
||||||
|
el_ref(content_el),
|
||||||
raw![&post.body]
|
raw![&post.body]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@ -1190,7 +1196,7 @@ fn reading_progress(ratio: f64) -> Node<Msg> {
|
|||||||
"progress",
|
"progress",
|
||||||
"is-success",
|
"is-success",
|
||||||
"is-small",
|
"is-small",
|
||||||
IF!(percent<5. => "is-invisible")
|
IF!(percent<1. => "is-invisible")
|
||||||
],
|
],
|
||||||
attrs! {
|
attrs! {
|
||||||
At::Value=>percent,
|
At::Value=>percent,
|
||||||
@ -1200,7 +1206,7 @@ fn reading_progress(ratio: f64) -> Node<Msg> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
pub fn versions(versions: &crate::state::Version) -> Node<Msg> {
|
pub fn versions(versions: &crate::state::Version) -> Node<Msg> {
|
||||||
info!("versions {versions:?}");
|
debug!("versions {versions:?}");
|
||||||
aside![
|
aside![
|
||||||
C!["tags-menu", "menu"],
|
C!["tags-menu", "menu"],
|
||||||
p![C!["menu-label"], "Versions"],
|
p![C!["menu-label"], "Versions"],
|
||||||
|
|||||||
@ -14,11 +14,11 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
|
|||||||
Context::ThreadResult {
|
Context::ThreadResult {
|
||||||
thread: ShowThreadQueryThread::EmailThread(thread),
|
thread: ShowThreadQueryThread::EmailThread(thread),
|
||||||
open_messages,
|
open_messages,
|
||||||
} => view::thread(thread, open_messages, show_icon_text),
|
} => view::thread(thread, open_messages, show_icon_text, &model.content_el),
|
||||||
Context::ThreadResult {
|
Context::ThreadResult {
|
||||||
thread: ShowThreadQueryThread::NewsPost(post),
|
thread: ShowThreadQueryThread::NewsPost(post),
|
||||||
..
|
..
|
||||||
} => view::news_post(post, show_icon_text),
|
} => view::news_post(post, show_icon_text, &model.content_el),
|
||||||
Context::SearchResult {
|
Context::SearchResult {
|
||||||
query,
|
query,
|
||||||
results,
|
results,
|
||||||
|
|||||||
@ -345,7 +345,12 @@ display: none;
|
|||||||
}
|
}
|
||||||
|
|
||||||
progress.read-progress {
|
progress.read-progress {
|
||||||
|
border-radius: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress.read-progress.is-small {
|
||||||
|
height: .25rem;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user