Compare commits
No commits in common. "eb9a5aeb4215f7acd58b346de1461f3cc0d1b645" and "8c888906c92a457bc325654e658bebed5c772ba7" have entirely different histories.
eb9a5aeb42
...
8c888906c9
|
@ -49,12 +49,7 @@ public final class Account: AccountProtocol, Decodable {
|
||||||
self.avatarStatic = try? container.decode(URL.self, forKey: .avatarStatic)
|
self.avatarStatic = try? container.decode(URL.self, forKey: .avatarStatic)
|
||||||
self.header = try? container.decode(URL.self, forKey: .header)
|
self.header = try? container.decode(URL.self, forKey: .header)
|
||||||
self.headerStatic = try? container.decode(URL.self, forKey: .headerStatic)
|
self.headerStatic = try? container.decode(URL.self, forKey: .headerStatic)
|
||||||
// even up-to-date pixelfed instances sometimes lack this, for reasons unclear
|
self.emojis = try container.decode([Emoji].self, forKey: .emojis)
|
||||||
if let emojis = try container.decodeIfPresent([Emoji].self, forKey: .emojis) {
|
|
||||||
self.emojis = emojis
|
|
||||||
} else {
|
|
||||||
self.emojis = []
|
|
||||||
}
|
|
||||||
self.fields = (try? container.decode([Field].self, forKey: .fields)) ?? []
|
self.fields = (try? container.decode([Field].self, forKey: .fields)) ?? []
|
||||||
self.bot = try? container.decode(Bool.self, forKey: .bot)
|
self.bot = try? container.decode(Bool.self, forKey: .bot)
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct NotificationGroup: Identifiable, Hashable {
|
public class NotificationGroup: Identifiable, Hashable {
|
||||||
public private(set) var notifications: [Notification]
|
public let notifications: [Notification]
|
||||||
public let id: String
|
public let id: String
|
||||||
public let kind: Notification.Kind
|
public let kind: Notification.Kind
|
||||||
public let statusState: StatusState?
|
public let statusState: StatusState?
|
||||||
|
@ -27,90 +27,34 @@ public struct NotificationGroup: Identifiable, Hashable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool {
|
public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool {
|
||||||
guard lhs.notifications.count == rhs.notifications.count else {
|
return lhs.id == rhs.id
|
||||||
return false
|
|
||||||
}
|
|
||||||
for (a, b) in zip(lhs.notifications, rhs.notifications) where a.id != b.id {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
for notification in notifications {
|
hasher.combine(id)
|
||||||
hasher.combine(notification.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private mutating func append(_ notification: Notification) {
|
|
||||||
notifications.append(notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
private mutating func append(group: NotificationGroup) {
|
|
||||||
notifications.append(contentsOf: group.notifications)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func createGroups(notifications: [Notification], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] {
|
public static func createGroups(notifications: [Notification], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] {
|
||||||
var groups = [NotificationGroup]()
|
var groups = [[Notification]]()
|
||||||
for notification in notifications {
|
for notification in notifications {
|
||||||
if allowedTypes.contains(notification.kind) {
|
if allowedTypes.contains(notification.kind) {
|
||||||
if let lastGroup = groups.last, canMerge(notification: notification, into: lastGroup) {
|
if let lastGroup = groups.last, let firstNotification = lastGroup.first, firstNotification.kind == notification.kind, firstNotification.status?.id == notification.status?.id {
|
||||||
groups[groups.count - 1].append(notification)
|
groups[groups.count - 1].append(notification)
|
||||||
continue
|
continue
|
||||||
} else if groups.count >= 2 {
|
} else if groups.count >= 2 {
|
||||||
let secondToLastGroup = groups[groups.count - 2]
|
let secondToLastGroup = groups[groups.count - 2]
|
||||||
if allowedTypes.contains(groups[groups.count - 1].kind), canMerge(notification: notification, into: secondToLastGroup) {
|
if allowedTypes.contains(groups[groups.count - 1][0].kind), let firstNotification = secondToLastGroup.first, firstNotification.kind == notification.kind, firstNotification.status?.id == notification.status?.id {
|
||||||
groups[groups.count - 2].append(notification)
|
groups[groups.count - 2].append(notification)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.append(NotificationGroup(notifications: [notification])!)
|
groups.append([notification])
|
||||||
}
|
}
|
||||||
return groups
|
return groups.map {
|
||||||
|
NotificationGroup(notifications: $0)!
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func canMerge(notification: Notification, into group: NotificationGroup) -> Bool {
|
|
||||||
return notification.kind == group.kind && notification.status?.id == group.notifications.first!.status?.id
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func mergeGroups(first: [NotificationGroup], second: [NotificationGroup], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] {
|
|
||||||
guard !first.isEmpty else {
|
|
||||||
return second
|
|
||||||
}
|
|
||||||
guard !second.isEmpty else {
|
|
||||||
return first
|
|
||||||
}
|
|
||||||
|
|
||||||
var merged = first
|
|
||||||
var second = second
|
|
||||||
merged.reserveCapacity(second.count)
|
|
||||||
while let firstGroupFromSecond = second.first,
|
|
||||||
allowedTypes.contains(firstGroupFromSecond.kind) {
|
|
||||||
|
|
||||||
second.removeFirst()
|
|
||||||
|
|
||||||
guard let lastGroup = merged.last,
|
|
||||||
allowedTypes.contains(lastGroup.kind) else {
|
|
||||||
merged.append(firstGroupFromSecond)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if canMerge(notification: firstGroupFromSecond.notifications.first!, into: lastGroup) {
|
|
||||||
merged[merged.count - 1].append(group: firstGroupFromSecond)
|
|
||||||
} else if merged.count >= 2 {
|
|
||||||
let secondToLastGroup = merged[merged.count - 2]
|
|
||||||
if allowedTypes.contains(secondToLastGroup.kind), canMerge(notification: firstGroupFromSecond.notifications.first!, into: secondToLastGroup) {
|
|
||||||
merged[merged.count - 2].append(group: firstGroupFromSecond)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
merged.append(firstGroupFromSecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
merged.append(contentsOf: second)
|
|
||||||
return merged
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,235 +0,0 @@
|
||||||
//
|
|
||||||
// NotificationGroupTests.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 4/26/22.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
@testable import Pachyderm
|
|
||||||
|
|
||||||
class NotificationGroupTests: XCTestCase {
|
|
||||||
|
|
||||||
let decoder: JSONDecoder = {
|
|
||||||
let d = JSONDecoder()
|
|
||||||
d.dateDecodingStrategy = .iso8601
|
|
||||||
return d
|
|
||||||
}()
|
|
||||||
|
|
||||||
let statusA = """
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"created_at": "2019-11-23T07:28:34Z",
|
|
||||||
"account": {
|
|
||||||
"id": "2",
|
|
||||||
"username": "bar",
|
|
||||||
"acct": "bar",
|
|
||||||
"display_name": "bar",
|
|
||||||
"locked": false,
|
|
||||||
"created_at": "2019-11-01T01:01:01Z",
|
|
||||||
"followers_count": 0,
|
|
||||||
"following_count": 0,
|
|
||||||
"statuses_count": 0,
|
|
||||||
"note": "",
|
|
||||||
"url": "https://example.com/@bar",
|
|
||||||
"uri": "https://example.com/@bar",
|
|
||||||
},
|
|
||||||
"url": "https://example.com/@bar/1",
|
|
||||||
"uri": "https://example.com/@bar/1",
|
|
||||||
"content": "",
|
|
||||||
"emojis": [],
|
|
||||||
"reblogs_count": 0,
|
|
||||||
"favourites_count": 0,
|
|
||||||
"sensitive": false,
|
|
||||||
"spoiler_text": "",
|
|
||||||
"visibility": "public",
|
|
||||||
"media_attachments": [],
|
|
||||||
"mentions": [],
|
|
||||||
"tags": [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
lazy var likeA1Data = """
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"type": "favourite",
|
|
||||||
"created_at": "2019-11-23T07:29:18Z",
|
|
||||||
"account": {
|
|
||||||
"id": "1",
|
|
||||||
"username": "foo",
|
|
||||||
"acct": "foo",
|
|
||||||
"display_name": "foo",
|
|
||||||
"locked": false,
|
|
||||||
"created_at": "2019-11-01T01:01:01Z",
|
|
||||||
"followers_count": 0,
|
|
||||||
"following_count": 0,
|
|
||||||
"statuses_count": 0,
|
|
||||||
"note": "",
|
|
||||||
"url": "https://example.com/@foo",
|
|
||||||
"uri": "https://example.com/@foo",
|
|
||||||
},
|
|
||||||
"status": \(statusA)
|
|
||||||
""".data(using: .utf8)!
|
|
||||||
lazy var likeA1 = try! decoder.decode(Notification.self, from: likeA1Data)
|
|
||||||
lazy var likeA2Data = """
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"type": "favourite",
|
|
||||||
"created_at": "2019-11-23T07:30:00Z",
|
|
||||||
"account": {
|
|
||||||
"id": "2",
|
|
||||||
"username": "baz",
|
|
||||||
"acct": "baz",
|
|
||||||
"display_name": "baz",
|
|
||||||
"locked": false,
|
|
||||||
"created_at": "2019-11-01T01:01:01Z",
|
|
||||||
"followers_count": 0,
|
|
||||||
"following_count": 0,
|
|
||||||
"statuses_count": 0,
|
|
||||||
"note": "",
|
|
||||||
"url": "https://example.com/@baz",
|
|
||||||
"uri": "https://example.com/@baz",
|
|
||||||
},
|
|
||||||
"status": \(statusA)
|
|
||||||
""".data(using: .utf8)!
|
|
||||||
lazy var likeA2 = try! decoder.decode(Notification.self, from: likeA2Data)
|
|
||||||
let statusB = """
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"created_at": "2019-11-23T07:28:34Z",
|
|
||||||
"account": {
|
|
||||||
"id": "2",
|
|
||||||
"username": "bar",
|
|
||||||
"acct": "bar",
|
|
||||||
"display_name": "bar",
|
|
||||||
"locked": false,
|
|
||||||
"created_at": "2019-11-01T01:01:01Z",
|
|
||||||
"followers_count": 0,
|
|
||||||
"following_count": 0,
|
|
||||||
"statuses_count": 0,
|
|
||||||
"note": "",
|
|
||||||
"url": "https://example.com/@bar",
|
|
||||||
"uri": "https://example.com/@bar",
|
|
||||||
},
|
|
||||||
"url": "https://example.com/@bar/1",
|
|
||||||
"uri": "https://example.com/@bar/1",
|
|
||||||
"content": "",
|
|
||||||
"emojis": [],
|
|
||||||
"reblogs_count": 0,
|
|
||||||
"favourites_count": 0,
|
|
||||||
"sensitive": false,
|
|
||||||
"spoiler_text": "",
|
|
||||||
"visibility": "public",
|
|
||||||
"media_attachments": [],
|
|
||||||
"mentions": [],
|
|
||||||
"tags": [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
lazy var likeBData = """
|
|
||||||
{
|
|
||||||
"id": "3",
|
|
||||||
"type": "favourite",
|
|
||||||
"created_at": "2019-11-23T07:29:18Z",
|
|
||||||
"account": {
|
|
||||||
"id": "1",
|
|
||||||
"username": "foo",
|
|
||||||
"acct": "foo",
|
|
||||||
"display_name": "foo",
|
|
||||||
"locked": false,
|
|
||||||
"created_at": "2019-11-01T01:01:01Z",
|
|
||||||
"followers_count": 0,
|
|
||||||
"following_count": 0,
|
|
||||||
"statuses_count": 0,
|
|
||||||
"note": "",
|
|
||||||
"url": "https://example.com/@foo",
|
|
||||||
"uri": "https://example.com/@foo",
|
|
||||||
},
|
|
||||||
"status": \(statusB)
|
|
||||||
""".data(using: .utf8)!
|
|
||||||
lazy var likeB = try! decoder.decode(Notification.self, from: likeBData)
|
|
||||||
lazy var mentionBData = """
|
|
||||||
{
|
|
||||||
"id": "4",
|
|
||||||
"type": "mention",
|
|
||||||
"created_at": "2019-11-23T07:29:18Z",
|
|
||||||
"account": {
|
|
||||||
"id": "1",
|
|
||||||
"username": "foo",
|
|
||||||
"acct": "foo",
|
|
||||||
"display_name": "foo",
|
|
||||||
"locked": false,
|
|
||||||
"created_at": "2019-11-01T01:01:01Z",
|
|
||||||
"followers_count": 0,
|
|
||||||
"following_count": 0,
|
|
||||||
"statuses_count": 0,
|
|
||||||
"note": "",
|
|
||||||
"url": "https://example.com/@foo",
|
|
||||||
"uri": "https://example.com/@foo",
|
|
||||||
},
|
|
||||||
"status": \(statusB)
|
|
||||||
""".data(using: .utf8)!
|
|
||||||
lazy var mentionB = try! decoder.decode(Notification.self, from: mentionBData)
|
|
||||||
|
|
||||||
|
|
||||||
func testGroupSimple() {
|
|
||||||
let groups = NotificationGroup.createGroups(notifications: [likeA1, likeA2], only: [.favourite])
|
|
||||||
XCTAssertEqual(groups, [NotificationGroup(notifications: [likeA1, likeA2])!])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGroupWithOtherGroupableInBetween() {
|
|
||||||
let groups = NotificationGroup.createGroups(notifications: [likeA1, likeB, likeA2], only: [.favourite])
|
|
||||||
XCTAssertEqual(groups, [
|
|
||||||
NotificationGroup(notifications: [likeA1, likeA2])!,
|
|
||||||
NotificationGroup(notifications: [likeB])!,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testDontGroupWithUngroupableInBetween() {
|
|
||||||
let groups = NotificationGroup.createGroups(notifications: [likeA1, mentionB, likeA2], only: [.favourite])
|
|
||||||
XCTAssertEqual(groups, [
|
|
||||||
NotificationGroup(notifications: [likeA1])!,
|
|
||||||
NotificationGroup(notifications: [mentionB])!,
|
|
||||||
NotificationGroup(notifications: [likeA2])!,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testMergeSimpleGroups() {
|
|
||||||
let group1 = NotificationGroup(notifications: [likeA1])!
|
|
||||||
let group2 = NotificationGroup(notifications: [likeA2])!
|
|
||||||
let merged = NotificationGroup.mergeGroups(first: [group1], second: [group2], only: [.favourite])
|
|
||||||
XCTAssertEqual(merged, [
|
|
||||||
NotificationGroup(notifications: [likeA1, likeA2])!
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testMergeGroupsWithOtherGroupableInBetween() {
|
|
||||||
let group1 = NotificationGroup(notifications: [likeA1])!
|
|
||||||
let group2 = NotificationGroup(notifications: [likeB])!
|
|
||||||
let group3 = NotificationGroup(notifications: [likeA2])!
|
|
||||||
let merged = NotificationGroup.mergeGroups(first: [group1, group2], second: [group3], only: [.favourite])
|
|
||||||
XCTAssertEqual(merged, [
|
|
||||||
NotificationGroup(notifications: [likeA1, likeA2])!,
|
|
||||||
NotificationGroup(notifications: [likeB])!,
|
|
||||||
])
|
|
||||||
|
|
||||||
let merged2 = NotificationGroup.mergeGroups(first: [group1], second: [group2, group3], only: [.favourite])
|
|
||||||
XCTAssertEqual(merged2, [
|
|
||||||
NotificationGroup(notifications: [likeA1, likeA2])!,
|
|
||||||
NotificationGroup(notifications: [likeB])!,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
func testDontMergeWithUngroupableInBetween() {
|
|
||||||
let group1 = NotificationGroup(notifications: [likeA1])!
|
|
||||||
let group2 = NotificationGroup(notifications: [mentionB])!
|
|
||||||
let group3 = NotificationGroup(notifications: [likeA2])!
|
|
||||||
let merged = NotificationGroup.mergeGroups(first: [group1, group2], second: [group3], only: [.favourite])
|
|
||||||
XCTAssertEqual(merged, [
|
|
||||||
NotificationGroup(notifications: [likeA1])!,
|
|
||||||
NotificationGroup(notifications: [mentionB])!,
|
|
||||||
NotificationGroup(notifications: [likeA2])!,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -28,16 +28,6 @@
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
|
||||||
skipped = "NO">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "PachydermTests"
|
|
||||||
BuildableName = "PachydermTests"
|
|
||||||
BlueprintName = "PachydermTests"
|
|
||||||
ReferencedContainer = "container:Pachyderm">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
|
|
|
@ -116,7 +116,7 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
rootVC.sceneDidEnterBackground()
|
rootVC.sceneDidEnterBackground()
|
||||||
}
|
}
|
||||||
|
|
||||||
try? scene.session.mastodonController?.persistentContainer.viewContext.save()
|
try! scene.session.mastodonController?.persistentContainer.viewContext.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handlePendingCrashReport(_ report: PLCrashReport, session: UISceneSession) {
|
private func handlePendingCrashReport(_ report: PLCrashReport, session: UISceneSession) {
|
||||||
|
|
|
@ -140,14 +140,11 @@ class NotificationsTableViewController: DiffableTimelineLikeTableViewController<
|
||||||
self.older = older
|
self.older = older
|
||||||
}
|
}
|
||||||
|
|
||||||
let olderGroups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes)
|
let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes)
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(notifications: newNotifications) {
|
self.mastodonController.persistentContainer.addAll(notifications: newNotifications) {
|
||||||
let existingGroups = currentSnapshot().itemIdentifiers
|
var snapshot = currentSnapshot()
|
||||||
let merged = NotificationGroup.mergeGroups(first: existingGroups, second: olderGroups, only: self.groupTypes)
|
snapshot.appendItems(groups, toSection: .notifications)
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, NotificationGroup>()
|
|
||||||
snapshot.appendSections([.notifications])
|
|
||||||
snapshot.appendItems(merged, toSection: .notifications)
|
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,14 +173,15 @@ class NotificationsTableViewController: DiffableTimelineLikeTableViewController<
|
||||||
self.newer = newer
|
self.newer = newer
|
||||||
}
|
}
|
||||||
|
|
||||||
let newerGroups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes)
|
let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes)
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(notifications: newNotifications) {
|
self.mastodonController.persistentContainer.addAll(notifications: newNotifications) {
|
||||||
let existingGroups = currentSnapshot().itemIdentifiers
|
var snapshot = currentSnapshot()
|
||||||
let merged = NotificationGroup.mergeGroups(first: newerGroups, second: existingGroups, only: self.groupTypes)
|
if let first = snapshot.itemIdentifiers(inSection: .notifications).first {
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, NotificationGroup>()
|
snapshot.insertItems(groups, beforeItem: first)
|
||||||
snapshot.appendSections([.notifications])
|
} else {
|
||||||
snapshot.appendItems(merged, toSection: .notifications)
|
snapshot.appendItems(groups, toSection: .notifications)
|
||||||
|
}
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,23 +120,12 @@ class ProfileViewController: UIPageViewController {
|
||||||
let req = Client.getAccount(id: accountID)
|
let req = Client.getAccount(id: accountID)
|
||||||
mastodonController.run(req) { [weak self] (response) in
|
mastodonController.run(req) { [weak self] (response) in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
switch response {
|
guard case let .success(account, _) = response else { fatalError() }
|
||||||
case .success(let account, _):
|
|
||||||
self.mastodonController.persistentContainer.addOrUpdate(account: account, incrementReferenceCount: true) { (account) in
|
self.mastodonController.persistentContainer.addOrUpdate(account: account, incrementReferenceCount: true) { (account) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.updateAccountUI()
|
self.updateAccountUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure(let error):
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
let config = ToastConfiguration(from: error, with: "Loading", in: self) { [unowned self] (toast) in
|
|
||||||
toast.dismissToast(animated: true)
|
|
||||||
self.loadAccount()
|
|
||||||
}
|
|
||||||
self.showToast(configuration: config, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,6 +271,3 @@ extension ProfileViewController: TabbedPageViewController {
|
||||||
selectPage(at: currentIndex - 1, animated: true)
|
selectPage(at: currentIndex - 1, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProfileViewController: ToastableViewController {
|
|
||||||
}
|
|
||||||
|
|
|
@ -182,12 +182,12 @@ class ProfileHeaderView: UIView {
|
||||||
|
|
||||||
@objc private func updateUIForPreferences() {
|
@objc private func updateUIForPreferences() {
|
||||||
// todo: mastodonController should never be nil, but ProfileHeaderViews are getting leaked
|
// todo: mastodonController should never be nil, but ProfileHeaderViews are getting leaked
|
||||||
guard let mastodonController = mastodonController,
|
guard let mastodonController = mastodonController else {
|
||||||
// nil if prefs changed before own account is loaded
|
|
||||||
let accountID = accountID,
|
|
||||||
let account = mastodonController.persistentContainer.account(for: accountID) else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
guard let account = mastodonController.persistentContainer.account(for: accountID) else {
|
||||||
|
fatalError("Missing cached account \(accountID!)")
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -12,7 +12,6 @@ class ToastView: UIView {
|
||||||
|
|
||||||
let configuration: ToastConfiguration
|
let configuration: ToastConfiguration
|
||||||
|
|
||||||
private var panRecognizer: UIPanGestureRecognizer!
|
|
||||||
private var shrinkAnimator: UIViewPropertyAnimator?
|
private var shrinkAnimator: UIViewPropertyAnimator?
|
||||||
private var recognizedGesture = false
|
private var recognizedGesture = false
|
||||||
private var handledLongPress = false
|
private var handledLongPress = false
|
||||||
|
@ -102,10 +101,9 @@ class ToastView: UIView {
|
||||||
stack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4),
|
stack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4),
|
||||||
])
|
])
|
||||||
|
|
||||||
panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panRecognized))
|
let pan = UIPanGestureRecognizer(target: self, action: #selector(panRecognized))
|
||||||
addGestureRecognizer(panRecognizer)
|
addGestureRecognizer(pan)
|
||||||
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPressRecognized))
|
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPressRecognized))
|
||||||
longPress.delegate = self
|
|
||||||
addGestureRecognizer(longPress)
|
addGestureRecognizer(longPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,11 +266,3 @@ class ToastView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ToastView: UIGestureRecognizerDelegate {
|
|
||||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
||||||
// if another recognizer can recognize simulatenously (e.g., table view cell drag initiation) it should require the toast one to fail
|
|
||||||
// otherwise long-pressing on a toast results in the drag beginning instead
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue