markupr 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/review-feedback.md +47 -0
- package/.eslintrc.json +35 -0
- package/.github/CODEOWNERS +16 -0
- package/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +56 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +54 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +89 -0
- package/.github/dependabot.yml +70 -0
- package/.github/workflows/ci.yml +184 -0
- package/.github/workflows/deploy-landing.yml +134 -0
- package/.github/workflows/nightly.yml +288 -0
- package/.github/workflows/release.yml +318 -0
- package/CHANGELOG.md +127 -0
- package/CLAUDE.md +137 -0
- package/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +390 -0
- package/LICENSE +21 -0
- package/PRODUCT_VISION.md +277 -0
- package/README.md +517 -0
- package/SECURITY.md +51 -0
- package/SIGNING_INSTRUCTIONS.md +284 -0
- package/assets/DMG_BACKGROUND_INSTRUCTIONS.md +130 -0
- package/assets/svg-source/dmg-background.svg +70 -0
- package/assets/svg-source/icon.svg +20 -0
- package/assets/svg-source/tray-icon-processing.svg +7 -0
- package/assets/svg-source/tray-icon-recording.svg +7 -0
- package/assets/svg-source/tray-icon.svg +6 -0
- package/assets/tray-complete.png +0 -0
- package/assets/tray-complete@2x.png +0 -0
- package/assets/tray-completeTemplate.png +0 -0
- package/assets/tray-completeTemplate@2x.png +0 -0
- package/assets/tray-error.png +0 -0
- package/assets/tray-error@2x.png +0 -0
- package/assets/tray-errorTemplate.png +0 -0
- package/assets/tray-errorTemplate@2x.png +0 -0
- package/assets/tray-icon-processing.png +0 -0
- package/assets/tray-icon-processing@2x.png +0 -0
- package/assets/tray-icon-processingTemplate.png +0 -0
- package/assets/tray-icon-processingTemplate@2x.png +0 -0
- package/assets/tray-icon-recording.png +0 -0
- package/assets/tray-icon-recording@2x.png +0 -0
- package/assets/tray-icon-recordingTemplate.png +0 -0
- package/assets/tray-icon-recordingTemplate@2x.png +0 -0
- package/assets/tray-icon.png +0 -0
- package/assets/tray-icon@2x.png +0 -0
- package/assets/tray-iconTemplate.png +0 -0
- package/assets/tray-iconTemplate@2x.png +0 -0
- package/assets/tray-idle.png +0 -0
- package/assets/tray-idle@2x.png +0 -0
- package/assets/tray-idleTemplate.png +0 -0
- package/assets/tray-idleTemplate@2x.png +0 -0
- package/assets/tray-processing-0.png +0 -0
- package/assets/tray-processing-0@2x.png +0 -0
- package/assets/tray-processing-0Template.png +0 -0
- package/assets/tray-processing-0Template@2x.png +0 -0
- package/assets/tray-processing-1.png +0 -0
- package/assets/tray-processing-1@2x.png +0 -0
- package/assets/tray-processing-1Template.png +0 -0
- package/assets/tray-processing-1Template@2x.png +0 -0
- package/assets/tray-processing-2.png +0 -0
- package/assets/tray-processing-2@2x.png +0 -0
- package/assets/tray-processing-2Template.png +0 -0
- package/assets/tray-processing-2Template@2x.png +0 -0
- package/assets/tray-processing-3.png +0 -0
- package/assets/tray-processing-3@2x.png +0 -0
- package/assets/tray-processing-3Template.png +0 -0
- package/assets/tray-processing-3Template@2x.png +0 -0
- package/assets/tray-processing.png +0 -0
- package/assets/tray-processing@2x.png +0 -0
- package/assets/tray-processingTemplate.png +0 -0
- package/assets/tray-processingTemplate@2x.png +0 -0
- package/assets/tray-recording.png +0 -0
- package/assets/tray-recording@2x.png +0 -0
- package/assets/tray-recordingTemplate.png +0 -0
- package/assets/tray-recordingTemplate@2x.png +0 -0
- package/build/DMG_BACKGROUND_SPEC.md +50 -0
- package/build/dmg-background.png +0 -0
- package/build/dmg-background@2x.png +0 -0
- package/build/entitlements.mac.inherit.plist +27 -0
- package/build/entitlements.mac.plist +41 -0
- package/build/favicon-16.png +0 -0
- package/build/favicon-180.png +0 -0
- package/build/favicon-192.png +0 -0
- package/build/favicon-32.png +0 -0
- package/build/favicon-48.png +0 -0
- package/build/favicon-512.png +0 -0
- package/build/favicon-64.png +0 -0
- package/build/icon-128.png +0 -0
- package/build/icon-16.png +0 -0
- package/build/icon-24.png +0 -0
- package/build/icon-256.png +0 -0
- package/build/icon-32.png +0 -0
- package/build/icon-48.png +0 -0
- package/build/icon-64.png +0 -0
- package/build/icon.icns +0 -0
- package/build/icon.ico +0 -0
- package/build/icon.iconset/icon_128x128.png +0 -0
- package/build/icon.iconset/icon_128x128@2x.png +0 -0
- package/build/icon.iconset/icon_16x16.png +0 -0
- package/build/icon.iconset/icon_16x16@2x.png +0 -0
- package/build/icon.iconset/icon_256x256.png +0 -0
- package/build/icon.iconset/icon_256x256@2x.png +0 -0
- package/build/icon.iconset/icon_32x32.png +0 -0
- package/build/icon.iconset/icon_32x32@2x.png +0 -0
- package/build/icon.iconset/icon_512x512.png +0 -0
- package/build/icon.iconset/icon_512x512@2x.png +0 -0
- package/build/icon.png +0 -0
- package/build/installer-header.bmp +0 -0
- package/build/installer-header.png +0 -0
- package/build/installer-sidebar.bmp +0 -0
- package/build/installer-sidebar.png +0 -0
- package/build/installer.nsh +45 -0
- package/build/overlay-processing.png +0 -0
- package/build/overlay-recording.png +0 -0
- package/build/toolbar-record.png +0 -0
- package/build/toolbar-screenshot.png +0 -0
- package/build/toolbar-settings.png +0 -0
- package/build/toolbar-stop.png +0 -0
- package/dist/main/index.mjs +12612 -0
- package/dist/preload/index.mjs +907 -0
- package/dist/renderer/assets/index-CCmUjl9K.js +19495 -0
- package/dist/renderer/assets/index-CUqz_Gs6.css +2270 -0
- package/dist/renderer/index.html +27 -0
- package/docs/AI_AGENT_QUICKSTART.md +42 -0
- package/docs/AI_PIPELINE_DESIGN.md +595 -0
- package/docs/API.md +514 -0
- package/docs/ARCHITECTURE.md +460 -0
- package/docs/CONFIGURATION.md +336 -0
- package/docs/DEVELOPMENT.md +508 -0
- package/docs/EXPORT_FORMATS.md +451 -0
- package/docs/GETTING_STARTED.md +236 -0
- package/docs/KEYBOARD_SHORTCUTS.md +334 -0
- package/docs/TROUBLESHOOTING.md +418 -0
- package/docs/landing/index.html +672 -0
- package/docs/landing/script.js +342 -0
- package/docs/landing/styles.css +1543 -0
- package/electron-builder.yml +140 -0
- package/electron.vite.config.ts +63 -0
- package/package.json +108 -0
- package/railway.json +12 -0
- package/scripts/build.mjs +51 -0
- package/scripts/generate-icons.mjs +314 -0
- package/scripts/generate-installer-images.cjs +253 -0
- package/scripts/generate-tray-icons.mjs +258 -0
- package/scripts/notarize.cjs +180 -0
- package/scripts/one-click-clean-test.sh +147 -0
- package/scripts/postinstall.mjs +36 -0
- package/scripts/setup-markupr.sh +55 -0
- package/setup +17 -0
- package/site/index.html +1835 -0
- package/site/package.json +11 -0
- package/site/railway.json +12 -0
- package/site/server.js +31 -0
- package/src/main/AutoUpdater.ts +392 -0
- package/src/main/CrashRecovery.ts +655 -0
- package/src/main/ErrorHandler.ts +703 -0
- package/src/main/HotkeyManager.ts +399 -0
- package/src/main/MenuManager.ts +529 -0
- package/src/main/PermissionManager.ts +420 -0
- package/src/main/SessionController.ts +1465 -0
- package/src/main/TrayManager.ts +540 -0
- package/src/main/ai/AIPipelineManager.ts +199 -0
- package/src/main/ai/ClaudeAnalyzer.ts +339 -0
- package/src/main/ai/ImageOptimizer.ts +176 -0
- package/src/main/ai/StructuredMarkdownBuilder.ts +379 -0
- package/src/main/ai/index.ts +16 -0
- package/src/main/ai/types.ts +258 -0
- package/src/main/analysis/ClarificationGenerator.ts +385 -0
- package/src/main/analysis/FeedbackAnalyzer.ts +531 -0
- package/src/main/analysis/index.ts +19 -0
- package/src/main/audio/AudioCapture.ts +978 -0
- package/src/main/audio/audioUtils.ts +100 -0
- package/src/main/audio/index.ts +20 -0
- package/src/main/capture/index.ts +1 -0
- package/src/main/index.ts +1693 -0
- package/src/main/ipc/captureHandlers.ts +272 -0
- package/src/main/ipc/index.ts +45 -0
- package/src/main/ipc/outputHandlers.ts +302 -0
- package/src/main/ipc/sessionHandlers.ts +56 -0
- package/src/main/ipc/settingsHandlers.ts +471 -0
- package/src/main/ipc/types.ts +56 -0
- package/src/main/ipc/windowHandlers.ts +277 -0
- package/src/main/output/ClipboardService.ts +369 -0
- package/src/main/output/ExportService.ts +539 -0
- package/src/main/output/FileManager.ts +416 -0
- package/src/main/output/MarkdownGenerator.ts +791 -0
- package/src/main/output/MarkdownPatcher.ts +299 -0
- package/src/main/output/index.ts +186 -0
- package/src/main/output/sessionAdapter.ts +207 -0
- package/src/main/output/templates/html-template.ts +553 -0
- package/src/main/pipeline/FrameExtractor.ts +330 -0
- package/src/main/pipeline/PostProcessor.ts +399 -0
- package/src/main/pipeline/TranscriptAnalyzer.ts +226 -0
- package/src/main/pipeline/index.ts +36 -0
- package/src/main/platform/WindowsTaskbar.ts +600 -0
- package/src/main/platform/index.ts +16 -0
- package/src/main/settings/SettingsManager.ts +730 -0
- package/src/main/settings/index.ts +19 -0
- package/src/main/transcription/ModelDownloadManager.ts +494 -0
- package/src/main/transcription/TierManager.ts +219 -0
- package/src/main/transcription/TranscriptionRecoveryService.ts +340 -0
- package/src/main/transcription/WhisperService.ts +748 -0
- package/src/main/transcription/index.ts +56 -0
- package/src/main/transcription/types.ts +135 -0
- package/src/main/windows/PopoverManager.ts +284 -0
- package/src/main/windows/TaskbarIntegration.ts +452 -0
- package/src/main/windows/index.ts +23 -0
- package/src/preload/index.ts +1047 -0
- package/src/renderer/App.tsx +515 -0
- package/src/renderer/AppWrapper.tsx +28 -0
- package/src/renderer/assets/logo-dark.svg +7 -0
- package/src/renderer/assets/logo.svg +7 -0
- package/src/renderer/audio/AudioCaptureRenderer.ts +454 -0
- package/src/renderer/capture/ScreenRecordingRenderer.ts +492 -0
- package/src/renderer/components/AnnotationOverlay.tsx +836 -0
- package/src/renderer/components/AudioWaveform.tsx +811 -0
- package/src/renderer/components/ClarificationQuestions.tsx +656 -0
- package/src/renderer/components/CountdownTimer.tsx +495 -0
- package/src/renderer/components/CrashRecoveryDialog.tsx +632 -0
- package/src/renderer/components/DonateButton.tsx +127 -0
- package/src/renderer/components/ErrorBoundary.tsx +308 -0
- package/src/renderer/components/ExportDialog.tsx +872 -0
- package/src/renderer/components/HotkeyHint.tsx +261 -0
- package/src/renderer/components/KeyboardShortcuts.tsx +787 -0
- package/src/renderer/components/ModelDownloadDialog.tsx +844 -0
- package/src/renderer/components/Onboarding.tsx +1830 -0
- package/src/renderer/components/ProcessingOverlay.tsx +157 -0
- package/src/renderer/components/RecordingOverlay.tsx +423 -0
- package/src/renderer/components/SessionHistory.tsx +1746 -0
- package/src/renderer/components/SessionReview.tsx +1321 -0
- package/src/renderer/components/SettingsPanel.tsx +217 -0
- package/src/renderer/components/Skeleton.tsx +347 -0
- package/src/renderer/components/StatusIndicator.tsx +86 -0
- package/src/renderer/components/ThemeProvider.tsx +429 -0
- package/src/renderer/components/Tooltip.tsx +370 -0
- package/src/renderer/components/TranscriptionPreview.tsx +183 -0
- package/src/renderer/components/TranscriptionTierSelector.tsx +640 -0
- package/src/renderer/components/UpdateNotification.tsx +377 -0
- package/src/renderer/components/WindowSelector.tsx +947 -0
- package/src/renderer/components/index.ts +99 -0
- package/src/renderer/components/primitives/ApiKeyInput.tsx +98 -0
- package/src/renderer/components/primitives/ColorPicker.tsx +65 -0
- package/src/renderer/components/primitives/DangerButton.tsx +45 -0
- package/src/renderer/components/primitives/DirectoryPicker.tsx +41 -0
- package/src/renderer/components/primitives/Dropdown.tsx +34 -0
- package/src/renderer/components/primitives/KeyRecorder.tsx +117 -0
- package/src/renderer/components/primitives/SettingsSection.tsx +32 -0
- package/src/renderer/components/primitives/Slider.tsx +43 -0
- package/src/renderer/components/primitives/Toggle.tsx +36 -0
- package/src/renderer/components/primitives/index.ts +10 -0
- package/src/renderer/components/settings/AdvancedTab.tsx +174 -0
- package/src/renderer/components/settings/AppearanceTab.tsx +77 -0
- package/src/renderer/components/settings/GeneralTab.tsx +40 -0
- package/src/renderer/components/settings/HotkeysTab.tsx +79 -0
- package/src/renderer/components/settings/RecordingTab.tsx +84 -0
- package/src/renderer/components/settings/index.ts +9 -0
- package/src/renderer/components/settings/settingsStyles.ts +673 -0
- package/src/renderer/components/settings/tabConfig.tsx +85 -0
- package/src/renderer/components/settings/useSettingsPanel.ts +447 -0
- package/src/renderer/contexts/ProcessingContext.tsx +227 -0
- package/src/renderer/contexts/RecordingContext.tsx +683 -0
- package/src/renderer/contexts/UIContext.tsx +326 -0
- package/src/renderer/contexts/index.ts +24 -0
- package/src/renderer/donateMessages.ts +69 -0
- package/src/renderer/hooks/index.ts +75 -0
- package/src/renderer/hooks/useAnimation.tsx +544 -0
- package/src/renderer/hooks/useTheme.ts +313 -0
- package/src/renderer/index.html +26 -0
- package/src/renderer/main.tsx +52 -0
- package/src/renderer/styles/animations.css +1093 -0
- package/src/renderer/styles/app-shell.css +662 -0
- package/src/renderer/styles/globals.css +515 -0
- package/src/renderer/styles/theme.ts +578 -0
- package/src/renderer/types/electron.d.ts +385 -0
- package/src/shared/hotkeys.ts +283 -0
- package/src/shared/types.ts +809 -0
- package/tests/clipboard.test.ts +228 -0
- package/tests/e2e/criticalPaths.test.ts +594 -0
- package/tests/feedbackAnalyzer.test.ts +303 -0
- package/tests/integration/sessionFlow.test.ts +583 -0
- package/tests/markdownGenerator.test.ts +418 -0
- package/tests/output.test.ts +96 -0
- package/tests/setup.ts +486 -0
- package/tests/unit/appIntegration.test.ts +676 -0
- package/tests/unit/appViewState.test.ts +281 -0
- package/tests/unit/audioIpcChannels.test.ts +17 -0
- package/tests/unit/exportService.test.ts +492 -0
- package/tests/unit/hotkeys.test.ts +92 -0
- package/tests/unit/navigationPreload.test.ts +94 -0
- package/tests/unit/onboardingFlow.test.ts +345 -0
- package/tests/unit/permissionManager.test.ts +175 -0
- package/tests/unit/permissionManagerExpanded.test.ts +296 -0
- package/tests/unit/screenRecordingRenderer.test.ts +368 -0
- package/tests/unit/sessionController.test.ts +515 -0
- package/tests/unit/tierManager.test.ts +61 -0
- package/tests/unit/tierManagerExpanded.test.ts +142 -0
- package/tests/unit/transcriptAnalyzer.test.ts +64 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +46 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProcessingContext
|
|
3
|
+
*
|
|
4
|
+
* Manages the post-processing progress display: smoothing raw progress events
|
|
5
|
+
* into a believable, continuous progress bar animation. Consumes raw progress
|
|
6
|
+
* data from RecordingContext and provides smoothed display values.
|
|
7
|
+
*
|
|
8
|
+
* Uses useAnimatedValue from hooks/useAnimation.tsx for smooth interpolation
|
|
9
|
+
* instead of a custom Bezier implementation.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
13
|
+
import { useAnimatedValue } from '../hooks/useAnimation';
|
|
14
|
+
import { useRecording } from './RecordingContext';
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Constants
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
export const PROCESSING_BASELINE_PERCENT = 4;
|
|
21
|
+
export const PROCESSING_VISIBLE_MAX = 96;
|
|
22
|
+
const PROCESSING_TARGET_TICK_MS = 120;
|
|
23
|
+
|
|
24
|
+
export const PROCESSING_DOT_FRAMES = ['∙∙∙', '●∙∙', '●●∙', '●●●'] as const;
|
|
25
|
+
|
|
26
|
+
const PROCESSING_STEP_LABELS: Record<string, string> = {
|
|
27
|
+
preparing: 'Finalizing recording assets...',
|
|
28
|
+
transcribing: 'Transcribing narration...',
|
|
29
|
+
analyzing: 'Analyzing spoken context...',
|
|
30
|
+
saving: 'Saving session artifacts...',
|
|
31
|
+
'extracting-frames': 'Extracting key visual frames...',
|
|
32
|
+
'generating-report': 'Generating markdown report...',
|
|
33
|
+
complete: 'Finalizing output files...',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const PROCESSING_STEP_TARGETS: Record<string, number> = {
|
|
37
|
+
preparing: 28,
|
|
38
|
+
transcribing: 58,
|
|
39
|
+
analyzing: 72,
|
|
40
|
+
saving: 82,
|
|
41
|
+
'extracting-frames': 90,
|
|
42
|
+
'generating-report': PROCESSING_VISIBLE_MAX,
|
|
43
|
+
complete: PROCESSING_VISIBLE_MAX,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Helpers
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
function normalizeProcessingStep(step?: string): string {
|
|
51
|
+
if (!step) return 'preparing';
|
|
52
|
+
return step.toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function formatProcessingStep(step?: string): string {
|
|
56
|
+
const normalized = normalizeProcessingStep(step);
|
|
57
|
+
return PROCESSING_STEP_LABELS[normalized] || 'Finalizing report output...';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveProcessingStageTarget(step?: string): number {
|
|
61
|
+
const normalized = normalizeProcessingStep(step);
|
|
62
|
+
return PROCESSING_STEP_TARGETS[normalized] ?? 88;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Types
|
|
67
|
+
// ============================================================================
|
|
68
|
+
|
|
69
|
+
interface ProcessingProgress {
|
|
70
|
+
percent: number;
|
|
71
|
+
step: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ProcessingContextValue {
|
|
75
|
+
/** Smoothed processing progress for display */
|
|
76
|
+
processingProgress: ProcessingProgress | null;
|
|
77
|
+
/** Current dot-animation frame index */
|
|
78
|
+
processingDotFrame: number;
|
|
79
|
+
/** Whether the app is in a processing state */
|
|
80
|
+
isProcessing: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const ProcessingContext = createContext<ProcessingContextValue | null>(null);
|
|
84
|
+
|
|
85
|
+
export function useProcessing(): ProcessingContextValue {
|
|
86
|
+
const context = useContext(ProcessingContext);
|
|
87
|
+
if (!context) {
|
|
88
|
+
throw new Error('useProcessing must be used within ProcessingProvider');
|
|
89
|
+
}
|
|
90
|
+
return context;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// Provider
|
|
95
|
+
// ============================================================================
|
|
96
|
+
|
|
97
|
+
export const ProcessingProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
98
|
+
const { state, rawProcessingProgress, processingStartedAt } = useRecording();
|
|
99
|
+
|
|
100
|
+
const isProcessing = state === 'stopping' || state === 'processing';
|
|
101
|
+
|
|
102
|
+
// Track the target percent that we want to animate toward
|
|
103
|
+
const [targetPercent, setTargetPercent] = useState(PROCESSING_BASELINE_PERCENT);
|
|
104
|
+
const [stepLabel, setStepLabel] = useState<string>('');
|
|
105
|
+
const [processingDotFrame, setProcessingDotFrame] = useState(0);
|
|
106
|
+
|
|
107
|
+
// Ref to track the processing start time (local copy since ref from recording
|
|
108
|
+
// context value is a snapshot)
|
|
109
|
+
const processingStartRef = useRef<number | null>(null);
|
|
110
|
+
|
|
111
|
+
// Sync the processing start time
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (isProcessing && !processingStartRef.current) {
|
|
114
|
+
processingStartRef.current = processingStartedAt ?? Date.now();
|
|
115
|
+
}
|
|
116
|
+
if (!isProcessing) {
|
|
117
|
+
processingStartRef.current = null;
|
|
118
|
+
}
|
|
119
|
+
}, [isProcessing, processingStartedAt]);
|
|
120
|
+
|
|
121
|
+
// Compute target percent periodically (same interval as original)
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (!isProcessing) {
|
|
124
|
+
setTargetPercent(PROCESSING_BASELINE_PERCENT);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const interval = window.setInterval(() => {
|
|
129
|
+
const startedAt = processingStartRef.current ?? Date.now();
|
|
130
|
+
const elapsedMs = Date.now() - startedAt;
|
|
131
|
+
|
|
132
|
+
// Time-based floor (asymptotic curve ensuring progress even without events)
|
|
133
|
+
const elapsedFloor = (() => {
|
|
134
|
+
if (elapsedMs < 2200) {
|
|
135
|
+
return PROCESSING_BASELINE_PERCENT + elapsedMs / 120;
|
|
136
|
+
}
|
|
137
|
+
if (elapsedMs < 9000) {
|
|
138
|
+
return 22 + (elapsedMs - 2200) / 170;
|
|
139
|
+
}
|
|
140
|
+
if (elapsedMs < 22000) {
|
|
141
|
+
return 62 + (elapsedMs - 9000) / 420;
|
|
142
|
+
}
|
|
143
|
+
return 85 + (elapsedMs - 22000) / 1300;
|
|
144
|
+
})();
|
|
145
|
+
|
|
146
|
+
// Raw progress guided value
|
|
147
|
+
const rawPercent = Math.max(0, Math.min(100, rawProcessingProgress?.percent ?? 0));
|
|
148
|
+
const rawGuided = Math.min(PROCESSING_VISIBLE_MAX, rawPercent + 8);
|
|
149
|
+
|
|
150
|
+
// Stage target based on current step
|
|
151
|
+
const stageTarget = resolveProcessingStageTarget(rawProcessingProgress?.step);
|
|
152
|
+
|
|
153
|
+
// Final target: max of all three signals, clamped
|
|
154
|
+
const nextTarget = Math.max(
|
|
155
|
+
PROCESSING_BASELINE_PERCENT,
|
|
156
|
+
Math.min(PROCESSING_VISIBLE_MAX, Math.max(elapsedFloor, rawGuided, stageTarget))
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
setTargetPercent(nextTarget);
|
|
160
|
+
setStepLabel(formatProcessingStep(rawProcessingProgress?.step));
|
|
161
|
+
}, PROCESSING_TARGET_TICK_MS);
|
|
162
|
+
|
|
163
|
+
return () => window.clearInterval(interval);
|
|
164
|
+
}, [isProcessing, rawProcessingProgress]);
|
|
165
|
+
|
|
166
|
+
// Handle the 100% completion case (bypass animation, snap to 100)
|
|
167
|
+
const isComplete = rawProcessingProgress?.percent === 100;
|
|
168
|
+
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (isComplete) {
|
|
171
|
+
setTargetPercent(100);
|
|
172
|
+
setStepLabel(formatProcessingStep('complete'));
|
|
173
|
+
}
|
|
174
|
+
}, [isComplete]);
|
|
175
|
+
|
|
176
|
+
// Smooth the percent using useAnimatedValue
|
|
177
|
+
const smoothedPercent = useAnimatedValue(
|
|
178
|
+
isProcessing || isComplete ? targetPercent : PROCESSING_BASELINE_PERCENT,
|
|
179
|
+
{ duration: 280 }
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Dot frame animation
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (!isProcessing) {
|
|
185
|
+
setProcessingDotFrame(0);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const interval = window.setInterval(() => {
|
|
190
|
+
setProcessingDotFrame((prev) => (prev + 1) % 4);
|
|
191
|
+
}, 360);
|
|
192
|
+
|
|
193
|
+
return () => window.clearInterval(interval);
|
|
194
|
+
}, [isProcessing]);
|
|
195
|
+
|
|
196
|
+
// Build the final progress value
|
|
197
|
+
const processingProgress = useMemo((): ProcessingProgress | null => {
|
|
198
|
+
if (!isProcessing && !isComplete) return null;
|
|
199
|
+
|
|
200
|
+
// For 100% completion, return exact value without rounding noise
|
|
201
|
+
if (isComplete) {
|
|
202
|
+
return { percent: 100, step: formatProcessingStep('complete') };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
percent: Math.round(Math.min(PROCESSING_VISIBLE_MAX, smoothedPercent)),
|
|
207
|
+
step: stepLabel || formatProcessingStep('preparing'),
|
|
208
|
+
};
|
|
209
|
+
}, [isProcessing, isComplete, smoothedPercent, stepLabel]);
|
|
210
|
+
|
|
211
|
+
const value = useMemo(
|
|
212
|
+
(): ProcessingContextValue => ({
|
|
213
|
+
processingProgress,
|
|
214
|
+
processingDotFrame,
|
|
215
|
+
isProcessing,
|
|
216
|
+
}),
|
|
217
|
+
[processingProgress, processingDotFrame, isProcessing]
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<ProcessingContext.Provider value={value}>
|
|
222
|
+
{children}
|
|
223
|
+
</ProcessingContext.Provider>
|
|
224
|
+
);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
export default ProcessingContext;
|