| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -1861,47 +1861,49 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let existingText: String = textView.text ?? ""
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let proposedText: String = (existingText as NSString).replacingCharacters(in: range, with: text)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Don't complicate things by mixing media attachments with oversize text attachments
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        guard proposedText.utf8.count <= kOversizeTextMessageSizeThreshold else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Logger.debug("long text was truncated")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.lengthLimitLabel.isHidden = false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // `range` represents the section of the existing text we will replace. We can re-use that space.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // Range is in units of NSStrings's standard UTF-16 characters. Since some of those chars could be
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // represented as single bytes in utf-8, while others may be 8 or more, the only way to be sure is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // to just measure the utf8 encoded bytes of the replaced substring.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let bytesAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").utf8.count
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if !FeatureFlags.sendingMediaWithOversizeText {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let existingText: String = textView.text ?? ""
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let proposedText: String = (existingText as NSString).replacingCharacters(in: range, with: text)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // Don't complicate things by mixing media attachments with oversize text attachments
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            guard proposedText.utf8.count <= kOversizeTextMessageSizeThreshold else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                Logger.debug("long text was truncated")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                self.lengthLimitLabel.isHidden = false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // `range` represents the section of the existing text we will replace. We can re-use that space.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // Range is in units of NSStrings's standard UTF-16 characters. Since some of those chars could be
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // represented as single bytes in utf-8, while others may be 8 or more, the only way to be sure is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // to just measure the utf8 encoded bytes of the replaced substring.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let bytesAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").utf8.count
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // Accept as much of the input as we can
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let byteBudget: Int = Int(kOversizeTextMessageSizeThreshold) - bytesAfterDelete
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                if byteBudget >= 0, let acceptableNewText = text.truncated(toByteCount: UInt(byteBudget)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // Accept as much of the input as we can
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let byteBudget: Int = Int(kOversizeTextMessageSizeThreshold) - bytesAfterDelete
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if byteBudget >= 0, let acceptableNewText = text.truncated(toByteCount: UInt(byteBudget)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                return false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.lengthLimitLabel.isHidden = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.lengthLimitLabel.isHidden = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // After verifying the byte-length is sufficiently small, verify the character count is within bounds.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            guard proposedText.count <= kMaxMessageBodyCharacterCount else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                Logger.debug("hit attachment message body character count limit")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // After verifying the byte-length is sufficiently small, verify the character count is within bounds.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        guard proposedText.count <= kMaxMessageBodyCharacterCount else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Logger.debug("hit attachment message body character count limit")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                self.lengthLimitLabel.isHidden = false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.lengthLimitLabel.isHidden = false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // `range` represents the section of the existing text we will replace. We can re-use that space.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let charsAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").count
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // `range` represents the section of the existing text we will replace. We can re-use that space.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let charsAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").count
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // Accept as much of the input as we can
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let charBudget: Int = Int(kMaxMessageBodyCharacterCount) - charsAfterDelete
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                if charBudget >= 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let acceptableNewText = String(text.prefix(charBudget))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // Accept as much of the input as we can
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let charBudget: Int = Int(kMaxMessageBodyCharacterCount) - charsAfterDelete
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if charBudget >= 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let acceptableNewText = String(text.prefix(charBudget))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                return false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Though we can wrap the text, we don't want to encourage multline captions, plus a "done" button
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |