mirror of
https://github.com/stablyai/orca.git
synced 2026-09-28 00:02:41 +00:00
fix: own remaining ui interaction timers (#3388)
This commit is contained in:
@@ -94,6 +94,8 @@ export function UpdateCard() {
|
||||
const reassuranceSeen = useAppStore((s) => s.updateReassuranceSeen)
|
||||
const markReassuranceSeen = useAppStore((s) => s.markUpdateReassuranceSeen)
|
||||
const hasStartedDownload = useRef(false)
|
||||
const dismissAnimationTimerRef = useRef<number | null>(null)
|
||||
const collapseAnimationTimerRef = useRef<number | null>(null)
|
||||
const [mediaFailed, setMediaFailed] = useState(false)
|
||||
const [mediaLoaded, setMediaLoaded] = useState(false)
|
||||
const [installError, setInstallError] = useState<string | null>(null)
|
||||
@@ -204,6 +206,17 @@ export function UpdateCard() {
|
||||
return () => mq.removeEventListener('change', handler)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (dismissAnimationTimerRef.current !== null) {
|
||||
window.clearTimeout(dismissAnimationTimerRef.current)
|
||||
}
|
||||
if (collapseAnimationTimerRef.current !== null) {
|
||||
window.clearTimeout(collapseAnimationTimerRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
// ── Visibility gates ──────────────────────────────────────────────
|
||||
|
||||
const isUserInitiated = 'userInitiated' in status && status.userInitiated
|
||||
@@ -358,7 +371,13 @@ export function UpdateCard() {
|
||||
return
|
||||
}
|
||||
setExiting(true)
|
||||
setTimeout(handleClose, 150)
|
||||
if (dismissAnimationTimerRef.current !== null) {
|
||||
window.clearTimeout(dismissAnimationTimerRef.current)
|
||||
}
|
||||
dismissAnimationTimerRef.current = window.setTimeout(() => {
|
||||
dismissAnimationTimerRef.current = null
|
||||
handleClose()
|
||||
}, 150)
|
||||
}
|
||||
|
||||
// Why: long-running phases (downloading, downloaded, error) minimize to the
|
||||
@@ -370,7 +389,11 @@ export function UpdateCard() {
|
||||
return
|
||||
}
|
||||
setExiting(true)
|
||||
setTimeout(() => {
|
||||
if (collapseAnimationTimerRef.current !== null) {
|
||||
window.clearTimeout(collapseAnimationTimerRef.current)
|
||||
}
|
||||
collapseAnimationTimerRef.current = window.setTimeout(() => {
|
||||
collapseAnimationTimerRef.current = null
|
||||
setCollapsed(true)
|
||||
setExiting(false)
|
||||
}, 150)
|
||||
|
||||
@@ -68,6 +68,19 @@ export default function BrowserAddressBar({
|
||||
const browserKagiSessionLink = useAppStore((s) => s.browserKagiSessionLink)
|
||||
const closingRef = useRef(false)
|
||||
const openedAtRef = useRef(0)
|
||||
const blurCloseTimerRef = useRef<number | null>(null)
|
||||
const closingResetTimerRef = useRef<number | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (blurCloseTimerRef.current !== null) {
|
||||
window.clearTimeout(blurCloseTimerRef.current)
|
||||
}
|
||||
if (closingResetTimerRef.current !== null) {
|
||||
window.clearTimeout(closingResetTimerRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const searchEngine: SearchEngine =
|
||||
(browserDefaultSearchEngine as SearchEngine | null) ?? DEFAULT_SEARCH_ENGINE
|
||||
@@ -147,6 +160,10 @@ export default function BrowserAddressBar({
|
||||
if (closingRef.current) {
|
||||
return
|
||||
}
|
||||
if (blurCloseTimerRef.current !== null) {
|
||||
window.clearTimeout(blurCloseTimerRef.current)
|
||||
blurCloseTimerRef.current = null
|
||||
}
|
||||
inputRef.current?.select()
|
||||
openedAtRef.current = Date.now()
|
||||
setOpen(true)
|
||||
@@ -164,7 +181,11 @@ export default function BrowserAddressBar({
|
||||
// — producing the "flash then disappear" on first click.
|
||||
const elapsed = Date.now() - openedAtRef.current
|
||||
const grace = elapsed < 400
|
||||
setTimeout(() => {
|
||||
if (blurCloseTimerRef.current !== null) {
|
||||
window.clearTimeout(blurCloseTimerRef.current)
|
||||
}
|
||||
blurCloseTimerRef.current = window.setTimeout(() => {
|
||||
blurCloseTimerRef.current = null
|
||||
if (grace && inputRef.current && document.activeElement === inputRef.current) {
|
||||
return
|
||||
}
|
||||
@@ -178,7 +199,11 @@ export default function BrowserAddressBar({
|
||||
setOpen(false)
|
||||
setSelectedValueOverride(null)
|
||||
onNavigate(url)
|
||||
setTimeout(() => {
|
||||
if (closingResetTimerRef.current !== null) {
|
||||
window.clearTimeout(closingResetTimerRef.current)
|
||||
}
|
||||
closingResetTimerRef.current = window.setTimeout(() => {
|
||||
closingResetTimerRef.current = null
|
||||
closingRef.current = false
|
||||
}, 100)
|
||||
},
|
||||
|
||||
@@ -113,6 +113,17 @@ export function RuntimePairingUrlGenerator({
|
||||
const networkInterfaceLoadIdRef = useRef(0)
|
||||
const accessGrantLoadIdRef = useRef(0)
|
||||
|
||||
useEffect(() => {
|
||||
if (copiedTarget === null) {
|
||||
return
|
||||
}
|
||||
const target = copiedTarget
|
||||
const timeout = window.setTimeout(() => {
|
||||
setCopiedTarget((current) => (current === target ? null : current))
|
||||
}, 1400)
|
||||
return () => window.clearTimeout(timeout)
|
||||
}, [copiedTarget])
|
||||
|
||||
const loadRuntimeAccessGrants = useCallback(
|
||||
async (options: { showToastOnError?: boolean } = {}): Promise<void> => {
|
||||
const loadId = accessGrantLoadIdRef.current + 1
|
||||
@@ -240,9 +251,6 @@ export function RuntimePairingUrlGenerator({
|
||||
await window.api.ui.writeClipboardText(value)
|
||||
setCopiedTarget(target)
|
||||
toast.success(target === 'web' ? 'Copied web client URL.' : 'Copied pairing URL.')
|
||||
window.setTimeout(() => {
|
||||
setCopiedTarget((current) => (current === target ? null : current))
|
||||
}, 1400)
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : 'Failed to copy URL.')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user