@@ -86,21 +86,33 @@ struct UpdatesView: View {
8686 Text ( " v \( updatesModel. currentVersion) " )
8787 . font ( . system( size: 11 , weight: . medium) )
8888 . foregroundStyle ( . primary)
89+
90+ if !updatesModel. releases. isEmpty {
91+ Button {
92+ activeSheet = . releaseNotes
93+ } label: {
94+ Text ( " Release notes " )
95+ . font ( . system( size: 11 , weight: . medium) )
96+ }
97+ . buttonStyle ( . link)
98+ }
8999 }
90100 }
91101 }
92102
93103 HStack ( spacing: 12 ) {
94104 if let descriptor = currentOperationStatusDescriptor {
95105 UpdateOperationStatusView ( descriptor: descriptor)
96- . frame ( maxWidth: . infinity)
97106 } else {
98- Button ( action: updatesModel. checkForUpdates) {
99- Label ( " Check for updates " , systemImage: " arrow.clockwise " )
100- . font ( . system( size: 13 , weight: . semibold) )
101- . labelStyle ( . titleAndIcon)
107+ // Pokaż ręczne sprawdzanie tylko, gdy auto-check = Never
108+ if updatesModel. frequency == . never {
109+ Button ( action: updatesModel. checkForUpdates) {
110+ Label ( " Check for updates " , systemImage: " arrow.clockwise " )
111+ . font ( . system( size: 13 , weight: . semibold) )
112+ . labelStyle ( . titleAndIcon)
113+ }
114+ . buttonStyle ( UpdatesPrimaryButtonStyle ( ) ) // domyślny akcentowy kolor
102115 }
103- . buttonStyle ( UpdatesPrimaryButtonStyle ( ) )
104116 }
105117
106118 if currentOperationStatusDescriptor == nil && updatesModel. updateAvailable {
@@ -109,27 +121,7 @@ struct UpdatesView: View {
109121 . font ( . system( size: 13 , weight: . semibold) )
110122 . labelStyle ( . titleAndIcon)
111123 }
112- . buttonStyle ( UpdatesSecondaryButtonStyle ( ) )
113- }
114-
115- // if updatesModel.announcementAvailable {
116- // Button {
117- // activeSheet = .announcement
118- // } label: {
119- // Label("View announcement", systemImage: "sparkles")
120- // .font(.system(size: 12, weight: .medium))
121- // }
122- // .buttonStyle(.link)
123- // }
124-
125- if !updatesModel. releases. isEmpty {
126- Button {
127- activeSheet = . releaseNotes
128- } label: {
129- Label ( " Release notes " , systemImage: " doc.richtext " )
130- . font ( . system( size: 12 , weight: . medium) )
131- }
132- . buttonStyle ( . link)
124+ . buttonStyle ( UpdatesPrimaryButtonStyle ( color: . orange) )
133125 }
134126 }
135127
@@ -153,11 +145,10 @@ struct UpdatesView: View {
153145 Spacer ( )
154146 Button ( action: updatesModel. restartApplication) {
155147 Label ( " Restart " , systemImage: " power " )
156- . font ( . system( size: 12 , weight: . semibold) )
157- . padding ( . vertical, 4 )
158- . padding ( . horizontal, 10 )
148+ . font ( . system( size: 13 , weight: . semibold) )
149+ . labelStyle ( . titleAndIcon)
159150 }
160- . buttonStyle ( . borderedProminent )
151+ . buttonStyle ( UpdatesPrimaryButtonStyle ( color : . blue ) )
161152 }
162153 }
163154 . padding ( 14 )
@@ -459,16 +450,18 @@ private struct ReleaseNotesSheet: View {
459450 let onDismiss : ( ) -> Void
460451
461452 var body : some View {
453+ let releasesToShow = Array ( releases. prefix ( 3 ) )
454+
462455 VStack ( spacing: 16 ) {
463- header
456+ header ( count : releasesToShow . count )
464457
465- if releases . isEmpty {
458+ if releasesToShow . isEmpty {
466459 emptyState
467460 } else {
468461 ScrollView {
469462 LazyVStack ( alignment: . leading, spacing: 18 ) {
470- ForEach ( releases , id: \. id) { release in
471- releaseCard ( for: release)
463+ ForEach ( releasesToShow , id: \. id) { release in
464+ releaseCard ( for: release, releasesToShow : releasesToShow )
472465 . padding ( . horizontal, 2 )
473466 }
474467 }
@@ -482,7 +475,7 @@ private struct ReleaseNotesSheet: View {
482475 . frame ( maxWidth: . infinity, alignment: . leading)
483476 }
484477
485- private var header : some View {
478+ private func header( count : Int ) -> some View {
486479 HStack ( alignment: . center, spacing: 10 ) {
487480 Image ( systemName: " doc.richtext " )
488481 . font ( . system( size: 20 , weight: . semibold) )
@@ -491,7 +484,7 @@ private struct ReleaseNotesSheet: View {
491484 VStack ( alignment: . leading, spacing: 2 ) {
492485 Text ( " Recent release notes " )
493486 . font ( . headline)
494- Text ( " Pulled straight from GitHub " )
487+ Text ( " Showing last \( count ) releases " )
495488 . font ( . subheadline)
496489 . foregroundStyle ( . secondary)
497490 }
@@ -517,9 +510,9 @@ private struct ReleaseNotesSheet: View {
517510 }
518511
519512 @ViewBuilder
520- private func releaseCard( for release: SettingsRelease ) -> some View {
513+ private func releaseCard( for release: SettingsRelease , releasesToShow : [ SettingsRelease ] ) -> some View {
521514 let title = release. tagName. isEmpty ? release. displayTitle : release. tagName
522- let isLatest = release. id == releases . first? . id
515+ let isLatest = release. id == releasesToShow . first? . id
523516
524517 VStack ( alignment: . leading, spacing: 10 ) {
525518 HStack ( alignment: . center, spacing: 8 ) {
@@ -564,39 +557,66 @@ private struct ReleaseNotesSheet: View {
564557private struct UpdateOperationStatusView : View {
565558 let descriptor : UpdateOperationStatusDescriptor
566559
560+ // Nie skalujemy widoku, gdy pokazujemy spinner — to eliminuje błąd NSProgressIndicator.
561+ private var scale : CGFloat {
562+ if descriptor. showsSpinner { return 1.0 }
563+ if let progress = descriptor. progress {
564+ return 1.0 + CGFloat( min ( max ( progress, 0 ) , 1 ) ) * 0.04
565+ }
566+ return 1.0
567+ }
568+
567569 var body : some View {
568- HStack ( alignment: . center, spacing: 12 ) {
570+ let shape = RoundedRectangle ( cornerRadius: 12 , style: . continuous)
571+ let base = descriptor. iconColor
572+
573+ HStack ( alignment: . center, spacing: 10 ) {
569574 if descriptor. showsSpinner {
570575 ProgressView ( )
571576 . controlSize ( . small)
577+ . tint ( . white)
578+ . frame ( width: 16 , height: 16 )
572579 } else if let icon = descriptor. iconName {
573580 Image ( systemName: icon)
574- . font ( . system( size: 16 , weight: . semibold) )
575- . foregroundStyle ( descriptor . iconColor )
576- . frame ( width: 18 )
581+ . font ( . system( size: 13 , weight: . semibold) )
582+ . foregroundStyle ( Color . white )
583+ . frame ( width: 16 , height : 16 )
577584 }
578585
579586 Text ( descriptor. title)
580587 . font ( . system( size: 13 , weight: . semibold) )
581- . foregroundStyle ( descriptor. textColor)
582- . frame ( maxWidth: . infinity, alignment: . leading)
588+ . foregroundStyle ( Color . white)
583589
584590 if let progress = descriptor. progress {
585591 Text ( progressFormatted ( progress) )
586592 . font ( . system( size: 12 , weight: . semibold) )
587- . foregroundStyle ( descriptor . iconColor )
593+ . foregroundStyle ( Color . white . opacity ( 0.95 ) )
588594 }
589595 }
590- . padding ( . vertical, 10 )
591- . padding ( . horizontal, 12 )
596+ . fixedSize ( horizontal: true , vertical: false )
597+ . padding ( . vertical, 8 )
598+ . padding ( . horizontal, 14 )
592599 . background (
593- RoundedRectangle ( cornerRadius: 12 , style: . continuous)
594- . fill ( descriptor. background)
600+ ZStack {
601+ shape. fill (
602+ LinearGradient (
603+ colors: [ base. opacity ( 0.98 ) , base. opacity ( 0.78 ) ] ,
604+ startPoint: . topLeading,
605+ endPoint: . bottomTrailing
606+ )
607+ )
608+ shape. stroke ( Color . white. opacity ( 0.18 ) , lineWidth: 0.6 )
609+ . blur ( radius: 0.4 )
610+ . clipShape ( shape)
611+ }
595612 )
596613 . overlay (
597- RoundedRectangle ( cornerRadius: 12 , style: . continuous)
598- . stroke ( descriptor. border, lineWidth: 1 )
614+ shape. stroke ( base. opacity ( 0.55 ) , lineWidth: 1 )
599615 )
616+ . shadow ( color: base. opacity ( 0.45 ) , radius: 6 , y: 4 )
617+ // Animację skali włączamy tylko, gdy spinner nie jest aktywny.
618+ . scaleEffect ( scale)
619+ . animation ( descriptor. showsSpinner ? nil : . easeInOut( duration: 0.2 ) , value: scale)
600620 }
601621
602622 private func progressFormatted( _ value: Double ) -> String {
@@ -662,7 +682,7 @@ private struct FrequencyOptionButtonStyle: ButtonStyle {
662682 . background (
663683 ZStack {
664684 RoundedRectangle ( cornerRadius: 12 , style: . continuous)
665- . fill ( . ultraThinMaterial )
685+ . fill ( Color . white . opacity ( 0.03 ) )
666686
667687 if isHovered {
668688 RoundedRectangle ( cornerRadius: 12 , style: . continuous)
@@ -680,26 +700,22 @@ private struct FrequencyOptionButtonStyle: ButtonStyle {
680700 }
681701 }
682702 )
683- . overlay (
684- RoundedRectangle ( cornerRadius: 12 , style: . continuous)
685- . stroke ( Color . white. opacity ( isSelected ? 0.3 : 0.12 ) , lineWidth: isSelected ? 1.1 : 1 )
686- )
687703 . scaleEffect ( configuration. isPressed ? 0.97 : 1 )
688704 . animation ( . easeInOut( duration: 0.12 ) , value: configuration. isPressed)
689705 }
690706}
691707
692708private struct UpdatesPrimaryButtonStyle : ButtonStyle {
709+ var color : Color = . accentColor
693710 @Environment ( \. isEnabled) private var isEnabled
694711
695712 func makeBody( configuration: Configuration ) -> some View {
696713 let shape = RoundedRectangle ( cornerRadius: 12 , style: . continuous)
697- let accent = Color . accentColor
698714 let activeOpacity : Double = configuration. isPressed ? 0.85 : 1.0
699715 let inactiveOpacity : Double = configuration. isPressed ? 0.65 : 0.78
700716 let gradientColors : [ Color ] = isEnabled
701- ? [ accent . opacity ( activeOpacity) , accent . opacity ( inactiveOpacity) ]
702- : [ accent . opacity ( 0.42 ) , accent . opacity ( 0.32 ) ]
717+ ? [ color . opacity ( activeOpacity) , color . opacity ( inactiveOpacity) ]
718+ : [ color . opacity ( 0.42 ) , color . opacity ( 0.32 ) ]
703719
704720 return configuration. label
705721 . foregroundColor ( isEnabled ? Color . white : Color . white. opacity ( 0.7 ) )
@@ -717,9 +733,9 @@ private struct UpdatesPrimaryButtonStyle: ButtonStyle {
717733 }
718734 )
719735 . overlay (
720- shape. stroke ( accent . opacity ( isEnabled ? 0.55 : 0.32 ) , lineWidth: 1 )
736+ shape. stroke ( color . opacity ( isEnabled ? 0.55 : 0.32 ) , lineWidth: 1 )
721737 )
722- . shadow ( color: accent . opacity ( isEnabled ? 0.45 : 0.2 ) , radius: configuration. isPressed ? 4 : 8 , y: configuration. isPressed ? 2 : 6 )
738+ . shadow ( color: color . opacity ( isEnabled ? 0.45 : 0.2 ) , radius: configuration. isPressed ? 4 : 8 , y: configuration. isPressed ? 2 : 6 )
723739 . scaleEffect ( configuration. isPressed ? 0.97 : 1 )
724740 . animation ( . easeInOut( duration: 0.12 ) , value: configuration. isPressed)
725741 }
0 commit comments