Compare commits
No commits in common. "999118798c01976725aa674920b6d882cfcaa2c0" and "b9555cf7dd0c90081ddc95191cd6c9cb0b109512" have entirely different histories.
999118798c
...
b9555cf7dd
|
@ -22,7 +22,8 @@ extension NSTextAttachment {
|
||||||
image.draw(in: CGRect(origin: .zero, size: imageSizeMatchingFontSize))
|
image.draw(in: CGRect(origin: .zero, size: imageSizeMatchingFontSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.init(image: attachmentImage)
|
self.init()
|
||||||
|
self.image = attachmentImage
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(emojiPlaceholderIn font: UIFont) {
|
convenience init(emojiPlaceholderIn font: UIFont) {
|
||||||
|
@ -30,6 +31,7 @@ extension NSTextAttachment {
|
||||||
// assumes emoji are mostly square
|
// assumes emoji are mostly square
|
||||||
let size = CGSize(width: adjustedCapHeight, height: adjustedCapHeight)
|
let size = CGSize(width: adjustedCapHeight, height: adjustedCapHeight)
|
||||||
let image = UIGraphicsImageRenderer(size: size).image { (_) in }
|
let image = UIGraphicsImageRenderer(size: size).image { (_) in }
|
||||||
self.init(image: image)
|
self.init()
|
||||||
|
self.image = image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,11 @@ import Pachyderm
|
||||||
|
|
||||||
extension StatusState {
|
extension StatusState {
|
||||||
|
|
||||||
func resolveFor(status: StatusMO, height: CGFloat) {
|
func resolveFor(status: StatusMO, text: String?) {
|
||||||
let longEnoughToCollapse: Bool
|
let longEnoughToCollapse: Bool
|
||||||
if Preferences.shared.collapseLongPosts,
|
if Preferences.shared.collapseLongPosts,
|
||||||
height > 500 {
|
let text = text,
|
||||||
|
text.count > 500 {
|
||||||
longEnoughToCollapse = true
|
longEnoughToCollapse = true
|
||||||
} else {
|
} else {
|
||||||
longEnoughToCollapse = false
|
longEnoughToCollapse = false
|
||||||
|
|
|
@ -64,18 +64,3 @@ extension Status.Visibility {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Status.Visibility: Comparable {
|
|
||||||
public static func < (lhs: Pachyderm.Status.Visibility, rhs: Pachyderm.Status.Visibility) -> Bool {
|
|
||||||
switch (lhs, rhs) {
|
|
||||||
case (.direct, .public), (.private, .public), (.unlisted, .public):
|
|
||||||
return true
|
|
||||||
case (.direct, .unlisted), (.private, .unlisted):
|
|
||||||
return true
|
|
||||||
case (.direct, .private):
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -187,14 +187,14 @@ extension MastodonController {
|
||||||
func createDraft(inReplyToID: String? = nil, mentioningAcct: String? = nil) -> Draft {
|
func createDraft(inReplyToID: String? = nil, mentioningAcct: String? = nil) -> Draft {
|
||||||
var acctsToMention = [String]()
|
var acctsToMention = [String]()
|
||||||
|
|
||||||
var visibility = inReplyToID != nil ? Preferences.shared.defaultReplyVisibility.resolved : Preferences.shared.defaultPostVisibility
|
var visibility = Preferences.shared.defaultPostVisibility
|
||||||
var contentWarning = ""
|
var contentWarning = ""
|
||||||
|
|
||||||
if let inReplyToID = inReplyToID,
|
if let inReplyToID = inReplyToID,
|
||||||
let inReplyTo = persistentContainer.status(for: inReplyToID) {
|
let inReplyTo = persistentContainer.status(for: inReplyToID) {
|
||||||
acctsToMention.append(inReplyTo.account.acct)
|
acctsToMention.append(inReplyTo.account.acct)
|
||||||
acctsToMention.append(contentsOf: inReplyTo.mentions.map(\.acct))
|
acctsToMention.append(contentsOf: inReplyTo.mentions.map(\.acct))
|
||||||
visibility = min(visibility, inReplyTo.visibility)
|
visibility = inReplyTo.visibility
|
||||||
|
|
||||||
if !inReplyTo.spoilerText.isEmpty {
|
if !inReplyTo.spoilerText.isEmpty {
|
||||||
switch Preferences.shared.contentWarningCopyMode {
|
switch Preferences.shared.contentWarningCopyMode {
|
||||||
|
|
|
@ -45,14 +45,12 @@ class Preferences: Codable, ObservableObject {
|
||||||
self.hideActionsInTimeline = try container.decodeIfPresent(Bool.self, forKey: .hideActionsInTimeline) ?? false
|
self.hideActionsInTimeline = try container.decodeIfPresent(Bool.self, forKey: .hideActionsInTimeline) ?? false
|
||||||
|
|
||||||
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility)
|
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility)
|
||||||
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
|
|
||||||
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
|
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
|
||||||
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
||||||
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
||||||
self.mentionReblogger = try container.decode(Bool.self, forKey: .mentionReblogger)
|
self.mentionReblogger = try container.decode(Bool.self, forKey: .mentionReblogger)
|
||||||
|
|
||||||
self.blurAllMedia = try container.decode(Bool.self, forKey: .blurAllMedia)
|
self.blurAllMedia = try container.decode(Bool.self, forKey: .blurAllMedia)
|
||||||
self.blurMediaBehindContentWarning = try container.decodeIfPresent(Bool.self, forKey: .blurMediaBehindContentWarning) ?? true
|
|
||||||
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
|
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
|
||||||
|
|
||||||
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
||||||
|
@ -86,14 +84,12 @@ class Preferences: Codable, ObservableObject {
|
||||||
try container.encode(hideActionsInTimeline, forKey: .hideActionsInTimeline)
|
try container.encode(hideActionsInTimeline, forKey: .hideActionsInTimeline)
|
||||||
|
|
||||||
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
|
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
|
||||||
try container.encode(defaultReplyVisibility, forKey: .defaultReplyVisibility)
|
|
||||||
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
|
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
|
||||||
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
|
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
|
||||||
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
|
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
|
||||||
try container.encode(mentionReblogger, forKey: .mentionReblogger)
|
try container.encode(mentionReblogger, forKey: .mentionReblogger)
|
||||||
|
|
||||||
try container.encode(blurAllMedia, forKey: .blurAllMedia)
|
try container.encode(blurAllMedia, forKey: .blurAllMedia)
|
||||||
try container.encode(blurMediaBehindContentWarning, forKey: .blurMediaBehindContentWarning)
|
|
||||||
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
|
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
|
||||||
|
|
||||||
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
||||||
|
@ -126,21 +122,13 @@ class Preferences: Codable, ObservableObject {
|
||||||
|
|
||||||
// MARK: Composing
|
// MARK: Composing
|
||||||
@Published var defaultPostVisibility = Status.Visibility.public
|
@Published var defaultPostVisibility = Status.Visibility.public
|
||||||
@Published var defaultReplyVisibility = ReplyVisibility.sameAsPost
|
|
||||||
@Published var automaticallySaveDrafts = true
|
@Published var automaticallySaveDrafts = true
|
||||||
@Published var requireAttachmentDescriptions = false
|
@Published var requireAttachmentDescriptions = false
|
||||||
@Published var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
@Published var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
||||||
@Published var mentionReblogger = false
|
@Published var mentionReblogger = false
|
||||||
|
|
||||||
// MARK: Media
|
// MARK: Media
|
||||||
@Published var blurAllMedia = false {
|
@Published var blurAllMedia = false
|
||||||
didSet {
|
|
||||||
if blurAllMedia {
|
|
||||||
blurMediaBehindContentWarning = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Published var blurMediaBehindContentWarning = true
|
|
||||||
@Published var automaticallyPlayGifs = true
|
@Published var automaticallyPlayGifs = true
|
||||||
|
|
||||||
// MARK: Behavior
|
// MARK: Behavior
|
||||||
|
@ -176,14 +164,12 @@ class Preferences: Codable, ObservableObject {
|
||||||
case hideActionsInTimeline
|
case hideActionsInTimeline
|
||||||
|
|
||||||
case defaultPostVisibility
|
case defaultPostVisibility
|
||||||
case defaultReplyVisibility
|
|
||||||
case automaticallySaveDrafts
|
case automaticallySaveDrafts
|
||||||
case requireAttachmentDescriptions
|
case requireAttachmentDescriptions
|
||||||
case contentWarningCopyMode
|
case contentWarningCopyMode
|
||||||
case mentionReblogger
|
case mentionReblogger
|
||||||
|
|
||||||
case blurAllMedia
|
case blurAllMedia
|
||||||
case blurMediaBehindContentWarning
|
|
||||||
case automaticallyPlayGifs
|
case automaticallyPlayGifs
|
||||||
|
|
||||||
case openLinksInApps
|
case openLinksInApps
|
||||||
|
@ -208,40 +194,4 @@ class Preferences: Codable, ObservableObject {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Preferences {
|
|
||||||
enum ReplyVisibility: Codable, Hashable, CaseIterable {
|
|
||||||
case sameAsPost
|
|
||||||
case visibility(Status.Visibility)
|
|
||||||
|
|
||||||
static var allCases: [Preferences.ReplyVisibility] = [.sameAsPost] + Status.Visibility.allCases.map { .visibility($0) }
|
|
||||||
|
|
||||||
var resolved: Status.Visibility {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return Preferences.shared.defaultPostVisibility
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var displayName: String {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return "Same as Default"
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis.displayName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var imageName: String? {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return nil
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis.imageName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UIUserInterfaceStyle: Codable {}
|
extension UIUserInterfaceStyle: Codable {}
|
||||||
|
|
|
@ -14,30 +14,6 @@ protocol ComposeDrawingViewControllerDelegate: AnyObject {
|
||||||
func composeDrawingViewController(_ drawingController: ComposeDrawingViewController, saveDrawing drawing: PKDrawing)
|
func composeDrawingViewController(_ drawingController: ComposeDrawingViewController, saveDrawing drawing: PKDrawing)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComposeDrawingNavigationController: UINavigationController {
|
|
||||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
|
||||||
.darkContent
|
|
||||||
}
|
|
||||||
|
|
||||||
init(editing initialDrawing: PKDrawing, delegate: ComposeDrawingViewControllerDelegate) {
|
|
||||||
let vc = ComposeDrawingViewController(editing: initialDrawing)
|
|
||||||
vc.delegate = delegate
|
|
||||||
super.init(rootViewController: vc)
|
|
||||||
|
|
||||||
modalPresentationStyle = .fullScreen
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
overrideUserInterfaceStyle = .light
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComposeDrawingViewController: UIViewController {
|
class ComposeDrawingViewController: UIViewController {
|
||||||
|
|
||||||
weak var delegate: ComposeDrawingViewControllerDelegate?
|
weak var delegate: ComposeDrawingViewControllerDelegate?
|
||||||
|
@ -50,7 +26,7 @@ class ComposeDrawingViewController: UIViewController {
|
||||||
private var toolPicker: PKToolPicker!
|
private var toolPicker: PKToolPicker!
|
||||||
|
|
||||||
private var initialDrawing: PKDrawing?
|
private var initialDrawing: PKDrawing?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
}
|
}
|
||||||
|
@ -69,7 +45,7 @@ class ComposeDrawingViewController: UIViewController {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
overrideUserInterfaceStyle = .light
|
overrideUserInterfaceStyle = .light
|
||||||
|
|
||||||
navigationItem.title = NSLocalizedString("Draw", comment: "compose drawing screen title")
|
navigationItem.title = NSLocalizedString("Draw", comment: "compose drawing screen title")
|
||||||
cancelBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed))
|
cancelBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed))
|
||||||
undoBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "arrow.uturn.left.circle"), style: .plain, target: self, action: #selector(undoPressed))
|
undoBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "arrow.uturn.left.circle"), style: .plain, target: self, action: #selector(undoPressed))
|
||||||
|
@ -87,8 +63,7 @@ class ComposeDrawingViewController: UIViewController {
|
||||||
canvasView.drawingPolicy = .anyInput
|
canvasView.drawingPolicy = .anyInput
|
||||||
canvasView.minimumZoomScale = 0.5
|
canvasView.minimumZoomScale = 0.5
|
||||||
canvasView.maximumZoomScale = 2
|
canvasView.maximumZoomScale = 2
|
||||||
canvasView.backgroundColor = .white
|
canvasView.backgroundColor = .systemBackground
|
||||||
canvasView.overrideUserInterfaceStyle = .light
|
|
||||||
canvasView.translatesAutoresizingMaskIntoConstraints = false
|
canvasView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(canvasView)
|
view.addSubview(canvasView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
|
@ -99,7 +74,6 @@ class ComposeDrawingViewController: UIViewController {
|
||||||
])
|
])
|
||||||
|
|
||||||
toolPicker = PKToolPicker()
|
toolPicker = PKToolPicker()
|
||||||
toolPicker.overrideUserInterfaceStyle = .light
|
|
||||||
toolPicker.setVisible(true, forFirstResponder: canvasView)
|
toolPicker.setVisible(true, forFirstResponder: canvasView)
|
||||||
toolPicker.addObserver(canvasView)
|
toolPicker.addObserver(canvasView)
|
||||||
toolPicker.addObserver(self)
|
toolPicker.addObserver(self)
|
||||||
|
|
|
@ -360,7 +360,11 @@ extension ComposeHostingController: ComposeUIStateDelegate {
|
||||||
drawing = PKDrawing()
|
drawing = PKDrawing()
|
||||||
}
|
}
|
||||||
|
|
||||||
present(ComposeDrawingNavigationController(editing: drawing, delegate: self), animated: true)
|
let drawingVC = ComposeDrawingViewController(editing: drawing)
|
||||||
|
drawingVC.delegate = self
|
||||||
|
let nav = UINavigationController(rootViewController: drawingVC)
|
||||||
|
nav.modalPresentationStyle = .fullScreen
|
||||||
|
present(nav, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ struct ComposingPrefsView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
visibilitySection
|
|
||||||
composingSection
|
composingSection
|
||||||
replyingSection
|
replyingSection
|
||||||
}
|
}
|
||||||
|
@ -22,9 +21,9 @@ struct ComposingPrefsView: View {
|
||||||
.navigationBarTitle("Composing")
|
.navigationBarTitle("Composing")
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibilitySection: some View {
|
var composingSection: some View {
|
||||||
Section {
|
Section(header: Text("Composing")) {
|
||||||
Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Visibility")) {
|
Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Post Visibility")) {
|
||||||
ForEach(Status.Visibility.allCases, id: \.self) { visibility in
|
ForEach(Status.Visibility.allCases, id: \.self) { visibility in
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: visibility.imageName)
|
Image(systemName: visibility.imageName)
|
||||||
|
@ -34,26 +33,6 @@ struct ComposingPrefsView: View {
|
||||||
}//.navigationBarTitle("Default Post Visibility")
|
}//.navigationBarTitle("Default Post Visibility")
|
||||||
// navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291
|
// navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291
|
||||||
}
|
}
|
||||||
Picker(selection: $preferences.defaultReplyVisibility, label: Text("Reply Visibility")) {
|
|
||||||
ForEach(Preferences.ReplyVisibility.allCases, id: \.self) { visibility in
|
|
||||||
HStack {
|
|
||||||
if let imageName = visibility.imageName {
|
|
||||||
Image(systemName: imageName)
|
|
||||||
}
|
|
||||||
Text(visibility.displayName)
|
|
||||||
}
|
|
||||||
.tag(visibility)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} header: {
|
|
||||||
Text("Visibility")
|
|
||||||
} footer: {
|
|
||||||
Text("When starting a reply, Tusker will use your preferred visibility or the visibility of the post to which you're replying, whichever is narrower.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var composingSection: some View {
|
|
||||||
Section(header: Text("Composing")) {
|
|
||||||
Toggle(isOn: $preferences.automaticallySaveDrafts) {
|
Toggle(isOn: $preferences.automaticallySaveDrafts) {
|
||||||
Text("Automatically Save Drafts")
|
Text("Automatically Save Drafts")
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,6 @@ struct MediaPrefsView: View {
|
||||||
Toggle(isOn: $preferences.blurAllMedia) {
|
Toggle(isOn: $preferences.blurAllMedia) {
|
||||||
Text("Blur All Media")
|
Text("Blur All Media")
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle(isOn: $preferences.blurMediaBehindContentWarning) {
|
|
||||||
Text("Blur Media Behind Content Warning")
|
|
||||||
}
|
|
||||||
.disabled(preferences.blurAllMedia)
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
||||||
Text("Automatically Play GIFs")
|
Text("Automatically Play GIFs")
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,17 +222,7 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
||||||
}
|
}
|
||||||
|
|
||||||
var snapshot = dataSource.snapshot()
|
var snapshot = dataSource.snapshot()
|
||||||
let existingPinned = snapshot.itemIdentifiers(inSection: .pinned)
|
let items = statuses.map { Item.status(id: $0.id, state: .unknown, pinned: true) }
|
||||||
let items = statuses.map {
|
|
||||||
let item = Item.status(id: $0.id, state: .unknown, pinned: true)
|
|
||||||
// try to keep the existing status state
|
|
||||||
if let existing = existingPinned.first(where: { $0 == item }) {
|
|
||||||
return existing
|
|
||||||
} else {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .pinned))
|
|
||||||
snapshot.appendItems(items, toSection: .pinned)
|
snapshot.appendItems(items, toSection: .pinned)
|
||||||
await apply(snapshot, animatingDifferences: true)
|
await apply(snapshot, animatingDifferences: true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,9 +236,27 @@ class AttachmentsContainerView: UIView {
|
||||||
// Make sure accessibilityElements is set every time the UI is updated, otherwise it holds
|
// Make sure accessibilityElements is set every time the UI is updated, otherwise it holds
|
||||||
// on to strong references to the old set of attachment views
|
// on to strong references to the old set of attachment views
|
||||||
self.accessibilityElements = accessibilityElements
|
self.accessibilityElements = accessibilityElements
|
||||||
|
|
||||||
|
contentHidden = Preferences.shared.blurAllMedia || status.sensitive
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createAttachmentView(index: Int, hSize: RelativeSize, vSize: RelativeSize) -> AttachmentView {
|
private func createAttachmentView(index: Int, hSize: RelativeSize, vSize: RelativeSize) -> AttachmentView {
|
||||||
|
let width: CGFloat
|
||||||
|
switch hSize {
|
||||||
|
case .full:
|
||||||
|
width = bounds.width
|
||||||
|
case .half:
|
||||||
|
width = (bounds.width - 4) / 2
|
||||||
|
}
|
||||||
|
let height: CGFloat
|
||||||
|
switch vSize {
|
||||||
|
case .full:
|
||||||
|
height = bounds.height
|
||||||
|
case .half:
|
||||||
|
height = (bounds.height - 4) / 2
|
||||||
|
}
|
||||||
|
let size = CGSize(width: width, height: height)
|
||||||
|
|
||||||
let attachmentView = AttachmentView(attachment: attachments[index], index: index)
|
let attachmentView = AttachmentView(attachment: attachments[index], index: index)
|
||||||
attachmentView.delegate = delegate
|
attachmentView.delegate = delegate
|
||||||
attachmentView.translatesAutoresizingMaskIntoConstraints = false
|
attachmentView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
|
@ -86,31 +86,28 @@ extension BaseEmojiLabel {
|
||||||
func buildStringWithEmojisReplaced(usePlaceholders: Bool) -> NSAttributedString {
|
func buildStringWithEmojisReplaced(usePlaceholders: Bool) -> NSAttributedString {
|
||||||
let mutAttrString = NSMutableAttributedString(attributedString: attributedString)
|
let mutAttrString = NSMutableAttributedString(attributedString: attributedString)
|
||||||
|
|
||||||
|
// lock once for the entire loop, rather than lock/unlocking for each iteration to do the lookup
|
||||||
// OSAllocatedUnfairLock.withLock expects a @Sendable closure, so this warns about captures of non-sendable types (attribute dstrings, text checking results)
|
// OSAllocatedUnfairLock.withLock expects a @Sendable closure, so this warns about captures of non-sendable types (attribute dstrings, text checking results)
|
||||||
// even though the closures is invoked on the same thread that withLock is called, so it's unclear why it needs to be @Sendable (FB11494878)
|
// even though the closures is invoked on the same thread that withLock is called, so it's unclear why it needs to be @Sendable (FB11494878)
|
||||||
// so, just ignore the warnings
|
// so, just ignore the warnings
|
||||||
let emojiAttachments = emojiImages.withLock {
|
emojiImages.withLock { emojiImages in
|
||||||
$0.mapValues { image in
|
// replaces the emojis starting from the end of the string as to not alter the indices of preceeding emojis
|
||||||
NSTextAttachment(emojiImage: image, in: self.emojiFont, with: self.emojiTextColor)
|
for match in matches.reversed() {
|
||||||
|
let shortcode = (attributedString.string as NSString).substring(with: match.range(at: 1))
|
||||||
|
let attachment: NSTextAttachment
|
||||||
|
|
||||||
|
if let emojiImage = emojiImages[shortcode] {
|
||||||
|
attachment = NSTextAttachment(emojiImage: emojiImage, in: self.emojiFont, with: self.emojiTextColor)
|
||||||
|
} else if usePlaceholders {
|
||||||
|
attachment = NSTextAttachment(emojiPlaceholderIn: self.emojiFont)
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let attachmentStr = NSAttributedString(attachment: attachment)
|
||||||
|
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let placeholder = usePlaceholders ? NSTextAttachment(emojiPlaceholderIn: self.emojiFont) : nil
|
|
||||||
|
|
||||||
// replaces the emojis starting from the end of the string as to not alter the indices of preceeding emojis
|
|
||||||
for match in matches.reversed() {
|
|
||||||
let shortcode = (attributedString.string as NSString).substring(with: match.range(at: 1))
|
|
||||||
let attachment: NSTextAttachment
|
|
||||||
if let emoji = emojiAttachments[shortcode] {
|
|
||||||
attachment = emoji
|
|
||||||
} else if usePlaceholders {
|
|
||||||
attachment = placeholder!
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let attachmentStr = NSAttributedString(attachment: attachment)
|
|
||||||
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutAttrString
|
return mutAttrString
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,8 +182,7 @@ class BaseStatusTableViewCell: UITableViewCell {
|
||||||
updateStatusIconsForPreferences(status)
|
updateStatusIconsForPreferences(status)
|
||||||
|
|
||||||
if state.unknown {
|
if state.unknown {
|
||||||
layoutIfNeeded()
|
state.resolveFor(status: status, text: contentTextView.text)
|
||||||
state.resolveFor(status: status, height: contentTextView.bounds.height)
|
|
||||||
if state.collapsible! && showStatusAutomatically {
|
if state.collapsible! && showStatusAutomatically {
|
||||||
state.collapsed = false
|
state.collapsed = false
|
||||||
}
|
}
|
||||||
|
@ -231,17 +230,7 @@ class BaseStatusTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
func updateUIForPreferences(account: AccountMO, status: StatusMO) {
|
func updateUIForPreferences(account: AccountMO, status: StatusMO) {
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
||||||
if Preferences.shared.blurAllMedia {
|
attachmentsView.contentHidden = Preferences.shared.blurAllMedia || status.sensitive
|
||||||
attachmentsView.contentHidden = true
|
|
||||||
} else if status.sensitive {
|
|
||||||
if !Preferences.shared.blurMediaBehindContentWarning && !status.spoilerText.isEmpty {
|
|
||||||
attachmentsView.contentHidden = false
|
|
||||||
} else {
|
|
||||||
attachmentsView.contentHidden = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
attachmentsView.contentHidden = false
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatusIconsForPreferences(status)
|
updateStatusIconsForPreferences(status)
|
||||||
|
|
||||||
|
|
|
@ -104,9 +104,7 @@ extension StatusCollectionViewCell {
|
||||||
favoriteButton.isEnabled = mastodonController.loggedIn
|
favoriteButton.isEnabled = mastodonController.loggedIn
|
||||||
|
|
||||||
if statusState.unknown {
|
if statusState.unknown {
|
||||||
// layout so that we can take the content height into consideration when deciding whether to collapse
|
statusState.resolveFor(status: status, text: contentContainer.contentTextView.text)
|
||||||
layoutIfNeeded()
|
|
||||||
statusState.resolveFor(status: status, height: contentContainer.contentTextView.bounds.height)
|
|
||||||
if statusState.collapsible! && showStatusAutomatically {
|
if statusState.collapsible! && showStatusAutomatically {
|
||||||
statusState.collapsed = false
|
statusState.collapsed = false
|
||||||
}
|
}
|
||||||
|
@ -147,17 +145,7 @@ extension StatusCollectionViewCell {
|
||||||
|
|
||||||
func baseUpdateUIForPreferences(status: StatusMO) {
|
func baseUpdateUIForPreferences(status: StatusMO) {
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.avatarImageViewSize
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.avatarImageViewSize
|
||||||
if Preferences.shared.blurAllMedia {
|
contentContainer.attachmentsView.contentHidden = Preferences.shared.blurAllMedia || status.sensitive
|
||||||
contentContainer.attachmentsView.contentHidden = true
|
|
||||||
} else if status.sensitive {
|
|
||||||
if !Preferences.shared.blurMediaBehindContentWarning && !status.spoilerText.isEmpty {
|
|
||||||
contentContainer.attachmentsView.contentHidden = false
|
|
||||||
} else {
|
|
||||||
contentContainer.attachmentsView.contentHidden = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
contentContainer.attachmentsView.contentHidden = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let reblogButtonImage: UIImage
|
let reblogButtonImage: UIImage
|
||||||
if Preferences.shared.alwaysShowStatusVisibilityIcon || reblogEnabled(status: status) {
|
if Preferences.shared.alwaysShowStatusVisibilityIcon || reblogEnabled(status: status) {
|
||||||
|
|
Loading…
Reference in New Issue