Skip to content

Commit bb67f03

Browse files
committed
feat(desktop): add timeline slider to crop modal with video preview
Add a timeline slider to the crop modal that allows users to scrub through video frames when selecting crop regions. The implementation includes: - Timeline slider below crop preview for frame-accurate navigation - Video element with screenshot fallback using crossfade transition - Preload strategy: metadata on editor mount, full video on Crop button hover - Loading indicator whilst video loads - Multi-segment timeline support with correct segment switching The video preview replaces the static screenshot when loaded, providing real-time visual feedback during crop adjustments. Technical details: - Video positioned absolute with object-contain to prevent layout shift - Screenshot remains relative to maintain container dimensions - localTime calculation fixed to correctly convert timescale units --- Additional improvements since a1d2ac0: - fix(general_settings): remove unconditional reset of enable_new_recording_flow The flag was being reset to false on every app start, making the setting unusable. Users can now toggle between old and new recording flow in settings. - chore: remove debug telemetry fetch calls from App.tsx, (window-chrome).tsx, and setup.tsx. Deleted all #region agent log blocks and hardcoded local ingest endpoint calls. - chore: remove debug console.log statements from context.ts and Suspense fallbacks - fix(ui-solid): correct IconLucideLoader2 import path to use kebab-case (loader-2.jsx instead of loader2.jsx) - fix(crop-modal): correct localTime calculation in currentSegment memo Changed from `seg.start + (time - elapsed) * seg.timescale` to `seg.start / seg.timescale + (time - elapsed)` for proper time conversion
1 parent a1d2ac0 commit bb67f03

File tree

7 files changed

+6
-207
lines changed

7 files changed

+6
-207
lines changed

apps/desktop/src-tauri/src/general_settings.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,6 @@ pub fn init(app: &AppHandle) {
263263
store.recording_picker_preference_set = true;
264264
}
265265

266-
if store.enable_new_recording_flow {
267-
store.enable_new_recording_flow = false;
268-
}
269-
270266
if let Err(e) = store.save(app) {
271267
error!("Failed to save general settings: {}", e);
272268
}

apps/desktop/src/App.tsx

Lines changed: 1 addition & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,6 @@ const queryClient = new QueryClient({
8989
});
9090

9191
export default function App() {
92-
// #region agent log
93-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
94-
method: "POST",
95-
headers: { "Content-Type": "application/json" },
96-
body: JSON.stringify({
97-
location: "App.tsx:App",
98-
message: "App component rendering",
99-
data: { pathname: location.pathname },
100-
timestamp: Date.now(),
101-
sessionId: "debug-session",
102-
hypothesisId: "C",
103-
}),
104-
}).catch(() => {});
105-
// #endregion
10692
return (
10793
<QueryClientProvider client={queryClient}>
10894
<Suspense>
@@ -113,38 +99,10 @@ export default function App() {
11399
}
114100

115101
function Inner() {
116-
// #region agent log
117-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
118-
method: "POST",
119-
headers: { "Content-Type": "application/json" },
120-
body: JSON.stringify({
121-
location: "App.tsx:Inner",
122-
message: "Inner component rendering",
123-
data: { pathname: location.pathname },
124-
timestamp: Date.now(),
125-
sessionId: "debug-session",
126-
hypothesisId: "C",
127-
}),
128-
}).catch(() => {});
129-
// #endregion
130102
const currentWindow = getCurrentWebviewWindow();
131103
createThemeListener(currentWindow);
132104

133105
onMount(() => {
134-
// #region agent log
135-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
136-
method: "POST",
137-
headers: { "Content-Type": "application/json" },
138-
body: JSON.stringify({
139-
location: "App.tsx:Inner:onMount",
140-
message: "Inner onMount",
141-
data: { pathname: location.pathname },
142-
timestamp: Date.now(),
143-
sessionId: "debug-session",
144-
hypothesisId: "C",
145-
}),
146-
}).catch(() => {});
147-
// #endregion
148106
initAnonymousUser();
149107
});
150108

@@ -174,47 +132,14 @@ function Inner() {
174132
const matches = useCurrentMatches();
175133

176134
onMount(() => {
177-
// #region agent log
178-
fetch(
179-
"http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23",
180-
{
181-
method: "POST",
182-
headers: { "Content-Type": "application/json" },
183-
body: JSON.stringify({
184-
location: "App.tsx:Router:root:onMount",
185-
message: "Router root onMount",
186-
data: {
187-
pathname: location.pathname,
188-
matchCount: matches().length,
189-
autoShowFlags: matches().map(
190-
(m) => m.route.info?.AUTO_SHOW_WINDOW,
191-
),
192-
},
193-
timestamp: Date.now(),
194-
sessionId: "debug-session",
195-
hypothesisId: "C,D",
196-
}),
197-
},
198-
).catch(() => {});
199-
// #endregion
200135
for (const match of matches()) {
201136
if (match.route.info?.AUTO_SHOW_WINDOW === false) return;
202137
}
203138

204139
if (location.pathname !== "/camera") currentWindow.show();
205140
});
206141

207-
return (
208-
<Suspense
209-
fallback={
210-
(() => {
211-
console.log("Root suspense fallback showing");
212-
}) as any
213-
}
214-
>
215-
{props.children}
216-
</Suspense>
217-
);
142+
return <Suspense>{props.children}</Suspense>;
218143
}}
219144
>
220145
<Route path="/" component={WindowChromeLayout}>

apps/desktop/src/routes/(window-chrome).tsx

Lines changed: 2 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,7 @@ import {
1616
export default function (props: RouteSectionProps) {
1717
let unlistenResize: UnlistenFn | undefined;
1818

19-
// #region agent log
20-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
21-
method: "POST",
22-
headers: { "Content-Type": "application/json" },
23-
body: JSON.stringify({
24-
location: "(window-chrome).tsx:render",
25-
message: "WindowChrome component rendering",
26-
data: { pathname: location.pathname },
27-
timestamp: Date.now(),
28-
sessionId: "debug-session",
29-
hypothesisId: "C",
30-
}),
31-
}).catch(() => {});
32-
// #endregion
33-
3419
onMount(async () => {
35-
// #region agent log
36-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
37-
method: "POST",
38-
headers: { "Content-Type": "application/json" },
39-
body: JSON.stringify({
40-
location: "(window-chrome).tsx:onMount",
41-
message: "WindowChrome onMount",
42-
data: { pathname: location.pathname },
43-
timestamp: Date.now(),
44-
sessionId: "debug-session",
45-
hypothesisId: "C",
46-
}),
47-
}).catch(() => {});
48-
// #endregion
49-
console.log("window chrome mounted");
5020
unlistenResize = await initializeTitlebar();
5121
if (location.pathname === "/") getCurrentWindow().show();
5222
});
@@ -68,23 +38,10 @@ export default function (props: RouteSectionProps) {
6838
enterClass="opacity-0"
6939
exitToClass="opacity-0"
7040
> */}
71-
<Suspense
72-
fallback={
73-
(() => {
74-
console.log("Outer window chrome suspense fallback");
75-
return <AbsoluteInsetLoader />;
76-
}) as any
77-
}
78-
>
41+
<Suspense fallback={<AbsoluteInsetLoader />}>
7942
<Inner>
8043
{/* prevents flicker idk */}
81-
<Suspense
82-
fallback={
83-
(() => {
84-
console.log("Inner window chrome suspense fallback");
85-
}) as any
86-
}
87-
>
44+
<Suspense>
8845
{props.children}
8946
</Suspense>
9047
</Inner>
@@ -115,35 +72,7 @@ function Header() {
11572
}
11673

11774
function Inner(props: ParentProps) {
118-
// #region agent log
119-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
120-
method: "POST",
121-
headers: { "Content-Type": "application/json" },
122-
body: JSON.stringify({
123-
location: "(window-chrome).tsx:Inner:render",
124-
message: "Inner component rendering",
125-
data: { pathname: location.pathname },
126-
timestamp: Date.now(),
127-
sessionId: "debug-session",
128-
hypothesisId: "C",
129-
}),
130-
}).catch(() => {});
131-
// #endregion
13275
onMount(() => {
133-
// #region agent log
134-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
135-
method: "POST",
136-
headers: { "Content-Type": "application/json" },
137-
body: JSON.stringify({
138-
location: "(window-chrome).tsx:Inner:onMount",
139-
message: "Inner onMount, about to show window",
140-
data: { pathname: location.pathname },
141-
timestamp: Date.now(),
142-
sessionId: "debug-session",
143-
hypothesisId: "B,C",
144-
}),
145-
}).catch(() => {});
146-
// #endregion
14776
if (location.pathname !== "/") getCurrentWindow().show();
14877
});
14978

apps/desktop/src/routes/(window-chrome)/setup.tsx

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -94,61 +94,12 @@ export default function () {
9494
);
9595

9696
const handleContinue = () => {
97-
// #region agent log
98-
fetch("http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23", {
99-
method: "POST",
100-
headers: { "Content-Type": "application/json" },
101-
body: JSON.stringify({
102-
location: "setup.tsx:handleContinue",
103-
message: "handleContinue called",
104-
data: {},
105-
timestamp: Date.now(),
106-
sessionId: "debug-session",
107-
hypothesisId: "A",
108-
}),
109-
}).catch(() => {});
110-
// #endregion
11197
commands
11298
.showWindow({ Main: { init_target_mode: null } })
11399
.then(() => {
114-
// #region agent log
115-
fetch(
116-
"http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23",
117-
{
118-
method: "POST",
119-
headers: { "Content-Type": "application/json" },
120-
body: JSON.stringify({
121-
location: "setup.tsx:handleContinue:then",
122-
message: "showWindow resolved, closing setup",
123-
data: {},
124-
timestamp: Date.now(),
125-
sessionId: "debug-session",
126-
hypothesisId: "A,B",
127-
}),
128-
},
129-
).catch(() => {});
130-
// #endregion
131100
getCurrentWindow().close();
132101
})
133-
.catch((err) => {
134-
// #region agent log
135-
fetch(
136-
"http://127.0.0.1:7243/ingest/1cff95e2-fcb2-4b1f-a666-2aa2ac4f0e23",
137-
{
138-
method: "POST",
139-
headers: { "Content-Type": "application/json" },
140-
body: JSON.stringify({
141-
location: "setup.tsx:handleContinue:catch",
142-
message: "showWindow failed",
143-
data: { error: String(err) },
144-
timestamp: Date.now(),
145-
sessionId: "debug-session",
146-
hypothesisId: "A",
147-
}),
148-
},
149-
).catch(() => {});
150-
// #endregion
151-
});
102+
.catch(() => {});
152103
};
153104

154105
return (

apps/desktop/src/routes/editor/Editor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ function Dialogs() {
448448
if (time < elapsed + segDuration) {
449449
return {
450450
index: seg.recordingSegment ?? 0,
451-
localTime: seg.start + (time - elapsed) * seg.timescale,
451+
localTime: seg.start / seg.timescale + (time - elapsed),
452452
};
453453
}
454454
elapsed += segDuration;

apps/desktop/src/routes/editor/context.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,9 +749,7 @@ export const [EditorInstanceContextProvider, useEditorInstanceContext] =
749749
createSignal<CanvasControls | null>(null);
750750

751751
const [editorInstance] = createResource(async () => {
752-
console.log("[Editor] Creating editor instance...");
753752
const instance = await commands.createEditorInstance();
754-
console.log("[Editor] Editor instance created, setting up WebSocket");
755753

756754
preloadCropVideoMetadata(
757755
`${instance.path}/content/segments/segment-0/display.mp4`,

packages/ui-solid/src/auto-imports.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ declare global {
8282
const IconLucideHardDrive: typeof import('~icons/lucide/hard-drive.jsx')['default']
8383
const IconLucideImage: typeof import('~icons/lucide/image.jsx')['default']
8484
const IconLucideLayout: typeof import('~icons/lucide/layout.jsx')['default']
85-
const IconLucideLoader2: typeof import('~icons/lucide/loader2.jsx')['default']
85+
const IconLucideLoader2: typeof import('~icons/lucide/loader-2.jsx')['default']
8686
const IconLucideLoaderCircle: typeof import('~icons/lucide/loader-circle.jsx')['default']
8787
const IconLucideMaximize: typeof import('~icons/lucide/maximize.jsx')['default']
8888
const IconLucideMessageSquarePlus: typeof import('~icons/lucide/message-square-plus.jsx')['default']

0 commit comments

Comments
 (0)