Compare commits

..

No commits in common. "6a5753fac8bfd6a60dd3e5fa0b44815df3e2bcdb" and "cc33cf18f239e2be8606e691a28994539eb39c3c" have entirely different histories.

26 changed files with 37 additions and 83 deletions

View File

@ -1,15 +1,5 @@
# Changelog
## 2022.1 (42)
Features/Improvements:
- Add automatic crash reporting
- Tweak spacing on timeline statuses
Bugfixes:
- Fix status collapse/expand not animating on profiles
- Fix crash when opening profile for unloaded account (e.g., by tapping mentions)
- macOS: Add workaround for Follow/Unfollow menu item never loading
## 2022.1 (41)
Features/Improvements:
- Rewrite profile screens to use new timeline implementation

View File

@ -12,7 +12,6 @@ public class Instance: Decodable {
public let uri: String
public let title: String
public let description: String
public let shortDescription: String?
public let email: String?
public let version: String
public let urls: [String: URL]
@ -41,7 +40,6 @@ public class Instance: Decodable {
self.uri = try container.decode(String.self, forKey: .uri)
self.title = try container.decode(String.self, forKey: .title)
self.description = try container.decode(String.self, forKey: .description)
self.shortDescription = try container.decodeIfPresent(String.self, forKey: .shortDescription)
self.email = try container.decodeIfPresent(String.self, forKey: .email)
self.version = try container.decode(String.self, forKey: .version)
if let urls = try? container.decodeIfPresent([String: URL].self, forKey: .urls) {
@ -74,7 +72,6 @@ public class Instance: Decodable {
case uri
case title
case description
case shortDescription = "short_description"
case email
case version
case urls

View File

@ -1717,7 +1717,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
shellScript = "echo \"$CONFIGURATION\"\nif [ \"$CONFIGURATION\" == \"Dist\" ]; then\nif which sentry-cli >/dev/null; then\nexport SENTRY_ORG=vaccor\nexport SENTRY_PROJECT=tusker\nERROR=$(sentry-cli upload-dif \"$DWARF_DSYM_FOLDER_PATH\" --force-foreground 2>&1)\nif [ ! $? -eq 0 ]; then\necho \"sentry-cli uploaded debug info\"\nelse\necho \"error: sentry-cli - $ERROR\"\nexit 1\nfi\nelse\necho \"error: sentry-cli not installed, download from https://github.com/getsentry/sentry-cli/releases\"\nexit 1\nfi\nfi\n";
shellScript = "echo \"$CONFIGURATION\"\nif [ \"$CONFIGURATION\" == \"Dist\" ]; then\nif which sentry-cli >/dev/null; then\nexport SENTRY_ORG=vaccor\nexport SENTRY_PROJECT=tusker\nERROR=$(sentry-cli upload-dif \"$DWARF_DSYM_FOLDER_PATH\" --force-foreground 2>&1 >/dev/null)\nif [ ! $? -eq 0 ]; then\necho \"sentry-cli uploaded debug info\"\nelse\necho \"error: sentry-cli - $ERROR\"\nfi\nelse\necho \"error: sentry-cli not installed, download from https://github.com/getsentry/sentry-cli/releases\"\nfi\nfi\n";
showEnvVarsInLog = 0;
};
D65F612C23AE957600F3CFD3 /* Embed debug-only frameworks */ = {
@ -2154,7 +2154,7 @@
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 42;
CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = Tusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2222,7 +2222,7 @@
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 42;
CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = OpenInTusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
@ -2244,6 +2244,7 @@
};
D6D4DDF2212518A200E1C4BB /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D63CC703290EC472000E19DE /* Dist.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
@ -2372,7 +2373,7 @@
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 42;
CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = Tusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2401,7 +2402,7 @@
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 42;
CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = Tusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2511,7 +2512,7 @@
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 42;
CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = OpenInTusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
@ -2538,7 +2539,7 @@
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 42;
CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = OpenInTusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;

View File

@ -64,20 +64,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
options.dsn = "https://\(dsn)"
options.enableSwizzling = false
// required to support releases/release health
options.enableAutoSessionTracking = true
options.enableAutoSessionTracking = false
options.enableOutOfMemoryTracking = false
options.enableAutoPerformanceTracking = false
options.enableNetworkTracking = false
options.enableAppHangTracking = false
options.enableCoreDataTracking = false
// we don't care about events like battery, keyboard show/hide
options.enableAutoBreadcrumbTracking = false
options.beforeSend = { event in
// just no, why would anyone need this information
event.context?.removeValue(forKey: "culture")
return Preferences.shared.reportErrorsAutomatically ? event : nil
Preferences.shared.reportErrorsAutomatically ? event : nil
}
}
}

View File

@ -11,7 +11,6 @@ import CoreData
import Pachyderm
import Combine
import OSLog
import Sentry
fileprivate let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PersistentStore")
@ -74,9 +73,6 @@ class MastodonCachePersistentStore: NSPersistentContainer {
try context.save()
} catch {
logger.error("Unable to save managed object context: \(String(describing: error), privacy: .public)")
let crumb = Breadcrumb(level: .fatal, category: "PersistentStore")
crumb.message = String(describing: error)
SentrySDK.addBreadcrumb(crumb: crumb)
fatalError("Unable to save managed object context")
}
}

View File

@ -65,7 +65,7 @@ class AccountListTableViewController: EnhancedTableViewController {
}
extension AccountListTableViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension AccountListTableViewController: ToastableViewController {

View File

@ -154,7 +154,6 @@ class BookmarksTableViewController: EnhancedTableViewController {
}
extension BookmarksTableViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
}
extension BookmarksTableViewController: ToastableViewController {
@ -164,6 +163,8 @@ extension BookmarksTableViewController: MenuActionProvider {
}
extension BookmarksTableViewController: StatusTableViewCellDelegate {
var apiController: MastodonController { mastodonController }
func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) {
tableView.beginUpdates()
tableView.endUpdates()

View File

@ -11,20 +11,12 @@ import Pachyderm
struct MainComposeTextView: View {
@ObservedObject var draft: Draft
@State private var placeholder: Text = {
let placeholder: Text = {
let components = Calendar.current.dateComponents([.month, .day], from: Date())
if components.month == 3 && components.day == 14 {
if Date().formatted(date: .numeric, time: .omitted).starts(with: "3") {
return Text("Happy π day!")
}
} else if components.month == 9 && components.day == 21 {
if components.month == 9 && components.day == 21 {
return Text("Do you remember?")
} else if components.month == 10 && components.day == 31 {
if .random() {
return Text("Post something spooky!")
} else {
return Text("Any questions?")
}
}
return Text("What's on your mind?")
}()

View File

@ -441,8 +441,6 @@ extension ConversationTableViewController {
}
extension ConversationTableViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
func conversation(mainStatusID: String, state: StatusState) -> ConversationTableViewController {
let vc = ConversationTableViewController(for: mainStatusID, state: state, mastodonController: mastodonController)
// transfer show statuses automatically state when showing new conversation
@ -455,6 +453,7 @@ extension ConversationTableViewController: MenuActionProvider {
}
extension ConversationTableViewController: StatusTableViewCellDelegate {
var apiController: MastodonController { mastodonController }
func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) {
// causes the table view to recalculate the cell heights
tableView.beginUpdates()

View File

@ -147,7 +147,7 @@ extension ProfileDirectoryViewController {
}
extension ProfileDirectoryViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension ProfileDirectoryViewController: ToastableViewController {

View File

@ -120,7 +120,7 @@ extension TrendingHashtagsViewController: UICollectionViewDragDelegate {
}
extension TrendingHashtagsViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension TrendingHashtagsViewController: ToastableViewController {

View File

@ -101,7 +101,7 @@ extension TrendingLinksViewController {
}
extension TrendingLinksViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension TrendingLinksViewController: ToastableViewController {

View File

@ -82,7 +82,7 @@ extension TrendingStatusesViewController {
}
extension TrendingStatusesViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension TrendingStatusesViewController: ToastableViewController {

View File

@ -37,15 +37,8 @@ class FindInstanceViewController: InstanceSelectorTableViewController {
// MARK: - Interaction
@objc func cancelButtonPressed() {
// when the search controller is active, dismiss exits it rather than dismissing ourself, so we have to dismiss twice
if searchController.isActive {
dismiss(animated: false) {
self.dismiss(animated: true)
}
} else {
dismiss(animated: true)
}
}
}

View File

@ -174,7 +174,7 @@ extension EditListAccountsViewController: SearchResultsViewControllerDelegate {
}
extension EditListAccountsViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension EditListAccountsViewController: ToastableViewController {

View File

@ -269,7 +269,7 @@ extension NotificationsTableViewController {
}
extension NotificationsTableViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension NotificationsTableViewController: MenuActionProvider {

View File

@ -100,7 +100,7 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
}
case .loading:
break
case .loaded, .setupInitialSnapshot:
case .loaded, .addedHeader:
var snapshot = dataSource.snapshot()
snapshot.reconfigureItems([.header(id)])
dataSource.apply(snapshot, animatingDifferences: true)
@ -183,7 +183,7 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
snapshot.appendItems([.header(accountID)], toSection: .header)
await apply(snapshot, animatingDifferences: false)
state = .setupInitialSnapshot
state = .addedHeader
await controller.loadInitial()
await tryLoadPinned()
@ -225,12 +225,6 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
}
@objc func refresh() {
guard case .loaded = state else {
#if !targetEnvironment(macCatalyst)
collectionView.refreshControl?.endRefreshing()
#endif
return
}
Task {
// TODO: coalesce these data source updates
// TODO: refresh profile
@ -248,7 +242,7 @@ extension ProfileStatusesViewController {
enum State {
case unloaded
case loading
case setupInitialSnapshot
case addedHeader
case loaded
}
}
@ -455,7 +449,7 @@ extension ProfileStatusesViewController: UICollectionViewDragDelegate {
}
extension ProfileStatusesViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension ProfileStatusesViewController: MenuActionProvider {

View File

@ -279,7 +279,7 @@ extension ProfileViewController {
}
extension ProfileViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension ProfileViewController: ToastableViewController {

View File

@ -289,7 +289,6 @@ extension SearchResultsViewController: UISearchBarDelegate {
}
extension SearchResultsViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
}
extension SearchResultsViewController: ToastableViewController {
@ -299,6 +298,7 @@ extension SearchResultsViewController: MenuActionProvider {
}
extension SearchResultsViewController: StatusTableViewCellDelegate {
var apiController: MastodonController { mastodonController }
func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) {
tableView.beginUpdates()
tableView.endUpdates()

View File

@ -319,7 +319,7 @@ extension SearchViewController: UICollectionViewDragDelegate {
}
extension SearchViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension SearchViewController: ToastableViewController {

View File

@ -145,7 +145,6 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController {
}
extension StatusActionAccountListTableViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
}
extension StatusActionAccountListTableViewController: ToastableViewController {
@ -155,6 +154,7 @@ extension StatusActionAccountListTableViewController: MenuActionProvider {
}
extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate {
var apiController: MastodonController { mastodonController }
func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) {
// causes the table view to recalculate the cell heights
tableView.beginUpdates()

View File

@ -294,7 +294,7 @@ extension TimelineTableViewController {
}
extension TimelineTableViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension TimelineTableViewController: StatusTableViewCellDelegate {

View File

@ -398,7 +398,7 @@ extension TimelineViewController: UICollectionViewDragDelegate {
}
extension TimelineViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController }
var apiController: MastodonController { mastodonController }
}
extension TimelineViewController: MenuActionProvider {

View File

@ -96,11 +96,7 @@ actor TimelineLikeController<Item> {
return
}
let token = LoadAttemptToken()
guard await delegate.canLoadOlder(),
// Make sure we're still in the idle state before continuing on, since that may have chnaged while waiting for user input.
// If the load more cell appears, then the users scrolls up and back down, the VC may kick off a second loadOlder task
// but we only want one to proceed. The actor prevents a data race, and this prevents multiple simultaneousl loadOlder tasks from running.
state == .idle else {
guard await delegate.canLoadOlder() else {
return
}
state = .loadingOlder(token, hasAddedLoadingIndicator: false)

View File

@ -11,7 +11,7 @@ import SafariServices
import Pachyderm
protocol TuskerNavigationDelegate: UIViewController, ToastableViewController {
var apiController: MastodonController! { get }
var apiController: MastodonController { get }
func conversation(mainStatusID: String, state: StatusState) -> ConversationTableViewController
}

View File

@ -48,7 +48,7 @@ class InstanceTableViewCell: UITableViewCell {
domainLabel.text = URLComponents(string: instance.uri)?.host ?? instance.uri
adultLabel.isHidden = true
descriptionTextView.setTextFromHtml(instance.shortDescription ?? instance.description)
descriptionTextView.setTextFromHtml(instance.description)
if let thumbnail = instance.thumbnail {
updateThumbnail(url: thumbnail)