Compare commits
No commits in common. "6a5753fac8bfd6a60dd3e5fa0b44815df3e2bcdb" and "cc33cf18f239e2be8606e691a28994539eb39c3c" have entirely different histories.
6a5753fac8
...
cc33cf18f2
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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?")
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -37,15 +37,8 @@ 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
|
|
||||||
if searchController.isActive {
|
|
||||||
dismiss(animated: false) {
|
|
||||||
self.dismiss(animated: true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dismiss(animated: true)
|
dismiss(animated: true)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue