Compare commits
No commits in common. "22022f5ef65fb3aad8feb09dbdaaaf3302c426e2" and "7470b053c6663524236436005c1807ea8ebc11b3" have entirely different histories.
22022f5ef6
...
7470b053c6
|
@ -1,14 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2022.1 (40)
|
|
||||||
Bugfixes:
|
|
||||||
- Fix selecting reblogged statuses in the timeline
|
|
||||||
- Fix links/mentions/hashtags in the timeline not being tappable
|
|
||||||
- Fix mentions from Misskey opening in the browser rather than the profile screen
|
|
||||||
- Fix crash when leaving timeline tab before it finished loading
|
|
||||||
- Fix status cells in the timeline not deselected when tapped in split navigation mode on iPad
|
|
||||||
- Fix keyboard shortcuts not working on iPad
|
|
||||||
|
|
||||||
## 2022.1 (39)
|
## 2022.1 (39)
|
||||||
This is a(nother) hotfix for the previous build. Their changelogs are included below.
|
This is a(nother) hotfix for the previous build. Their changelogs are included below.
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,14 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import WebURL
|
import WebURL
|
||||||
|
|
||||||
public struct Mention: Codable {
|
public class Mention: Codable {
|
||||||
public let url: WebURL
|
public let url: WebURL
|
||||||
public let username: String
|
public let username: String
|
||||||
public let acct: String
|
public let acct: String
|
||||||
/// The instance-local ID of the user being mentioned.
|
/// The instance-local ID of the user being mentioned.
|
||||||
public let id: String
|
public let id: String
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public required init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
self.username = try container.decode(String.self, forKey: .username)
|
self.username = try container.decode(String.self, forKey: .username)
|
||||||
self.acct = try container.decode(String.self, forKey: .acct)
|
self.acct = try container.decode(String.self, forKey: .acct)
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61AC1D4232E9FA600C54D2D /* InstanceSelectorTableViewController.swift */; };
|
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61AC1D4232E9FA600C54D2D /* InstanceSelectorTableViewController.swift */; };
|
||||||
D61AC1D8232EA42D00C54D2D /* InstanceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61AC1D6232EA42D00C54D2D /* InstanceTableViewCell.swift */; };
|
D61AC1D8232EA42D00C54D2D /* InstanceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61AC1D6232EA42D00C54D2D /* InstanceTableViewCell.swift */; };
|
||||||
D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D61AC1D7232EA42D00C54D2D /* InstanceTableViewCell.xib */; };
|
D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D61AC1D7232EA42D00C54D2D /* InstanceTableViewCell.xib */; };
|
||||||
D61DC84628F498F200B82C6E /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61DC84528F498F200B82C6E /* Logging.swift */; };
|
|
||||||
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483323D3801D008A63EF /* LinkTextView.swift */; };
|
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483323D3801D008A63EF /* LinkTextView.swift */; };
|
||||||
D620483623D38075008A63EF /* ContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483523D38075008A63EF /* ContentTextView.swift */; };
|
D620483623D38075008A63EF /* ContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483523D38075008A63EF /* ContentTextView.swift */; };
|
||||||
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; };
|
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; };
|
||||||
|
@ -395,7 +394,6 @@
|
||||||
D61AC1D4232E9FA600C54D2D /* InstanceSelectorTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceSelectorTableViewController.swift; sourceTree = "<group>"; };
|
D61AC1D4232E9FA600C54D2D /* InstanceSelectorTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceSelectorTableViewController.swift; sourceTree = "<group>"; };
|
||||||
D61AC1D6232EA42D00C54D2D /* InstanceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceTableViewCell.swift; sourceTree = "<group>"; };
|
D61AC1D6232EA42D00C54D2D /* InstanceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D61AC1D7232EA42D00C54D2D /* InstanceTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InstanceTableViewCell.xib; sourceTree = "<group>"; };
|
D61AC1D7232EA42D00C54D2D /* InstanceTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InstanceTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
D61DC84528F498F200B82C6E /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
|
||||||
D620483323D3801D008A63EF /* LinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = "<group>"; };
|
D620483323D3801D008A63EF /* LinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = "<group>"; };
|
||||||
D620483523D38075008A63EF /* ContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTextView.swift; sourceTree = "<group>"; };
|
D620483523D38075008A63EF /* ContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTextView.swift; sourceTree = "<group>"; };
|
||||||
D620483723D38190008A63EF /* StatusContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentTextView.swift; sourceTree = "<group>"; };
|
D620483723D38190008A63EF /* StatusContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentTextView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1378,7 +1376,6 @@
|
||||||
D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */,
|
D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */,
|
||||||
D60E2F2B24423EAD005F8713 /* LazilyDecoding.swift */,
|
D60E2F2B24423EAD005F8713 /* LazilyDecoding.swift */,
|
||||||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
||||||
D61DC84528F498F200B82C6E /* Logging.swift */,
|
|
||||||
D6AC956623C4347E008C9946 /* MainSceneDelegate.swift */,
|
D6AC956623C4347E008C9946 /* MainSceneDelegate.swift */,
|
||||||
D6B81F432560390300F6E31D /* MenuController.swift */,
|
D6B81F432560390300F6E31D /* MenuController.swift */,
|
||||||
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */,
|
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */,
|
||||||
|
@ -1849,7 +1846,6 @@
|
||||||
D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */,
|
D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */,
|
||||||
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
||||||
D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */,
|
D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */,
|
||||||
D61DC84628F498F200B82C6E /* Logging.swift in Sources */,
|
|
||||||
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */,
|
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */,
|
||||||
D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */,
|
D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */,
|
||||||
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */,
|
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */,
|
||||||
|
@ -2217,7 +2213,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 = 40;
|
CURRENT_PROJECT_VERSION = 39;
|
||||||
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;
|
||||||
|
@ -2246,7 +2242,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 = 40;
|
CURRENT_PROJECT_VERSION = 39;
|
||||||
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;
|
||||||
|
@ -2356,7 +2352,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 = 40;
|
CURRENT_PROJECT_VERSION = 39;
|
||||||
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;
|
||||||
|
@ -2383,7 +2379,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 = 40;
|
CURRENT_PROJECT_VERSION = 39;
|
||||||
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;
|
||||||
|
|
|
@ -8,19 +8,6 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>DEFAULT-OPTIONS</key>
|
<key>DEFAULT-OPTIONS</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>TTL</key>
|
|
||||||
<dict>
|
|
||||||
<key>Fault</key>
|
|
||||||
<integer>30</integer>
|
|
||||||
<key>Error</key>
|
|
||||||
<integer>30</integer>
|
|
||||||
<key>Debug</key>
|
|
||||||
<integer>15</integer>
|
|
||||||
<key>Info</key>
|
|
||||||
<integer>30</integer>
|
|
||||||
<key>Default</key>
|
|
||||||
<integer>30</integer>
|
|
||||||
</dict>
|
|
||||||
<key>Level</key>
|
<key>Level</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>Persist</key>
|
<key>Persist</key>
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
//
|
|
||||||
// Logging.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 10/10/22.
|
|
||||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import OSLog
|
|
||||||
|
|
||||||
struct Logging {
|
|
||||||
private init() {}
|
|
||||||
|
|
||||||
static let general = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "General")
|
|
||||||
|
|
||||||
static func getLogData() -> Data? {
|
|
||||||
do {
|
|
||||||
let store = try OSLogStore(scope: .currentProcessIdentifier)
|
|
||||||
// past hour
|
|
||||||
let position = store.position(date: Date().addingTimeInterval(-60 * 60))
|
|
||||||
let entries = try store.getEntries(at: position, matching: NSPredicate(format: "subsystem = %@", Bundle.main.bundleIdentifier!))
|
|
||||||
var data = Data()
|
|
||||||
for entry in entries {
|
|
||||||
guard let entry = entry as? OSLogEntryLog else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
data.append(contentsOf: entry.date.formatted(.iso8601).utf8)
|
|
||||||
data.append(32) // ' '
|
|
||||||
data.append(91) // '['
|
|
||||||
data.append(contentsOf: entry.category.utf8)
|
|
||||||
data.append(93) // ']'
|
|
||||||
data.append(32) // ' '
|
|
||||||
data.append(contentsOf: entry.composedMessage.utf8)
|
|
||||||
data.append(10) // '\n'
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
} catch {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,7 +48,7 @@ class IssueReporterViewController: UIViewController {
|
||||||
self.logDataTask = Task(priority: .userInitiated) {
|
self.logDataTask = Task(priority: .userInitiated) {
|
||||||
return await withCheckedContinuation({ continuation in
|
return await withCheckedContinuation({ continuation in
|
||||||
DispatchQueue.global().async {
|
DispatchQueue.global().async {
|
||||||
continuation.resume(returning: Logging.getLogData())
|
continuation.resume(returning: getLogData())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -158,3 +158,29 @@ extension IssueReporterViewController: MFMailComposeViewControllerDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate func getLogData() -> Data? {
|
||||||
|
do {
|
||||||
|
let store = try OSLogStore(scope: .currentProcessIdentifier)
|
||||||
|
// past hour
|
||||||
|
let position = store.position(date: Date().addingTimeInterval(-60 * 60))
|
||||||
|
let entries = try store.getEntries(at: position, matching: NSPredicate(format: "subsystem = %@", Bundle.main.bundleIdentifier!))
|
||||||
|
var data = Data()
|
||||||
|
for entry in entries {
|
||||||
|
guard let entry = entry as? OSLogEntryLog else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data.append(contentsOf: entry.date.formatted(.iso8601).utf8)
|
||||||
|
data.append(32) // ' '
|
||||||
|
data.append(91) // '['
|
||||||
|
data.append(contentsOf: entry.category.utf8)
|
||||||
|
data.append(93) // ']'
|
||||||
|
data.append(32) // ' '
|
||||||
|
data.append(contentsOf: entry.composedMessage.utf8)
|
||||||
|
data.append(10) // '\n'
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
} catch {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ class MainSplitViewController: UISplitViewController {
|
||||||
|
|
||||||
private var tabBarViewController: MainTabBarViewController!
|
private var tabBarViewController: MainTabBarViewController!
|
||||||
|
|
||||||
|
// private var secondaryNavController: UINavigationController! {
|
||||||
|
// viewController(for: .secondary) as? UINavigationController
|
||||||
|
// }
|
||||||
private var secondaryNavController: SplitNavigationController! {
|
private var secondaryNavController: SplitNavigationController! {
|
||||||
viewController(for: .secondary) as? SplitNavigationController
|
viewController(for: .secondary) as? SplitNavigationController
|
||||||
}
|
}
|
||||||
|
@ -46,6 +49,8 @@ class MainSplitViewController: UISplitViewController {
|
||||||
setViewController(sidebar, for: .primary)
|
setViewController(sidebar, for: .primary)
|
||||||
primaryBackgroundStyle = .sidebar
|
primaryBackgroundStyle = .sidebar
|
||||||
|
|
||||||
|
// let secondaryNav = EnhancedNavigationViewController()
|
||||||
|
// secondaryNav.useBrowserStyleNavigation = true
|
||||||
let splitNav = SplitNavigationController()
|
let splitNav = SplitNavigationController()
|
||||||
setViewController(splitNav, for: .secondary)
|
setViewController(splitNav, for: .secondary)
|
||||||
// don't unnecesarily construct a content VC unless the we're in actually split mode
|
// don't unnecesarily construct a content VC unless the we're in actually split mode
|
||||||
|
|
|
@ -175,9 +175,6 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var snapshot = dataSource.snapshot()
|
var snapshot = dataSource.snapshot()
|
||||||
guard snapshot.indexOfSection(.statuses) != nil else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let items = snapshot.itemIdentifiers(inSection: .statuses)
|
let items = snapshot.itemIdentifiers(inSection: .statuses)
|
||||||
let pageSize = 20
|
let pageSize = 20
|
||||||
let numberOfPagesToPrune = (items.count - lastVisibleIndexPath.row - 1) / pageSize
|
let numberOfPagesToPrune = (items.count - lastVisibleIndexPath.row - 1) / pageSize
|
||||||
|
@ -371,9 +368,7 @@ extension TimelineViewController: UICollectionViewDelegate {
|
||||||
case .publicTimelineDescription:
|
case .publicTimelineDescription:
|
||||||
removeTimelineDescriptionCell()
|
removeTimelineDescriptionCell()
|
||||||
case .status(id: let id, state: let state):
|
case .status(id: let id, state: let state):
|
||||||
let status = mastodonController.persistentContainer.status(for: id)!
|
selected(status: id, state: state.copy())
|
||||||
// if the status in the timeline is a reblog, show the status that it is a reblog of
|
|
||||||
selected(status: status.reblog?.id ?? id, state: state.copy())
|
|
||||||
case .loadingIndicator, .confirmLoadMore:
|
case .loadingIndicator, .confirmLoadMore:
|
||||||
fatalError("unreachable")
|
fatalError("unreachable")
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,16 +301,13 @@ extension MenuActionProvider {
|
||||||
}), at: 0)
|
}), at: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var shareSection: [UIAction] = []
|
var shareSection = [
|
||||||
if let url = status.url {
|
openInSafariAction(url: status.url!),
|
||||||
shareSection.append(openInSafariAction(url: url))
|
createAction(identifier: "share", title: "Share", systemImageName: "square.and.arrow.up", handler: { [weak self, weak sourceView] (_) in
|
||||||
} else {
|
|
||||||
Logging.general.fault("Status missing URL: id=\(status.id, privacy: .public), reblog=\((status.reblog?.id).debugDescription, privacy: .public)")
|
|
||||||
}
|
|
||||||
shareSection.append(createAction(identifier: "share", title: "Share", systemImageName: "square.and.arrow.up", handler: { [weak self, weak sourceView] (_) in
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.navigationDelegate?.showMoreOptions(forStatus: status.id, sourceView: sourceView)
|
self.navigationDelegate?.showMoreOptions(forStatus: status.id, sourceView: sourceView)
|
||||||
}))
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
addOpenInNewWindow(actions: &shareSection, activity: UserActivityManager.showConversationActivity(mainStatusID: status.id, accountID: accountID))
|
addOpenInNewWindow(actions: &shareSection, activity: UserActivityManager.showConversationActivity(mainStatusID: status.id, accountID: accountID))
|
||||||
|
|
||||||
|
|
|
@ -55,18 +55,11 @@ class SplitNavigationController: UIViewController {
|
||||||
if let tableVC = sender as? UITableViewController,
|
if let tableVC = sender as? UITableViewController,
|
||||||
let selectedIndexPath = tableVC.tableView.indexPathForSelectedRow {
|
let selectedIndexPath = tableVC.tableView.indexPathForSelectedRow {
|
||||||
tableVC.tableView.deselectRow(at: selectedIndexPath, animated: true)
|
tableVC.tableView.deselectRow(at: selectedIndexPath, animated: true)
|
||||||
} else if let sender = sender as? UIViewController,
|
|
||||||
let collectionView = sender.view as? UICollectionView {
|
|
||||||
// the collection view's animation speed is weirdly fast, so we do it slower
|
|
||||||
UIView.animate(withDuration: 0.5, delay: 0) {
|
|
||||||
collectionView.indexPathsForSelectedItems?.forEach { collectionView.deselectItem(at: $0, animated: false) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.rootNav.pushViewController(vc, animated: true)
|
self.rootNav.pushViewController(vc, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
secondaryNav.owner = self
|
|
||||||
secondaryNav.closeSecondaryImpl = { [unowned self] in
|
secondaryNav.closeSecondaryImpl = { [unowned self] in
|
||||||
self.popToRootViewController(animated: true)
|
self.popToRootViewController(animated: true)
|
||||||
}
|
}
|
||||||
|
@ -79,18 +72,25 @@ class SplitNavigationController: UIViewController {
|
||||||
// it needs a UINavigationController to be this VC's first child, otherwise it will embed this VC inside
|
// it needs a UINavigationController to be this VC's first child, otherwise it will embed this VC inside
|
||||||
// yet another UINavigationController, which can then cause a crash when we try to embed a nav controller inside
|
// yet another UINavigationController, which can then cause a crash when we try to embed a nav controller inside
|
||||||
// of ourself (because nested nav controllers are forbidden)
|
// of ourself (because nested nav controllers are forbidden)
|
||||||
// and because of that, the view needs to be added here, in between the addChild/didMove(toParent:) calls
|
rootNav.willMove(toParent: self)
|
||||||
// and so the view needs to be loaded immediately
|
|
||||||
loadViewIfNeeded()
|
|
||||||
|
|
||||||
addChild(rootNav)
|
addChild(rootNav)
|
||||||
|
rootNav.didMove(toParent: self)
|
||||||
|
secondaryNav.willMove(toParent: self)
|
||||||
|
addChild(secondaryNav)
|
||||||
|
secondaryNav.didMove(toParent: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
rootNav.view.translatesAutoresizingMaskIntoConstraints = false
|
rootNav.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(rootNav.view)
|
view.addSubview(rootNav.view)
|
||||||
rootNav.didMove(toParent: self)
|
|
||||||
addChild(secondaryNav)
|
|
||||||
secondaryNav.view.translatesAutoresizingMaskIntoConstraints = false
|
secondaryNav.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(secondaryNav.view)
|
view.addSubview(secondaryNav.view)
|
||||||
secondaryNav.didMove(toParent: self)
|
|
||||||
|
|
||||||
separatorView.backgroundColor = .separator
|
separatorView.backgroundColor = .separator
|
||||||
separatorView.translatesAutoresizingMaskIntoConstraints = false
|
separatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
@ -114,16 +114,6 @@ class SplitNavigationController: UIViewController {
|
||||||
updateSecondaryNavVisibility()
|
updateSecondaryNavVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
// NOTE: as explained by the large comment above, viewDidLoad is called during initialization, and so things may not be fully setup when it is
|
|
||||||
}
|
|
||||||
|
|
||||||
override func show(_ vc: UIViewController, sender: Any?) {
|
override func show(_ vc: UIViewController, sender: Any?) {
|
||||||
if !canShowSecondaryNav {
|
if !canShowSecondaryNav {
|
||||||
rootNav.pushViewController(vc, animated: true)
|
rootNav.pushViewController(vc, animated: true)
|
||||||
|
@ -257,7 +247,6 @@ private class SplitRootNavigationController: UINavigationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SplitSecondaryNavigationController: EnhancedNavigationViewController {
|
private class SplitSecondaryNavigationController: EnhancedNavigationViewController {
|
||||||
fileprivate unowned var owner: SplitNavigationController!
|
|
||||||
fileprivate var closeSecondaryImpl: (() -> Void)!
|
fileprivate var closeSecondaryImpl: (() -> Void)!
|
||||||
|
|
||||||
override var viewControllers: [UIViewController] {
|
override var viewControllers: [UIViewController] {
|
||||||
|
@ -268,12 +257,6 @@ private class SplitSecondaryNavigationController: EnhancedNavigationViewControll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override var next: UIResponder? {
|
|
||||||
// ordinarily, the next responder in the chain would be the SplitNavigationController's view
|
|
||||||
// but that would bypass the VC in the root nav, so we reroute the repsonder chain to include it
|
|
||||||
owner.viewControllers.first!.view
|
|
||||||
}
|
|
||||||
|
|
||||||
private func configureSecondarySplitCloseButton(for viewController: UIViewController) {
|
private func configureSecondarySplitCloseButton(for viewController: UIViewController) {
|
||||||
guard viewController.navigationItem.leftBarButtonItem?.tag != ViewTags.splitNavCloseSecondaryButton else {
|
guard viewController.navigationItem.leftBarButtonItem?.tag != ViewTags.splitNavCloseSecondaryButton else {
|
||||||
return
|
return
|
||||||
|
|
|
@ -140,10 +140,7 @@ extension TuskerNavigationDelegate {
|
||||||
|
|
||||||
private func moreOptions(forStatus statusID: String) -> UIActivityViewController {
|
private func moreOptions(forStatus statusID: String) -> UIActivityViewController {
|
||||||
guard let status = apiController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID)") }
|
guard let status = apiController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID)") }
|
||||||
guard let url = status.url else {
|
guard let url = status.url else { fatalError("Missing url for status \(statusID)") }
|
||||||
Logging.general.fault("Status missing URL: id=\(status.id, privacy: .public), reblog=\((status.reblog?.id).debugDescription, privacy: .public)")
|
|
||||||
fatalError("Cannot create UIActivityViewController for status without URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
return UIActivityViewController(activityItems: [url, StatusActivityItemSource(status)], applicationActivities: nil)
|
return UIActivityViewController(activityItems: [url, StatusActivityItemSource(status)], applicationActivities: nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,6 @@ extension StatusCollectionViewCell {
|
||||||
updateUIForPreferences(status: status)
|
updateUIForPreferences(status: status)
|
||||||
|
|
||||||
contentContainer.contentTextView.setTextFrom(status: status)
|
contentContainer.contentTextView.setTextFrom(status: status)
|
||||||
contentContainer.contentTextView.navigationDelegate = delegate
|
|
||||||
contentContainer.attachmentsView.delegate = self
|
contentContainer.attachmentsView.delegate = self
|
||||||
contentContainer.attachmentsView.updateUI(status: status)
|
contentContainer.attachmentsView.updateUI(status: status)
|
||||||
contentContainer.cardView.updateUI(status: status)
|
contentContainer.cardView.updateUI(status: status)
|
||||||
|
|
|
@ -26,11 +26,8 @@ class StatusContentTextView: ContentTextView {
|
||||||
let mastodonController = mastodonController,
|
let mastodonController = mastodonController,
|
||||||
let status = mastodonController.persistentContainer.status(for: statusID) {
|
let status = mastodonController.persistentContainer.status(for: statusID) {
|
||||||
mention = status.mentions.first { (mention) in
|
mention = status.mentions.first { (mention) in
|
||||||
url.host == mention.url.host!.serialized && (
|
// Mastodon and Pleroma include the @ in the <a> text, GNU Social does not
|
||||||
text.dropFirst() == mention.username // Mastodon and Pleroma include @ in the text
|
(text.dropFirst() == mention.username || text == mention.username) && url.host == mention.url.host!.serialized
|
||||||
|| text.dropFirst() == mention.acct // Misskey includes @ and uses the whole acct
|
|
||||||
|| text == mention.username // GNU Social does not include the @ in the text, so we don't need to drop it
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mention = nil
|
mention = nil
|
||||||
|
|
Loading…
Reference in New Issue