mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
1224e539ea
Updated the database to better support the application getting suspended (0xdead10cc crash) Updated the SOGS message handling to delete messages based on a new 'deleted' flag instead of 'data' being null Updated the code to prevent the typing indicator from needing a DB write block as frequently Updated the code to stop any pending jobs when entering the background (in an attempt to prevent the database suspension from causing issues) Removed the duplicate 'Capabilities.Capability' type (updated 'Capability.Variant' to work in the same way) Fixed a bug where a number of icons (inc. the "download document" icon) were the wrong colour in dark mode Fixed a bug where the '@You' highlight could incorrectly have it's width reduced in some cases (had protection to prevent it being larger than the line, but that is a valid case) Fixed a bug where the JobRunner was starting the background (which could lead to trying to access the database once it had been suspended) Updated to the latest version of GRDB Added some logic to the BackgroundPoller process to try and stop processing if the timeout is triggered (will catch some cases but others will end up logging a bunch of "Database is suspended" errors) Added in some protection to prevent future deferral loops in the JobRunner
159 lines
6.7 KiB
Swift
159 lines
6.7 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import UIKit
|
|
|
|
public extension NSAttributedString.Key {
|
|
static let currentUserMentionBackgroundColor: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundColor")
|
|
static let currentUserMentionBackgroundCornerRadius: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundCornerRadius")
|
|
static let currentUserMentionBackgroundPadding: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundPadding")
|
|
}
|
|
|
|
class HighlightMentionBackgroundView: UIView {
|
|
var maxPadding: CGFloat = 0
|
|
|
|
init() {
|
|
super.init(frame: .zero)
|
|
|
|
self.isOpaque = false
|
|
self.layer.zPosition = -1
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
// MARK: - Functions
|
|
|
|
public func calculateMaxPadding(for attributedText: NSAttributedString) -> CGFloat {
|
|
var allMentionRadii: [CGFloat?] = []
|
|
let path: CGMutablePath = CGMutablePath()
|
|
path.addRect(CGRect(
|
|
x: 0,
|
|
y: 0,
|
|
width: CGFloat.greatestFiniteMagnitude,
|
|
height: CGFloat.greatestFiniteMagnitude
|
|
))
|
|
|
|
let framesetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString)
|
|
let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedText.length), path, nil)
|
|
let lines: [CTLine] = frame.lines
|
|
|
|
lines.forEach { line in
|
|
let runs: [CTRun] = line.ctruns
|
|
|
|
runs.forEach { run in
|
|
let attributes: NSDictionary = CTRunGetAttributes(run)
|
|
allMentionRadii.append(
|
|
attributes
|
|
.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundPadding.rawValue) as? CGFloat
|
|
)
|
|
}
|
|
}
|
|
|
|
return allMentionRadii
|
|
.compactMap { $0 }
|
|
.max()
|
|
.defaulting(to: 0)
|
|
}
|
|
|
|
// MARK: - Drawing
|
|
|
|
override func draw(_ rect: CGRect) {
|
|
guard
|
|
let superview: UITextView = (self.superview as? UITextView),
|
|
let context = UIGraphicsGetCurrentContext()
|
|
else { return }
|
|
|
|
// Need to invery the Y axis because iOS likes to render from the bottom left instead of the top left
|
|
context.textMatrix = .identity
|
|
context.translateBy(x: 0, y: bounds.size.height)
|
|
context.scaleBy(x: 1.0, y: -1.0)
|
|
|
|
// Note: Calculations MUST happen based on the 'superview' size as this class has extra padding which
|
|
// can result in calculations being off
|
|
let path = CGMutablePath()
|
|
let size = superview.sizeThatFits(CGSize(width: superview.bounds.width, height: .greatestFiniteMagnitude))
|
|
path.addRect(CGRect(x: 0, y: 0, width: size.width, height: size.height), transform: .identity)
|
|
|
|
let framesetter = CTFramesetterCreateWithAttributedString(superview.attributedText as CFAttributedString)
|
|
let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, superview.attributedText.length), path, nil)
|
|
let lines: [CTLine] = frame.lines
|
|
|
|
var origins = [CGPoint](repeating: .zero, count: lines.count)
|
|
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &origins)
|
|
|
|
for lineIndex in 0..<lines.count {
|
|
let line = lines[lineIndex]
|
|
let runs: [CTRun] = line.ctruns
|
|
var ascent: CGFloat = 0
|
|
var descent: CGFloat = 0
|
|
var leading: CGFloat = 0
|
|
let lineWidth = CGFloat(CTLineGetTypographicBounds(line, &ascent, &descent, &leading))
|
|
|
|
for run in runs {
|
|
let attributes: NSDictionary = CTRunGetAttributes(run)
|
|
|
|
guard let mentionBackgroundColor: UIColor = attributes.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundColor.rawValue) as? UIColor else {
|
|
continue
|
|
}
|
|
|
|
let cornerRadius: CGFloat = (attributes
|
|
.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundCornerRadius.rawValue) as? CGFloat)
|
|
.defaulting(to: 0)
|
|
let padding: CGFloat = (attributes
|
|
.value(forKey: NSAttributedString.Key.currentUserMentionBackgroundPadding.rawValue) as? CGFloat)
|
|
.defaulting(to: 0)
|
|
|
|
let range = CTRunGetStringRange(run)
|
|
var runBounds: CGRect = .zero
|
|
var runAscent: CGFloat = 0
|
|
var runDescent: CGFloat = 0
|
|
runBounds.size.width = CGFloat(CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &runAscent, &runDescent, nil) + (padding * 2))
|
|
runBounds.size.height = (runAscent + runDescent + (padding * 2))
|
|
|
|
let xOffset: CGFloat = {
|
|
switch CTRunGetStatus(run) {
|
|
case .rightToLeft:
|
|
return CTLineGetOffsetForStringIndex(line, range.location + range.length, nil)
|
|
|
|
default:
|
|
return CTLineGetOffsetForStringIndex(line, range.location, nil)
|
|
}
|
|
}()
|
|
|
|
// HACK: This `extraYOffset` value is a hack to resolve a weird issue where the positioning
|
|
// seems to be slightly off every additional line of text we add (it doesn't seem to be related
|
|
// to line spacing or anything, more related to the bold mention text being positioned slightly
|
|
// differently from the non-bold text)
|
|
let extraYOffset: CGFloat = (CGFloat(lineIndex) * (runDescent / 12))
|
|
|
|
// Note: Changes to `origin.y` need to be inverted since the context has been flipped
|
|
runBounds.origin.x = origins[lineIndex].x + rect.origin.x + self.maxPadding + xOffset - padding
|
|
runBounds.origin.y = (
|
|
origins[lineIndex].y + rect.origin.y +
|
|
self.maxPadding -
|
|
padding -
|
|
runDescent -
|
|
extraYOffset
|
|
)
|
|
|
|
let path = UIBezierPath(roundedRect: runBounds, cornerRadius: cornerRadius)
|
|
mentionBackgroundColor.setFill()
|
|
path.fill()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension CTFrame {
|
|
var lines: [CTLine] {
|
|
return ((CTFrameGetLines(self) as [AnyObject] as? [CTLine]) ?? [])
|
|
}
|
|
}
|
|
|
|
extension CTLine {
|
|
var ctruns: [CTRun] {
|
|
return ((CTLineGetGlyphRuns(self) as [AnyObject] as? [CTRun]) ?? [])
|
|
}
|
|
}
|