Skip to content

Commit 4294c76

Browse files
Merge branch 'main' into improve-area-select2
2 parents b90daf5 + 8a0b685 commit 4294c76

18 files changed

Lines changed: 556 additions & 226 deletions

File tree

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ pub struct GeneralSettingsStore {
116116
pub enable_new_recording_flow: bool,
117117
#[serde(default)]
118118
pub post_deletion_behaviour: PostDeletionBehaviour,
119-
#[serde(default = "default_enable_new_uploader", skip_serializing_if = "no")]
120-
pub enable_new_uploader: bool,
121119
#[serde(default = "default_excluded_windows")]
122120
pub excluded_windows: Vec<WindowExclusion>,
123121
#[serde(default)]
@@ -133,10 +131,6 @@ fn default_enable_new_recording_flow() -> bool {
133131
cfg!(debug_assertions)
134132
}
135133

136-
fn default_enable_new_uploader() -> bool {
137-
true
138-
}
139-
140134
fn no(_: &bool) -> bool {
141135
false
142136
}
@@ -184,7 +178,6 @@ impl Default for GeneralSettingsStore {
184178
auto_zoom_on_clicks: false,
185179
enable_new_recording_flow: default_enable_new_recording_flow(),
186180
post_deletion_behaviour: PostDeletionBehaviour::DoNothing,
187-
enable_new_uploader: default_enable_new_uploader(),
188181
excluded_windows: default_excluded_windows(),
189182
delete_instant_recordings_after_upload: false,
190183
}

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

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,21 +2216,10 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
22162216
tokio::spawn({
22172217
let app = app.clone();
22182218
async move {
2219-
let is_new_uploader_enabled = GeneralSettingsStore::get(&app)
2220-
.map_err(|err| {
2221-
error!(
2222-
"Error checking status of new uploader flow from settings: {err}"
2223-
)
2224-
})
2225-
.ok()
2226-
.and_then(|v| v.map(|v| v.enable_new_uploader))
2227-
.unwrap_or(false);
2228-
if is_new_uploader_enabled {
2229-
resume_uploads(app)
2230-
.await
2231-
.map_err(|err| warn!("Error resuming uploads: {err}"))
2232-
.ok();
2233-
}
2219+
resume_uploads(app)
2220+
.await
2221+
.map_err(|err| warn!("Error resuming uploads: {err}"))
2222+
.ok();
22342223
}
22352224
});
22362225

@@ -2386,10 +2375,34 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
23862375
window_ids.ids.lock().unwrap().retain(|(_, _id)| *_id != id);
23872376

23882377
tokio::spawn(EditorInstances::remove(window.clone()));
2378+
2379+
#[cfg(target_os = "windows")]
2380+
if CapWindowId::Settings.get(&app).is_none() {
2381+
reopen_main_window(&app);
2382+
}
2383+
}
2384+
CapWindowId::Settings => {
2385+
for (label, window) in app.webview_windows() {
2386+
if let Ok(id) = CapWindowId::from_str(&label)
2387+
&& matches!(
2388+
id,
2389+
CapWindowId::TargetSelectOverlay { .. }
2390+
| CapWindowId::Main
2391+
| CapWindowId::Camera
2392+
)
2393+
{
2394+
let _ = window.show();
2395+
}
2396+
}
2397+
2398+
#[cfg(target_os = "windows")]
2399+
if !has_open_editor_window(&app) {
2400+
reopen_main_window(&app);
2401+
}
2402+
2403+
return;
23892404
}
2390-
CapWindowId::Settings
2391-
| CapWindowId::Upgrade
2392-
| CapWindowId::ModeSelect => {
2405+
CapWindowId::Upgrade | CapWindowId::ModeSelect => {
23932406
for (label, window) in app.webview_windows() {
23942407
if let Ok(id) = CapWindowId::from_str(&label)
23952408
&& matches!(
@@ -2508,6 +2521,30 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
25082521
});
25092522
}
25102523

2524+
#[cfg(target_os = "windows")]
2525+
fn has_open_editor_window(app: &AppHandle) -> bool {
2526+
app.webview_windows()
2527+
.keys()
2528+
.any(|label| matches!(CapWindowId::from_str(label), Ok(CapWindowId::Editor { .. })))
2529+
}
2530+
2531+
#[cfg(target_os = "windows")]
2532+
fn reopen_main_window(app: &AppHandle) {
2533+
if let Some(main) = CapWindowId::Main.get(app) {
2534+
let _ = main.show();
2535+
let _ = main.set_focus();
2536+
} else {
2537+
let handle = app.clone();
2538+
tokio::spawn(async move {
2539+
let _ = ShowCapWindow::Main {
2540+
init_target_mode: None,
2541+
}
2542+
.show(&handle)
2543+
.await;
2544+
});
2545+
}
2546+
}
2547+
25112548
async fn resume_uploads(app: AppHandle) -> Result<(), String> {
25122549
let recordings_dir = recordings_path(&app);
25132550
if !recordings_dir.exists() {

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
};
77

88
use base64::prelude::*;
9+
use cap_recording::screen_capture::ScreenCaptureTarget;
910

1011
use crate::windows::{CapWindowId, ShowCapWindow};
1112
use scap_targets::{
@@ -46,6 +47,7 @@ pub struct DisplayInformation {
4647
pub async fn open_target_select_overlays(
4748
app: AppHandle,
4849
state: tauri::State<'_, WindowFocusManager>,
50+
focused_target: Option<ScreenCaptureTarget>,
4951
) -> Result<(), String> {
5052
let displays = scap_targets::Display::list()
5153
.into_iter()
@@ -59,11 +61,18 @@ pub async fn open_target_select_overlays(
5961

6062
let handle = tokio::spawn({
6163
let app = app.clone();
64+
6265
async move {
6366
loop {
6467
{
65-
let display = scap_targets::Display::get_containing_cursor();
66-
let window = scap_targets::Window::get_topmost_at_cursor();
68+
let display = focused_target
69+
.as_ref()
70+
.map(|v| v.display())
71+
.unwrap_or_else(|| scap_targets::Display::get_containing_cursor());
72+
let window = focused_target
73+
.as_ref()
74+
.map(|v| v.window().and_then(|id| scap_targets::Window::from_id(&id)))
75+
.unwrap_or_else(|| scap_targets::Window::get_topmost_at_cursor());
6776

6877
let _ = TargetUnderCursor {
6978
display_id: display.map(|d| d.id()),
@@ -171,13 +180,30 @@ pub async fn focus_window(window_id: WindowId) -> Result<(), String> {
171180
#[cfg(target_os = "windows")]
172181
{
173182
use windows::Win32::UI::WindowsAndMessaging::{
174-
SW_RESTORE, SetForegroundWindow, ShowWindow,
183+
GetWindowPlacement, IsIconic, SW_RESTORE, SetForegroundWindow, SetWindowPlacement,
184+
ShowWindow, WINDOWPLACEMENT,
175185
};
176186

177187
let hwnd = window.raw_handle().inner();
178188

179189
unsafe {
180-
ShowWindow(hwnd, SW_RESTORE);
190+
// Only restore if the window is actually minimized
191+
if IsIconic(hwnd).as_bool() {
192+
// Get current window placement to preserve size/position
193+
let mut wp = WINDOWPLACEMENT::default();
194+
wp.length = std::mem::size_of::<WINDOWPLACEMENT>() as u32;
195+
196+
if GetWindowPlacement(hwnd, &mut wp).is_ok() {
197+
// Restore using the previous placement to avoid resizing
198+
wp.showCmd = SW_RESTORE.0 as u32;
199+
SetWindowPlacement(hwnd, &wp);
200+
} else {
201+
// Fallback to simple restore if placement fails
202+
ShowWindow(hwnd, SW_RESTORE);
203+
}
204+
}
205+
206+
// Always try to bring to foreground
181207
SetForegroundWindow(hwnd);
182208
}
183209
}

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

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
use crate::{
44
UploadProgress, VideoUploadInfo,
55
api::{self, PresignedS3PutRequest, PresignedS3PutRequestMethod, S3VideoMeta, UploadedPart},
6-
general_settings::GeneralSettingsStore,
76
posthog::{PostHogEvent, async_capture_event},
8-
upload_legacy,
97
web_api::{AuthedApiError, ManagerExt},
108
};
119
use async_stream::{stream, try_stream};
@@ -68,29 +66,6 @@ pub async fn upload_video(
6866
channel: Option<Channel<UploadProgress>>,
6967
) -> Result<UploadedItem, AuthedApiError> {
7068
println!("Uploading video {video_id}...");
71-
let is_new_uploader_enabled = GeneralSettingsStore::get(&app)
72-
.map_err(|err| error!("Error checking status of new uploader flow from settings: {err}"))
73-
.ok()
74-
.and_then(|v| v.map(|v| v.enable_new_uploader))
75-
.unwrap_or(false);
76-
info!("uploader_video: is new uploader enabled? {is_new_uploader_enabled}");
77-
if !is_new_uploader_enabled {
78-
return upload_legacy::upload_video(
79-
app,
80-
video_id,
81-
file_path,
82-
None,
83-
Some(screenshot_path),
84-
Some(meta),
85-
channel,
86-
)
87-
.await
88-
.map(|v| UploadedItem {
89-
link: v.link,
90-
id: v.id,
91-
});
92-
}
93-
9469
info!("Uploading video {video_id}...");
9570

9671
let start = Instant::now();
@@ -187,22 +162,6 @@ pub async fn upload_image(
187162
app: &AppHandle,
188163
file_path: PathBuf,
189164
) -> Result<UploadedItem, AuthedApiError> {
190-
let is_new_uploader_enabled = GeneralSettingsStore::get(app)
191-
.map_err(|err| error!("Error checking status of new uploader flow from settings: {err}"))
192-
.ok()
193-
.and_then(|v| v.map(|v| v.enable_new_uploader))
194-
.unwrap_or(false);
195-
info!("upload_image: is new uploader enabled? {is_new_uploader_enabled}");
196-
if !is_new_uploader_enabled {
197-
return upload_legacy::upload_image(app, file_path)
198-
.await
199-
.map(|v| UploadedItem {
200-
link: v.link,
201-
id: v.id,
202-
})
203-
.map_err(Into::into);
204-
}
205-
206165
let file_name = file_path
207166
.file_name()
208167
.and_then(|name| name.to_str())
@@ -395,26 +354,6 @@ impl InstantMultipartUpload {
395354
realtime_video_done: Option<Receiver<()>>,
396355
recording_dir: PathBuf,
397356
) -> Result<(), AuthedApiError> {
398-
let is_new_uploader_enabled = GeneralSettingsStore::get(&app)
399-
.map_err(|err| {
400-
error!("Error checking status of new uploader flow from settings: {err}")
401-
})
402-
.ok()
403-
.and_then(|v| v.map(|v| v.enable_new_uploader))
404-
.unwrap_or(false);
405-
info!("InstantMultipartUpload::run: is new uploader enabled? {is_new_uploader_enabled}");
406-
if !is_new_uploader_enabled {
407-
return upload_legacy::InstantMultipartUpload::run(
408-
app,
409-
pre_created_video.id.clone(),
410-
file_path,
411-
pre_created_video,
412-
realtime_video_done,
413-
)
414-
.await
415-
.map_err(Into::into);
416-
}
417-
418357
let video_id = pre_created_video.id.clone();
419358
debug!("Initiating multipart upload for {video_id}...");
420359

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ function TargetMenuPanel(props: TargetMenuPanelProps & SharedTargetMenuProps) {
195195
<div class="flex gap-3 justify-between items-center mt-3">
196196
<div
197197
onClick={() => props.onBack()}
198-
class="flex gap-1 items-center rounded-md px-1.5 text-xs
199-
text-gray-11 transition-opacity hover:opacity-70 hover:text-gray-12
198+
class="flex gap-1 items-center rounded-md px-1.5 text-xs
199+
text-gray-11 transition-opacity hover:opacity-70 hover:text-gray-12
200200
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-9 focus-visible:ring-offset-2 focus-visible:ring-offset-gray-1"
201201
>
202202
<IconLucideArrowLeft class="size-3 text-gray-11" />
@@ -383,6 +383,7 @@ function Page() {
383383
reconcile({ variant: "display", id: target.id }),
384384
);
385385
setOptions("targetMode", "display");
386+
commands.openTargetSelectOverlays(rawOptions.captureTarget);
386387
setDisplayMenuOpen(false);
387388
displayTriggerRef?.focus();
388389
};
@@ -393,6 +394,7 @@ function Page() {
393394
reconcile({ variant: "window", id: target.id }),
394395
);
395396
setOptions("targetMode", "window");
397+
commands.openTargetSelectOverlays(rawOptions.captureTarget);
396398
setWindowMenuOpen(false);
397399
windowTriggerRef?.focus();
398400

@@ -412,7 +414,10 @@ function Page() {
412414
createUpdateCheck();
413415

414416
onMount(async () => {
415-
setOptions({ targetMode: (window as any).__CAP__.initialTargetMode });
417+
const targetMode = (window as any).__CAP__.initialTargetMode;
418+
setOptions({ targetMode });
419+
if (rawOptions.targetMode) commands.openTargetSelectOverlays(null);
420+
else commands.closeTargetSelectOverlays();
416421

417422
const currentWindow = getCurrentWindow();
418423

@@ -444,11 +449,6 @@ function Page() {
444449
if (!monitor) return;
445450
});
446451

447-
createEffect(() => {
448-
if (rawOptions.targetMode) commands.openTargetSelectOverlays();
449-
else commands.closeTargetSelectOverlays();
450-
});
451-
452452
const cameras = useQuery(() => listVideoDevices);
453453
const mics = useQuery(() => listAudioDevices);
454454

@@ -649,6 +649,9 @@ function Page() {
649649
setOptions("targetMode", (v) =>
650650
v === "display" ? null : "display",
651651
);
652+
if (rawOptions.targetMode)
653+
commands.openTargetSelectOverlays(null);
654+
else commands.closeTargetSelectOverlays();
652655
}}
653656
name="Display"
654657
class="flex-1 rounded-none focus-visible:ring-0 focus-visible:ring-offset-0"
@@ -691,6 +694,9 @@ function Page() {
691694
setOptions("targetMode", (v) =>
692695
v === "window" ? null : "window",
693696
);
697+
if (rawOptions.targetMode)
698+
commands.openTargetSelectOverlays(null);
699+
else commands.closeTargetSelectOverlays();
694700
}}
695701
name="Window"
696702
class="flex-1 rounded-none focus-visible:ring-0 focus-visible:ring-offset-0"
@@ -724,6 +730,9 @@ function Page() {
724730
onClick={() => {
725731
if (isRecording()) return;
726732
setOptions("targetMode", (v) => (v === "area" ? null : "area"));
733+
if (rawOptions.targetMode)
734+
commands.openTargetSelectOverlays(null);
735+
else commands.closeTargetSelectOverlays();
727736
}}
728737
name="Area"
729738
/>

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

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
2626
enableNewRecordingFlow: false,
2727
autoZoomOnClicks: false,
2828
custom_cursor_capture2: true,
29-
enableNewUploader: false,
3029
},
3130
);
3231

@@ -97,19 +96,6 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
9796
);
9897
}}
9998
/>
100-
<ToggleSettingItem
101-
label="New uploader"
102-
description="Improved uploader for faster and more reliable uploads!"
103-
value={!!settings.enableNewUploader}
104-
onChange={(value) => {
105-
handleChange("enableNewUploader", value);
106-
// This is bad code, but I just want the UI to not jank and can't seem to find the issue.
107-
setTimeout(
108-
() => window.scrollTo({ top: 0, behavior: "instant" }),
109-
5,
110-
);
111-
}}
112-
/>
11399
</div>
114100
</div>
115101
</div>

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ const createDefaultGeneralSettings = (): GeneralSettingsStore => ({
7070
enableNewRecordingFlow: false,
7171
autoZoomOnClicks: false,
7272
custom_cursor_capture2: true,
73-
enableNewUploader: false,
7473
excludedWindows: [],
7574
});
7675

0 commit comments

Comments
 (0)