Skip to content

Commit c1fada0

Browse files
committed
Move updates interface to "About" page
Rework forms, group boxes, and sections
1 parent e5d5504 commit c1fada0

File tree

11 files changed

+210
-169
lines changed

11 files changed

+210
-169
lines changed

Ice.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@
318318
INFOPLIST_FILE = Ice/Info.plist;
319319
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
320320
INFOPLIST_KEY_LSUIElement = YES;
321-
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Jordan Baird";
321+
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Jordan Baird";
322322
LD_RUNPATH_SEARCH_PATHS = (
323323
"$(inherited)",
324324
"@executable_path/../Frameworks",
@@ -351,7 +351,7 @@
351351
INFOPLIST_FILE = Ice/Info.plist;
352352
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
353353
INFOPLIST_KEY_LSUIElement = YES;
354-
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Jordan Baird";
354+
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Jordan Baird";
355355
LD_RUNPATH_SEARCH_PATHS = (
356356
"$(inherited)",
357357
"@executable_path/../Frameworks",

Ice/Main/Navigation/NavigationIdentifiers/SettingsNavigationIdentifier.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ enum SettingsNavigationIdentifier: String, NavigationIdentifier {
1010
case menuBarAppearance = "Menu Bar Appearance"
1111
case hotkeys = "Hotkeys"
1212
case advanced = "Advanced"
13-
case updates = "Updates"
1413
case about = "About"
1514
}

Ice/MenuBar/Appearance/MenuBarAppearanceEditor/MenuBarAppearanceEditor.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,11 @@ private struct LabeledPartialEditor: View {
223223
let appearance: SystemAppearance
224224

225225
var body: some View {
226-
IceSection {
226+
IceSection(options: .plain) {
227227
labelStack
228228
} content: {
229229
partialEditor
230230
}
231-
.bordered(false)
232-
.dividers(false)
233231
.onReceive(NSApp.publisher(for: \.effectiveAppearance)) { _ in
234232
currentAppearance = .current
235233
}

Ice/Settings/SettingsPanes/AboutSettingsPane.swift

Lines changed: 143 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
import SwiftUI
77

88
struct AboutSettingsPane: View {
9+
@EnvironmentObject var appState: AppState
910
@Environment(\.openURL) private var openURL
10-
@State private var frame = CGRect.zero
11+
12+
private var updatesManager: UpdatesManager {
13+
appState.updatesManager
14+
}
1115

1216
private var acknowledgementsURL: URL {
1317
// swiftlint:disable:next force_unwrapping
@@ -28,65 +32,154 @@ struct AboutSettingsPane: View {
2832
URL(string: "https://icemenubar.app/Donate")!
2933
}
3034

31-
private var minFrameDimension: CGFloat {
32-
min(frame.width, frame.height)
35+
private var lastUpdateCheckString: String {
36+
if let date = updatesManager.lastUpdateCheckDate {
37+
date.formatted(date: .abbreviated, time: .standard)
38+
} else {
39+
"Never"
40+
}
3341
}
3442

3543
var body: some View {
36-
HStack {
37-
if let nsImage = NSImage(named: NSImage.applicationIconName) {
38-
Image(nsImage: nsImage)
39-
.resizable()
40-
.aspectRatio(contentMode: .fit)
41-
.frame(width: minFrameDimension / 1.5)
42-
}
44+
VStack(spacing: 0) {
45+
mainForm
46+
Spacer(minLength: 20)
47+
bottomBar
48+
}
49+
.padding(30)
50+
}
4351

44-
VStack(alignment: .leading) {
45-
Text("Ice")
46-
.font(.system(size: minFrameDimension / 7))
47-
.foregroundStyle(.primary)
52+
@ViewBuilder
53+
private var mainForm: some View {
54+
IceForm(padding: EdgeInsets(top: 5, leading: 30, bottom: 30, trailing: 30), spacing: 0) {
55+
appIconAndCopyrightSection
56+
.layoutPriority(1)
4857

49-
HStack(spacing: 4) {
50-
Text("Version")
51-
Text(Constants.appVersion)
52-
}
53-
.font(.system(size: minFrameDimension / 30))
54-
.foregroundStyle(.secondary)
58+
Spacer(minLength: 0)
59+
.frame(maxHeight: 20)
5560

56-
Text(Constants.copyright)
57-
.font(.system(size: minFrameDimension / 37))
58-
.foregroundStyle(.tertiary)
59-
}
60-
.fontWeight(.medium)
61-
.padding([.vertical, .trailing])
61+
updatesSection
62+
.layoutPriority(1)
6263
}
63-
.frame(maxWidth: .infinity, maxHeight: .infinity)
64-
.onFrameChange(update: $frame)
65-
.bottomBar {
66-
HStack {
67-
Button("Quit Ice") {
68-
NSApp.terminate(nil)
69-
}
70-
Spacer()
71-
Button("Acknowledgements") {
72-
NSWorkspace.shared.open(acknowledgementsURL)
73-
}
74-
Button("Contribute") {
75-
openURL(contributeURL)
76-
}
77-
Button("Report a Bug") {
78-
openURL(issuesURL)
64+
.scrollDisabled(true)
65+
.frame(maxHeight: 500)
66+
.background(.quinary, in: RoundedRectangle(cornerRadius: 20, style: .circular))
67+
}
68+
69+
@ViewBuilder
70+
private var appIconAndCopyrightSection: some View {
71+
IceSection(options: .plain) {
72+
HStack(spacing: 10) {
73+
if let nsImage = NSImage(named: NSImage.applicationIconName) {
74+
Image(nsImage: nsImage)
75+
.resizable()
76+
.aspectRatio(contentMode: .fit)
77+
.frame(width: 225)
7978
}
80-
Button {
81-
openURL(donateURL)
82-
} label: {
83-
Label(
84-
"Support Ice",
85-
systemImage: "heart.circle.fill"
86-
)
79+
80+
VStack(alignment: .leading) {
81+
Text("Ice")
82+
.font(.system(size: 72, weight: .medium))
83+
.foregroundStyle(.primary)
84+
85+
Text("Version \(Constants.versionString)")
86+
.font(.system(size: 18))
87+
.foregroundStyle(.secondary)
88+
89+
Text(Constants.copyrightString)
90+
.font(.system(size: 14, weight: .medium))
91+
.foregroundStyle(.tertiary)
8792
}
8893
}
89-
.padding()
9094
}
9195
}
96+
97+
@ViewBuilder
98+
private var updatesSection: some View {
99+
IceSection(options: .hasDividers) {
100+
automaticallyCheckForUpdates
101+
automaticallyDownloadUpdates
102+
if updatesManager.canCheckForUpdates {
103+
checkForUpdates
104+
}
105+
}
106+
.frame(maxWidth: 600)
107+
}
108+
109+
@ViewBuilder
110+
private var automaticallyCheckForUpdates: some View {
111+
Toggle(
112+
"Automatically check for updates",
113+
isOn: updatesManager.bindings.automaticallyChecksForUpdates
114+
)
115+
}
116+
117+
@ViewBuilder
118+
private var automaticallyDownloadUpdates: some View {
119+
Toggle(
120+
"Automatically download updates",
121+
isOn: updatesManager.bindings.automaticallyDownloadsUpdates
122+
)
123+
}
124+
125+
@ViewBuilder
126+
private var checkForUpdates: some View {
127+
HStack {
128+
Button("Check for Updates") {
129+
updatesManager.checkForUpdates()
130+
}
131+
Spacer()
132+
Text("Last checked: \(lastUpdateCheckString)")
133+
.font(.caption)
134+
}
135+
}
136+
137+
@ViewBuilder
138+
private var bottomBar: some View {
139+
HStack {
140+
Button("Quit Ice") {
141+
NSApp.terminate(nil)
142+
}
143+
Spacer()
144+
Button("Acknowledgements") {
145+
NSWorkspace.shared.open(acknowledgementsURL)
146+
}
147+
Button("Contribute") {
148+
openURL(contributeURL)
149+
}
150+
Button("Report a Bug") {
151+
openURL(issuesURL)
152+
}
153+
Button("Support Ice", systemImage: "heart.circle.fill") {
154+
openURL(donateURL)
155+
}
156+
}
157+
.padding(8)
158+
.buttonStyle(BottomBarButtonStyle())
159+
.background(.quinary, in: Capsule(style: .circular))
160+
.frame(height: 40)
161+
}
162+
}
163+
164+
private struct BottomBarButtonStyle: ButtonStyle {
165+
@State private var isHovering = false
166+
167+
private var borderShape: some InsettableShape {
168+
Capsule(style: .circular)
169+
}
170+
171+
func makeBody(configuration: Configuration) -> some View {
172+
configuration.label
173+
.padding(.horizontal, 10)
174+
.padding(.vertical, 4)
175+
.background {
176+
borderShape
177+
.fill(configuration.isPressed ? .tertiary : .quaternary)
178+
.opacity(isHovering ? 1 : 0)
179+
}
180+
.contentShape([.focusEffect, .interaction], borderShape)
181+
.onHover { hovering in
182+
isHovering = hovering
183+
}
184+
}
92185
}

Ice/Settings/SettingsPanes/UpdatesSettingsPane.swift

Lines changed: 0 additions & 71 deletions
This file was deleted.

Ice/Settings/SettingsView.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ struct SettingsView: View {
7878
HotkeysSettingsPane()
7979
case .advanced:
8080
AdvancedSettingsPane()
81-
case .updates:
82-
UpdatesSettingsPane()
8381
case .about:
8482
AboutSettingsPane()
8583
}
@@ -104,7 +102,6 @@ struct SettingsView: View {
104102
case .menuBarAppearance: .systemSymbol("swatchpalette")
105103
case .hotkeys: .systemSymbol("keyboard")
106104
case .advanced: .systemSymbol("gearshape.2")
107-
case .updates: .systemSymbol("arrow.triangle.2.circlepath.circle")
108105
case .about: .assetCatalog(.iceCubeStroke)
109106
}
110107
}

Ice/UI/IceUI/IceForm.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import SwiftUI
77

88
struct IceForm<Content: View>: View {
9+
@Environment(\.isScrollEnabled) private var isScrollEnabled
910
@State private var contentFrame = CGRect.zero
1011

1112
private let alignment: HorizontalAlignment
@@ -41,15 +42,19 @@ struct IceForm<Content: View>: View {
4142
}
4243

4344
var body: some View {
44-
GeometryReader { geometry in
45-
if contentFrame.height > geometry.size.height {
46-
ScrollView {
45+
if isScrollEnabled {
46+
GeometryReader { geometry in
47+
if contentFrame.height > geometry.size.height {
48+
ScrollView {
49+
contentStack
50+
}
51+
.scrollContentBackground(.hidden)
52+
} else {
4753
contentStack
4854
}
49-
.scrollContentBackground(.hidden)
50-
} else {
51-
contentStack
5255
}
56+
} else {
57+
contentStack
5358
}
5459
}
5560

0 commit comments

Comments
 (0)