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 # 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) ## 2022.1 (41)
Features/Improvements: Features/Improvements:
- Rewrite profile screens to use new timeline implementation - Rewrite profile screens to use new timeline implementation

View File

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

View File

@ -1717,7 +1717,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash; 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; showEnvVarsInLog = 0;
}; };
D65F612C23AE957600F3CFD3 /* Embed debug-only frameworks */ = { D65F612C23AE957600F3CFD3 /* Embed debug-only frameworks */ = {
@ -2154,7 +2154,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 = 42; CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2; DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2222,7 +2222,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 = 42; CURRENT_PROJECT_VERSION = 41;
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;
@ -2244,6 +2244,7 @@
}; };
D6D4DDF2212518A200E1C4BB /* Debug */ = { D6D4DDF2212518A200E1C4BB /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = D63CC703290EC472000E19DE /* Dist.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
@ -2372,7 +2373,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 = 42; CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2; DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2401,7 +2402,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 = 42; CURRENT_PROJECT_VERSION = 41;
DEVELOPMENT_TEAM = V4WK9KR9U2; DEVELOPMENT_TEAM = V4WK9KR9U2;
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2511,7 +2512,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 = 42; CURRENT_PROJECT_VERSION = 41;
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;
@ -2538,7 +2539,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 = 42; CURRENT_PROJECT_VERSION = 41;
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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,14 +37,7 @@ class FindInstanceViewController: InstanceSelectorTableViewController {
// MARK: - Interaction // MARK: - Interaction
@objc func cancelButtonPressed() { @objc func cancelButtonPressed() {
// when the search controller is active, dismiss exits it rather than dismissing ourself, so we have to dismiss twice dismiss(animated: true)
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 { extension EditListAccountsViewController: TuskerNavigationDelegate {
var apiController: MastodonController! { mastodonController } var apiController: MastodonController { mastodonController }
} }
extension EditListAccountsViewController: ToastableViewController { extension EditListAccountsViewController: ToastableViewController {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -96,11 +96,7 @@ actor TimelineLikeController<Item> {
return return
} }
let token = LoadAttemptToken() let token = LoadAttemptToken()
guard await delegate.canLoadOlder(), guard await delegate.canLoadOlder() else {
// 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 {
return return
} }
state = .loadingOlder(token, hasAddedLoadingIndicator: false) state = .loadingOlder(token, hasAddedLoadingIndicator: false)

View File

@ -11,7 +11,7 @@ import SafariServices
import Pachyderm import Pachyderm
protocol TuskerNavigationDelegate: UIViewController, ToastableViewController { protocol TuskerNavigationDelegate: UIViewController, ToastableViewController {
var apiController: MastodonController! { get } var apiController: MastodonController { get }
func conversation(mainStatusID: String, state: StatusState) -> ConversationTableViewController 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 domainLabel.text = URLComponents(string: instance.uri)?.host ?? instance.uri
adultLabel.isHidden = true adultLabel.isHidden = true
descriptionTextView.setTextFromHtml(instance.shortDescription ?? instance.description) descriptionTextView.setTextFromHtml(instance.description)
if let thumbnail = instance.thumbnail { if let thumbnail = instance.thumbnail {
updateThumbnail(url: thumbnail) updateThumbnail(url: thumbnail)