@@ -22,6 +22,8 @@ final class UpdateTabView : Control {
2222 let imageView : ImageView = ImageView ( )
2323 let shimmer = ShimmerEffectView ( )
2424 let progressView : ProgressIndicator = ProgressIndicator ( frame : NSMakeRect ( 0 , 0 , 24 , 24 ) )
25+ private let glassView = LiquidGlassView ( frame : . zero , cornerRadius : 20 )
26+ private var updateState : UpdateButtonState = . common
2527
2628 var bottomOverlayChanged : ( ( ) -> Void ) ?
2729
@@ -37,96 +39,107 @@ final class UpdateTabView : Control {
3739
3840 var isInstalling : Bool = false {
3941 didSet {
40- shimmer . change ( opacity : isInstalling ? 0 : 1 )
41- textView . isHidden = isInstalling || layoutState == . minimisize
42- progressView . isHidden = ! isInstalling
43- imageView . isHidden = isInstalling || layoutState != . minimisize
44-
45- if layoutState != . minimisize , isInstalling , let superview = self . superview {
46- self . layer ? . cornerRadius = frame . height / 2
47- change ( size : NSMakeSize ( 60 , frame . height ) , animated : true , timingFunction : . spring )
48- change ( pos : NSMakePoint ( superview . bounds . focus ( self . frame . size ) . minX , self . frame . minY ) , animated : true , timingFunction : . spring )
49- progressView . change ( pos : self . bounds . focus ( progressView . frame . size ) . origin , animated : true , timingFunction : . spring )
50- } else {
51- if let superview = self . superview , isChatList {
52- change ( size : NSMakeSize ( self . textView . frame . width + 40 , frame . height ) , animated : true , timingFunction : . spring )
53- change ( pos : NSMakePoint ( superview . bounds . focus ( self . frame . size ) . minX , self . frame . minY ) , animated : true , timingFunction : . spring )
54- imageView . change ( pos : self . bounds . focus ( imageView . frame . size ) . origin , animated : true , timingFunction : . spring )
55- }
56- }
57-
42+ updateContent ( animated : isInstalling != oldValue )
5843 }
5944 }
6045
6146 var layoutState : SplitViewState = . dual {
6247 didSet {
63- let installing = self . isInstalling
64- self . isInstalling = installing
48+ updateContent ( animated : false )
6549 }
6650 }
67-
68-
69-
51+
52+ var preferredWidth : CGFloat {
53+ if layoutState == . minimisize {
54+ return 40
55+ }
56+ return isInstalling ? 60 : textView . frame . width + 40
57+ }
58+
59+ private func updateContent ( animated : Bool ) {
60+ shimmer . change ( opacity : isInstalling ? 0 : 1 , animated : animated )
61+ textView . isHidden = isInstalling || layoutState == . minimisize
62+ progressView . isHidden = ! isInstalling
63+ imageView . isHidden = isInstalling || layoutState != . minimisize
64+ if isChatList , let superview , frame . width != preferredWidth {
65+ change ( size : NSMakeSize ( preferredWidth , frame . height ) , animated : animated , timingFunction : . spring )
66+ change ( pos : NSMakePoint ( superview . bounds . focus ( frame . size ) . minX , frame . minY ) , animated : animated , timingFunction : . spring )
67+ }
68+ needsLayout = true
69+ }
70+
7071 required init ( frame frameRect : NSRect ) {
7172 super . init ( frame : frameRect )
73+ backgroundColor = . clear
74+ layer ? . masksToBounds = false
75+ glassView . isEventLess = true
76+ addSubview ( glassView )
77+ interactiveGlassView = glassView
78+ scaleOnClick = true
7279 textView . userInteractionEnabled = false
7380 textView . isSelectable = false
81+ textView . disableBackgroundDrawing = true
82+ textView . isAccessibilityDecorative = true
7483 addSubview ( textView )
84+ progressView . isEventLess = true
85+ progressView . isAccessibilityDecorative = true
7586 addSubview ( progressView )
87+ imageView . isEventLess = true
88+ imageView . isAccessibilityDecorative = true
7689 addSubview ( imageView )
90+ shimmer . isEventLess = true
91+ shimmer . layer ? . masksToBounds = true
7792 addSubview ( shimmer )
78-
7993 shimmer . isStatic = true
80-
81- progressView . progressColor = theme . colors . underSelectedColor
82- isInstalling = false
83-
84- let layout = TextViewLayout ( . initialize ( string : strings ( ) . updateUpdateTelegram , color : theme . colors . underSelectedColor , font : . medium ( . title ) ) )
85- layout . measure ( width : max ( 280 , frame . width ) )
86- textView . update ( layout )
87- imageView . isAccessibilityDecorative = true
88- setAccessibilityLabel ( strings ( ) . updateUpdateTelegram )
89-
90- let shadow = NSShadow ( )
91- shadow . shadowBlurRadius = 5
92- shadow . shadowColor = NSColor . black . withAlphaComponent ( 0.3 )
93- shadow . shadowOffset = NSMakeSize ( 0 , 2 )
94- self . shadow = shadow
95-
94+ updateLocalizationAndTheme ( theme : theme )
9695 }
9796
9897 override func cursorUpdate ( with event : NSEvent ) {
9998 NSCursor . pointingHand . set ( )
10099 }
101100
102- override var backgroundColor : NSColor {
103- didSet {
104- textView . backgroundColor = backgroundColor
105- }
101+ func update ( _ state : UpdateButtonState ) {
102+ updateState = state
103+ updateLocalizationAndTheme ( theme : theme )
106104 }
107-
105+
108106 override func updateLocalizationAndTheme ( theme : PresentationTheme ) {
109107 super . updateLocalizationAndTheme ( theme : theme )
110- imageView . image = ( theme as! TelegramPresentationTheme ) . icons . appUpdate
108+ let theme = theme as! TelegramPresentationTheme
109+ let tint : NSColor
110+ switch updateState {
111+ case . common :
112+ tint = theme . colors . accent
113+ case . important :
114+ tint = theme . colors . greenUI
115+ case . critical :
116+ tint = theme . colors . redUI
117+ }
118+ glassView . customTint = tint
119+ let foreground = tint . lightness > 0.8 ? NSColor ( 0x000000 ) : NSColor ( 0xffffff )
120+ let layout = TextViewLayout ( . initialize ( string : strings ( ) . updateUpdateTelegram , color : foreground , font : . medium ( . title ) ) , maximumNumberOfLines : 1 )
121+ layout . measure ( width : max ( 280 , frame . width ) )
122+ textView . update ( layout )
123+ imageView . image = generateTintedImage ( image : theme . icons . appUpdate , color : foreground )
111124 imageView . sizeToFit ( )
112- needsLayout = true
113- shimmer . updateAbsoluteRect ( bounds , within : bounds . size )
114- shimmer . update ( backgroundColor : . clear , foregroundColor : . clear , shimmeringColor : NSColor . white . withAlphaComponent ( 0.3 ) , shapes : [ . roundedRect ( rect : bounds , cornerRadius : bounds . height / 2 ) ] , horizontal : true , size : bounds . size )
115- progressView . progressColor = theme . colors . underSelectedColor
116- }
117-
118- override func setFrameOrigin ( _ newOrigin : NSPoint ) {
119- super . setFrameOrigin ( newOrigin )
125+ progressView . progressColor = foreground
126+ setAccessibilityLabel ( strings ( ) . updateUpdateTelegram )
127+ updateContent ( animated : false )
120128 }
121-
122-
129+
123130 override func layout ( ) {
124131 super . layout ( )
125-
126-
127-
132+ let cornerRadius : CGFloat = isChatList ? bounds . height / 2 : 0
133+ layer ? . cornerRadius = cornerRadius
134+ glassView . cornerRadius = cornerRadius
135+ glassView . frame = bounds
136+ glassView . updateLayout ( size : bounds . size , transition : . immediate )
128137 shimmer . frame = bounds
129- shimmer . layer ? . cornerRadius = bounds . height / 2
138+ shimmer . layer ? . cornerRadius = cornerRadius
139+ if bounds . width > 0 , bounds . height > 0 {
140+ shimmer . updateAbsoluteRect ( bounds , within : bounds . size )
141+ shimmer . update ( backgroundColor : . clear , foregroundColor : . clear , shimmeringColor : NSColor . white . withAlphaComponent ( 0.3 ) , shapes : [ . roundedRect ( rect : bounds , cornerRadius : cornerRadius ) ] , horizontal : true , size : bounds . size )
142+ }
130143 textView . center ( )
131144 progressView . center ( )
132145 imageView . center ( )
@@ -145,14 +158,7 @@ final class UpdateTabController: GenericViewController<UpdateTabView> {
145158 private let context : SharedAccountContext
146159 private var state : UpdateButtonState = . common {
147160 didSet {
148- switch state {
149- case . common :
150- genericView . backgroundColor = theme . colors . accent
151- case . important :
152- genericView . backgroundColor = theme . colors . greenUI
153- case . critical :
154- genericView . backgroundColor = theme . colors . redUI
155- }
161+ genericView . update ( state )
156162 }
157163 }
158164 private var parentSize : NSSize = . zero
@@ -204,7 +210,7 @@ final class UpdateTabController: GenericViewController<UpdateTabView> {
204210 let context = self . context
205211
206212
207- genericView . set ( background : theme . colors . grayForeground , for : . Normal )
213+ genericView . set ( background : . clear , for : . Normal )
208214 genericView . isHidden = true
209215
210216 #if APP_STORE
@@ -254,20 +260,17 @@ final class UpdateTabController: GenericViewController<UpdateTabView> {
254260 }
255261
256262 func updateLayout ( _ layout : SplitViewState , parentSize : NSSize , isChatList : Bool ) {
263+ genericView . isChatList = isChatList
257264 genericView . layoutState = layout
258265 self . parentSize = parentSize
259- genericView . isChatList = isChatList
260266 if isChatList && layout == . minimisize {
261- // Icon-only circular button in single-column minimisize mode —
262- // there's no room for the text pill, so render as a 40×40 circle
263- // centered horizontally above the bottom edge.
264267 let side : CGFloat = 40
265268 genericView . setFrameSize ( NSMakeSize ( side , side ) )
266269 genericView . layer ? . cornerRadius = side / 2
267270 genericView . centerX ( y : parentSize . height - side - 10 )
268271 shakeDisposable . set ( nil )
269272 } else if isChatList {
270- genericView . setFrameSize ( NSMakeSize ( genericView . textView . frame . width + 40 , 40 ) )
273+ genericView . setFrameSize ( NSMakeSize ( genericView . preferredWidth , 40 ) )
271274 genericView . layer ? . cornerRadius = genericView . frame . height / 2
272275 let bottom = parentSize . height - genericView . frame . height
273276 genericView . centerX ( y : bottom - 60 )
0 commit comments