diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index cb88c3960..879d91053 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,12 +7,12 @@
AppShared.xcscheme_^#shared#^_
orderHint
- 42
+ 35
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 43
+ 36
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -97,7 +97,7 @@
MastodonIntent.xcscheme_^#shared#^_
orderHint
- 44
+ 37
MastodonIntents.xcscheme_^#shared#^_
@@ -117,7 +117,7 @@
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 41
+ 38
SuppressBuildableAutocreation
diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift
index 23c2a6f44..696b211bc 100644
--- a/Mastodon/Coordinator/SceneCoordinator.swift
+++ b/Mastodon/Coordinator/SceneCoordinator.swift
@@ -139,6 +139,7 @@ extension SceneCoordinator {
case show // push
case showDetail // replace
case modal(animated: Bool, completion: (() -> Void)? = nil)
+ case popover(sourceView: UIView)
case panModal
case custom(transitioningDelegate: UIViewControllerTransitioningDelegate)
case customPush
@@ -326,7 +327,10 @@ extension SceneCoordinator {
panModalPresentable.transitioningDelegate = PanModalPresentationDelegate.default
presentingViewController.present(panModalPresentable, animated: true, completion: nil)
//presentingViewController.presentPanModal(panModalPresentable)
-
+ case .popover(let sourceView):
+ viewController.modalPresentationStyle = .popover
+ viewController.popoverPresentationController?.sourceView = sourceView
+ (splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil)
case .custom(let transitioningDelegate):
viewController.modalPresentationStyle = .custom
viewController.transitioningDelegate = transitioningDelegate
diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift
index 743ad1dc2..722896641 100644
--- a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift
+++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift
@@ -9,7 +9,7 @@ import UIKit
import MetaTextKit
final class AddAccountTableViewCell: UITableViewCell {
-
+
let iconImageView: UIImageView = {
let image = UIImage(systemName: "plus.circle.fill")!
let imageView = UIImageView(image: image)
@@ -51,6 +51,28 @@ extension AddAccountTableViewCell {
])
iconImageView.setContentHuggingPriority(.defaultLow, for: .horizontal)
iconImageView.setContentHuggingPriority(.defaultLow, for: .vertical)
+
+ // layout the same placeholder UI from `AccountListTableViewCell`
+ let placeholderLabelContainerStackView = UIStackView()
+ placeholderLabelContainerStackView.axis = .vertical
+ placeholderLabelContainerStackView.distribution = .equalCentering
+ placeholderLabelContainerStackView.spacing = 2
+ placeholderLabelContainerStackView.distribution = .fillProportionally
+ placeholderLabelContainerStackView.translatesAutoresizingMaskIntoConstraints = false
+ contentView.addSubview(placeholderLabelContainerStackView)
+ NSLayoutConstraint.activate([
+ placeholderLabelContainerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
+ placeholderLabelContainerStackView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10),
+ contentView.bottomAnchor.constraint(equalTo: placeholderLabelContainerStackView.bottomAnchor, constant: 10),
+ iconImageView.heightAnchor.constraint(equalTo: placeholderLabelContainerStackView.heightAnchor, multiplier: 0.8).priority(.required - 10),
+ ])
+ let _nameLabel = MetaLabel(style: .accountListName)
+ _nameLabel.configure(content: PlaintextMetaContent(string: " "))
+ let _usernameLabel = MetaLabel(style: .accountListUsername)
+ _usernameLabel.configure(content: PlaintextMetaContent(string: " "))
+ placeholderLabelContainerStackView.addArrangedSubview(_nameLabel)
+ placeholderLabelContainerStackView.addArrangedSubview(_usernameLabel)
+ placeholderLabelContainerStackView.isHidden = true
titleLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(titleLabel)
@@ -58,7 +80,7 @@ extension AddAccountTableViewCell {
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 15),
titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10),
contentView.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15),
- iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10),
+ // iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10),
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
])
diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift
index 6f5e294cd..6e595f2ee 100644
--- a/Mastodon/Scene/Root/ContentSplitViewController.swift
+++ b/Mastodon/Scene/Root/ContentSplitViewController.swift
@@ -63,7 +63,7 @@ extension ContentSplitViewController {
sidebarViewController.didMove(toParent: self)
NSLayoutConstraint.activate([
mainTabBarController.view.topAnchor.constraint(equalTo: view.topAnchor),
- mainTabBarController.view.leadingAnchor.constraint(equalTo: sidebarViewController.view.trailingAnchor),
+ mainTabBarController.view.leadingAnchor.constraint(equalTo: sidebarViewController.view.trailingAnchor, constant: UIView.separatorLineHeight(of: view)),
mainTabBarController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
mainTabBarController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
@@ -87,6 +87,22 @@ extension ContentSplitViewController: SidebarViewControllerDelegate {
assertionFailure()
return
}
+ let previousTab = currentSupplementaryTab
currentSupplementaryTab = tab
+
+ if previousTab == tab,
+ let navigationController = mainTabBarController.selectedViewController as? UINavigationController
+ {
+ navigationController.popToRootViewController(animated: true)
+ }
}
+
+ func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView) {
+ guard case let .tab(tab) = item, tab == .me else { return }
+
+ let accountListViewController = coordinator.present(scene: .accountList, from: nil, transition: .popover(sourceView: sourceView)) as! AccountListViewController
+ accountListViewController.dragIndicatorView.barView.isHidden = true
+ accountListViewController.preferredContentSize = CGSize(width: 300, height: 320)
+ }
+
}
diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift
index fc1e7a4f7..22354751d 100644
--- a/Mastodon/Scene/Root/RootSplitViewController.swift
+++ b/Mastodon/Scene/Root/RootSplitViewController.swift
@@ -26,8 +26,17 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
return contentSplitViewController
}()
+ private(set) lazy var searchViewController: SearchViewController = {
+ let searchViewController = SearchViewController()
+ searchViewController.context = context
+ searchViewController.coordinator = coordinator
+ return searchViewController
+ }()
+
lazy var compactMainTabBarViewController = MainTabBarController(context: context, coordinator: coordinator)
+ let separatorLine = UIView.separatorLine
+
init(context: AppContext, coordinator: SceneCoordinator) {
self.context = context
self.coordinator = coordinator
@@ -48,13 +57,9 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
// Fallback on earlier versions
}
- setViewController(UIViewController(), for: .primary)
+ setViewController(searchViewController, for: .primary)
setViewController(contentSplitViewController, for: .secondary)
setViewController(compactMainTabBarViewController, for: .compact)
-
- contentSplitViewController.sidebarViewController.view.layer.zPosition = 100
- contentSplitViewController.mainTabBarController.view.layer.zPosition = 90
- view.layer.zPosition = 80
}
required init?(coder: NSCoder) {
@@ -80,6 +85,15 @@ extension RootSplitViewController {
self.updateBehavior(size: self.view.frame.size)
}
.store(in: &disposeBag)
+
+ setupBackground(theme: ThemeService.shared.currentTheme.value)
+ ThemeService.shared.currentTheme
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] theme in
+ guard let self = self else { return }
+ self.setupBackground(theme: theme)
+ }
+ .store(in: &disposeBag)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
@@ -108,6 +122,15 @@ extension RootSplitViewController {
}
+extension RootSplitViewController {
+
+ private func setupBackground(theme: Theme) {
+ // this set column separator line color
+ view.backgroundColor = theme.separator
+ }
+
+}
+
// MARK: - UISplitViewControllerDelegate
extension RootSplitViewController: UISplitViewControllerDelegate {
diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
index 060091922..7958c5080 100644
--- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
+++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
@@ -12,10 +12,13 @@ import CoreDataStack
protocol SidebarViewControllerDelegate: AnyObject {
func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab)
+ func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView)
}
final class SidebarViewController: UIViewController, NeedsDependency {
+ let logger = Logger(subsystem: "SidebarViewController", category: "ViewController")
+
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
@@ -127,6 +130,10 @@ extension SidebarViewController {
self.collectionView.contentInset.bottom = height
}
.store(in: &observations)
+
+ let sidebarLongPressGestureRecognizer = UILongPressGestureRecognizer()
+ sidebarLongPressGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarLongPressGestureRecognizerHandler(_:)))
+ collectionView.addGestureRecognizer(sidebarLongPressGestureRecognizer)
}
private func setupBackground(theme: Theme) {
@@ -148,6 +155,23 @@ extension SidebarViewController {
}
+extension SidebarViewController {
+ @objc private func sidebarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) {
+ guard sender.state == .began else { return }
+
+ logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
+ assert(sender.view === collectionView)
+
+ let position = sender.location(in: collectionView)
+ guard let indexPath = collectionView.indexPathForItem(at: position) else { return }
+ guard let diffableDataSource = viewModel.diffableDataSource else { return }
+ guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
+ guard let cell = collectionView.cellForItem(at: indexPath) else { return }
+ delegate?.sidebarViewController(self, didLongPressItem: item, sourceView: cell)
+ }
+
+}
+
// MARK: - UICollectionViewDelegate
extension SidebarViewController: UICollectionViewDelegate {
@@ -179,25 +203,5 @@ extension SidebarViewController: UICollectionViewDelegate {
default:
assertionFailure()
}
-// switch item {
-// case .tab(let tab):
-// delegate?.sidebarViewController(self, didSelectTab: tab)
-// case .searchHistory(let viewModel):
-// delegate?.sidebarViewController(self, didSelectSearchHistory: viewModel)
-// case .header:
-// break
-// case .account(let viewModel):
-// assert(Thread.isMainThread)
-// let authentication = context.managedObjectContext.object(with: viewModel.authenticationObjectID) as! MastodonAuthentication
-// context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID)
-// .receive(on: DispatchQueue.main)
-// .sink { [weak self] result in
-// guard let self = self else { return }
-// self.coordinator.setup()
-// }
-// .store(in: &disposeBag)
-// case .addAccount:
-// coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
-// }
}
}
diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift
index 8c013efda..d85d3a8be 100644
--- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift
+++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift
@@ -18,6 +18,7 @@ final class SidebarListContentView: UIView, UIContentView {
let avatarButton: CircleAvatarButton = {
let button = CircleAvatarButton()
button.borderWidth = 2
+ button.borderColor = UIColor.label.cgColor
return button
}()
@@ -71,6 +72,9 @@ extension SidebarListContentView {
imageView.contentMode = .scaleAspectFit
avatarButton.contentMode = .scaleAspectFit
+
+ imageView.isUserInteractionEnabled = false
+ avatarButton.isUserInteractionEnabled = false
}
private func apply(configuration: ContentConfiguration) {