Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions Backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ fn build_invoke_handler<R: tauri::Runtime>() -> impl Fn(tauri::ipc::Invoke<R>) -
tauri_commands::git_discard_paths,
tauri_commands::git_discard_patch,
tauri_commands::git_fetch,
tauri_commands::git_fetch_all,
tauri_commands::git_pull,
tauri_commands::git_push,
tauri_commands::git_undo_since_push,
Expand All @@ -161,12 +162,6 @@ fn build_invoke_handler<R: tauri::Runtime>() -> impl Fn(tauri::ipc::Invoke<R>) -
]
}

fn handle_window_event<R: tauri::Runtime>(win: &tauri::Window<R>, event: &tauri::WindowEvent) {
match event {
tauri::WindowEvent::Focused(true) => {
// Fire a custom event to the frontend
let _ = win.emit("app:focus", ());
}
_ => {}
}
fn handle_window_event<R: tauri::Runtime>(_win: &tauri::Window<R>, _event: &tauri::WindowEvent) {
// Frontend now handles focus via window/visibility events; no backend emit needed.
}
30 changes: 30 additions & 0 deletions Backend/src/tauri_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,36 @@ pub fn git_fetch<R: Runtime>(window: Window<R>, state: State<'_, AppState>) -> R
Ok(())
}

#[tauri::command]
pub fn git_fetch_all<R: Runtime>(window: Window<R>, state: State<'_, AppState>) -> Result<(), String> {
info!("git_fetch_all called");

let repo = state
.current_repo()
.ok_or_else(|| "No repository selected".to_string())?;
let vcs = repo.inner();

let app = window.app_handle().clone();
let on = Some(progress_bridge(app));

// Fetch all remotes with all refs
let remotes = vcs.list_remotes().map_err(|e| {
error!("Failed to list remotes: {e}");
e.to_string()
})?;

for (r, _url) in remotes.into_iter() {
info!("Fetching all refs from remote '{r}'");
// empty refspec means all
if let Err(e) = vcs.fetch(&r, "", on.clone()) {
error!("Fetch failed for remote '{r}': {e}");
return Err(e.to_string());
}
}

Ok(())
}

#[tauri::command]
pub fn git_pull<R: Runtime>(window: Window<R>, state: State<'_, AppState>) -> Result<(), String> {
info!("git_pull called");
Expand Down
6 changes: 6 additions & 0 deletions Frontend/src/modals/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ <h3 id="settings-title" style="margin:0">Settings</h3>
</label>
</div>

<div class="group">
<label class="checkbox"><input type="checkbox" id="set-fetch-on-focus" /> Fetch on app focus
<span class="help-tip" title="Automatically runs git fetch when the app regains focus.">?</span>
</label>
</div>




Expand Down
4 changes: 3 additions & 1 deletion Frontend/src/scripts/features/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export function wireSettings() {
const cur = await TAURI.invoke<GlobalSettings>('get_global_settings');

cur.general = { theme: 'system', language: 'system', default_backend: 'git', update_channel: 'stable', reopen_last_repos: true, checks_on_launch: true, telemetry: false, crash_reports: false };
cur.git = { backend: 'system', default_branch: 'main', prune_on_fetch: true, allow_hooks: 'ask', respect_core_autocrlf: true };
cur.git = { backend: 'system', default_branch: 'main', prune_on_fetch: true, fetch_on_focus: true, allow_hooks: 'ask', respect_core_autocrlf: true };
cur.diff = { tab_width: 4, ignore_whitespace: 'none', max_file_size_mb: 10, intraline: true, show_binary_placeholders: true, external_diff: {enabled:false,path:'',args:''}, external_merge: {enabled:false,path:'',args:''}, binary_exts: ['png','jpg','dds','uasset'] };
cur.lfs = { enabled: true, concurrency: 4, require_lock_before_edit: false, background_fetch_on_checkout: true };
cur.performance = { progressive_render: true, gpu_accel: true };
Expand Down Expand Up @@ -123,6 +123,7 @@ function collectSettingsFromForm(root: HTMLElement): GlobalSettings {
...o.git,
backend: get<HTMLSelectElement>('#set-git-backend')?.value as any,
prune_on_fetch: !!get<HTMLInputElement>('#set-prune-on-fetch')?.checked,
fetch_on_focus: !!get<HTMLInputElement>('#set-fetch-on-focus')?.checked,
allow_hooks: get<HTMLSelectElement>('#set-hook-policy')?.value,
respect_core_autocrlf: !!get<HTMLInputElement>('#set-respect-autocrlf')?.checked,
};
Expand Down Expand Up @@ -200,6 +201,7 @@ export async function loadSettingsIntoForm(root?: HTMLElement) {
elGb.value = backend === 'libgit2' ? 'libgit2' : 'system';
}
const elPr = get<HTMLInputElement>('#set-prune-on-fetch'); if (elPr) elPr.checked = !!cfg.git?.prune_on_fetch;
const elFoF = get<HTMLInputElement>('#set-fetch-on-focus'); if (elFoF) elFoF.checked = !!cfg.git?.fetch_on_focus;

const elHp = get<HTMLSelectElement>('#set-hook-policy'); if (elHp) elHp.value = toKebab(cfg.git?.allow_hooks);
const elRc = get<HTMLInputElement>('#set-respect-autocrlf'); if (elRc) elRc.checked = !!cfg.git?.respect_core_autocrlf;
Expand Down
66 changes: 32 additions & 34 deletions Frontend/src/scripts/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,34 +58,26 @@ function boot() {
bindLayoutActionState()
bindRepoHotkeys(commitBtn || null, openSheet);

// title actions
fetchBtn?.addEventListener('click', async () => {
// shared fetch-or-pull routine (used by button and focus)
async function fetchOnly() {
const statusEl = document.getElementById('status');
const setBusy = (msg: string) => {
if (statusEl) { statusEl.textContent = msg; statusEl.classList.add('busy'); }
};
const clearBusy = () => { if (statusEl) statusEl.classList.remove('busy'); };
try {
if (!TAURI.has) return;
const hasLocalChanges = Array.isArray(state.files) && state.files.length > 0;
const ahead = (state as any).ahead || 0;
const behind = (state as any).behind || 0;
const canFastForward = !hasLocalChanges && ahead === 0;

if (canFastForward) {
setBusy('Pulling…');
await TAURI.invoke('git_pull', {});
notify(behind > 0 ? 'Pulled (fast-forward)' : 'Already up to date');
} else {
setBusy('Fetching…');
await TAURI.invoke('git_fetch', {});
notify('Fetched');
}
setBusy('Fetching…');
await TAURI.invoke('git_fetch', {});
notify('Fetched');
await Promise.allSettled([hydrateStatus(), hydrateCommits()]);
} catch {
notify('Fetch/Pull failed');
notify('Fetch failed');
} finally { clearBusy(); }
});
}

// title actions
fetchBtn?.addEventListener('click', fetchOnly);
pushBtn?.addEventListener('click', async () => {
const statusEl = document.getElementById('status');
const setBusy = (msg: string) => {
Expand Down Expand Up @@ -210,24 +202,30 @@ function boot() {
showUpdateDialog(payload);
});

// app focus throttle + refresh
(function () {
let cooling = false;
const COOL_MS = 350;

async function refreshAll() {
const statusEl = document.getElementById('status');
if (statusEl) statusEl.textContent = 'Refreshing…';
await Promise.allSettled([hydrateBranches(), hydrateStatus(), hydrateCommits()]);
if (statusEl) statusEl.textContent = 'Ready';
// App focus: handle entirely in TS (no backend event)
async function onFocus() {
let doFetch = false;
if (TAURI.has) {
try {
const cfg = await TAURI.invoke<any>('get_global_settings');
doFetch = cfg?.git?.fetch_on_focus !== false; // default true when unset
} catch {}
}
if (doFetch) {
try {
await TAURI.invoke('git_fetch_all', {});
notify('Fetched all remotes');
} catch {
await fetchOnly();
}
}
await Promise.allSettled([hydrateBranches(), hydrateStatus(), hydrateCommits()]);
}

TAURI.listen?.('app:focus', () => {
if (cooling) return;
cooling = true;
refreshAll().finally(() => setTimeout(() => (cooling = false), COOL_MS));
});
})();
window.addEventListener('focus', () => { onFocus().catch(() => {}); });
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') onFocus().catch(() => {});
});

// open settings via event
TAURI.listen?.('ui:open-settings', () => openModal('settings-modal'));
Expand Down
1 change: 1 addition & 0 deletions Frontend/src/scripts/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface GlobalSettings {
backend?: 'system'|'libgit2'|string;
default_branch?: string;
prune_on_fetch?: boolean;
fetch_on_focus?: boolean;
allow_hooks?: string;
respect_core_autocrlf?: boolean;
};
Expand Down
Loading