66import SwiftUI
77
88struct 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}
0 commit comments