Skip to content

Commit 677993f

Browse files
author
Francis
committed
ui tweaks
1 parent 3aef418 commit 677993f

File tree

8 files changed

+157
-50
lines changed

8 files changed

+157
-50
lines changed

macos/SourcePrint.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@
436436
CODE_SIGN_ENTITLEMENTS = SourcePrint/SourcePrint.entitlements;
437437
CODE_SIGN_STYLE = Automatic;
438438
COMBINE_HIDPI_IMAGES = YES;
439-
CURRENT_PROJECT_VERSION = 204;
439+
CURRENT_PROJECT_VERSION = 211;
440440
DEVELOPMENT_ASSET_PATHS = "\"SourcePrint/Preview Content\"";
441441
DEVELOPMENT_TEAM = 5AUBAVQ835;
442442
ENABLE_HARDENED_RUNTIME = YES;
@@ -466,7 +466,7 @@
466466
CODE_SIGN_ENTITLEMENTS = SourcePrint/SourcePrint.entitlements;
467467
CODE_SIGN_STYLE = Automatic;
468468
COMBINE_HIDPI_IMAGES = YES;
469-
CURRENT_PROJECT_VERSION = 204;
469+
CURRENT_PROJECT_VERSION = 211;
470470
DEVELOPMENT_ASSET_PATHS = "\"SourcePrint/Preview Content\"";
471471
DEVELOPMENT_TEAM = 5AUBAVQ835;
472472
ENABLE_HARDENED_RUNTIME = YES;
@@ -493,7 +493,7 @@
493493
buildSettings = {
494494
BUNDLE_LOADER = "$(TEST_HOST)";
495495
CODE_SIGN_STYLE = Automatic;
496-
CURRENT_PROJECT_VERSION = 204;
496+
CURRENT_PROJECT_VERSION = 211;
497497
DEVELOPMENT_TEAM = 5AUBAVQ835;
498498
GENERATE_INFOPLIST_FILE = YES;
499499
MACOSX_DEPLOYMENT_TARGET = 15.0;
@@ -511,7 +511,7 @@
511511
buildSettings = {
512512
BUNDLE_LOADER = "$(TEST_HOST)";
513513
CODE_SIGN_STYLE = Automatic;
514-
CURRENT_PROJECT_VERSION = 204;
514+
CURRENT_PROJECT_VERSION = 211;
515515
DEVELOPMENT_TEAM = 5AUBAVQ835;
516516
GENERATE_INFOPLIST_FILE = YES;
517517
MACOSX_DEPLOYMENT_TARGET = 15.0;
@@ -528,7 +528,7 @@
528528
isa = XCBuildConfiguration;
529529
buildSettings = {
530530
CODE_SIGN_STYLE = Automatic;
531-
CURRENT_PROJECT_VERSION = 204;
531+
CURRENT_PROJECT_VERSION = 211;
532532
DEVELOPMENT_TEAM = 5AUBAVQ835;
533533
GENERATE_INFOPLIST_FILE = YES;
534534
MARKETING_VERSION = 1.0;
@@ -544,7 +544,7 @@
544544
isa = XCBuildConfiguration;
545545
buildSettings = {
546546
CODE_SIGN_STYLE = Automatic;
547-
CURRENT_PROJECT_VERSION = 204;
547+
CURRENT_PROJECT_VERSION = 211;
548548
DEVELOPMENT_TEAM = 5AUBAVQ835;
549549
GENERATE_INFOPLIST_FILE = YES;
550550
MARKETING_VERSION = 1.0;

macos/SourcePrint/Features/Linking/LinkingResultsView.swift

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -438,15 +438,10 @@ struct LinkingResultsView: View {
438438

439439
Spacer()
440440

441-
HStack(spacing: 12) {
442-
if let performLinking = onPerformLinking {
443-
Button("Run Auto-Linking") {
444-
performLinking()
445-
}
446-
.buttonStyle(CompressorButtonStyle(prominent: true))
447-
.disabled(project.model.ocfFiles.isEmpty || project.model.segments.isEmpty)
448-
}
449-
}
441+
// Auto-linking happens automatically after import
442+
Text("Linking will run automatically when files are imported")
443+
.font(.caption)
444+
.foregroundColor(.secondary)
450445
}
451446
.padding()
452447

@@ -619,37 +614,6 @@ struct LinkingResultsView: View {
619614

620615
Spacer()
621616

622-
// Action buttons
623-
HStack(spacing: 12) {
624-
if let performLinking = onPerformLinking {
625-
Button("Run Auto-Linking") {
626-
performLinking()
627-
}
628-
.buttonStyle(CompressorButtonStyle(prominent: true))
629-
.disabled(
630-
project.model.ocfFiles.isEmpty || project.model.segments.isEmpty
631-
)
632-
}
633-
634-
if !confidentlyLinkedParents.isEmpty {
635-
Group {
636-
Button("Select All") {
637-
selectedOCFParents = Set(
638-
confidentlyLinkedParents.map { $0.ocf.fileName })
639-
}
640-
.keyboardShortcut("a", modifiers: .command)
641-
642-
Button("Clear Selection") {
643-
selectedOCFParents.removeAll()
644-
}
645-
.keyboardShortcut(.escape, modifiers: [])
646-
.opacity(selectedOCFParents.isEmpty ? 0 : 1)
647-
.disabled(selectedOCFParents.isEmpty)
648-
}
649-
.buttonStyle(CompressorButtonStyle())
650-
}
651-
}
652-
653617
// Show toggle button here when drawer is hidden
654618
if !showUnmatchedDrawer {
655619
Button {
@@ -680,6 +644,10 @@ struct LinkingResultsView: View {
680644
}
681645
}
682646
.padding()
647+
.contentShape(Rectangle())
648+
.onTapGesture {
649+
selectedOCFParents.removeAll()
650+
}
683651

684652
// Use ScrollView for true card layout
685653
ScrollView {

macos/SourcePrint/Features/Linking/LinkingTab.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ struct LinkingTab: View {
3030
}
3131
.onAppear {
3232
generateTimelineVisualizationFromExistingData()
33+
// Set up auto-linking callback
34+
project.autoLinkingCallback = performLinkingIfNeeded
35+
// Set status bar tab context
36+
statusBarVM.currentTab = .linking
3337
}
3438
}
3539

@@ -298,4 +302,33 @@ struct LinkingTab: View {
298302
statusBarVM.reset()
299303
}
300304
}
305+
306+
/// Perform linking with safety checks and debouncing
307+
private func performLinkingIfNeeded() {
308+
// Safety checks
309+
guard !isLinking else {
310+
NSLog("⏸️ Auto-linking skipped: already linking")
311+
return
312+
}
313+
314+
guard !project.model.ocfFiles.isEmpty && !project.model.segments.isEmpty else {
315+
NSLog("⏸️ Auto-linking skipped: need both OCF files and segments")
316+
return
317+
}
318+
319+
// Debounce: wait 2 seconds before triggering (allows batch imports to complete)
320+
Task {
321+
try? await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
322+
323+
// Check again after debounce in case conditions changed
324+
guard !isLinking && !project.model.ocfFiles.isEmpty && !project.model.segments.isEmpty else {
325+
return
326+
}
327+
328+
await MainActor.run {
329+
NSLog("🔗 Auto-linking triggered")
330+
performLinking()
331+
}
332+
}
333+
}
301334
}

macos/SourcePrint/Features/MediaImport/MediaImportTab.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct MediaImportTab: View {
1313
@ObservedObject var project: ProjectViewModel
1414
@EnvironmentObject var projectManager: ProjectManager
1515
@EnvironmentObject var statusBarVM: StatusBarViewModel
16+
@Binding var selectedTab: ProjectTab
1617
@State private var importingOCF = false
1718
@State private var isAnalyzing = false
1819
@State private var selectedOCFFiles: Set<String> = []
@@ -109,6 +110,28 @@ struct MediaImportTab: View {
109110
} message: {
110111
Text("This will permanently remove all offline media files from the project. This cannot be undone.")
111112
}
113+
.onAppear {
114+
// Set status bar tab context
115+
statusBarVM.currentTab = .media
116+
117+
// Wire up link button callback
118+
statusBarVM.onLinkFiles = {
119+
// Trigger linking
120+
project.autoLinkingCallback?()
121+
122+
// Switch to linking tab
123+
selectedTab = .linking
124+
}
125+
126+
// Update file counts
127+
updateStatusBarCounts()
128+
}
129+
.onChange(of: project.model.ocfFiles.count) { _ in
130+
updateStatusBarCounts()
131+
}
132+
.onChange(of: project.model.segments.count) { _ in
133+
updateStatusBarCounts()
134+
}
112135
}
113136

114137
private func showImportPicker() {
@@ -206,6 +229,9 @@ struct MediaImportTab: View {
206229
statusBarVM.completeOperation(summary: "Imported \(mediaFiles.count) \(isOCF ? "OCF" : "segment") file\(mediaFiles.count == 1 ? "" : "s")")
207230

208231
NSLog("✅ Imported \(mediaFiles.count) \(isOCF ? "OCF" : "segment") files")
232+
233+
// Trigger automatic linking after manual import
234+
project.autoLinkingCallback?()
209235
}
210236
}
211237
}
@@ -321,6 +347,11 @@ struct MediaImportTab: View {
321347
projectManager.saveProject(project)
322348
NSLog("🗑️ Removed \(fileNames.count) segment(s): \(fileNames.joined(separator: ", "))")
323349
}
350+
351+
private func updateStatusBarCounts() {
352+
statusBarVM.ocfFileCount = project.model.ocfFiles.count
353+
statusBarVM.segmentFileCount = project.model.segments.count
354+
}
324355
}
325356

326357
// MARK: - Watch Folder Section

macos/SourcePrint/Features/ProjectManagement/ProjectDetailView.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,38 @@
88
import SwiftUI
99
import SourcePrintCore
1010

11+
enum ProjectTab {
12+
case overview
13+
case media
14+
case linking
15+
}
16+
1117
struct ProjectDetailView: View {
1218
let project: ProjectViewModel
1319
@EnvironmentObject var projectManager: ProjectManager
14-
20+
@State private var selectedTab: ProjectTab = .overview
21+
1522
var body: some View {
16-
TabView {
23+
TabView(selection: $selectedTab) {
1724
ProjectOverviewTab(project: project)
1825
.tabItem {
1926
Label("Overview", systemImage: "list.bullet")
2027
}
28+
.tag(ProjectTab.overview)
2129

22-
MediaImportTab(project: project)
30+
MediaImportTab(project: project, selectedTab: $selectedTab)
2331
.environmentObject(projectManager)
2432
.tabItem {
2533
Label("Media", systemImage: "folder")
2634
}
35+
.tag(ProjectTab.media)
2736

2837
LinkingTab(project: project)
2938
.environmentObject(projectManager)
3039
.tabItem {
3140
Label("Linking", systemImage: "link")
3241
}
42+
.tag(ProjectTab.linking)
3343
}
3444
.frame(maxWidth: .infinity, maxHeight: .infinity)
3545
.navigationBarBackButtonHidden(true)

macos/SourcePrint/Features/StatusBar/StatusBarView.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,45 @@ struct StatusBarView: View {
194194
}
195195
}
196196

197-
// MARK: - Render Buttons
197+
// MARK: - Action Buttons (Tab-Aware)
198198

199199
private var renderButtons: some View {
200+
HStack(spacing: 8) {
201+
// Show different buttons based on active tab
202+
switch viewModel.currentTab {
203+
case .media:
204+
linkButton
205+
case .linking:
206+
renderingButtons
207+
case .overview:
208+
EmptyView()
209+
}
210+
}
211+
}
212+
213+
// MARK: - Link Button (Media Import Tab)
214+
215+
private var linkButton: some View {
216+
Group {
217+
if viewModel.ocfFileCount > 0 && viewModel.segmentFileCount > 0 {
218+
Button(action: {
219+
viewModel.onLinkFiles?()
220+
}) {
221+
Text("Link Files")
222+
.font(.system(size: 14, weight: .medium))
223+
.frame(minWidth: 100)
224+
}
225+
.buttonStyle(.borderedProminent)
226+
.tint(accentColor)
227+
.controlSize(.regular)
228+
.help("Link \(viewModel.ocfFileCount) OCF file\(viewModel.ocfFileCount == 1 ? "" : "s") with \(viewModel.segmentFileCount) segment\(viewModel.segmentFileCount == 1 ? "" : "s")")
229+
}
230+
}
231+
}
232+
233+
// MARK: - Render Buttons (Linking Tab)
234+
235+
private var renderingButtons: some View {
200236
HStack(spacing: 8) {
201237
// Primary render button (changes based on selection)
202238
if viewModel.totalRenderableCount > 0 {

macos/SourcePrint/Features/StatusBar/StatusBarViewModel.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ enum OperationType: Equatable {
1818
case watchFolderImport
1919
}
2020

21+
/// Active tab context for showing appropriate buttons
22+
enum TabContext: Equatable {
23+
case overview
24+
case media
25+
case linking
26+
}
27+
2128
/// Detailed progress information for expanded view
2229
struct DetailedProgress {
2330
let fileName: String?
@@ -78,6 +85,22 @@ class StatusBarViewModel: ObservableObject {
7885
/// Callback for canceling current operation
7986
var onCancel: (() -> Void)?
8087

88+
// MARK: - Tab Context
89+
90+
/// Current active tab
91+
@Published var currentTab: TabContext = .overview
92+
93+
// MARK: - Link Button State
94+
95+
/// Callback for link files action
96+
var onLinkFiles: (() -> Void)?
97+
98+
/// Number of OCF files available for linking
99+
@Published var ocfFileCount: Int = 0
100+
101+
/// Number of segment files available for linking
102+
@Published var segmentFileCount: Int = 0
103+
81104
// MARK: - Progress Update Methods
82105

83106
/// Update import progress

macos/SourcePrint/ViewModels/ProjectViewModel.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class ProjectViewModel: ObservableObject, Codable, Identifiable, WatchFolderDele
4848
/// Project validation result (UI-only, not persisted)
4949
@Published var validationResult: ProjectValidationResult?
5050

51+
/// Callback for automatic linking (set by LinkingTab)
52+
var autoLinkingCallback: (() -> Void)?
53+
5154
/// Watch folder service instance
5255
private var watchFolderService: WatchFolderService?
5356

@@ -371,6 +374,9 @@ class ProjectViewModel: ObservableObject, Codable, Identifiable, WatchFolderDele
371374
await MainActor.run {
372375
addSegments(mediaFiles)
373376
NSLog("✅ Auto-imported %d new %@ files from watch folder", mediaFiles.count, isVFX ? "VFX" : "grade")
377+
378+
// Trigger automatic linking after import
379+
autoLinkingCallback?()
374380
}
375381
}
376382
}

0 commit comments

Comments
 (0)