@@ -61,8 +61,7 @@ class UIMessageView: UIView {
6161 label. font = . systemFont( ofSize: 18 )
6262 label. textColor = textColor
6363 label. numberOfLines = 0
64- // label.setContentHuggingPriority(.defaultLow, for: .horizontal)
65- // label.setContentCompressionResistancePriority(.required, for: .horizontal)
64+
6665 return label
6766 } ( )
6867
@@ -105,11 +104,7 @@ class UIMessageView: UIView {
105104 }
106105
107106 private var isMultiline : Bool {
108- if let file = fullMessage. file,
109- let width = file. width,
110- let height = file. height,
111- height > width && width < 250
112- {
107+ if fullMessage. file != nil {
113108 return true
114109 }
115110
@@ -181,23 +176,63 @@ class UIMessageView: UIView {
181176
182177 private func setupMessageContainer( ) {
183178 if isMultiline {
184- multiLineContainer. addArrangedSubview ( messageLabel)
179+ setupMultilineMessage ( )
180+ } else {
181+ setupSingleLineMessage ( )
182+ }
183+ }
184+
185+ private func setupMultilineMessage( ) {
186+ if message. hasFile, message. hasText {
187+ let innerContainer = UIStackView ( )
188+ innerContainer. axis = . vertical
189+ innerContainer. translatesAutoresizingMaskIntoConstraints = false
190+ innerContainer. layoutMargins = UIEdgeInsets (
191+ top: 0 ,
192+ left: StackPadding . leading,
193+ bottom: 0 ,
194+ right: StackPadding . trailing
195+ )
196+ innerContainer. spacing = 10
197+ innerContainer. isLayoutMarginsRelativeArrangement = true
198+ innerContainer. insetsLayoutMarginsFromSafeArea = false
199+
200+ innerContainer. addArrangedSubview ( messageLabel)
185201
186202 let metadataContainer = UIStackView ( )
187203 metadataContainer. axis = . horizontal
188- metadataContainer. addArrangedSubview ( UIView ( ) ) // Spacer
204+ metadataContainer. translatesAutoresizingMaskIntoConstraints = false
205+ metadataContainer. addArrangedSubview ( UIView ( ) )
189206 metadataContainer. addArrangedSubview ( metadataView)
190- multiLineContainer . addArrangedSubview ( metadataContainer)
207+ innerContainer . addArrangedSubview ( metadataContainer)
191208
192- containerStack. addArrangedSubview ( multiLineContainer)
193- } else {
194- singleLineContainer. addArrangedSubview ( messageLabel)
195- singleLineContainer. addArrangedSubview ( metadataView)
209+ multiLineContainer. addArrangedSubview ( innerContainer)
196210
197- containerStack. addArrangedSubview ( singleLineContainer)
211+ containerStack. addArrangedSubview ( innerContainer)
212+ } else {
213+ multiLineContainer. addArrangedSubview ( messageLabel)
214+ if !message. hasFile || message. hasText {
215+ setupMultilineMetadata ( )
216+ containerStack. addArrangedSubview ( multiLineContainer)
217+ return
218+ }
198219 }
199220 }
200221
222+ private func setupMultilineMetadata( ) {
223+ let metadataContainer = UIStackView ( )
224+ metadataContainer. axis = . horizontal
225+ metadataContainer. addArrangedSubview ( UIView ( ) ) // Spacer
226+ metadataContainer. addArrangedSubview ( metadataView)
227+ multiLineContainer. addArrangedSubview ( metadataContainer)
228+ }
229+
230+ private func setupSingleLineMessage( ) {
231+ singleLineContainer. addArrangedSubview ( messageLabel)
232+ singleLineContainer. addArrangedSubview ( metadataView)
233+ containerStack. addArrangedSubview ( singleLineContainer)
234+ }
235+
201236 private func addGestureRecognizer( ) {
202237 bubbleView. isUserInteractionEnabled = true
203238 messageLabel. isUserInteractionEnabled = true
@@ -206,29 +241,98 @@ class UIMessageView: UIView {
206241 bubbleView. addGestureRecognizer ( tapGesture)
207242 }
208243
244+ enum StackPadding {
245+ static let top : CGFloat = 9
246+ static let leading : CGFloat = 12
247+ static let bottom : CGFloat = 9
248+ static let trailing : CGFloat = 12
249+ }
250+
209251 private func setupConstraints( ) {
210- NSLayoutConstraint . activate ( [
252+ let padding = NSDirectionalEdgeInsets (
253+ top: StackPadding . top,
254+ leading: StackPadding . leading,
255+ bottom: isMultiline ? 14 : StackPadding . bottom,
256+ trailing: StackPadding . trailing
257+ )
258+
259+ let baseConstraints : [ NSLayoutConstraint ] = [
211260 bubbleView. topAnchor. constraint ( equalTo: topAnchor) ,
212261 bubbleView. bottomAnchor. constraint ( equalTo: bottomAnchor) ,
213262 bubbleView. widthAnchor. constraint ( lessThanOrEqualTo: widthAnchor, multiplier: 0.9 ) ,
263+ ]
264+
265+ let withoutFileConstraints : [ NSLayoutConstraint ] = [
266+ containerStack. topAnchor. constraint (
267+ equalTo: bubbleView. topAnchor,
268+ constant: padding. top
269+ ) ,
270+ containerStack. leadingAnchor. constraint (
271+ equalTo: bubbleView. leadingAnchor,
272+ constant: padding. leading
273+ ) ,
274+ containerStack. trailingAnchor. constraint (
275+ equalTo: bubbleView. trailingAnchor,
276+ constant: - padding. trailing
277+ ) ,
278+ containerStack. bottomAnchor. constraint (
279+ equalTo: bubbleView. bottomAnchor,
280+ constant: - padding. bottom
281+ ) . withPriority ( . defaultHigh) ,
282+ ]
214283
284+ let withFileConstraints : [ NSLayoutConstraint ] = [
215285 containerStack. topAnchor. constraint (
216286 equalTo: bubbleView. topAnchor,
217- constant: labelVerticalPadding
287+ constant: 0
218288 ) ,
219289 containerStack. leadingAnchor. constraint (
220290 equalTo: bubbleView. leadingAnchor,
221- constant: labelHorizantalPadding
291+ constant: 0
222292 ) ,
223293 containerStack. trailingAnchor. constraint (
224294 equalTo: bubbleView. trailingAnchor,
225- constant: - labelHorizantalPadding
295+ constant: 0
226296 ) ,
227297 containerStack. bottomAnchor. constraint (
228298 equalTo: bubbleView. bottomAnchor,
229- constant: isMultiline ? - 14 : - labelVerticalPadding
299+ constant: 0
230300 ) . withPriority ( . defaultHigh) ,
231- ] )
301+ ]
302+
303+ let withFileAndTextConstraints : [ NSLayoutConstraint ] = [
304+ containerStack. topAnchor. constraint (
305+ equalTo: bubbleView. topAnchor,
306+ constant: 0
307+ ) ,
308+ containerStack. leadingAnchor. constraint (
309+ equalTo: bubbleView. leadingAnchor,
310+ constant: 0
311+ ) ,
312+ containerStack. trailingAnchor. constraint (
313+ equalTo: bubbleView. trailingAnchor,
314+ constant: 0
315+ ) ,
316+ containerStack. bottomAnchor. constraint (
317+ equalTo: bubbleView. bottomAnchor,
318+ constant: - padding. bottom
319+ ) . withPriority ( . defaultHigh) ,
320+ ]
321+
322+ let constraints : [ NSLayoutConstraint ] = switch ( message. hasFile, message. hasText) {
323+ case ( true , false ) :
324+ // File only
325+ withFileConstraints
326+ case ( true , true ) :
327+ // File with text
328+ withFileAndTextConstraints
329+ default :
330+ // Text only
331+ withoutFileConstraints
332+ }
333+
334+ NSLayoutConstraint . activate ( baseConstraints + constraints)
335+
232336 if outgoing {
233337 bubbleView. trailingAnchor. constraint ( equalTo: trailingAnchor, constant: - 8 ) . isActive = true
234338 } else {
@@ -575,3 +679,14 @@ extension String {
575679 contains { $0. isEmoji }
576680 }
577681}
682+
683+ extension Message {
684+ var hasFile : Bool {
685+ fileId != nil
686+ }
687+
688+ var hasText : Bool {
689+ guard let text else { return false }
690+ return !text. isEmpty
691+ }
692+ }
0 commit comments