Compare commits
No commits in common. "dc818524b2611e690d9715d44ffd21862b6767e8" and "0a7709526f839ac5c5ce8433a6db7c91d815969e" have entirely different histories.
dc818524b2
...
0a7709526f
|
@ -1,8 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2022.1 (26)
|
|
||||||
This build contains hotfixes for several crashes that may occur when logged-in to a Pixelfed account.
|
|
||||||
|
|
||||||
## 2022.1 (25)
|
## 2022.1 (25)
|
||||||
Features/Improvements:
|
Features/Improvements:
|
||||||
- Improve error reporting for non-crash errors
|
- Improve error reporting for non-crash errors
|
||||||
|
|
|
@ -25,7 +25,6 @@ let package = Package(
|
||||||
name: "Pachyderm",
|
name: "Pachyderm",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "WebURL", package: "swift-url"),
|
.product(name: "WebURL", package: "swift-url"),
|
||||||
.product(name: "WebURLFoundationExtras", package: "swift-url"),
|
|
||||||
]),
|
]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "PachydermTests",
|
name: "PachydermTests",
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import WebURL
|
|
||||||
import WebURLFoundationExtras
|
|
||||||
|
|
||||||
public class Hashtag: Codable {
|
public class Hashtag: Codable {
|
||||||
public let name: String
|
public let name: String
|
||||||
|
@ -22,18 +20,6 @@ public class Hashtag: Codable {
|
||||||
self.history = nil
|
self.history = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public required init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
self.name = try container.decode(String.self, forKey: .name)
|
|
||||||
// pixelfed (possibly others) don't fully escape special characters in the hashtag url
|
|
||||||
if let url = URL(try container.decode(WebURL.self, forKey: .url)) {
|
|
||||||
self.url = url
|
|
||||||
} else {
|
|
||||||
throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "unable to convert WebURL to URL")
|
|
||||||
}
|
|
||||||
self.history = try container.decodeIfPresent([History].self, forKey: .history)
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case name
|
case name
|
||||||
case url
|
case url
|
||||||
|
|
|
@ -2165,7 +2165,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 26;
|
CURRENT_PROJECT_VERSION = 25;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
@ -2196,7 +2196,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 26;
|
CURRENT_PROJECT_VERSION = 25;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
@ -2306,7 +2306,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 26;
|
CURRENT_PROJECT_VERSION = 25;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
@ -2333,7 +2333,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 26;
|
CURRENT_PROJECT_VERSION = 25;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
|
|
@ -85,16 +85,14 @@ class ProfileStatusesViewController: DiffableTimelineLikeTableViewController<Pro
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
completion(.failure(.client(error)))
|
completion(.failure(.client(error)))
|
||||||
|
|
||||||
case let .success(statuses, _):
|
case let .success(statuses, pagination):
|
||||||
if !statuses.isEmpty {
|
self.older = pagination?.older
|
||||||
self.newer = .after(id: statuses.first!.id, count: nil)
|
self.newer = pagination?.newer
|
||||||
self.older = .before(id: statuses.last!.id, count: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
var snapshot = self.dataSource.snapshot()
|
var snapshot = self.dataSource.snapshot()
|
||||||
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown, pinned: false) }, toSection: .statuses)
|
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown) }, toSection: .statuses)
|
||||||
if self.kind == .statuses {
|
if self.kind == .statuses {
|
||||||
self.loadPinnedStatuses(snapshot: { snapshot }, completion: completion)
|
self.loadPinnedStatuses(snapshot: { snapshot }, completion: completion)
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,7 +120,7 @@ class ProfileStatusesViewController: DiffableTimelineLikeTableViewController<Pro
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
var snapshot = snapshot()
|
var snapshot = snapshot()
|
||||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .pinned))
|
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .pinned))
|
||||||
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown, pinned: true) }, toSection: .pinned)
|
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown) }, toSection: .pinned)
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,17 +139,19 @@ class ProfileStatusesViewController: DiffableTimelineLikeTableViewController<Pro
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
completion(.failure(.client(error)))
|
completion(.failure(.client(error)))
|
||||||
|
|
||||||
case let .success(statuses, _):
|
case let .success(statuses, pagination):
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
completion(.failure(.noOlder))
|
completion(.failure(.noOlder))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.older = .before(id: statuses.last!.id, count: nil)
|
if let older = pagination?.older {
|
||||||
|
self.older = older
|
||||||
|
}
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
var snapshot = currentSnapshot()
|
var snapshot = currentSnapshot()
|
||||||
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown, pinned: false) }, toSection: .statuses)
|
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown) }, toSection: .statuses)
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,17 +170,19 @@ class ProfileStatusesViewController: DiffableTimelineLikeTableViewController<Pro
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
completion(.failure(.client(error)))
|
completion(.failure(.client(error)))
|
||||||
|
|
||||||
case let .success(statuses, _):
|
case let .success(statuses, pagination):
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
completion(.failure(.allCaughtUp))
|
completion(.failure(.noNewer))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.newer = .after(id: statuses.first!.id, count: nil)
|
if let newer = pagination?.newer {
|
||||||
|
self.newer = newer
|
||||||
|
}
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
var snapshot = currentSnapshot()
|
var snapshot = currentSnapshot()
|
||||||
let items = statuses.map { Item(id: $0.id, state: .unknown, pinned: false) }
|
let items = statuses.map { Item(id: $0.id, state: .unknown) }
|
||||||
if let first = snapshot.itemIdentifiers(inSection: .statuses).first {
|
if let first = snapshot.itemIdentifiers(inSection: .statuses).first {
|
||||||
snapshot.insertItems(items, beforeItem: first)
|
snapshot.insertItems(items, beforeItem: first)
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,15 +248,13 @@ extension ProfileStatusesViewController {
|
||||||
struct Item: Hashable {
|
struct Item: Hashable {
|
||||||
let id: String
|
let id: String
|
||||||
let state: StatusState
|
let state: StatusState
|
||||||
let pinned: Bool
|
|
||||||
|
|
||||||
static func ==(lhs: Item, rhs: Item) -> Bool {
|
static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||||
return lhs.id == rhs.id && lhs.pinned == rhs.pinned
|
return lhs.id == rhs.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(id)
|
hasher.combine(id)
|
||||||
hasher.combine(pinned)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,11 +151,9 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
completion(.failure(.client(error)))
|
completion(.failure(.client(error)))
|
||||||
|
|
||||||
case let .success(statuses, _):
|
case let .success(statuses, pagination):
|
||||||
if !statuses.isEmpty {
|
self.newer = pagination?.newer
|
||||||
self.newer = .after(id: statuses.first!.id, count: nil)
|
self.older = pagination?.older
|
||||||
self.older = .before(id: statuses.last!.id, count: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
@ -185,6 +183,7 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
snapshot.appendItems([.confirmLoadMore], toSection: .footer)
|
snapshot.appendItems([.confirmLoadMore], toSection: .footer)
|
||||||
|
self.dataSource.apply(snapshot)
|
||||||
completion(.success(snapshot))
|
completion(.success(snapshot))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -196,10 +195,8 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
completion(.failure(.client(error)))
|
completion(.failure(.client(error)))
|
||||||
|
|
||||||
case let .success(statuses, _):
|
case let .success(statuses, pagination):
|
||||||
if !statuses.isEmpty {
|
self.older = pagination?.older
|
||||||
self.older = .before(id: statuses.last!.id, count: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
var snapshot = currentSnapshot()
|
var snapshot = currentSnapshot()
|
||||||
|
@ -223,13 +220,17 @@ class TimelineTableViewController: DiffableTimelineLikeTableViewController<Timel
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
completion(.failure(.client(error)))
|
completion(.failure(.client(error)))
|
||||||
|
|
||||||
case let .success(statuses, _):
|
case let .success(statuses, pagination):
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
completion(.failure(.allCaughtUp))
|
completion(.failure(.allCaughtUp))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.newer = .after(id: statuses.first!.id, count: nil)
|
// if there are no new statuses, pagination is nil
|
||||||
|
// if we were to then overwrite self.newer, future refresh would fail
|
||||||
|
if let newer = pagination?.newer {
|
||||||
|
self.newer = newer
|
||||||
|
}
|
||||||
|
|
||||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
var snapshot = currentSnapshot()
|
var snapshot = currentSnapshot()
|
||||||
|
|
Loading…
Reference in New Issue