Skip to content

Commit 5d9b7f3

Browse files
feat (settings): re-add footer settings button with working selector
turns out the selector still worked, just under a new name refactor: user footer to be closer in styling to the official client’s one
1 parent 8be47fc commit 5d9b7f3

File tree

3 files changed

+108
-121
lines changed

3 files changed

+108
-121
lines changed

Swiftcord/Views/User/Avatar/UserAvatarView.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ struct UserAvatarView: View, Equatable {
9999
)
100100
.font(.headline)
101101
.textCase(.uppercase)
102+
.padding(.top, 6)
102103
if !roles.isEmpty {
103104
TagCloudView(
104105
content: roles.map { role in
@@ -124,7 +125,10 @@ struct UserAvatarView: View, Equatable {
124125
.tint(.blue)
125126
}
126127
}
127-
Text("user.note").font(.headline).textCase(.uppercase)
128+
Text("user.note")
129+
.font(.headline)
130+
.textCase(.uppercase)
131+
.padding(.top, 6)
128132
// Notes are stored locally for now, but eventually will be synced with the Discord API
129133
TextField("Add a note to this user (only visible to you)", text: $note)
130134
.textFieldStyle(.roundedBorder)

Swiftcord/Views/User/CurrentUserFooter.swift

Lines changed: 102 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ struct CurrentUserFooter: View {
2626
@EnvironmentObject var switcher: AccountSwitcher
2727
@EnvironmentObject var gateway: DiscordGateway
2828

29-
private static let presenceIconMapping: [PresenceStatus: String] = [
30-
.online: "circle.fill",
31-
.idle: "moon.fill",
32-
.dnd: "minus.circle",
33-
.invisible: "circle"
29+
private static let presences: [(presence: PresenceStatus, icon: String)] = [
30+
(.online, "circle.fill"),
31+
(.idle, "moon.fill"),
32+
(.dnd, "minus.circle"),
33+
(.invisible, "circle")
3434
]
3535

3636
private static let log = Logger(category: "CurrentUserFooter")
@@ -81,137 +81,120 @@ struct CurrentUserFooter: View {
8181
let curUserPresence = gateway.presences[user.id]?.status ?? .offline
8282
let customStatus = gateway.presences[user.id]?.activities.first { $0.type == .custom }
8383

84-
Button {
85-
userPopoverPresented = true
86-
AnalyticsWrapper.event(type: .openPopout, properties: [
87-
"type": "User Status Menu",
88-
"other_user_id": user.id
89-
])
90-
} label: {
91-
HStack(spacing: 8) {
92-
AvatarWithPresence(
93-
avatarURL: user.avatarURL(),
94-
presence: curUserPresence,
95-
animate: false
96-
)
97-
.controlSize(.small)
98-
.padding(.leading, 8)
99-
100-
VStack(alignment: .leading, spacing: 0) {
101-
Text(user.username).font(.headline)
102-
Group {
103-
if let customStatus = customStatus {
104-
Text(customStatus.state ?? "")
105-
} else {
106-
Text("#" + user.discriminator)
107-
}
108-
}.font(.system(size: 12)).opacity(0.75)
109-
}
110-
Spacer()
84+
HStack(spacing: 14) {
85+
Button {
86+
userPopoverPresented = true
87+
AnalyticsWrapper.event(type: .openPopout, properties: [
88+
"type": "User Status Menu",
89+
"other_user_id": user.id
90+
])
91+
} label: {
92+
HStack(spacing: 8) {
93+
AvatarWithPresence(
94+
avatarURL: user.avatarURL(),
95+
presence: curUserPresence,
96+
animate: false
97+
)
98+
.controlSize(.small)
11199

112-
// The hidden selector for opening the preferences window
113-
// is probably removed in macOS 13. Should check if this
114-
// is still broken once macOS 13 is stable.
115-
if #available(macOS 13.0, *) {
116-
EmptyView()
117-
} else {
118-
Button(action: {
119-
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
120-
}, label: {
121-
Image(systemName: "gearshape.fill")
122-
.font(.system(size: 18))
123-
.opacity(0.75)
124-
})
125-
.buttonStyle(.plain)
126-
.padding(.trailing, 14)
100+
VStack(alignment: .leading, spacing: 0) {
101+
Text(user.username).font(.headline)
102+
Group {
103+
if let customStatus = customStatus {
104+
Text(customStatus.state ?? "")
105+
} else {
106+
Text("#" + user.discriminator)
107+
}
108+
}.font(.system(size: 12)).opacity(0.75)
109+
}
127110
}
111+
.padding(2)
112+
.contentShape(Rectangle())
128113
}
129-
.frame(height: 52)
130-
.background(Color(nsColor: .controlBackgroundColor).opacity(0.5))
131-
}
132-
.buttonStyle(.plain)
133-
.popover(isPresented: $userPopoverPresented) {
134-
MiniUserProfileView(user: User(from: user), profile: .constant(UserProfile(
135-
connected_accounts: [],
136-
user: User(from: user)
137-
))) {
138-
VStack(spacing: 4) {
139-
if !(user.bio?.isEmpty ?? true) { Divider() }
140-
141-
// Set presence
142-
Menu {
143-
Button {
144-
updatePresence(with: .online)
145-
} label: {
146-
// Not possible to set custom image size and color
147-
Image(systemName: Self.presenceIconMapping[.online]!)
148-
Text("user.presence.online")
149-
}
150-
Divider()
151-
Button {
152-
updatePresence(with: .idle)
114+
.buttonStyle(.plain)
115+
.popover(isPresented: $userPopoverPresented) {
116+
MiniUserProfileView(user: User(from: user), profile: .constant(UserProfile(
117+
connected_accounts: [],
118+
user: User(from: user)
119+
))) {
120+
VStack(spacing: 4) {
121+
if !(user.bio?.isEmpty ?? true) { Divider() }
122+
123+
// Set presence
124+
Menu {
125+
ForEach(Self.presences, id: \.icon) { (presence, icon) in
126+
Button {
127+
updatePresence(with: presence)
128+
} label: {
129+
// Not possible to set custom image size and color
130+
Image(systemName: icon)
131+
Text(presence.toLocalizedString())
132+
}
133+
if presence == Self.presences.first?.presence { Divider() }
134+
}
153135
} label: {
154-
Image(systemName: Self.presenceIconMapping[.idle]!)
155-
Text("user.presence.idle")
136+
Text(curUserPresence.toLocalizedString())
156137
}
138+
.controlSize(.large)
139+
.disabled(settingPresence)
157140
Button {
158-
updatePresence(with: .dnd)
141+
customStatusPresented = true
159142
} label: {
160-
Image(systemName: Self.presenceIconMapping[.dnd]!)
161-
Text("user.presence.dnd")
143+
if customStatus != nil {
144+
HStack {
145+
Text("Edit Custom Status")
146+
Spacer()
147+
Button {
148+
updatePresence(with: curUserPresence, clearCustomStatus: true)
149+
} label: {
150+
Image(systemName: "xmark.circle.fill").font(.system(size: 18))
151+
}
152+
.buttonStyle(.plain)
153+
.help("Clear Custom Status")
154+
}
155+
} else {
156+
Label("Set Custom Status", systemImage: "face.smiling")
157+
.frame(maxWidth: .infinity, alignment: .leading)
158+
}
162159
}
160+
.buttonStyle(FlatButtonStyle(outlined: true, text: true))
161+
.controlSize(.small)
162+
.disabled(settingPresence)
163+
164+
Divider()
165+
163166
Button {
164-
updatePresence(with: .invisible)
167+
switcherPresented = true
168+
AnalyticsWrapper.event(type: .impressionAccountSwitcher)
165169
} label: {
166-
Image(systemName: Self.presenceIconMapping[.invisible]!)
167-
Text("user.presence.invisible")
168-
}
169-
} label: {
170-
Label(
171-
curUserPresence.toLocalizedString(),
172-
systemImage: Self.presenceIconMapping[curUserPresence] ?? "circle"
173-
)
174-
}
175-
.controlSize(.large)
176-
.disabled(settingPresence)
177-
Button {
178-
customStatusPresented = true
179-
} label: {
180-
if customStatus != nil {
181-
HStack {
182-
Text("Edit Custom Status")
183-
Spacer()
184-
Button {
185-
updatePresence(with: curUserPresence, clearCustomStatus: true)
186-
} label: {
187-
Image(systemName: "xmark.circle.fill").font(.system(size: 18))
188-
}
189-
.buttonStyle(.plain)
190-
.help("Clear Custom Status")
191-
}
192-
} else {
193-
Label("Set Custom Status", systemImage: "face.smiling")
170+
Label("Switch Accounts", systemImage: "arrow.left.arrow.right")
194171
.frame(maxWidth: .infinity, alignment: .leading)
195172
}
173+
.buttonStyle(FlatButtonStyle(outlined: true, text: true))
174+
.controlSize(.small)
196175
}
197-
.buttonStyle(FlatButtonStyle(outlined: true, text: true))
198-
.controlSize(.small)
199-
.disabled(settingPresence)
176+
}
177+
}
200178

201-
Divider()
179+
Spacer()
202180

203-
Button {
204-
switcherPresented = true
205-
AnalyticsWrapper.event(type: .impressionAccountSwitcher)
206-
} label: {
207-
Label("Switch Accounts", systemImage: "arrow.left.arrow.right")
208-
.frame(maxWidth: .infinity, alignment: .leading)
209-
}
210-
.buttonStyle(FlatButtonStyle(outlined: true, text: true))
211-
.controlSize(.small)
181+
Button(action: {
182+
if #available(macOS 13.0, *) {
183+
NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
184+
} else {
185+
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
212186
}
213-
}
187+
}, label: {
188+
Image(systemName: "gearshape.fill")
189+
.font(.system(size: 18))
190+
.opacity(0.75)
191+
})
192+
.buttonStyle(.plain)
193+
.frame(width: 32, height: 32)
214194
}
195+
.frame(height: 52)
196+
.padding(.horizontal, 8)
197+
.background(Color(nsColor: .controlBackgroundColor).opacity(0.5))
215198
.sheet(isPresented: $switcherPresented) {
216199
accountSwitcher()
217200
}

Swiftcord/Views/User/Profile/MiniUserProfileView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ struct MiniUserProfileView<RichContentSlot: View>: View {
125125
.fixedSize(horizontal: false, vertical: true)
126126
}
127127

128-
contentSlot.padding(.top, 6)
128+
contentSlot
129129
}
130130
}
131131
.padding(12)

0 commit comments

Comments
 (0)