diff --git a/.gitignore b/.gitignore index 394a48ea..aa48780b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ playwright/.cache/ redb-kv.db # dotenv -.env \ No newline at end of file +.env + +# ide config +.idea/ \ No newline at end of file diff --git a/src/page/post_view/video_iter.rs b/src/page/post_view/video_iter.rs index 8637feb6..d7077e77 100644 --- a/src/page/post_view/video_iter.rs +++ b/src/page/post_view/video_iter.rs @@ -33,7 +33,7 @@ impl Default for FetchCursor { impl FetchCursor { pub fn advance(&mut self) { self.start += self.limit; - self.limit = 50; + self.limit = 25; } } diff --git a/src/page/post_view/video_loader.rs b/src/page/post_view/video_loader.rs index b881c1b4..5b6c8a9d 100644 --- a/src/page/post_view/video_loader.rs +++ b/src/page/post_view/video_loader.rs @@ -1,4 +1,11 @@ -use super::{overlay::VideoDetailsOverlay, PostViewCtx}; +use std::cmp::Ordering; + +use leptos::{html::Video, *}; +use leptos_use::use_event_listener; +use serde_json::json; +use wasm_bindgen::JsCast; + +use crate::utils::event_streaming::send_event; use crate::{ canister::{ individual_user_template::PostViewDetailsFromFrontend, @@ -12,12 +19,8 @@ use crate::{ }, utils::event_streaming::send_event_warehouse, }; -use leptos::{html::Video, *}; -use leptos_use::{use_event_listener, watch_debounced}; -use crate::utils::event_streaming::send_event; -use serde_json::json; -use wasm_bindgen::JsCast; +use super::{overlay::VideoDetailsOverlay, PostViewCtx}; #[component] pub fn BgView(idx: usize, children: Children) -> impl IntoView { @@ -120,74 +123,85 @@ pub fn VideoView(idx: usize, muted: RwSignal) -> impl IntoView { Some(()) }); - let watched_percentage = create_rw_signal(0_u8); - let watched_count = create_rw_signal(0_u8); + // Video views send to canister + // 1. When video is paused (as in scrolled away) -> partial video view + // 2. When video is 95% done -> full view + + let post = Signal::derive(move || video_queue.with(|q| q.get(idx).cloned())); + + let send_view_detail_action = + create_action(move |(percentage_watched, watch_count): &(u8, u8)| { + let percentage_watched = *percentage_watched; + let watch_count = *watch_count; + + async move { + let canisters = unauth_canisters(); + + let payload = match percentage_watched.cmp(&95) { + Ordering::Less => { + PostViewDetailsFromFrontend::WatchedPartially { percentage_watched } + } + _ => PostViewDetailsFromFrontend::WatchedMultipleTimes { + percentage_watched, + watch_count, + }, + }; + + let post_id = post.get_untracked().as_ref().map(|p| p.post_id).unwrap(); + let canister_id = post + .get_untracked() + .as_ref() + .map(|p| p.canister_id) + .unwrap(); + let send_view_res = canisters + .individual_user(canister_id) + .update_post_add_view_details(post_id, payload) + .await; + + if let Err(err) = send_view_res { + log::warn!("failed to send view details: {:?}", err); + } + Some(()) + } + }); + + let video_views_watch_multiple = create_rw_signal(false); - let video_previous_current_time = store_value(0.0); - let _ = use_event_listener(container_ref, ev::timeupdate, move |_event| { + let _ = use_event_listener(container_ref, ev::pause, move |_evt| { let Some(video) = container_ref() else { return; }; let duration = video.duration(); let current_time = video.current_time(); - - if current_time < video_previous_current_time() { - watched_count.update(|wc| *wc += 1); + if current_time < 0.5 { + return; } - watched_percentage.update(|watched_percentage| { - *watched_percentage = (100.0 * (current_time / duration)) as u8; - }); - video_previous_current_time.update_value(|v| *v = current_time); + let percentage_watched = ((current_time / duration) * 100.0) as u8; + send_view_detail_action.dispatch((percentage_watched, 0_u8)); }); - let post = Signal::derive(move || video_queue.with(|q| q.get(idx).cloned())); - - let send_view_detail_action = create_action(move |()| async move { - let canisters = unauth_canisters(); - let current_watched_percentage = watched_percentage.get_untracked(); - let current_watched_count = watched_count.get_untracked(); - let payload = match current_watched_count { - 0 => PostViewDetailsFromFrontend::WatchedPartially { - percentage_watched: current_watched_percentage, - }, - _ => PostViewDetailsFromFrontend::WatchedMultipleTimes { - percentage_watched: current_watched_percentage, - watch_count: current_watched_count, - }, + let _ = use_event_listener(container_ref, ev::timeupdate, move |_evt| { + let Some(video) = container_ref() else { + return; }; - watched_count.update(|wc| *wc = 0); - watched_percentage.update(|watched_percentage| *watched_percentage = 0); - let post_id = post.get_untracked().as_ref().map(|p| p.post_id).unwrap(); - let canister_id = post - .get_untracked() - .as_ref() - .map(|p| p.canister_id) - .unwrap(); - let send_view_res = canisters - .individual_user(canister_id) - .update_post_add_view_details(post_id, payload) - .await; - - if let Err(err) = send_view_res { - log::warn!("failed to send view details: {:?}", err); + + let duration = video.duration(); + let current_time = video.current_time(); + let percentage_watched = ((current_time / duration) * 100.0) as u8; + + if current_time < 0.95 * duration { + video_views_watch_multiple.set(false); } - }); - let send_view_details_guard = create_memo(move |_| { - current_idx() != idx && (watched_percentage() != 0 || watched_count() != 0) + if percentage_watched >= 95 && !video_views_watch_multiple.get() { + send_view_detail_action.dispatch((percentage_watched, 0_u8)); + + video_views_watch_multiple.set(true); + } }); - let _ = watch_debounced( - watched_percentage, - move |_, _, _| { - if send_view_details_guard() { - send_view_detail_action.dispatch(()); - } - }, - 2000.0, - ); #[cfg(all(feature = "hydrate", feature = "ga4"))] { let profile_and_canister_details: AuthProfileCanisterResource = expect_context(); @@ -264,8 +278,6 @@ pub fn VideoView(idx: usize, muted: RwSignal) -> impl IntoView { } if current_time >= 3.0 { - // Video is halfway done, take action here - send_event( "video_viewed", &json!({