Compare commits

..

3 Commits

5 changed files with 41 additions and 2 deletions

View File

@ -15,9 +15,13 @@ import Pachyderm
import Intents import Intents
import HTMLStreamer import HTMLStreamer
import WebURL import WebURL
import UIKit
import TuskerPreferences
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "NotificationService") private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "NotificationService")
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
class NotificationService: UNNotificationServiceExtension { class NotificationService: UNNotificationServiceExtension {
private static let textConverter = TextConverter(configuration: .init(insertNewlines: false), callbacks: HTMLCallbacks.self) private static let textConverter = TextConverter(configuration: .init(insertNewlines: false), callbacks: HTMLCallbacks.self)
@ -225,8 +229,33 @@ class NotificationService: UNNotificationServiceExtension {
} }
let updatedContent: UNMutableNotificationContent let updatedContent: UNMutableNotificationContent
let contentProviding: any UNNotificationContentProviding
if #available(iOS 18.0, *),
await Preferences.shared.hasFeatureFlag(.pushNotifCustomEmoji) {
let attributedString = NSMutableAttributedString(string: content.body)
for match in emojiRegex.matches(in: content.body, range: NSRange(location: 0, length: content.body.utf16.count)).reversed() {
let emojiName = (content.body as NSString).substring(with: match.range(at: 1))
guard let emoji = notification.status?.emojis.first(where: { $0.shortcode == emojiName }),
let url = URL(emoji.url),
let (data, _) = try? await URLSession.shared.data(from: url),
let image = UIImage(data: data) else {
continue
}
let attachment = NSTextAttachment(image: image)
let attachmentStr = NSAttributedString(attachment: attachment)
attributedString.replaceCharacters(in: match.range, with: attachmentStr)
}
let attributedCtx = UNNotificationAttributedMessageContext(sendMessageIntent: intent, attributedContent: attributedString)
contentProviding = attributedCtx
} else {
contentProviding = intent
}
do { do {
let newContent = try content.updating(from: intent) let newContent = try content.updating(from: contentProviding)
if let newMutableContent = newContent.mutableCopy() as? UNMutableNotificationContent { if let newMutableContent = newContent.mutableCopy() as? UNMutableNotificationContent {
pendingRequest?.0 = newMutableContent pendingRequest?.0 = newMutableContent
updatedContent = newMutableContent updatedContent = newMutableContent

View File

@ -9,4 +9,5 @@ import Foundation
public enum FeatureFlag: String, Codable { public enum FeatureFlag: String, Codable {
case iPadBrowserNavigation = "ipad-browser-navigation" case iPadBrowserNavigation = "ipad-browser-navigation"
case pushNotifCustomEmoji = "push-notif-custom-emoji"
} }

View File

@ -77,6 +77,7 @@
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; }; D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; };
D6210D762C0B924F009BB569 /* RemoveProfileSuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6210D752C0B924F009BB569 /* RemoveProfileSuggestionService.swift */; }; D6210D762C0B924F009BB569 /* RemoveProfileSuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6210D752C0B924F009BB569 /* RemoveProfileSuggestionService.swift */; };
D621733328F1D5ED004C7DB1 /* ReblogService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621733228F1D5ED004C7DB1 /* ReblogService.swift */; }; D621733328F1D5ED004C7DB1 /* ReblogService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621733228F1D5ED004C7DB1 /* ReblogService.swift */; };
D62220472C7EA8DF003E43B7 /* TuskerPreferences in Frameworks */ = {isa = PBXBuildFile; productRef = D62220462C7EA8DF003E43B7 /* TuskerPreferences */; };
D62275A824F1CA2800B82A16 /* ComposeReplyContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */; }; D62275A824F1CA2800B82A16 /* ComposeReplyContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */; };
D623A53D2635F5590095BD04 /* StatusPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A53C2635F5590095BD04 /* StatusPollView.swift */; }; D623A53D2635F5590095BD04 /* StatusPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A53C2635F5590095BD04 /* StatusPollView.swift */; };
D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A5402635FB3C0095BD04 /* PollOptionView.swift */; }; D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A5402635FB3C0095BD04 /* PollOptionView.swift */; };
@ -828,6 +829,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D630C4252BC7845800208903 /* WebURL in Frameworks */, D630C4252BC7845800208903 /* WebURL in Frameworks */,
D62220472C7EA8DF003E43B7 /* TuskerPreferences in Frameworks */,
D630C4232BC7842C00208903 /* HTMLStreamer in Frameworks */, D630C4232BC7842C00208903 /* HTMLStreamer in Frameworks */,
D630C3E52BC6313400208903 /* Pachyderm in Frameworks */, D630C3E52BC6313400208903 /* Pachyderm in Frameworks */,
D630C3DF2BC61C4900208903 /* PushNotifications in Frameworks */, D630C3DF2BC61C4900208903 /* PushNotifications in Frameworks */,
@ -1795,6 +1797,7 @@
D630C3E42BC6313400208903 /* Pachyderm */, D630C3E42BC6313400208903 /* Pachyderm */,
D630C4222BC7842C00208903 /* HTMLStreamer */, D630C4222BC7842C00208903 /* HTMLStreamer */,
D630C4242BC7845800208903 /* WebURL */, D630C4242BC7845800208903 /* WebURL */,
D62220462C7EA8DF003E43B7 /* TuskerPreferences */,
); );
productName = NotificationExtension; productName = NotificationExtension;
productReference = D630C3D12BC61B6000208903 /* NotificationExtension.appex */; productReference = D630C3D12BC61B6000208903 /* NotificationExtension.appex */;
@ -3299,6 +3302,10 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = Pachyderm; productName = Pachyderm;
}; };
D62220462C7EA8DF003E43B7 /* TuskerPreferences */ = {
isa = XCSwiftPackageProductDependency;
productName = TuskerPreferences;
};
D630C3C72BC43AFD00208903 /* PushNotifications */ = { D630C3C72BC43AFD00208903 /* PushNotifications */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = PushNotifications; productName = PushNotifications;

View File

@ -285,7 +285,7 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
var tabs: [UITab] = [] var tabs: [UITab] = []
let savedReq = SavedHashtag.fetchRequest(account: mastodonController.accountInfo!) let savedReq = SavedHashtag.fetchRequest(account: mastodonController.accountInfo!)
let saved = (try? mastodonController.persistentContainer.viewContext.fetch(savedReq)) ?? [] let saved = (try? mastodonController.persistentContainer.viewContext.fetch(savedReq)) ?? []
for hashtag in saved { for hashtag in saved where !seenTags.contains(hashtag.name) {
seenTags.insert(hashtag.name) seenTags.insert(hashtag.name)
tabs.append(HashtagTab(hashtagName: hashtag.name, viewControllerProvider: viewControllerProvider)) tabs.append(HashtagTab(hashtagName: hashtag.name, viewControllerProvider: viewControllerProvider))
} }
@ -293,6 +293,7 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
let followedReq = FollowedHashtag.fetchRequest() let followedReq = FollowedHashtag.fetchRequest()
let followed = (try? mastodonController.persistentContainer.viewContext.fetch(followedReq)) ?? [] let followed = (try? mastodonController.persistentContainer.viewContext.fetch(followedReq)) ?? []
for hashtag in followed where !seenTags.contains(hashtag.name) { for hashtag in followed where !seenTags.contains(hashtag.name) {
seenTags.insert(hashtag.name)
tabs.append(HashtagTab(hashtagName: hashtag.name, viewControllerProvider: viewControllerProvider)) tabs.append(HashtagTab(hashtagName: hashtag.name, viewControllerProvider: viewControllerProvider))
} }

View File

@ -199,6 +199,7 @@ struct AdvancedPrefsView : View {
} header: { } header: {
Text("Feature Flags") Text("Feature Flags")
} }
.appGroupedListRowBackground()
} }
} }