Browse Source

Allow tabs to be enabled/disabled and reordered

pixelfed
Shadowfacts 3 years ago
parent
commit
57b4e67cc2
Signed by: shadowfacts GPG Key ID: 94A5AB95422746E5
  1. 26
      Tusker.xcodeproj/project.pbxproj
  2. 17
      Tusker/Preferences/Preferences.swift
  3. 35
      Tusker/Preferences/Tab.swift
  4. 66
      Tusker/Screens/Main/MainTabBarViewController.swift
  5. 102
      Tusker/Screens/Preferences/Preferences.storyboard
  6. 92
      Tusker/Screens/Preferences/TabsTableViewController.swift
  7. 47
      Tusker/Views/Tab/TabTableViewCell.swift
  8. 47
      Tusker/Views/Tab/TabTableViewCell.xib

26
Tusker.xcodeproj/project.pbxproj

@ -57,6 +57,9 @@
D6109A0D214599E100432DC2 /* RequestRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6109A0C214599E100432DC2 /* RequestRange.swift */; };
D6109A0F21459B6900432DC2 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6109A0E21459B6900432DC2 /* Pagination.swift */; };
D6109A11214607D500432DC2 /* Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6109A10214607D500432DC2 /* Timeline.swift */; };
D621544821682A9D0003D87D /* TabsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544721682A9D0003D87D /* TabsTableViewController.swift */; };
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544A21682AD30003D87D /* TabTableViewCell.swift */; };
D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D621544C21682AD90003D87D /* TabTableViewCell.xib */; };
D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Trim.swift */; };
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; };
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
@ -103,6 +106,7 @@
D6757A822157E8FA00721E32 /* XCBSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6757A812157E8FA00721E32 /* XCBSession.swift */; };
D679C09F215850EF00DA27FE /* XCBActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D679C09E215850EF00DA27FE /* XCBActions.swift */; };
D67E0513216438A7000E0927 /* AppearanceTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67E0512216438A7000E0927 /* AppearanceTableViewController.swift */; };
D67E051521643C77000E0927 /* Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67E051421643C77000E0927 /* Tab.swift */; };
D6BED170212663DA00F02DA0 /* SwiftSoup.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D6BED16E212663DA00F02DA0 /* SwiftSoup.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D6BED174212667E900F02DA0 /* StatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BED173212667E900F02DA0 /* StatusTableViewCell.swift */; };
D6C693CA2161253F007D6A6D /* SilentActionPermissionsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693C92161253F007D6A6D /* SilentActionPermissionsTableViewController.swift */; };
@ -241,6 +245,9 @@
D6109A0C214599E100432DC2 /* RequestRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestRange.swift; sourceTree = "<group>"; };
D6109A0E21459B6900432DC2 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = "<group>"; };
D6109A10214607D500432DC2 /* Timeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Timeline.swift; sourceTree = "<group>"; };
D621544721682A9D0003D87D /* TabsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewController.swift; sourceTree = "<group>"; };
D621544A21682AD30003D87D /* TabTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTableViewCell.swift; sourceTree = "<group>"; };
D621544C21682AD90003D87D /* TabTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TabTableViewCell.xib; sourceTree = "<group>"; };
D6333B362137838300CE884A /* AttributedString+Trim.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Trim.swift"; sourceTree = "<group>"; };
D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = "<group>"; };
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
@ -286,6 +293,7 @@
D6757A812157E8FA00721E32 /* XCBSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCBSession.swift; sourceTree = "<group>"; };
D679C09E215850EF00DA27FE /* XCBActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCBActions.swift; sourceTree = "<group>"; };
D67E0512216438A7000E0927 /* AppearanceTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceTableViewController.swift; sourceTree = "<group>"; };
D67E051421643C77000E0927 /* Tab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tab.swift; sourceTree = "<group>"; };
D6BED16E212663DA00F02DA0 /* SwiftSoup.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftSoup.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D6BED173212667E900F02DA0 /* StatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewCell.swift; sourceTree = "<group>"; };
D6C693C92161253F007D6A6D /* SilentActionPermissionsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPermissionsTableViewController.swift; sourceTree = "<group>"; };
@ -464,6 +472,15 @@
path = Model;
sourceTree = "<group>";
};
D621544921682AC60003D87D /* Tab */ = {
isa = PBXGroup;
children = (
D621544C21682AD90003D87D /* TabTableViewCell.xib */,
D621544A21682AD30003D87D /* TabTableViewCell.swift */,
);
path = Tab;
sourceTree = "<group>";
};
D641C780213DD7C4004B4513 /* Screens */ = {
isa = PBXGroup;
children = (
@ -558,8 +575,9 @@
isa = PBXGroup;
children = (
D663626521360DD700C9CBA2 /* Preferences.storyboard */,
D67E0512216438A7000E0927 /* AppearanceTableViewController.swift */,
D663626721360E2C00C9CBA2 /* PreferencesTableViewController.swift */,
D67E0512216438A7000E0927 /* AppearanceTableViewController.swift */,
D621544721682A9D0003D87D /* TabsTableViewController.swift */,
D641C78E213DF2AA004B4513 /* VisibilityTableViewController.swift */,
D6C693C92161253F007D6A6D /* SilentActionPermissionsTableViewController.swift */,
);
@ -620,6 +638,7 @@
D663626121360B1900C9CBA2 /* Preferences.swift */,
D663626321360D2300C9CBA2 /* AvatarStyle.swift */,
D66362692136163000C9CBA2 /* PreferencesAdaptive.swift */,
D67E051421643C77000E0927 /* Tab.swift */,
);
path = Preferences;
sourceTree = "<group>";
@ -653,6 +672,7 @@
D6BED1722126661300F02DA0 /* Views */ = {
isa = PBXGroup;
children = (
D621544921682AC60003D87D /* Tab */,
04496BD621625361001F1B23 /* ContentLabel.swift */,
D6C693F82162E4DB007D6A6D /* StatusContentLabel.swift */,
D6C94D882139E6EC00CB5196 /* AttachmentView.swift */,
@ -995,6 +1015,7 @@
D641C771213CA9EC004B4513 /* Notifications.storyboard in Resources */,
D663626621360DD700C9CBA2 /* Preferences.storyboard in Resources */,
D667E5E12134937B0057A976 /* StatusTableViewCell.xib in Resources */,
D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1085,9 +1106,11 @@
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */,
D67E051521643C77000E0927 /* Tab.swift in Sources */,
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */,
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */,
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */,
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */,
@ -1102,6 +1125,7 @@
D6434EB3215B1856001A919A /* XCBRequest.swift in Sources */,
D663626221360B1900C9CBA2 /* Preferences.swift in Sources */,
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */,
D621544821682A9D0003D87D /* TabsTableViewController.swift in Sources */,
D641C78F213DF2AA004B4513 /* VisibilityTableViewController.swift in Sources */,
D641C77F213DC78A004B4513 /* InlineTextAttachment.swift in Sources */,
04496BD721625361001F1B23 /* ContentLabel.swift in Sources */,

17
Tusker/Preferences/Preferences.swift

@ -31,16 +31,29 @@ class Preferences: Codable {
return Preferences()
}
var showRepliesInProfiles = false
private init() {}
// MARK: - Appearance
var showRepliesInProfiles = false
var avatarStyle = AvatarStyle.roundRect
var hideCustomEmojiInUsernames = false
var tabs: [Tab: Int] = [.home: 0, .notifications: 1, .local: -1, .federated: 2, .myProfile: 3, .preferences: 4]
var defaultPostVisibility = Status.Visibility.public
// MARK: - Advanced
var silentActions: [String: Permission] = [:]
// MARK: - Utility Methods
func tabIndex(_ tab: Tab) -> Int {
if let index = tabs[tab] {
return index
} else {
tabs[tab] = -1
return -1
}
}
}
extension Preferences {

35
Tusker/Preferences/Tab.swift

@ -0,0 +1,35 @@
//
// Tab.swift
// Tusker
//
// Created by Shadowfacts on 10/2/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import Foundation
enum Tab: String, Codable, CaseIterable {
case home
case federated
case local
case myProfile
case notifications
case preferences
var humanName: String {
switch self {
case .home:
return "Home"
case .federated:
return "Federated"
case .local:
return "Local"
case .myProfile:
return "My Profile"
case .notifications:
return "Notifications"
case .preferences:
return "Preferences"
}
}
}

66
Tusker/Screens/Main/MainTabBarViewController.swift

@ -13,35 +13,49 @@ class MainTabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let home = TimelineTableViewController.create(for: .home)
let federated = TimelineTableViewController.create(for: .public(local: false))
let local = TimelineTableViewController.create(for: .public(local: true))
let ownProfile = ProfileTableViewController.createForPending()
ownProfile.title = "My Profile"
let notifications = NotificationsTableViewController.create()
let preferences = PreferencesTableViewController.create()
viewControllers = [
navigationController(for: home),
navigationController(for: federated),
navigationController(for: local),
navigationController(for: ownProfile),
notifications,
preferences
]
MastodonController.getOwnAccount { (account) in
ownProfile.accountID = account.id
updateTabs(animated: false)
}
func updateTabs(animated: Bool) {
let currentTabs = Preferences.shared.tabs.filter { $1 >= 0 }.sorted { $1.1 > $0.1 }.map { $0.key }
let viewControllers: [UIViewController] = currentTabs.map { (tab) in
if tab == .preferences, let preferences = selectedViewController {
return preferences
} else {
return embedInNavigationController(createVC(for: tab))
}
}
setViewControllers(viewControllers, animated: animated)
}
func createVC(for tab: Tab) -> UIViewController {
switch tab {
case .home:
return TimelineTableViewController.create(for: .home)
case .federated:
return TimelineTableViewController.create(for: .public(local: false))
case .local:
return TimelineTableViewController.create(for: .public(local: true))
case .myProfile:
let myProfile = ProfileTableViewController.createForPending()
myProfile.title = "My Profile"
MastodonController.getOwnAccount { (account) in
myProfile.accountID = account.id
}
return myProfile
case .notifications:
return NotificationsTableViewController.create()
case .preferences:
return PreferencesTableViewController.create()
}
}
func navigationController(for vc: UIViewController) -> UINavigationController {
return UINavigationController(rootViewController: vc)
func embedInNavigationController(_ vc: UIViewController) -> UINavigationController {
if let vc = vc as? UINavigationController {
return vc
} else {
return UINavigationController(rootViewController: vc)
}
}
/*

102
Tusker/Screens/Preferences/Preferences.storyboard

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.15" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="VJJ-jC-9g8">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.23.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="VJJ-jC-9g8">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.9"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.16.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -44,22 +44,22 @@
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection id="1m2-cM-16u">
<tableViewSection id="QnL-PI-wDE">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="8Y3-if-FhA">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="RwH-Ti-TH8">
<rect key="frame" x="0.0" y="115" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="8Y3-if-FhA" id="ZpZ-BB-0Ti">
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="RwH-Ti-TH8" id="NJF-ED-5cF">
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Default post visibility" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VIi-n0-FBN">
<rect key="frame" x="16" y="11.5" width="159" height="21"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Default Post Visibility" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iEj-dZ-E4F">
<rect key="frame" x="16" y="11.5" width="162" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RXt-HZ-X6X">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="se3-JR-wRN">
<rect key="frame" x="294" y="11.5" width="47" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@ -67,28 +67,28 @@
</label>
</subviews>
<constraints>
<constraint firstItem="VIi-n0-FBN" firstAttribute="centerY" secondItem="ZpZ-BB-0Ti" secondAttribute="centerY" id="7qF-Va-DIX"/>
<constraint firstAttribute="trailing" secondItem="RXt-HZ-X6X" secondAttribute="trailing" id="8Y3-1J-Y5y"/>
<constraint firstItem="RXt-HZ-X6X" firstAttribute="centerY" secondItem="ZpZ-BB-0Ti" secondAttribute="centerY" id="8vB-O3-3p8"/>
<constraint firstItem="VIi-n0-FBN" firstAttribute="leading" secondItem="ZpZ-BB-0Ti" secondAttribute="leadingMargin" id="y3v-9l-ECZ"/>
<constraint firstItem="se3-JR-wRN" firstAttribute="centerY" secondItem="NJF-ED-5cF" secondAttribute="centerY" id="GGU-6Y-NSR"/>
<constraint firstItem="iEj-dZ-E4F" firstAttribute="leading" secondItem="NJF-ED-5cF" secondAttribute="leadingMargin" id="X5l-TE-I3w"/>
<constraint firstAttribute="trailing" secondItem="se3-JR-wRN" secondAttribute="trailing" id="eeH-Zb-ZS9"/>
<constraint firstItem="iEj-dZ-E4F" firstAttribute="centerY" secondItem="NJF-ED-5cF" secondAttribute="centerY" id="rak-B9-rwy"/>
</constraints>
</tableViewCellContentView>
<connections>
<segue destination="50Z-Q7-qIn" kind="show" id="Nns-Fe-keu"/>
<segue destination="50Z-Q7-qIn" kind="show" id="uHj-Vc-3uZ"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection id="QnL-PI-wDE">
<tableViewSection id="5L1-9T-nha">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="RwH-Ti-TH8">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="eQh-JA-eyx">
<rect key="frame" x="0.0" y="195" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="RwH-Ti-TH8" id="NJF-ED-5cF">
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eQh-JA-eyx" id="2y5-gN-4xJ">
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Advanced" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iEj-dZ-E4F">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Advanced" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SWr-6T-ZL5">
<rect key="frame" x="16" y="11.5" width="77" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
@ -96,12 +96,12 @@
</label>
</subviews>
<constraints>
<constraint firstItem="iEj-dZ-E4F" firstAttribute="leading" secondItem="NJF-ED-5cF" secondAttribute="leadingMargin" id="X5l-TE-I3w"/>
<constraint firstItem="iEj-dZ-E4F" firstAttribute="centerY" secondItem="NJF-ED-5cF" secondAttribute="centerY" id="rak-B9-rwy"/>
<constraint firstItem="SWr-6T-ZL5" firstAttribute="leading" secondItem="2y5-gN-4xJ" secondAttribute="leadingMargin" id="1hJ-fj-Llf"/>
<constraint firstItem="SWr-6T-ZL5" firstAttribute="centerY" secondItem="2y5-gN-4xJ" secondAttribute="centerY" id="Qao-fy-t0w"/>
</constraints>
</tableViewCellContentView>
<connections>
<segue destination="3mv-l7-6We" kind="show" id="LGp-xW-KyG"/>
<segue destination="3mv-l7-6We" kind="show" id="v4C-bk-CFc"/>
</connections>
</tableViewCell>
</cells>
@ -114,7 +114,7 @@
</tableView>
<navigationItem key="navigationItem" title="Preferences" id="dN7-yl-voz"/>
<connections>
<outlet property="defaultPostVisibilityLabel" destination="RXt-HZ-X6X" id="KEB-sg-UNE"/>
<outlet property="defaultPostVisibilityLabel" destination="se3-JR-wRN" id="YQM-H1-DBK"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="GBL-Cz-yNZ" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -130,10 +130,10 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<sections>
<tableViewSection id="gwC-db-0ec">
<tableViewSection headerTitle="Display" id="gwC-db-0ec">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="cSJ-mP-CMQ">
<rect key="frame" x="0.0" y="35" width="375" height="44"/>
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="cSJ-mP-CMQ" id="K0u-vm-1cA">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
@ -162,7 +162,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="KRM-HM-H3l">
<rect key="frame" x="0.0" y="79" width="375" height="44"/>
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="KRM-HM-H3l" id="1OA-09-UkD">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
@ -190,7 +190,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="KoZ-lA-gof">
<rect key="frame" x="0.0" y="123" width="375" height="44"/>
<rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="KoZ-lA-gof" id="ZiQ-kq-AHv">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
@ -219,6 +219,33 @@
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Interaction" id="2hR-aI-CRP">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="11q-UM-f40">
<rect key="frame" x="0.0" y="243.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="11q-UM-f40" id="Tp5-hX-pc3">
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tabs" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BdH-U9-Vcz">
<rect key="frame" x="16" y="11.5" width="37" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="BdH-U9-Vcz" firstAttribute="centerY" secondItem="Tp5-hX-pc3" secondAttribute="centerY" id="OfE-gk-aMJ"/>
<constraint firstItem="BdH-U9-Vcz" firstAttribute="leading" secondItem="Tp5-hX-pc3" secondAttribute="leadingMargin" id="dVK-2S-b6A"/>
</constraints>
</tableViewCellContentView>
<connections>
<segue destination="JJN-aw-37c" kind="show" id="6oX-43-R1z"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="oM9-mi-wRc" id="ubt-jB-z6P"/>
@ -234,7 +261,26 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Rkj-gt-dSt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="18" y="537"/>
<point key="canvasLocation" x="2" y="535"/>
</scene>
<!--Tabs-->
<scene sceneID="D4Y-D0-S4g">
<objects>
<tableViewController id="JJN-aw-37c" customClass="TabsTableViewController" customModule="Tusker" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="M8r-EE-Z7d">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="dataSource" destination="JJN-aw-37c" id="dC9-LA-KZy"/>
<outlet property="delegate" destination="JJN-aw-37c" id="6Zp-me-GOX"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Tabs" id="GwP-CQ-WwZ"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8dk-2n-9cx" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1" y="1243"/>
</scene>
<!--Default Post Visibility-->
<scene sceneID="z9g-ND-zkU">
@ -273,7 +319,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="JNY-yb-Efi" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="825" y="537"/>
<point key="canvasLocation" x="825" y="535"/>
</scene>
<!--Advanced-->
<scene sceneID="xgj-Fx-53j">
@ -321,7 +367,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4wC-Hp-AZk" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1612" y="538"/>
<point key="canvasLocation" x="1612" y="536"/>
</scene>
<!--Silent Actions-->
<scene sceneID="Vyy-sh-Tca">

92
Tusker/Screens/Preferences/TabsTableViewController.swift

@ -0,0 +1,92 @@
//
// TabsTableViewController.swift
// Tusker
//
// Created by Shadowfacts on 10/5/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
class TabsTableViewController: UITableViewController {
var tabs: [(Tab, Bool)] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "TabTableViewCell", bundle: nil), forCellReuseIdentifier: "tabCell")
tabs = Preferences.shared.tabs.filter { $0.value >= 0 }.sorted(by: { $0.value < $1.value }).map { ($0.key, true) }
tabs.append(contentsOf: Preferences.shared.tabs.filter { $0.value == -1 }.map { ($0.key, false) })
tableView.setEditing(true, animated: false)
}
func updatePreferences() {
var dict = [Tab: Int]()
var maxIndex = 0
for (tab, enabled) in tabs {
if enabled {
dict[tab] = maxIndex
maxIndex += 1
} else {
dict[tab] = -1
}
}
Preferences.shared.tabs = dict
guard let tabBarController = tabBarController as? MainTabBarViewController else { fatalError("Tab bar controller should be of type MainTabBarViewController") }
tabBarController.updateTabs(animated: true)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tabs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "tabCell", for: indexPath) as? TabTableViewCell else { fatalError() }
let (tab, _) = tabs[indexPath.row]
cell.updateUI(for: tab)
cell.delegate = self
return cell
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let tab = tabs.remove(at: sourceIndexPath.row)
tabs.insert(tab, at: destinationIndexPath.row)
updatePreferences()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
extension TabsTableViewController: TabTableViewCellDelegate {
func setEnabled(tab: Tab, enabled: Bool) {
let index = tabs.firstIndex(where: { $0.0 == tab })!
tabs[index] = (tab, enabled)
updatePreferences()
}
}

47
Tusker/Views/Tab/TabTableViewCell.swift

@ -0,0 +1,47 @@
//
// TabTableViewCell.swift
// Tusker
//
// Created by Shadowfacts on 10/5/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
protocol TabTableViewCellDelegate {
func setEnabled(tab: Tab, enabled: Bool)
}
class TabTableViewCell: UITableViewCell {
var delegate: TabTableViewCellDelegate?
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var enabledSwitch: UISwitch!
var tab: Tab!
override func awakeFromNib() {
super.awakeFromNib()
// compensate for inset created by table view editing mode even when no delete control shown
nameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: -20).isActive = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func updateUI(for tab: Tab) {
self.tab = tab
enabledSwitch.isEnabled = tab != .preferences
enabledSwitch.setOn(Preferences.shared.tabIndex(tab) >= 0, animated: false)
nameLabel.text = tab.humanName
}
@IBAction func enabledSwitchChanged(_ sender: Any) {
delegate?.setEnabled(tab: tab, enabled: enabledSwitch.isOn)
}
}

47
Tusker/Views/Tab/TabTableViewCell.xib

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.23.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.16.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="TY9-GT-fyh" customClass="TabTableViewCell" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="TY9-GT-fyh" id="5RM-4m-Lba">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dsQ-ir-jly">
<rect key="frame" x="16" y="11.5" width="45" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gxP-eh-ANw">
<rect key="frame" x="308" y="6.5" width="51" height="31"/>
<connections>
<action selector="enabledSwitchChanged:" destination="TY9-GT-fyh" eventType="valueChanged" id="MdE-f1-w07"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstItem="dsQ-ir-jly" firstAttribute="centerY" secondItem="5RM-4m-Lba" secondAttribute="centerY" id="Azd-iZ-FmM"/>
<constraint firstItem="gxP-eh-ANw" firstAttribute="centerY" secondItem="5RM-4m-Lba" secondAttribute="centerY" id="Ch4-Gf-4q2"/>
<constraint firstItem="dsQ-ir-jly" firstAttribute="leading" secondItem="5RM-4m-Lba" secondAttribute="leadingMargin" placeholder="YES" id="HIe-Qg-Jkj"/>
<constraint firstAttribute="trailing" secondItem="gxP-eh-ANw" secondAttribute="trailing" constant="18" id="P7D-Pk-13h"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="enabledSwitch" destination="gxP-eh-ANw" id="BP3-g2-HIV"/>
<outlet property="nameLabel" destination="dsQ-ir-jly" id="G9F-tK-Xi3"/>
</connections>
<point key="canvasLocation" x="-369" y="89"/>
</tableViewCell>
</objects>
</document>
Loading…
Cancel
Save