Compare commits
No commits in common. "b470ee6401f01bf31cf157fbcd603019072d59b5" and "5f040ed390e7fd5cf05b403b2537da7d54831423" have entirely different histories.
b470ee6401
...
5f040ed390
@ -122,12 +122,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
|
|
||||||
let notificationContent: String?
|
let notificationContent: String?
|
||||||
if let status = notification.status {
|
if let status = notification.status {
|
||||||
if notification.kind == .mention || notification.kind == .status,
|
notificationContent = NotificationService.textConverter.convert(html: status.content)
|
||||||
!status.spoilerText.isEmpty {
|
|
||||||
notificationContent = "⚠️ \(status.spoilerText)"
|
|
||||||
} else {
|
|
||||||
notificationContent = NotificationService.textConverter.convert(html: status.content)
|
|
||||||
}
|
|
||||||
} else if notification.kind == .follow || notification.kind == .followRequest {
|
} else if notification.kind == .follow || notification.kind == .followRequest {
|
||||||
notificationContent = nil
|
notificationContent = nil
|
||||||
} else {
|
} else {
|
||||||
@ -140,9 +135,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
// We deliberately don't include attachments for other types of notifications that have statuses (favs, etc.)
|
// We deliberately don't include attachments for other types of notifications that have statuses (favs, etc.)
|
||||||
// because we risk just fetching the same thing a bunch of times for many senders.
|
// because we risk just fetching the same thing a bunch of times for many senders.
|
||||||
if notification.kind == .mention || notification.kind == .status || notification.kind == .update,
|
if notification.kind == .mention || notification.kind == .status || notification.kind == .update,
|
||||||
let status = notification.status,
|
let attachment = notification.status?.attachments.first {
|
||||||
!status.sensitive,
|
|
||||||
let attachment = status.attachments.first {
|
|
||||||
let url = attachment.previewURL ?? attachment.url
|
let url = attachment.previewURL ?? attachment.url
|
||||||
attachmentDataTask = Task {
|
attachmentDataTask = Task {
|
||||||
do {
|
do {
|
||||||
|
@ -235,7 +235,6 @@
|
|||||||
D698F46D2BD0B8310054DB14 /* AnnouncementsCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */; };
|
D698F46D2BD0B8310054DB14 /* AnnouncementsCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */; };
|
||||||
D698F46F2BD0B8DF0054DB14 /* AddReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */; };
|
D698F46F2BD0B8DF0054DB14 /* AddReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */; };
|
||||||
D698F4712BD0CBAA0054DB14 /* AnnouncementContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */; };
|
D698F4712BD0CBAA0054DB14 /* AnnouncementContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */; };
|
||||||
D69F26342C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69F26332C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift */; };
|
|
||||||
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */; };
|
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */; };
|
||||||
D6A3A380295515550036B6EF /* ProfileHeaderButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */; };
|
D6A3A380295515550036B6EF /* ProfileHeaderButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */; };
|
||||||
D6A3A3822956123A0036B6EF /* TimelinePosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A3812956123A0036B6EF /* TimelinePosition.swift */; };
|
D6A3A3822956123A0036B6EF /* TimelinePosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A3812956123A0036B6EF /* TimelinePosition.swift */; };
|
||||||
@ -669,7 +668,6 @@
|
|||||||
D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsCollection.swift; sourceTree = "<group>"; };
|
D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsCollection.swift; sourceTree = "<group>"; };
|
||||||
D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReactionView.swift; sourceTree = "<group>"; };
|
D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReactionView.swift; sourceTree = "<group>"; };
|
||||||
D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnnouncementContentTextView.swift; sourceTree = "<group>"; };
|
D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnnouncementContentTextView.swift; sourceTree = "<group>"; };
|
||||||
D69F26332C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayAndUserNameLabel.swift; sourceTree = "<group>"; };
|
|
||||||
D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionsView.swift; sourceTree = "<group>"; };
|
D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionsView.swift; sourceTree = "<group>"; };
|
||||||
D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderButton.swift; sourceTree = "<group>"; };
|
D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderButton.swift; sourceTree = "<group>"; };
|
||||||
D6A3A3812956123A0036B6EF /* TimelinePosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePosition.swift; sourceTree = "<group>"; };
|
D6A3A3812956123A0036B6EF /* TimelinePosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePosition.swift; sourceTree = "<group>"; };
|
||||||
@ -1482,9 +1480,7 @@
|
|||||||
D6BED1722126661300F02DA0 /* Views */ = {
|
D6BED1722126661300F02DA0 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */,
|
|
||||||
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */,
|
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */,
|
||||||
D69F26332C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift */,
|
|
||||||
D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */,
|
D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */,
|
||||||
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */,
|
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */,
|
||||||
D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */,
|
D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */,
|
||||||
@ -1518,6 +1514,7 @@
|
|||||||
D641C78B213DD92F004B4513 /* Profile Header */,
|
D641C78B213DD92F004B4513 /* Profile Header */,
|
||||||
D641C78A213DD926004B4513 /* Status */,
|
D641C78A213DD926004B4513 /* Status */,
|
||||||
D64AAE8F26C80DB600FC57FB /* Toast */,
|
D64AAE8F26C80DB600FC57FB /* Toast */,
|
||||||
|
D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2360,7 +2357,6 @@
|
|||||||
D65B4B542971F71D00DABDFB /* EditedReport.swift in Sources */,
|
D65B4B542971F71D00DABDFB /* EditedReport.swift in Sources */,
|
||||||
D62D67C52A97D8CD00167EE2 /* MultiColumnNavigationController.swift in Sources */,
|
D62D67C52A97D8CD00167EE2 /* MultiColumnNavigationController.swift in Sources */,
|
||||||
D6A6C11525B62E9700298D0F /* CacheExpiry.swift in Sources */,
|
D6A6C11525B62E9700298D0F /* CacheExpiry.swift in Sources */,
|
||||||
D69F26342C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift in Sources */,
|
|
||||||
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
|
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
|
||||||
D68A76F129539116001DA1B3 /* FlipView.swift in Sources */,
|
D68A76F129539116001DA1B3 /* FlipView.swift in Sources */,
|
||||||
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
||||||
|
@ -13,7 +13,7 @@ struct CustomizeTimelinesView: View {
|
|||||||
let mastodonController: MastodonController
|
let mastodonController: MastodonController
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
CustomizeTimelinesList(pinnedTimelines: mastodonController.accountPreferences.pinnedTimelines)
|
CustomizeTimelinesList()
|
||||||
.environmentObject(mastodonController)
|
.environmentObject(mastodonController)
|
||||||
.environment(\.managedObjectContext, mastodonController.persistentContainer.viewContext)
|
.environment(\.managedObjectContext, mastodonController.persistentContainer.viewContext)
|
||||||
}
|
}
|
||||||
@ -26,15 +26,7 @@ struct CustomizeTimelinesList: View {
|
|||||||
@FetchRequest(sortDescriptors: []) private var filters: FetchedResults<FilterMO>
|
@FetchRequest(sortDescriptors: []) private var filters: FetchedResults<FilterMO>
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
@State private var deletionError: (any Error)?
|
@State private var deletionError: (any Error)?
|
||||||
// store this separately from AccountPreferences in the view, b/c the @LazilyDecoding wrapper breaks animations
|
|
||||||
@State private var pinnedTimelines: [PinnedTimeline]
|
|
||||||
@State private var isShowingAddHashtagSheet = false
|
|
||||||
@State private var isShowingAddInstanceSheet = false
|
|
||||||
|
|
||||||
init(pinnedTimelines: [PinnedTimeline]) {
|
|
||||||
self.pinnedTimelines = pinnedTimelines
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if #available(iOS 16.0, *) {
|
if #available(iOS 16.0, *) {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
@ -58,12 +50,8 @@ struct CustomizeTimelinesList: View {
|
|||||||
|
|
||||||
private var navigationBody: some View {
|
private var navigationBody: some View {
|
||||||
List {
|
List {
|
||||||
PinnedTimelinesView(
|
PinnedTimelinesView(accountPreferences: mastodonController.accountPreferences)
|
||||||
pinnedTimelines: $pinnedTimelines,
|
.appGroupedListRowBackground()
|
||||||
isShowingAddHashtagSheet: $isShowingAddHashtagSheet,
|
|
||||||
isShowingAddInstanceSheet: $isShowingAddInstanceSheet
|
|
||||||
)
|
|
||||||
.appGroupedListRowBackground()
|
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Toggle(isOn: $preferences.hideReblogsInTimelines) {
|
Toggle(isOn: $preferences.hideReblogsInTimelines) {
|
||||||
@ -111,12 +99,6 @@ struct CustomizeTimelinesList: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modifier(PinnedTimelinesModifier(
|
|
||||||
accountPreferences: mastodonController.accountPreferences,
|
|
||||||
pinnedTimelines: $pinnedTimelines,
|
|
||||||
isShowingAddHashtagSheet: $isShowingAddHashtagSheet,
|
|
||||||
isShowingAddInstanceSheet: $isShowingAddInstanceSheet
|
|
||||||
))
|
|
||||||
.alertWithData("Error Deleting Filter", data: $deletionError, actions: { _ in
|
.alertWithData("Error Deleting Filter", data: $deletionError, actions: { _ in
|
||||||
Button("OK") {
|
Button("OK") {
|
||||||
self.deletionError = nil
|
self.deletionError = nil
|
||||||
|
@ -11,10 +11,17 @@ import Pachyderm
|
|||||||
|
|
||||||
struct PinnedTimelinesView: View {
|
struct PinnedTimelinesView: View {
|
||||||
@EnvironmentObject private var mastodonController: MastodonController
|
@EnvironmentObject private var mastodonController: MastodonController
|
||||||
|
@ObservedObject private var accountPreferences: AccountPreferences
|
||||||
|
|
||||||
@Binding var pinnedTimelines: [PinnedTimeline]
|
@State private var isShowingAddHashtagSheet = false
|
||||||
@Binding var isShowingAddHashtagSheet: Bool
|
@State private var isShowingAddInstanceSheet = false
|
||||||
@Binding var isShowingAddInstanceSheet: Bool
|
// store this separately from AccountPreferences in the view, b/c the @LazilyDecoding wrapper breaks animations
|
||||||
|
@State private var pinnedTimelines: [PinnedTimeline]
|
||||||
|
|
||||||
|
init(accountPreferences: AccountPreferences) {
|
||||||
|
self.accountPreferences = accountPreferences
|
||||||
|
self.pinnedTimelines = accountPreferences.pinnedTimelines
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section {
|
Section {
|
||||||
@ -103,53 +110,42 @@ struct PinnedTimelinesView: View {
|
|||||||
} header: {
|
} header: {
|
||||||
Text("Pinned Timelines")
|
Text("Pinned Timelines")
|
||||||
}
|
}
|
||||||
}
|
.sheet(isPresented: $isShowingAddHashtagSheet, content: {
|
||||||
}
|
#if os(visionOS)
|
||||||
|
AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines)
|
||||||
struct PinnedTimelinesModifier: ViewModifier {
|
.edgesIgnoringSafeArea(.bottom)
|
||||||
let accountPreferences: AccountPreferences
|
#else
|
||||||
@Binding var pinnedTimelines: [PinnedTimeline]
|
if #available(iOS 16.0, *) {
|
||||||
@Binding var isShowingAddHashtagSheet: Bool
|
|
||||||
@Binding var isShowingAddInstanceSheet: Bool
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
content
|
|
||||||
.sheet(isPresented: $isShowingAddHashtagSheet, content: {
|
|
||||||
#if os(visionOS)
|
|
||||||
AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines)
|
AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines)
|
||||||
.edgesIgnoringSafeArea(.bottom)
|
.edgesIgnoringSafeArea(.bottom)
|
||||||
#else
|
} else {
|
||||||
if #available(iOS 16.0, *) {
|
AddHashtagPinnedTimelineRepresentable(pinnedTimelines: $pinnedTimelines)
|
||||||
AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines)
|
|
||||||
.edgesIgnoringSafeArea(.bottom)
|
|
||||||
} else {
|
|
||||||
AddHashtagPinnedTimelineRepresentable(pinnedTimelines: $pinnedTimelines)
|
|
||||||
.edgesIgnoringSafeArea(.bottom)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
})
|
|
||||||
.sheet(isPresented: $isShowingAddInstanceSheet, content: {
|
|
||||||
AddInstancePinnedTimelineView(pinnedTimelines: $pinnedTimelines)
|
|
||||||
.edgesIgnoringSafeArea(.bottom)
|
.edgesIgnoringSafeArea(.bottom)
|
||||||
})
|
|
||||||
.onReceive(accountPreferences.publisher(for: \.pinnedTimelinesData)) { _ in
|
|
||||||
if pinnedTimelines != accountPreferences.pinnedTimelines {
|
|
||||||
pinnedTimelines = accountPreferences.pinnedTimelines
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if os(visionOS)
|
|
||||||
.onChange(of: pinnedTimelines) {
|
|
||||||
if accountPreferences.pinnedTimelines != pinnedTimelines {
|
|
||||||
accountPreferences.pinnedTimelines = pinnedTimelines
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
.onChange(of: pinnedTimelines) { newValue in
|
|
||||||
if accountPreferences.pinnedTimelines != newValue {
|
|
||||||
accountPreferences.pinnedTimelines = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
})
|
||||||
|
.sheet(isPresented: $isShowingAddInstanceSheet, content: {
|
||||||
|
AddInstancePinnedTimelineView(pinnedTimelines: $pinnedTimelines)
|
||||||
|
.edgesIgnoringSafeArea(.bottom)
|
||||||
|
})
|
||||||
|
.onReceive(accountPreferences.publisher(for: \.pinnedTimelinesData)) { _ in
|
||||||
|
if pinnedTimelines != accountPreferences.pinnedTimelines {
|
||||||
|
pinnedTimelines = accountPreferences.pinnedTimelines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(visionOS)
|
||||||
|
.onChange(of: pinnedTimelines) {
|
||||||
|
if accountPreferences.pinnedTimelines != pinnedTimelines {
|
||||||
|
accountPreferences.pinnedTimelines = pinnedTimelines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
.onChange(of: pinnedTimelines) { newValue in
|
||||||
|
if accountPreferences.pinnedTimelines != newValue {
|
||||||
|
accountPreferences.pinnedTimelines = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class SuggestedProfileCardCollectionViewCell: UICollectionViewCell {
|
|||||||
@IBOutlet weak var headerImageView: CachedImageView!
|
@IBOutlet weak var headerImageView: CachedImageView!
|
||||||
@IBOutlet weak var avatarContainerView: UIView!
|
@IBOutlet weak var avatarContainerView: UIView!
|
||||||
@IBOutlet weak var avatarImageView: CachedImageView!
|
@IBOutlet weak var avatarImageView: CachedImageView!
|
||||||
@IBOutlet weak var displayAndUserNameLabel: AccountDisplayNameLabel!
|
@IBOutlet weak var displayNameLabel: AccountDisplayNameLabel!
|
||||||
@IBOutlet weak var usernameLabel: UILabel!
|
@IBOutlet weak var usernameLabel: UILabel!
|
||||||
@IBOutlet weak var noteTextView: StatusContentTextView!
|
@IBOutlet weak var noteTextView: StatusContentTextView!
|
||||||
@IBOutlet weak var suggestionSourceButton: UIButton!
|
@IBOutlet weak var suggestionSourceButton: UIButton!
|
||||||
@ -49,8 +49,8 @@ class SuggestedProfileCardCollectionViewCell: UICollectionViewCell {
|
|||||||
avatarImageView.layer.masksToBounds = true
|
avatarImageView.layer.masksToBounds = true
|
||||||
avatarImageView.layer.cornerCurve = .continuous
|
avatarImageView.layer.cornerCurve = .continuous
|
||||||
|
|
||||||
displayAndUserNameLabel.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 24, weight: .semibold))
|
displayNameLabel.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 24, weight: .semibold))
|
||||||
displayAndUserNameLabel.adjustsFontForContentSizeCategory = true
|
displayNameLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
|
||||||
usernameLabel.font = UIFontMetrics.default.scaledFont(for: .systemFont(ofSize: 15, weight: .light))
|
usernameLabel.font = UIFontMetrics.default.scaledFont(for: .systemFont(ofSize: 15, weight: .light))
|
||||||
usernameLabel.adjustsFontForContentSizeCategory = true
|
usernameLabel.adjustsFontForContentSizeCategory = true
|
||||||
@ -96,7 +96,7 @@ class SuggestedProfileCardCollectionViewCell: UICollectionViewCell {
|
|||||||
private func updateUIForPreferences(account: AccountMO) {
|
private func updateUIForPreferences(account: AccountMO) {
|
||||||
avatarContainerView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarContainerView)
|
avatarContainerView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarContainerView)
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
||||||
displayAndUserNameLabel.updateForAccountDisplayName(account: account)
|
displayNameLabel.updateForAccountDisplayName(account: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unneeded on visionOS since there is no light/dark mode
|
// Unneeded on visionOS since there is no light/dark mode
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
//
|
|
||||||
// AccountDisplayAndUserNameLabel.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 7/20/24.
|
|
||||||
// Copyright © 2024 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Pachyderm
|
|
||||||
|
|
||||||
class AccountDisplayAndUserNameLabel: EmojiLabel {
|
|
||||||
var baseFont: UIFontDescriptor = .preferredFontDescriptor(withTextStyle: .body)
|
|
||||||
|
|
||||||
private var state: State?
|
|
||||||
|
|
||||||
func updateUI(account: some AccountProtocol) {
|
|
||||||
let state = State(accountID: account.id, displayName: account.displayName, acct: account.acct)
|
|
||||||
guard state != self.state || Preferences.shared.hideCustomEmojiInUsernames != hasEmojis else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.state = state
|
|
||||||
self.attributedText = makeAttributedText(state: state)
|
|
||||||
if Preferences.shared.hideCustomEmojiInUsernames {
|
|
||||||
self.removeEmojis()
|
|
||||||
} else {
|
|
||||||
self.setEmojis(account.emojis, identifier: state.accountID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func makeAttributedText(state: State) -> NSAttributedString {
|
|
||||||
let s = NSMutableAttributedString()
|
|
||||||
s.append(NSAttributedString(string: state.displayName, attributes: [
|
|
||||||
.font: UIFont(descriptor: baseFont.addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0),
|
|
||||||
]))
|
|
||||||
s.append(NSAttributedString(string: " "))
|
|
||||||
s.append(NSAttributedString(string: "@\(state.acct)", attributes: [
|
|
||||||
.font: UIFont(descriptor: baseFont.addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0),
|
|
||||||
.foregroundColor: UIColor.secondaryLabel,
|
|
||||||
]))
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct State: Equatable {
|
|
||||||
var accountID: String
|
|
||||||
var displayName: String
|
|
||||||
var acct: String
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,7 @@ class AccountDisplayNameLabel: EmojiLabel {
|
|||||||
private var accountDisplayName: String?
|
private var accountDisplayName: String?
|
||||||
|
|
||||||
func updateForAccountDisplayName(account: some AccountProtocol) {
|
func updateForAccountDisplayName(account: some AccountProtocol) {
|
||||||
guard accountID != account.id || accountDisplayName != account.displayName || Preferences.shared.hideCustomEmojiInUsernames != hasEmojis else {
|
guard accountID != account.id || accountDisplayName != account.displayName || Preferences.shared.hideCustomEmojiInUsernames == hasEmojis else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
accountID = account.id
|
accountID = account.id
|
||||||
|
@ -14,8 +14,7 @@ class ProfileHeaderMovedOverlayView: UIView {
|
|||||||
weak var delegate: TuskerNavigationDelegate?
|
weak var delegate: TuskerNavigationDelegate?
|
||||||
|
|
||||||
var collapse: (() -> Void)?
|
var collapse: (() -> Void)?
|
||||||
var hide: (() -> Void)?
|
|
||||||
|
|
||||||
private var avatarImageView: CachedImageView!
|
private var avatarImageView: CachedImageView!
|
||||||
private var displayNameLabel: EmojiLabel!
|
private var displayNameLabel: EmojiLabel!
|
||||||
private var usernameLabel: UILabel!
|
private var usernameLabel: UILabel!
|
||||||
@ -145,46 +144,7 @@ class ProfileHeaderMovedOverlayView: UIView {
|
|||||||
@objc private func accountTapped() {
|
@objc private func accountTapped() {
|
||||||
delegate?.selected(account: movedToID)
|
delegate?.selected(account: movedToID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Accessibility
|
|
||||||
|
|
||||||
override var isAccessibilityElement: Bool {
|
|
||||||
get { true }
|
|
||||||
set {}
|
|
||||||
}
|
|
||||||
|
|
||||||
override var accessibilityLabel: String? {
|
|
||||||
get {
|
|
||||||
guard let movedToID,
|
|
||||||
let account = delegate?.apiController?.persistentContainer.account(for: movedToID) else {
|
|
||||||
return "This account has moved"
|
|
||||||
}
|
|
||||||
return "This account has moved to @\(account.acct)"
|
|
||||||
}
|
|
||||||
set {}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func accessibilityActivate() -> Bool {
|
|
||||||
guard let movedToID,
|
|
||||||
let delegate else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
delegate.selected(account: movedToID)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override var accessibilityCustomActions: [UIAccessibilityCustomAction]? {
|
|
||||||
get {
|
|
||||||
[
|
|
||||||
UIAccessibilityCustomAction(name: "Hide banner", actionHandler: { [unowned self] _ in
|
|
||||||
self.hide?()
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}
|
|
||||||
set {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProfileHeaderMovedOverlayView: UIPointerInteractionDelegate {
|
extension ProfileHeaderMovedOverlayView: UIPointerInteractionDelegate {
|
||||||
|
@ -41,7 +41,6 @@ class ProfileHeaderView: UIView {
|
|||||||
@IBOutlet weak var followersCountButton: UIButton!
|
@IBOutlet weak var followersCountButton: UIButton!
|
||||||
private(set) var pagesSegmentedControl: ScrollingSegmentedControl<ProfileViewController.Page>!
|
private(set) var pagesSegmentedControl: ScrollingSegmentedControl<ProfileViewController.Page>!
|
||||||
private var movedOverlayView: ProfileHeaderMovedOverlayView?
|
private var movedOverlayView: ProfileHeaderMovedOverlayView?
|
||||||
private var hideMovedOverlayView = false
|
|
||||||
|
|
||||||
var accountID: String!
|
var accountID: String!
|
||||||
|
|
||||||
@ -179,8 +178,7 @@ class ProfileHeaderView: UIView {
|
|||||||
followersCountButton.setAttributedTitle(followersCountTitle, for: .normal)
|
followersCountButton.setAttributedTitle(followersCountTitle, for: .normal)
|
||||||
followersCountButton.accessibilityLabel = "\(followersSpelledOut) followers"
|
followersCountButton.accessibilityLabel = "\(followersSpelledOut) followers"
|
||||||
|
|
||||||
if let movedTo = account.movedTo,
|
if let movedTo = account.movedTo {
|
||||||
!hideMovedOverlayView {
|
|
||||||
if let movedOverlayView {
|
if let movedOverlayView {
|
||||||
movedOverlayView.updateUI(movedTo: movedTo)
|
movedOverlayView.updateUI(movedTo: movedTo)
|
||||||
} else {
|
} else {
|
||||||
@ -209,7 +207,6 @@ class ProfileHeaderView: UIView {
|
|||||||
|
|
||||||
private func createMovedOverlayView(movedTo: AccountMO) -> ProfileHeaderMovedOverlayView {
|
private func createMovedOverlayView(movedTo: AccountMO) -> ProfileHeaderMovedOverlayView {
|
||||||
let overlay = ProfileHeaderMovedOverlayView()
|
let overlay = ProfileHeaderMovedOverlayView()
|
||||||
overlay.layer.zPosition = 1000
|
|
||||||
overlay.delegate = delegate
|
overlay.delegate = delegate
|
||||||
overlay.updateUI(movedTo: movedTo)
|
overlay.updateUI(movedTo: movedTo)
|
||||||
overlay.translatesAutoresizingMaskIntoConstraints = false
|
overlay.translatesAutoresizingMaskIntoConstraints = false
|
||||||
@ -237,12 +234,6 @@ class ProfileHeaderView: UIView {
|
|||||||
}
|
}
|
||||||
animator.startAnimation()
|
animator.startAnimation()
|
||||||
}
|
}
|
||||||
overlay.hide = { [weak self] in
|
|
||||||
guard let self else { return }
|
|
||||||
self.hideMovedOverlayView = true
|
|
||||||
self.updateUI(for: self.accountID)
|
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: self)
|
|
||||||
}
|
|
||||||
|
|
||||||
return overlay
|
return overlay
|
||||||
}
|
}
|
||||||
|
@ -514,15 +514,8 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status
|
|||||||
return contentContainer.estimateVisibleSubviewHeight(effectiveWidth: width)
|
return contentContainer.estimateVisibleSubviewHeight(effectiveWidth: width)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAccountUI(account: AccountMO) {
|
|
||||||
baseUpdateAccountUI(account: account)
|
|
||||||
displayNameLabel.updateForAccountDisplayName(account: account)
|
|
||||||
usernameLabel.text = "@\(account.acct)"
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIForPreferences(status: StatusMO) {
|
func updateUIForPreferences(status: StatusMO) {
|
||||||
baseUpdateUIForPreferences(status: status)
|
baseUpdateUIForPreferences(status: status)
|
||||||
displayNameLabel.updateForAccountDisplayName(account: status.account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func preferencesChanged() {
|
@objc private func preferencesChanged() {
|
||||||
|
@ -21,6 +21,8 @@ protocol StatusCollectionViewCellDelegate: AnyObject, TuskerNavigationDelegate,
|
|||||||
protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate {
|
protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate {
|
||||||
// MARK: Subviews
|
// MARK: Subviews
|
||||||
var avatarImageView: CachedImageView { get }
|
var avatarImageView: CachedImageView { get }
|
||||||
|
var displayNameLabel: AccountDisplayNameLabel { get }
|
||||||
|
var usernameLabel: UILabel { get }
|
||||||
var contentWarningLabel: EmojiLabel { get }
|
var contentWarningLabel: EmojiLabel { get }
|
||||||
var collapseButton: StatusCollapseButton { get }
|
var collapseButton: StatusCollapseButton { get }
|
||||||
var contentContainer: StatusContentContainer { get }
|
var contentContainer: StatusContentContainer { get }
|
||||||
@ -47,7 +49,6 @@ protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate
|
|||||||
var isGrayscale: Bool { get set }
|
var isGrayscale: Bool { get set }
|
||||||
var cancellables: Set<AnyCancellable> { get set }
|
var cancellables: Set<AnyCancellable> { get set }
|
||||||
|
|
||||||
func updateAccountUI(account: AccountMO)
|
|
||||||
func updateAttachmentsUI(status: StatusMO)
|
func updateAttachmentsUI(status: StatusMO)
|
||||||
func updateUIForPreferences(status: StatusMO)
|
func updateUIForPreferences(status: StatusMO)
|
||||||
func updateStatusState(status: StatusMO)
|
func updateStatusState(status: StatusMO)
|
||||||
@ -176,8 +177,10 @@ extension StatusCollectionViewCell {
|
|||||||
attachmentsView.updateUI(attachments: status.attachments)
|
attachmentsView.updateUI(attachments: status.attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseUpdateAccountUI(account: AccountMO) {
|
func updateAccountUI(account: AccountMO) {
|
||||||
avatarImageView.update(for: account.avatar)
|
avatarImageView.update(for: account.avatar)
|
||||||
|
displayNameLabel.updateForAccountDisplayName(account: account)
|
||||||
|
usernameLabel.text = "@\(account.acct)"
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseUpdateUIForPreferences(status: StatusMO) {
|
func baseUpdateUIForPreferences(status: StatusMO) {
|
||||||
@ -216,6 +219,7 @@ extension StatusCollectionViewCell {
|
|||||||
if contentTextView.hasEmojis {
|
if contentTextView.hasEmojis {
|
||||||
contentTextView.setEmojis(status.emojis, identifier: status.id)
|
contentTextView.setEmojis(status.emojis, identifier: status.id)
|
||||||
}
|
}
|
||||||
|
displayNameLabel.updateForAccountDisplayName(account: status.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
func baseUpdateStatusState(status: StatusMO) {
|
func baseUpdateStatusState(status: StatusMO) {
|
||||||
|
@ -121,7 +121,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lazy var nameHStack = UIStackView(arrangedSubviews: [
|
private lazy var nameHStack = UIStackView(arrangedSubviews: [
|
||||||
displayAndUserNameLabel,
|
displayNameLabel,
|
||||||
|
usernameLabel,
|
||||||
pinImageView,
|
pinImageView,
|
||||||
timestampLabel,
|
timestampLabel,
|
||||||
]).configure {
|
]).configure {
|
||||||
@ -129,10 +130,27 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||||||
$0.spacing = 4
|
$0.spacing = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
let displayAndUserNameLabel = AccountDisplayAndUserNameLabel().configure {
|
let displayNameLabel = AccountDisplayNameLabel().configure {
|
||||||
|
$0.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
||||||
|
.traits: [
|
||||||
|
UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue,
|
||||||
|
]
|
||||||
|
]), size: 0)
|
||||||
|
$0.adjustsFontForContentSizeCategory = true
|
||||||
|
$0.setContentHuggingPriority(.init(251), for: .horizontal)
|
||||||
|
$0.setContentCompressionResistancePriority(.init(749), for: .horizontal)
|
||||||
|
}
|
||||||
|
|
||||||
|
let usernameLabel = UILabel().configure {
|
||||||
|
$0.textColor = .secondaryLabel
|
||||||
|
$0.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
||||||
|
.traits: [
|
||||||
|
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
||||||
|
]
|
||||||
|
]), size: 0)
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
$0.adjustsFontForContentSizeCategory = true
|
||||||
$0.setContentHuggingPriority(.init(249), for: .horizontal)
|
$0.setContentHuggingPriority(.init(249), for: .horizontal)
|
||||||
$0.setContentCompressionResistancePriority(.init(749), for: .horizontal)
|
$0.setContentCompressionResistancePriority(.init(748), for: .horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let pinImageView = UIImageView(image: UIImage(systemName: "pin.fill")).configure {
|
private let pinImageView = UIImageView(image: UIImage(systemName: "pin.fill")).configure {
|
||||||
@ -675,11 +693,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateAccountUI(account: AccountMO) {
|
|
||||||
baseUpdateAccountUI(account: account)
|
|
||||||
displayAndUserNameLabel.updateUI(account: account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIForPreferences(status: StatusMO) {
|
func updateUIForPreferences(status: StatusMO) {
|
||||||
baseUpdateUIForPreferences(status: status)
|
baseUpdateUIForPreferences(status: status)
|
||||||
|
|
||||||
@ -691,8 +704,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||||||
metaIndicatorsView.updateUI(status: status)
|
metaIndicatorsView.updateUI(status: status)
|
||||||
|
|
||||||
timelineReasonIcon.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.timelineReasonIconSize
|
timelineReasonIcon.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.timelineReasonIconSize
|
||||||
|
|
||||||
displayAndUserNameLabel.updateUI(account: status.account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateStatusState(status: StatusMO) {
|
func updateStatusState(status: StatusMO) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user