forked from shadowfacts/Tusker
Add sidebar on iPadOS 14
This commit is contained in:
parent
fb11e36467
commit
6cf6db6a8d
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class List: Decodable {
|
public class List: Decodable, Equatable, Hashable {
|
||||||
public let id: String
|
public let id: String
|
||||||
public let title: String
|
public let title: String
|
||||||
|
|
||||||
|
@ -16,6 +16,14 @@ public class List: Decodable {
|
||||||
return .list(id: id)
|
return .list(id: id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: List, rhs: List) -> Bool {
|
||||||
|
return lhs.id == rhs.id
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
hasher.combine(id)
|
||||||
|
}
|
||||||
|
|
||||||
public static func getAccounts(_ list: List, range: RequestRange = .default) -> Request<[Account]> {
|
public static func getAccounts(_ list: List, range: RequestRange = .default) -> Request<[Account]> {
|
||||||
var request = Request<[Account]>(method: .get, path: "/api/v1/lists/\(list.id)/accounts")
|
var request = Request<[Account]>(method: .get, path: "/api/v1/lists/\(list.id)/accounts")
|
||||||
request.range = range
|
request.range = range
|
||||||
|
|
|
@ -174,6 +174,8 @@
|
||||||
D681E4D7246E32290053414F /* StatusActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D6246E32290053414F /* StatusActivityItemSource.swift */; };
|
D681E4D7246E32290053414F /* StatusActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D6246E32290053414F /* StatusActivityItemSource.swift */; };
|
||||||
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */; };
|
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */; };
|
||||||
D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */; };
|
D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */; };
|
||||||
|
D68E525B24A3D77E0054355A /* TuskerRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */; };
|
||||||
|
D68E525D24A3E8F00054355A /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68E525C24A3E8F00054355A /* SearchViewController.swift */; };
|
||||||
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */; };
|
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */; };
|
||||||
D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */; };
|
D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */; };
|
||||||
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5823FE24300061E07D /* InteractivePushTransition.swift */; };
|
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5823FE24300061E07D /* InteractivePushTransition.swift */; };
|
||||||
|
@ -249,6 +251,8 @@
|
||||||
D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; };
|
D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; };
|
||||||
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */; };
|
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */; };
|
||||||
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */; };
|
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */; };
|
||||||
|
D6F0B12B24A3071C001E48C3 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */; };
|
||||||
|
D6F0B17524A3A1AA001E48C3 /* MainSidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */; };
|
||||||
D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F1F84C2193B56E00F5FE67 /* Cache.swift */; };
|
D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F1F84C2193B56E00F5FE67 /* Cache.swift */; };
|
||||||
D6F2E965249E8BFD005846BB /* CrashReporterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */; };
|
D6F2E965249E8BFD005846BB /* CrashReporterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */; };
|
||||||
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */; };
|
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */; };
|
||||||
|
@ -481,6 +485,8 @@
|
||||||
D681E4D6246E32290053414F /* StatusActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityItemSource.swift; sourceTree = "<group>"; };
|
D681E4D6246E32290053414F /* StatusActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityItemSource.swift; sourceTree = "<group>"; };
|
||||||
D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountActivityItemSource.swift; sourceTree = "<group>"; };
|
D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountActivityItemSource.swift; sourceTree = "<group>"; };
|
||||||
D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeDrawingViewController.swift; sourceTree = "<group>"; };
|
D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeDrawingViewController.swift; sourceTree = "<group>"; };
|
||||||
|
D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TuskerRootViewController.swift; sourceTree = "<group>"; };
|
||||||
|
D68E525C24A3E8F00054355A /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = "<group>"; };
|
||||||
D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedPageViewController.swift; sourceTree = "<group>"; };
|
D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedPageViewController.swift; sourceTree = "<group>"; };
|
||||||
D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedNavigationViewController.swift; sourceTree = "<group>"; };
|
D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedNavigationViewController.swift; sourceTree = "<group>"; };
|
||||||
D693DE5823FE24300061E07D /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; };
|
D693DE5823FE24300061E07D /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; };
|
||||||
|
@ -558,6 +564,8 @@
|
||||||
D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = "<group>"; };
|
D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = "<group>"; };
|
||||||
D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Scenes.swift"; sourceTree = "<group>"; };
|
D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Scenes.swift"; sourceTree = "<group>"; };
|
||||||
D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISceneSession+MastodonController.swift"; sourceTree = "<group>"; };
|
D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISceneSession+MastodonController.swift"; sourceTree = "<group>"; };
|
||||||
|
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = "<group>"; };
|
||||||
|
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSidebarViewController.swift; sourceTree = "<group>"; };
|
||||||
D6F1F84C2193B56E00F5FE67 /* Cache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = "<group>"; };
|
D6F1F84C2193B56E00F5FE67 /* Cache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = "<group>"; };
|
||||||
D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReporterViewController.swift; sourceTree = "<group>"; };
|
D6F2E963249E8BFD005846BB /* CrashReporterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReporterViewController.swift; sourceTree = "<group>"; };
|
||||||
D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CrashReporterViewController.xib; sourceTree = "<group>"; };
|
D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CrashReporterViewController.xib; sourceTree = "<group>"; };
|
||||||
|
@ -896,7 +904,10 @@
|
||||||
D641C782213DD7F0004B4513 /* Main */ = {
|
D641C782213DD7F0004B4513 /* Main */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */,
|
||||||
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */,
|
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */,
|
||||||
|
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */,
|
||||||
|
D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Main;
|
path = Main;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1190,6 +1201,7 @@
|
||||||
D6BC9DD8232D8BCA002CA326 /* Search */ = {
|
D6BC9DD8232D8BCA002CA326 /* Search */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D68E525C24A3E8F00054355A /* SearchViewController.swift */,
|
||||||
D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */,
|
D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Search;
|
path = Search;
|
||||||
|
@ -1703,6 +1715,7 @@
|
||||||
D6757A822157E8FA00721E32 /* XCBSession.swift in Sources */,
|
D6757A822157E8FA00721E32 /* XCBSession.swift in Sources */,
|
||||||
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */,
|
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */,
|
||||||
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */,
|
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */,
|
||||||
|
D68E525D24A3E8F00054355A /* SearchViewController.swift in Sources */,
|
||||||
D6AEBB412321642700E5038B /* SendMesasgeActivity.swift in Sources */,
|
D6AEBB412321642700E5038B /* SendMesasgeActivity.swift in Sources */,
|
||||||
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
|
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
|
||||||
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
||||||
|
@ -1734,6 +1747,7 @@
|
||||||
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */,
|
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */,
|
||||||
D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */,
|
D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */,
|
||||||
D60309B52419D4F100A465FF /* ComposeAttachmentsViewController.swift in Sources */,
|
D60309B52419D4F100A465FF /* ComposeAttachmentsViewController.swift in Sources */,
|
||||||
|
D68E525B24A3D77E0054355A /* TuskerRootViewController.swift in Sources */,
|
||||||
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
|
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
|
||||||
D6CA6A92249FAD8900AD45C1 /* AudioSessionHelper.swift in Sources */,
|
D6CA6A92249FAD8900AD45C1 /* AudioSessionHelper.swift in Sources */,
|
||||||
D60D2B8223844C71001B87A3 /* BaseStatusTableViewCell.swift in Sources */,
|
D60D2B8223844C71001B87A3 /* BaseStatusTableViewCell.swift in Sources */,
|
||||||
|
@ -1773,6 +1787,7 @@
|
||||||
D6AEBB4523216AF800E5038B /* FollowAccountActivity.swift in Sources */,
|
D6AEBB4523216AF800E5038B /* FollowAccountActivity.swift in Sources */,
|
||||||
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */,
|
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */,
|
||||||
D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */,
|
D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */,
|
||||||
|
D6F0B17524A3A1AA001E48C3 /* MainSidebarViewController.swift in Sources */,
|
||||||
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */,
|
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */,
|
||||||
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */,
|
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */,
|
||||||
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */,
|
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */,
|
||||||
|
@ -1834,6 +1849,7 @@
|
||||||
D64D8CA92463B494006B0BAA /* CachedDictionary.swift in Sources */,
|
D64D8CA92463B494006B0BAA /* CachedDictionary.swift in Sources */,
|
||||||
D6757A7C2157E01900721E32 /* XCBManager.swift in Sources */,
|
D6757A7C2157E01900721E32 /* XCBManager.swift in Sources */,
|
||||||
D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */,
|
D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */,
|
||||||
|
D6F0B12B24A3071C001E48C3 /* MainSplitViewController.swift in Sources */,
|
||||||
0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */,
|
0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */,
|
||||||
D6AEBB3E2321638100E5038B /* UIActivity+Types.swift in Sources */,
|
D6AEBB3E2321638100E5038B /* UIActivity+Types.swift in Sources */,
|
||||||
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */,
|
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */,
|
||||||
|
|
|
@ -157,8 +157,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
mastodonController.getOwnAccount()
|
mastodonController.getOwnAccount()
|
||||||
mastodonController.getOwnInstance()
|
mastodonController.getOwnInstance()
|
||||||
|
|
||||||
let tabBarController = MainTabBarViewController(mastodonController: mastodonController)
|
let rootController: UIViewController
|
||||||
window!.rootViewController = tabBarController
|
if #available(iOS 14.0, *) {
|
||||||
|
rootController = MainSplitViewController(mastodonController: mastodonController)
|
||||||
|
} else {
|
||||||
|
rootController = MainTabBarViewController(mastodonController: mastodonController)
|
||||||
|
}
|
||||||
|
window!.rootViewController = rootController
|
||||||
}
|
}
|
||||||
|
|
||||||
func showOnboardingUI() {
|
func showOnboardingUI() {
|
||||||
|
|
|
@ -90,9 +90,7 @@ class ExploreViewController: EnhancedTableViewController {
|
||||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||||
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||||
// the initial, static items should not be displayed with an animation
|
// the initial, static items should not be displayed with an animation
|
||||||
UIView.performWithoutAnimation {
|
dataSource.apply(snapshot, animatingDifferences: false)
|
||||||
dataSource.apply(snapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultsController = SearchResultsViewController(mastodonController: mastodonController)
|
resultsController = SearchResultsViewController(mastodonController: mastodonController)
|
||||||
resultsController.exploreNavigationController = self.navigationController!
|
resultsController.exploreNavigationController = self.navigationController!
|
||||||
|
|
|
@ -0,0 +1,344 @@
|
||||||
|
//
|
||||||
|
// MainSidebarViewController.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/24/20.
|
||||||
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
protocol MainSidebarViewControllerDelegate: class {
|
||||||
|
func sidebarRequestPresentCompose(_ sidebarViewController: MainSidebarViewController)
|
||||||
|
func sidebar(_ sidebarViewController: MainSidebarViewController, didSelectItem item: MainSidebarViewController.Item)
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
class MainSidebarViewController: UIViewController {
|
||||||
|
|
||||||
|
weak var mastodonController: MastodonController!
|
||||||
|
|
||||||
|
weak var sidebarDelegate: MainSidebarViewControllerDelegate?
|
||||||
|
|
||||||
|
var collectionView: UICollectionView!
|
||||||
|
var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||||
|
|
||||||
|
init(mastodonController: MastodonController) {
|
||||||
|
self.mastodonController = mastodonController
|
||||||
|
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
navigationItem.title = "Tusker"
|
||||||
|
navigationItem.largeTitleDisplayMode = .always
|
||||||
|
navigationController!.navigationBar.prefersLargeTitles = true
|
||||||
|
|
||||||
|
let layout = UICollectionViewCompositionalLayout.list(using: .init(appearance: .sidebar))
|
||||||
|
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||||
|
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
|
collectionView.backgroundColor = .systemGroupedBackground
|
||||||
|
collectionView.delegate = self
|
||||||
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
|
dataSource = createDataSource()
|
||||||
|
|
||||||
|
applyInitialSnapshot()
|
||||||
|
|
||||||
|
select(.tab(.timelines), animated: false)
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(reloadSavedHashtags), name: .savedHashtagsChanged, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(reloadSavedInstances), name: .savedInstancesChanged, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func select(_ item: Item, animated: Bool) {
|
||||||
|
guard let indexPath = dataSource.indexPath(for: item) else { return }
|
||||||
|
collectionView.selectItem(at: indexPath, animated: animated, scrollPosition: .top)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
||||||
|
let listCell = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { (cell, indexPath, item) in
|
||||||
|
var config = cell.defaultContentConfiguration()
|
||||||
|
config.text = item.title
|
||||||
|
if let imageName = item.imageName {
|
||||||
|
config.image = UIImage(systemName: imageName)
|
||||||
|
}
|
||||||
|
cell.contentConfiguration = config
|
||||||
|
}
|
||||||
|
|
||||||
|
let outlineHeaderCell = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { (cell, indexPath, item) in
|
||||||
|
var config = cell.defaultContentConfiguration()
|
||||||
|
config.attributedText = NSAttributedString(string: item.title, attributes: [
|
||||||
|
.font: UIFont.boldSystemFont(ofSize: 21)
|
||||||
|
])
|
||||||
|
cell.contentConfiguration = config
|
||||||
|
cell.accessories = [.outlineDisclosure(options: .init(style: .header))]
|
||||||
|
}
|
||||||
|
|
||||||
|
return UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, item) -> UICollectionViewCell? in
|
||||||
|
if item.hasChildren {
|
||||||
|
return collectionView.dequeueConfiguredReusableCell(using: outlineHeaderCell, for: indexPath, item: item)
|
||||||
|
} else {
|
||||||
|
return collectionView.dequeueConfiguredReusableCell(using: listCell, for: indexPath, item: item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private func applyInitialSnapshot() {
|
||||||
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
|
snapshot.appendSections(Section.allCases)
|
||||||
|
snapshot.appendItems([
|
||||||
|
.tab(.timelines),
|
||||||
|
.tab(.notifications),
|
||||||
|
.search,
|
||||||
|
.bookmarks,
|
||||||
|
.tab(.myProfile)
|
||||||
|
], toSection: .tabs)
|
||||||
|
snapshot.appendItems([
|
||||||
|
.tab(.compose)
|
||||||
|
], toSection: .compose)
|
||||||
|
dataSource.apply(snapshot, animatingDifferences: false)
|
||||||
|
|
||||||
|
reloadLists()
|
||||||
|
reloadSavedHashtags()
|
||||||
|
reloadSavedInstances()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func reloadLists() {
|
||||||
|
let request = Client.getLists()
|
||||||
|
mastodonController.run(request) { [weak self] (response) in
|
||||||
|
guard let self = self, case let .success(lists, _) = response else { return }
|
||||||
|
|
||||||
|
var exploreSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
|
||||||
|
exploreSnapshot.append([.listsHeader])
|
||||||
|
exploreSnapshot.expand([.listsHeader])
|
||||||
|
exploreSnapshot.append(lists.map { .list($0) }, to: .listsHeader)
|
||||||
|
exploreSnapshot.append([.addList], to: .listsHeader)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.dataSource.apply(exploreSnapshot, to: .lists)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func reloadSavedHashtags() {
|
||||||
|
var hashtagsSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
|
||||||
|
hashtagsSnapshot.append([.savedHashtagsHeader])
|
||||||
|
hashtagsSnapshot.expand([.savedHashtagsHeader])
|
||||||
|
let sortedHashtags = SavedDataManager.shared.sortedHashtags(for: mastodonController.accountInfo!)
|
||||||
|
hashtagsSnapshot.append(sortedHashtags.map { .savedHashtag($0) }, to: .savedHashtagsHeader)
|
||||||
|
hashtagsSnapshot.append([.addSavedHashtag], to: .savedHashtagsHeader)
|
||||||
|
self.dataSource.apply(hashtagsSnapshot, to: .savedHashtags, animatingDifferences: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func reloadSavedInstances() {
|
||||||
|
var instancesSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
|
||||||
|
instancesSnapshot.append([.savedInstancesHeader])
|
||||||
|
instancesSnapshot.expand([.savedInstancesHeader])
|
||||||
|
let sortedInstances = SavedDataManager.shared.savedInstances(for: mastodonController.accountInfo!)
|
||||||
|
instancesSnapshot.append(sortedInstances.map { .savedInstance($0) }, to: .savedInstancesHeader)
|
||||||
|
instancesSnapshot.append([.addSavedInstance], to: .savedInstancesHeader)
|
||||||
|
self.dataSource.apply(instancesSnapshot, to: .savedInstances, animatingDifferences: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: deduplicate with ExploreViewController
|
||||||
|
private func showAddList() {
|
||||||
|
let alert = UIAlertController(title: "New List", message: "Choose a title for your new list", preferredStyle: .alert)
|
||||||
|
alert.addTextField(configurationHandler: nil)
|
||||||
|
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
|
||||||
|
alert.addAction(UIAlertAction(title: "Create List", style: .default, handler: { (_) in
|
||||||
|
guard let title = alert.textFields?.first?.text else {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = Client.createList(title: title)
|
||||||
|
self.mastodonController.run(request) { (response) in
|
||||||
|
guard case let .success(list, _) = response else { fatalError() }
|
||||||
|
|
||||||
|
self.reloadLists()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.sidebarDelegate?.sidebar(self, didSelectItem: .list(list))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
present(alert, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: deduplicate with ExploreViewController
|
||||||
|
private func showAddSavedHashtag() {
|
||||||
|
let navController = EnhancedNavigationViewController(rootViewController: AddSavedHashtagViewController(mastodonController: mastodonController))
|
||||||
|
present(navController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: deduplicate with ExploreViewController
|
||||||
|
private func showAddSavedInstance() {
|
||||||
|
let findController = FindInstanceViewController(parentMastodonController: mastodonController)
|
||||||
|
findController.instanceTimelineDelegate = self
|
||||||
|
let navController = EnhancedNavigationViewController(rootViewController: findController)
|
||||||
|
present(navController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
extension MainSidebarViewController {
|
||||||
|
enum Section: Int, Hashable, CaseIterable {
|
||||||
|
case tabs
|
||||||
|
case compose
|
||||||
|
case lists
|
||||||
|
case savedHashtags
|
||||||
|
case savedInstances
|
||||||
|
}
|
||||||
|
enum Item: Hashable {
|
||||||
|
case tab(MainTabBarViewController.Tab)
|
||||||
|
case search, bookmarks
|
||||||
|
case listsHeader, list(List), addList
|
||||||
|
case savedHashtagsHeader, savedHashtag(Hashtag), addSavedHashtag
|
||||||
|
case savedInstancesHeader, savedInstance(URL), addSavedInstance
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case let .tab(tab):
|
||||||
|
return tab.title
|
||||||
|
case .search:
|
||||||
|
return "Search"
|
||||||
|
case .bookmarks:
|
||||||
|
return "Bookmarks"
|
||||||
|
case .listsHeader:
|
||||||
|
return "Lists"
|
||||||
|
case let .list(list):
|
||||||
|
return list.title
|
||||||
|
case .addList:
|
||||||
|
return "New List..."
|
||||||
|
case .savedHashtagsHeader:
|
||||||
|
return "Saved Hashtags"
|
||||||
|
case let .savedHashtag(hashtag):
|
||||||
|
return hashtag.name
|
||||||
|
case .addSavedHashtag:
|
||||||
|
return "Save Hashtag..."
|
||||||
|
case .savedInstancesHeader:
|
||||||
|
return "Saved Instances"
|
||||||
|
case let .savedInstance(url):
|
||||||
|
return url.host!
|
||||||
|
case .addSavedInstance:
|
||||||
|
return "Find An Instance..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageName: String? {
|
||||||
|
switch self {
|
||||||
|
case let .tab(tab):
|
||||||
|
return tab.imageName
|
||||||
|
case .search:
|
||||||
|
return "magnifyingglass"
|
||||||
|
case .bookmarks:
|
||||||
|
return "bookmark"
|
||||||
|
case .list(_):
|
||||||
|
return "list.bullet"
|
||||||
|
case .savedHashtag(_):
|
||||||
|
return "number"
|
||||||
|
case .savedInstance(_):
|
||||||
|
return "globe"
|
||||||
|
case .listsHeader, .savedHashtagsHeader, .savedInstancesHeader:
|
||||||
|
return nil
|
||||||
|
case .addList, .addSavedHashtag, .addSavedInstance:
|
||||||
|
return "plus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasChildren: Bool {
|
||||||
|
switch self {
|
||||||
|
case .listsHeader, .savedHashtagsHeader, .savedInstancesHeader:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate extension MainTabBarViewController.Tab {
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .timelines:
|
||||||
|
return "Home"
|
||||||
|
case .notifications:
|
||||||
|
return "Notifications"
|
||||||
|
case .compose:
|
||||||
|
return "Compose"
|
||||||
|
case .explore:
|
||||||
|
return "Explore"
|
||||||
|
case .myProfile:
|
||||||
|
return "My Profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageName: String? {
|
||||||
|
switch self {
|
||||||
|
case .timelines:
|
||||||
|
return "house"
|
||||||
|
case .notifications:
|
||||||
|
return "bell"
|
||||||
|
case .compose:
|
||||||
|
return "pencil"
|
||||||
|
case .explore:
|
||||||
|
return "magnifyingglass"
|
||||||
|
case .myProfile:
|
||||||
|
// todo: use user avatar image
|
||||||
|
return "person"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
extension MainSidebarViewController: UICollectionViewDelegate {
|
||||||
|
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||||
|
guard let item = dataSource.itemIdentifier(for: indexPath) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch item {
|
||||||
|
case .tab(.compose):
|
||||||
|
sidebarDelegate?.sidebarRequestPresentCompose(self)
|
||||||
|
return false
|
||||||
|
case .addList:
|
||||||
|
showAddList()
|
||||||
|
return false
|
||||||
|
case .addSavedHashtag:
|
||||||
|
showAddSavedHashtag()
|
||||||
|
return false
|
||||||
|
case .addSavedInstance:
|
||||||
|
showAddSavedInstance()
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
|
guard let item = dataSource.itemIdentifier(for: indexPath) else {
|
||||||
|
collectionView.deselectItem(at: indexPath, animated: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sidebarDelegate?.sidebar(self, didSelectItem: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
extension MainSidebarViewController: InstanceTimelineViewControllerDelegate {
|
||||||
|
func didSaveInstance(url: URL) {
|
||||||
|
dismiss(animated: true) {
|
||||||
|
self.sidebarDelegate?.sidebar(self, didSelectItem: .savedInstance(url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func didUnsaveInstance(url: URL) {
|
||||||
|
dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
//
|
||||||
|
// MainSplitViewController.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/23/20.
|
||||||
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
class MainSplitViewController: UISplitViewController {
|
||||||
|
|
||||||
|
weak var mastodonController: MastodonController!
|
||||||
|
|
||||||
|
private var sidebar: MainSidebarViewController!
|
||||||
|
|
||||||
|
private var detailViewControllers: [MainSidebarViewController.Item: UIViewController] = [:]
|
||||||
|
|
||||||
|
init(mastodonController: MastodonController) {
|
||||||
|
self.mastodonController = mastodonController
|
||||||
|
|
||||||
|
super.init(style: .doubleColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
preferredDisplayMode = .oneBesideSecondary
|
||||||
|
preferredSplitBehavior = .tile
|
||||||
|
presentsWithGesture = false
|
||||||
|
showsSecondaryOnlyButton = false
|
||||||
|
|
||||||
|
sidebar = MainSidebarViewController(mastodonController: mastodonController)
|
||||||
|
sidebar.sidebarDelegate = self
|
||||||
|
setViewController(sidebar, for: .primary)
|
||||||
|
select(item: .tab(.timelines))
|
||||||
|
setViewController(MainTabBarViewController(mastodonController: mastodonController), for: .compact)
|
||||||
|
}
|
||||||
|
|
||||||
|
func select(item: MainSidebarViewController.Item) {
|
||||||
|
let itemController = getOrCreateDetailViewController(item: item)
|
||||||
|
setViewController(itemController, for: .secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOrCreateDetailViewController(item: MainSidebarViewController.Item) -> UIViewController? {
|
||||||
|
if let existing = detailViewControllers[item] {
|
||||||
|
return existing
|
||||||
|
} else {
|
||||||
|
guard let new = item.createRootViewController(mastodonController) else { return nil }
|
||||||
|
let nav = EnhancedNavigationViewController(rootViewController: new)
|
||||||
|
|
||||||
|
// Prevents the navigation bar from going transparent when switching sidebar sections.
|
||||||
|
nav.navigationBar.scrollEdgeAppearance = nav.navigationBar.standardAppearance
|
||||||
|
|
||||||
|
detailViewControllers[item] = nav
|
||||||
|
return nav
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
extension MainSplitViewController: MainSidebarViewControllerDelegate {
|
||||||
|
func sidebarRequestPresentCompose(_ sidebarViewController: MainSidebarViewController) {
|
||||||
|
presentCompose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sidebar(_ sidebarViewController: MainSidebarViewController, didSelectItem item: MainSidebarViewController.Item) {
|
||||||
|
select(item: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
fileprivate extension MainSidebarViewController.Item {
|
||||||
|
func createRootViewController(_ mastodonController: MastodonController) -> UIViewController? {
|
||||||
|
switch self {
|
||||||
|
case let .tab(tab):
|
||||||
|
return tab.createViewController(mastodonController)
|
||||||
|
case .search:
|
||||||
|
return SearchViewController(mastodonController: mastodonController)
|
||||||
|
case .bookmarks:
|
||||||
|
return BookmarksTableViewController(mastodonController: mastodonController)
|
||||||
|
case let .list(list):
|
||||||
|
return ListTimelineViewController(for: list, mastodonController: mastodonController)
|
||||||
|
case let .savedHashtag(hashtag):
|
||||||
|
return HashtagTimelineViewController(for: hashtag, mastodonController: mastodonController)
|
||||||
|
case let .savedInstance(url):
|
||||||
|
return InstanceTimelineViewController(for: url, parentMastodonController: mastodonController)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
extension MainSplitViewController: TuskerRootViewController {
|
||||||
|
func presentCompose() {
|
||||||
|
let compose = ComposeViewController(mastodonController: mastodonController)
|
||||||
|
let navigationController = EnhancedNavigationViewController(rootViewController: compose)
|
||||||
|
navigationController.presentationController?.delegate = compose
|
||||||
|
present(navigationController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func select(tab: MainTabBarViewController.Tab) {
|
||||||
|
if tab == .compose {
|
||||||
|
presentCompose()
|
||||||
|
} else {
|
||||||
|
select(item: .tab(tab))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
|
||||||
|
|
||||||
weak var mastodonController: MastodonController!
|
weak var mastodonController: MastodonController!
|
||||||
|
|
||||||
|
private var composePlaceholder: UIViewController!
|
||||||
|
|
||||||
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||||
return .portrait
|
return .portrait
|
||||||
|
@ -35,12 +37,16 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
|
||||||
|
|
||||||
self.delegate = self
|
self.delegate = self
|
||||||
|
|
||||||
|
composePlaceholder = UIViewController()
|
||||||
|
composePlaceholder.title = "Compose"
|
||||||
|
composePlaceholder.tabBarItem.image = UIImage(systemName: "pencil")
|
||||||
|
|
||||||
viewControllers = [
|
viewControllers = [
|
||||||
embedInNavigationController(TimelinesPageViewController(mastodonController: mastodonController)),
|
embedInNavigationController(Tab.timelines.createViewController(mastodonController)),
|
||||||
embedInNavigationController(NotificationsPageViewController(mastodonController: mastodonController)),
|
embedInNavigationController(Tab.notifications.createViewController(mastodonController)),
|
||||||
ComposeViewController(mastodonController: mastodonController),
|
composePlaceholder,
|
||||||
embedInNavigationController(ExploreViewController(mastodonController: mastodonController)),
|
embedInNavigationController(Tab.explore.createViewController(mastodonController)),
|
||||||
embedInNavigationController(MyProfileTableViewController(mastodonController: mastodonController)),
|
embedInNavigationController(Tab.myProfile.createViewController(mastodonController)),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,37 +59,39 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
|
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
|
||||||
if viewController is ComposeViewController {
|
if viewController == composePlaceholder {
|
||||||
presentCompose()
|
presentCompose()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func presentCompose() {
|
|
||||||
let compose = ComposeViewController(mastodonController: mastodonController)
|
|
||||||
let navigationController = embedInNavigationController(compose)
|
|
||||||
navigationController.presentationController?.delegate = compose
|
|
||||||
present(navigationController, animated: true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MainTabBarViewController {
|
extension MainTabBarViewController {
|
||||||
enum Tab: Int {
|
enum Tab: Int, Hashable, CaseIterable {
|
||||||
case timelines
|
case timelines
|
||||||
case notifications
|
case notifications
|
||||||
case compose
|
case compose
|
||||||
case explore
|
case explore
|
||||||
case myProfile
|
case myProfile
|
||||||
|
|
||||||
|
func createViewController(_ mastodonController: MastodonController) -> UIViewController {
|
||||||
|
switch self {
|
||||||
|
case .timelines:
|
||||||
|
return TimelinesPageViewController(mastodonController: mastodonController)
|
||||||
|
case .notifications:
|
||||||
|
return NotificationsPageViewController(mastodonController: mastodonController)
|
||||||
|
case .compose:
|
||||||
|
return ComposeViewController(mastodonController: mastodonController)
|
||||||
|
case .explore:
|
||||||
|
return ExploreViewController(mastodonController: mastodonController)
|
||||||
|
case .myProfile:
|
||||||
|
return MyProfileTableViewController(mastodonController: mastodonController)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func select(tab: Tab) {
|
|
||||||
if tab == .compose {
|
|
||||||
presentCompose()
|
|
||||||
} else {
|
|
||||||
selectedIndex = tab.rawValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTabController(tab: Tab) -> UIViewController? {
|
func getTabController(tab: Tab) -> UIViewController? {
|
||||||
if tab == .compose {
|
if tab == .compose {
|
||||||
|
@ -93,3 +101,20 @@ extension MainTabBarViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension MainTabBarViewController: TuskerRootViewController {
|
||||||
|
func presentCompose() {
|
||||||
|
let compose = ComposeViewController(mastodonController: mastodonController)
|
||||||
|
let navigationController = embedInNavigationController(compose)
|
||||||
|
navigationController.presentationController?.delegate = compose
|
||||||
|
present(navigationController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func select(tab: Tab) {
|
||||||
|
if tab == .compose {
|
||||||
|
presentCompose()
|
||||||
|
} else {
|
||||||
|
selectedIndex = tab.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// TuskerRootViewController.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/24/20.
|
||||||
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
protocol TuskerRootViewController: UIViewController {
|
||||||
|
func presentCompose()
|
||||||
|
func select(tab: MainTabBarViewController.Tab)
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ extension SearchResultsViewControllerDelegate {
|
||||||
|
|
||||||
class SearchResultsViewController: EnhancedTableViewController {
|
class SearchResultsViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
let mastodonController: MastodonController!
|
weak var mastodonController: MastodonController!
|
||||||
|
|
||||||
weak var exploreNavigationController: UINavigationController?
|
weak var exploreNavigationController: UINavigationController?
|
||||||
weak var delegate: SearchResultsViewControllerDelegate?
|
weak var delegate: SearchResultsViewControllerDelegate?
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// SearchViewController.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/24/20.
|
||||||
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SearchViewController: UIViewController {
|
||||||
|
|
||||||
|
weak var mastodonController: MastodonController!
|
||||||
|
|
||||||
|
var resultsController: SearchResultsViewController!
|
||||||
|
var searchController: UISearchController!
|
||||||
|
|
||||||
|
init(mastodonController: MastodonController) {
|
||||||
|
self.mastodonController = mastodonController
|
||||||
|
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
|
title = NSLocalizedString("Search", comment: "search tab title")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
resultsController = SearchResultsViewController(mastodonController: mastodonController)
|
||||||
|
resultsController.exploreNavigationController = self.navigationController
|
||||||
|
searchController = UISearchController(searchResultsController: resultsController)
|
||||||
|
searchController.searchResultsUpdater = resultsController
|
||||||
|
searchController.searchBar.autocapitalizationType = .none
|
||||||
|
searchController.searchBar.delegate = resultsController
|
||||||
|
definesPresentationContext = true
|
||||||
|
|
||||||
|
navigationItem.searchController = searchController
|
||||||
|
navigationItem.hidesSearchBarWhenScrolling = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue