forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDesktopTopBar.swift
More file actions
125 lines (117 loc) · 4.81 KB
/
Copy pathDesktopTopBar.swift
File metadata and controls
125 lines (117 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import OmiTheme
import SwiftUI
/// The constant floating top bar that replaces the left nav rail: primary
/// navigation (Home / Memory / Tasks / Apps), a "new since you were last here"
/// counter (conversations · memories · tasks created while Omi wasn't in front),
/// and the Capture/Listening controls on the right.
struct DesktopTopBar: View {
@Binding var selectedIndex: Int
@ObservedObject var appState: AppState
@ObservedObject var memoriesViewModel: MemoriesViewModel
@ObservedObject var tasksStore: TasksStore
/// Items created after this instant count as "new" — updated whenever Omi
/// last resigned front (see DesktopHomeView).
let sinceDate: Date
let onRewind: () -> Void
private struct NavItem: Identifiable {
let index: Int
let title: String
let icon: String
var id: Int { index }
}
private var navItems: [NavItem] {
[
NavItem(index: SidebarNavItem.dashboard.rawValue, title: "Home", icon: "house.fill"),
NavItem(index: SidebarNavItem.conversations.rawValue, title: "Memory", icon: "brain"),
NavItem(index: SidebarNavItem.tasks.rawValue, title: "Tasks", icon: "checklist"),
NavItem(index: SidebarNavItem.apps.rawValue, title: "Apps", icon: "puzzlepiece.fill"),
]
}
private var newConversations: Int {
appState.conversations.filter { $0.createdAt > sinceDate && $0.deleted != true }.count
}
private var newMemories: Int {
memoriesViewModel.memories.filter { $0.createdAt > sinceDate }.count
}
private var newTasks: Int {
tasksStore.tasks.filter { $0.createdAt > sinceDate && $0.deleted != true }.count
}
var body: some View {
HStack(spacing: OmiSpacing.md) {
navPills
Spacer(minLength: OmiSpacing.md)
CaptureListeningControls(appState: appState, onRewind: onRewind)
settingsButton
}
.frame(height: 44)
.padding(.horizontal, OmiSpacing.lg)
.padding(.vertical, OmiSpacing.sm)
}
/// Gear that opens Settings. The old left rail held the settings/profile entry;
/// with the rail gone this is the only visible way in (⌘, still works too).
private var settingsButton: some View {
let isActive = selectedIndex == SidebarNavItem.settings.rawValue
return Button {
OmiMotion.withGated(.easeOut(duration: 0.08)) {
selectedIndex = SidebarNavItem.settings.rawValue
}
} label: {
Image(systemName: "gearshape")
.scaledFont(size: OmiType.body, weight: .semibold)
.foregroundColor(isActive ? OmiColors.textPrimary : OmiColors.textTertiary)
.frame(width: 32, height: 32)
.background(Circle().fill(isActive ? OmiColors.textPrimary.opacity(0.08) : Color.clear))
.contentShape(Circle())
}
.buttonStyle(.plain)
.help("Settings")
}
private var navPills: some View {
// Flat, containerless nav so the bar blends with the chat page: unselected
// items are muted text; the selected item gets a subtle highlight only.
HStack(spacing: OmiSpacing.xs) {
ForEach(navItems) { item in
Button {
OmiMotion.withGated(.easeOut(duration: 0.08)) { selectedIndex = item.index }
} label: {
HStack(spacing: 6) {
Image(systemName: item.icon)
.scaledFont(size: OmiType.caption, weight: .semibold)
Text(item.title)
.scaledFont(size: OmiType.caption, weight: .semibold)
// New-item badge lives on the button it belongs to (Memory =
// memories + conversations, Tasks = tasks) since Omi was last front.
if newCount(for: item) > 0 {
Text("+\(newCount(for: item))")
.scaledFont(size: OmiType.micro, weight: .bold)
.foregroundColor(OmiColors.textPrimary)
.padding(.horizontal, 5)
.padding(.vertical, 1)
.background(Capsule(style: .continuous).fill(OmiColors.textPrimary.opacity(0.16)))
}
}
.foregroundColor(selectedIndex == item.index ? OmiColors.textPrimary : OmiColors.textTertiary)
.padding(.horizontal, OmiSpacing.md)
.padding(.vertical, 6)
.background(
Capsule(style: .continuous)
.fill(selectedIndex == item.index ? OmiColors.textPrimary.opacity(0.08) : Color.clear)
)
.contentShape(Capsule())
}
.buttonStyle(.plain)
.help(item.title)
}
}
}
/// New-item count to badge on a nav button (since Omi was last in front).
/// The Memory hub holds both memories and conversations, so its badge sums
/// them; Tasks badges new tasks. Home/Apps have no counter.
private func newCount(for item: NavItem) -> Int {
switch item.index {
case SidebarNavItem.conversations.rawValue: return newMemories + newConversations
case SidebarNavItem.tasks.rawValue: return newTasks
default: return 0
}
}
}