Browse Source

Development

master
Dwayne Harris 6 years ago
parent
commit
55662cf2dc
  1. 3
      .gitmodules
  2. 1
      Frameworks/FLAnimatedImage
  3. 65
      elpha-ios.xcodeproj/project.pbxproj
  4. 65
      elpha-ios/AbstractStatusTableViewController.swift
  5. 109
      elpha-ios/AccountTableViewController.swift
  6. 3
      elpha-ios/AuthenticateViewController.swift
  7. 8
      elpha-ios/Base.lproj/Main.storyboard
  8. 39
      elpha-ios/CellHeightManager.swift
  9. 63
      elpha-ios/StatusTableViewController.swift
  10. 14
      elpha-ios/StatusView.swift
  11. 109
      elpha-ios/TimelineTableViewController.swift
  12. 5
      elpha-ios/UITextViewFixed.swift

3
.gitmodules

@ -7,3 +7,6 @@
[submodule "Frameworks/AlamofireNetworkActivityIndicator"] [submodule "Frameworks/AlamofireNetworkActivityIndicator"]
path = Frameworks/AlamofireNetworkActivityIndicator path = Frameworks/AlamofireNetworkActivityIndicator
url = https://github.com/Alamofire/AlamofireNetworkActivityIndicator.git url = https://github.com/Alamofire/AlamofireNetworkActivityIndicator.git
[submodule "Frameworks/FLAnimatedImage"]
path = Frameworks/FLAnimatedImage
url = https://github.com/Flipboard/FLAnimatedImage.git

1
Frameworks/FLAnimatedImage

@ -0,0 +1 @@
Subproject commit 16fe62b540f63294cfdfdcd04ebcd9e2c093819c

65
elpha-ios.xcodeproj/project.pbxproj

@ -18,6 +18,10 @@
152734D22186DC74003DB3C8 /* TimelinesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152734D12186DC74003DB3C8 /* TimelinesViewController.swift */; }; 152734D22186DC74003DB3C8 /* TimelinesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152734D12186DC74003DB3C8 /* TimelinesViewController.swift */; };
152FB0F8218ADC1A001D6574 /* AttachmentPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FB0F7218ADC1A001D6574 /* AttachmentPageViewController.swift */; }; 152FB0F8218ADC1A001D6574 /* AttachmentPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FB0F7218ADC1A001D6574 /* AttachmentPageViewController.swift */; };
152FB0FA218ADDD0001D6574 /* AttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FB0F9218ADDD0001D6574 /* AttachmentViewController.swift */; }; 152FB0FA218ADDD0001D6574 /* AttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FB0F9218ADDD0001D6574 /* AttachmentViewController.swift */; };
152FBCD2219682E80079B3E8 /* AbstractStatusTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FBCD1219682E80079B3E8 /* AbstractStatusTableViewController.swift */; };
152FBCE621978C4A0079B3E8 /* CellHeightManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FBCE521978C4A0079B3E8 /* CellHeightManager.swift */; };
152FBCED219799FC0079B3E8 /* FLAnimatedImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 152FBCEC219799E50079B3E8 /* FLAnimatedImage.framework */; };
152FBCEE219799FC0079B3E8 /* FLAnimatedImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 152FBCEC219799E50079B3E8 /* FLAnimatedImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1539509121894A38009BA6E7 /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1539509021894A38009BA6E7 /* AlertManager.swift */; }; 1539509121894A38009BA6E7 /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1539509021894A38009BA6E7 /* AlertManager.swift */; };
156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF014217289380074D9CA /* AccountTableViewCell.swift */; }; 156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF014217289380074D9CA /* AccountTableViewCell.swift */; };
156FF0312174797E0074D9CA /* StatusTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF0302174797E0074D9CA /* StatusTableViewController.swift */; }; 156FF0312174797E0074D9CA /* StatusTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF0302174797E0074D9CA /* StatusTableViewController.swift */; };
@ -150,6 +154,20 @@
remoteGlobalIDString = 4CB928381C66E1A600CE5F08; remoteGlobalIDString = 4CB928381C66E1A600CE5F08;
remoteInfo = AlamofireNetworkActivityIndicator; remoteInfo = AlamofireNetworkActivityIndicator;
}; };
152FBCEB219799E50079B3E8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 152FBCE7219799E50079B3E8 /* FLAnimatedImage.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 92C9BC0C1B199DC500D79B06;
remoteInfo = FLAnimatedImage;
};
152FBCEF219799FC0079B3E8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 152FBCE7219799E50079B3E8 /* FLAnimatedImage.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 92C9BC0B1B199DC500D79B06;
remoteInfo = FLAnimatedImage;
};
157405C2215890BC00EEAAEB /* PBXContainerItemProxy */ = { 157405C2215890BC00EEAAEB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 157405B7215890BC00EEAAEB /* Alamofire.xcodeproj */; containerPortal = 157405B7215890BC00EEAAEB /* Alamofire.xcodeproj */;
@ -209,6 +227,7 @@
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
151AD4D9216899AD00F07403 /* AlamofireImage.framework in Embed Frameworks */, 151AD4D9216899AD00F07403 /* AlamofireImage.framework in Embed Frameworks */,
152FBCEE219799FC0079B3E8 /* FLAnimatedImage.framework in Embed Frameworks */,
151AD4E621689A0F00F07403 /* Alamofire.framework in Embed Frameworks */, 151AD4E621689A0F00F07403 /* Alamofire.framework in Embed Frameworks */,
1522EC802193EBCB0082C3FA /* AlamofireNetworkActivityIndicator.framework in Embed Frameworks */, 1522EC802193EBCB0082C3FA /* AlamofireNetworkActivityIndicator.framework in Embed Frameworks */,
); );
@ -227,6 +246,9 @@
152734D12186DC74003DB3C8 /* TimelinesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesViewController.swift; sourceTree = "<group>"; }; 152734D12186DC74003DB3C8 /* TimelinesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesViewController.swift; sourceTree = "<group>"; };
152FB0F7218ADC1A001D6574 /* AttachmentPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentPageViewController.swift; sourceTree = "<group>"; }; 152FB0F7218ADC1A001D6574 /* AttachmentPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentPageViewController.swift; sourceTree = "<group>"; };
152FB0F9218ADDD0001D6574 /* AttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentViewController.swift; sourceTree = "<group>"; }; 152FB0F9218ADDD0001D6574 /* AttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentViewController.swift; sourceTree = "<group>"; };
152FBCD1219682E80079B3E8 /* AbstractStatusTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractStatusTableViewController.swift; sourceTree = "<group>"; };
152FBCE521978C4A0079B3E8 /* CellHeightManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellHeightManager.swift; sourceTree = "<group>"; };
152FBCE7219799E50079B3E8 /* FLAnimatedImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = FLAnimatedImage.xcodeproj; path = Frameworks/FLAnimatedImage/FLAnimatedImage.xcodeproj; sourceTree = "<group>"; };
1539509021894A38009BA6E7 /* AlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertManager.swift; sourceTree = "<group>"; }; 1539509021894A38009BA6E7 /* AlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertManager.swift; sourceTree = "<group>"; };
156FF014217289380074D9CA /* AccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTableViewCell.swift; sourceTree = "<group>"; }; 156FF014217289380074D9CA /* AccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTableViewCell.swift; sourceTree = "<group>"; };
156FF0302174797E0074D9CA /* StatusTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewController.swift; sourceTree = "<group>"; }; 156FF0302174797E0074D9CA /* StatusTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewController.swift; sourceTree = "<group>"; };
@ -274,6 +296,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
15A79B2E215C63B6007A326E /* AlamofireImage.framework in Frameworks */, 15A79B2E215C63B6007A326E /* AlamofireImage.framework in Frameworks */,
152FBCED219799FC0079B3E8 /* FLAnimatedImage.framework in Frameworks */,
157405D1215890D700EEAAEB /* Alamofire.framework in Frameworks */, 157405D1215890D700EEAAEB /* Alamofire.framework in Frameworks */,
1522EC7F2193EBCB0082C3FA /* AlamofireNetworkActivityIndicator.framework in Frameworks */, 1522EC7F2193EBCB0082C3FA /* AlamofireNetworkActivityIndicator.framework in Frameworks */,
); );
@ -312,6 +335,7 @@
1539509021894A38009BA6E7 /* AlertManager.swift */, 1539509021894A38009BA6E7 /* AlertManager.swift */,
1574148C2169AD0100C841BD /* AttachmentManager.swift */, 1574148C2169AD0100C841BD /* AttachmentManager.swift */,
15960E7B213272CD00C38CE9 /* AuthenticationManager.swift */, 15960E7B213272CD00C38CE9 /* AuthenticationManager.swift */,
152FBCE521978C4A0079B3E8 /* CellHeightManager.swift */,
15A79B42215EB959007A326E /* CoreDataManager.swift */, 15A79B42215EB959007A326E /* CoreDataManager.swift */,
157405B32151A93E00EEAAEB /* InstancesDataManager.swift */, 157405B32151A93E00EEAAEB /* InstancesDataManager.swift */,
15F998342162C0E8009E58DA /* MastodonDataManager.swift */, 15F998342162C0E8009E58DA /* MastodonDataManager.swift */,
@ -362,6 +386,22 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
152FBCE4219789450079B3E8 /* Abstract View Controllers */ = {
isa = PBXGroup;
children = (
152FBCD1219682E80079B3E8 /* AbstractStatusTableViewController.swift */,
);
name = "Abstract View Controllers";
sourceTree = "<group>";
};
152FBCE8219799E50079B3E8 /* Products */ = {
isa = PBXGroup;
children = (
152FBCEC219799E50079B3E8 /* FLAnimatedImage.framework */,
);
name = Products;
sourceTree = "<group>";
};
156FF05621779C140074D9CA /* API */ = { 156FF05621779C140074D9CA /* API */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -399,6 +439,7 @@
157405B7215890BC00EEAAEB /* Alamofire.xcodeproj */, 157405B7215890BC00EEAAEB /* Alamofire.xcodeproj */,
1517EA6F2159D72200DE80D6 /* AlamofireImage.xcodeproj */, 1517EA6F2159D72200DE80D6 /* AlamofireImage.xcodeproj */,
1522EC752193EBA10082C3FA /* AlamofireNetworkActivityIndicator.xcodeproj */, 1522EC752193EBA10082C3FA /* AlamofireNetworkActivityIndicator.xcodeproj */,
152FBCE7219799E50079B3E8 /* FLAnimatedImage.xcodeproj */,
15960E59213145E100C38CE9 /* elpha-ios */, 15960E59213145E100C38CE9 /* elpha-ios */,
15960E58213145E100C38CE9 /* Products */, 15960E58213145E100C38CE9 /* Products */,
157405D0215890D700EEAAEB /* Frameworks */, 157405D0215890D700EEAAEB /* Frameworks */,
@ -428,6 +469,7 @@
151AD4AC2166DD0200F07403 /* Managers */, 151AD4AC2166DD0200F07403 /* Managers */,
151AD4AD2166DD1B00F07403 /* Reusable Views */, 151AD4AD2166DD1B00F07403 /* Reusable Views */,
151AD4AB2166DCEE00F07403 /* Storyboards */, 151AD4AB2166DCEE00F07403 /* Storyboards */,
152FBCE4219789450079B3E8 /* Abstract View Controllers */,
15960E782132383600C38CE9 /* View Controllers */, 15960E782132383600C38CE9 /* View Controllers */,
151AD4AE2166DD3500F07403 /* Views */, 151AD4AE2166DD3500F07403 /* Views */,
); );
@ -480,6 +522,7 @@
151AD4DB216899AD00F07403 /* PBXTargetDependency */, 151AD4DB216899AD00F07403 /* PBXTargetDependency */,
151AD4E821689A0F00F07403 /* PBXTargetDependency */, 151AD4E821689A0F00F07403 /* PBXTargetDependency */,
1522EC822193EBCB0082C3FA /* PBXTargetDependency */, 1522EC822193EBCB0082C3FA /* PBXTargetDependency */,
152FBCF0219799FC0079B3E8 /* PBXTargetDependency */,
); );
name = "elpha-ios"; name = "elpha-ios";
productName = "elpha-ios"; productName = "elpha-ios";
@ -526,6 +569,10 @@
ProductGroup = 1522EC762193EBA10082C3FA /* Products */; ProductGroup = 1522EC762193EBA10082C3FA /* Products */;
ProjectRef = 1522EC752193EBA10082C3FA /* AlamofireNetworkActivityIndicator.xcodeproj */; ProjectRef = 1522EC752193EBA10082C3FA /* AlamofireNetworkActivityIndicator.xcodeproj */;
}, },
{
ProductGroup = 152FBCE8219799E50079B3E8 /* Products */;
ProjectRef = 152FBCE7219799E50079B3E8 /* FLAnimatedImage.xcodeproj */;
},
); );
projectRoot = ""; projectRoot = "";
targets = ( targets = (
@ -605,6 +652,13 @@
remoteRef = 1522EC7D2193EBA10082C3FA /* PBXContainerItemProxy */; remoteRef = 1522EC7D2193EBA10082C3FA /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
152FBCEC219799E50079B3E8 /* FLAnimatedImage.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = FLAnimatedImage.framework;
remoteRef = 152FBCEB219799E50079B3E8 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
157405C3215890BC00EEAAEB /* Alamofire.framework */ = { 157405C3215890BC00EEAAEB /* Alamofire.framework */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = wrapper.framework; fileType = wrapper.framework;
@ -707,11 +761,13 @@
15960E7321322BC700C38CE9 /* KeychainItemAccessibility.swift in Sources */, 15960E7321322BC700C38CE9 /* KeychainItemAccessibility.swift in Sources */,
156FF051217683270074D9CA /* StatusTableViewCell.swift in Sources */, 156FF051217683270074D9CA /* StatusTableViewCell.swift in Sources */,
159026D02163069600D362DD /* Date+TimeAgo.swift in Sources */, 159026D02163069600D362DD /* Date+TimeAgo.swift in Sources */,
152FBCD2219682E80079B3E8 /* AbstractStatusTableViewController.swift in Sources */,
15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */, 15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */,
15BB72AB2171A8D4002F1FA4 /* TimelinesTableViewCell.swift in Sources */, 15BB72AB2171A8D4002F1FA4 /* TimelinesTableViewCell.swift in Sources */,
1574148D2169AD0100C841BD /* AttachmentManager.swift in Sources */, 1574148D2169AD0100C841BD /* AttachmentManager.swift in Sources */,
156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */, 156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */,
15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */, 15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */,
152FBCE621978C4A0079B3E8 /* CellHeightManager.swift in Sources */,
156FF04F2175CDBC0074D9CA /* MainStatusTableViewCell.swift in Sources */, 156FF04F2175CDBC0074D9CA /* MainStatusTableViewCell.swift in Sources */,
159026AE2162CF5600D362DD /* TimelineTableViewCell.swift in Sources */, 159026AE2162CF5600D362DD /* TimelineTableViewCell.swift in Sources */,
); );
@ -735,6 +791,11 @@
name = AlamofireNetworkActivityIndicator; name = AlamofireNetworkActivityIndicator;
targetProxy = 1522EC812193EBCB0082C3FA /* PBXContainerItemProxy */; targetProxy = 1522EC812193EBCB0082C3FA /* PBXContainerItemProxy */;
}; };
152FBCF0219799FC0079B3E8 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = FLAnimatedImage;
targetProxy = 152FBCEF219799FC0079B3E8 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
@ -878,7 +939,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = 4HV9QP2X8X;
INFOPLIST_FILE = "elpha-ios/Info.plist"; INFOPLIST_FILE = "elpha-ios/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.1; IPHONEOS_DEPLOYMENT_TARGET = 12.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
@ -887,7 +948,7 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = "xyz.elpha.elpha-ios"; PRODUCT_BUNDLE_IDENTIFIER = "xyz.elpha.elpha-ios";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
PROVISIONING_PROFILE_SPECIFIER = Elpha;
SWIFT_VERSION = 4.2; SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = 1; TARGETED_DEVICE_FAMILY = 1;
}; };

65
elpha-ios/AbstractStatusTableViewController.swift

@ -0,0 +1,65 @@
//
// ELStatusTableViewController.swift
// elpha-ios
//
// Created by Dwayne Harris on 11/9/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import UIKit
import SafariServices
class AbstractStatusTableViewController: UITableViewController, StatusViewDelegate {
let fetchLimit = 20
var loading: Bool = false
var currentPaginationContext: String = ""
var cellHeightsDictionary: NSMutableDictionary = [:]
func accountTapped(account: AccountMO) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "AccountTableViewController") as? AccountTableViewController {
controller.account = account
self.navigationController?.pushViewController(controller, animated: true)
}
}
func statusTapped(status: StatusMO) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "StatusTableViewController") as? StatusTableViewController {
controller.status = status
self.navigationController?.pushViewController(controller, animated: true)
}
}
func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {
}
func attachmentTapped(status: StatusMO, index: Int) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "AttachmentPageViewController") as? AttachmentPageViewController {
controller.status = status
controller.attachmentIndex = index
present(controller, animated: false)
}
}
func urlTapped(url: URL) {
let controller = SFSafariViewController(url: url)
controller.delegate = self
controller.dismissButtonStyle = .done
controller.preferredControlTintColor = UIColor(named: "Primary")
present(controller, animated: true)
}
}
extension AbstractStatusTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true)
}
}

109
elpha-ios/AccountTableViewController.swift

@ -11,7 +11,7 @@ import CoreData
import UIKit import UIKit
import SafariServices import SafariServices
class AccountTableViewController: UITableViewController {
class AccountTableViewController: AbstractStatusTableViewController {
@IBOutlet var headerView: UIView! @IBOutlet var headerView: UIView!
@IBOutlet var headerImageView: UIImageView! @IBOutlet var headerImageView: UIImageView!
@IBOutlet var avatarImageView: UIImageView! @IBOutlet var avatarImageView: UIImageView!
@ -23,21 +23,25 @@ class AccountTableViewController: UITableViewController {
@IBOutlet var followersLabel: UILabel! @IBOutlet var followersLabel: UILabel!
@IBOutlet var statusTypeSegmentedControl: UISegmentedControl! @IBOutlet var statusTypeSegmentedControl: UISegmentedControl!
let fetchLimit = 20
var fetchedResultsController: NSFetchedResultsController<StatusMO>? = nil var fetchedResultsController: NSFetchedResultsController<StatusMO>? = nil
var account: AccountMO? = nil var account: AccountMO? = nil
var loading: Bool = false
var currentPaginationContext: String {
guard let account = self.account else {
return ""
override var currentPaginationContext: String {
get {
guard let account = self.account else {
return ""
}
switch statusTypeSegmentedControl.selectedSegmentIndex {
case 3:
return "timeline:favorites"
case let index:
return "account:\(account.acct!):\(index)"
}
} }
switch statusTypeSegmentedControl.selectedSegmentIndex {
case 3:
return "timeline:favorites"
case let index:
return "account:\(account.acct!):\(index)"
set {
} }
} }
@ -113,6 +117,20 @@ class AccountTableViewController: UITableViewController {
} }
} }
override func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {
if let markers = status.markers {
markers.forEach { marker in
if marker.context == self.currentPaginationContext && marker.item.direction == direction {
fetchStatuses(withPagination: marker.item) { error in
if error != nil {
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
}
}
}
}
}
}
@objc func fetch() { @objc func fetch() {
fetchStatuses { error in fetchStatuses { error in
if error != nil { if error != nil {
@ -260,6 +278,16 @@ extension AccountTableViewController: NSFetchedResultsControllerDelegate {
return 1 return 1
} }
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let cell = cell as? AccountTableViewCell {
CellHeightManager.set(status: cell.statusView.status, height: cell.frame.size.height)
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CellHeightManager.get(status: fetchedResultsController?.object(at: indexPath))
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let count = fetchedResultsController?.fetchedObjects?.count else { guard let count = fetchedResultsController?.fetchedObjects?.count else {
return 0 return 0
@ -321,62 +349,3 @@ extension AccountTableViewController: NSFetchedResultsControllerDelegate {
return cell return cell
} }
} }
extension AccountTableViewController: StatusViewDelegate {
func accountTapped(account: AccountMO) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "AccountTableViewController") as? AccountTableViewController {
controller.account = account
self.navigationController?.pushViewController(controller, animated: true)
}
}
func statusTapped(status: StatusMO) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "StatusTableViewController") as? StatusTableViewController {
controller.status = status
self.navigationController?.pushViewController(controller, animated: true)
}
}
func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {
if let markers = status.markers {
markers.forEach { marker in
if marker.context == self.currentPaginationContext && marker.item.direction == direction {
fetchStatuses(withPagination: marker.item) { error in
if error != nil {
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
}
}
}
}
}
}
func attachmentTapped(status: StatusMO, index: Int) {
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AttachmentPageViewController") as? AttachmentPageViewController {
controller.status = status
controller.attachmentIndex = index
present(controller, animated: false)
}
}
func urlTapped(url: URL) {
let controller = SFSafariViewController(url: url)
controller.delegate = self
controller.dismissButtonStyle = .done
// controller.preferredBarTintColor = UIColor(named: "Secondary")
controller.preferredControlTintColor = UIColor(named: "Text")
present(controller, animated: true)
}
}
extension AccountTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true)
}
}

3
elpha-ios/AuthenticateViewController.swift

@ -54,8 +54,7 @@ class AuthenticateViewController: UIViewController {
let controller = SFSafariViewController(url: authorizeURL!) let controller = SFSafariViewController(url: authorizeURL!)
controller.delegate = self controller.delegate = self
controller.dismissButtonStyle = .cancel controller.dismissButtonStyle = .cancel
controller.preferredBarTintColor = UIColor(named: "Secondary")
controller.preferredControlTintColor = UIColor(named: "Text")
controller.preferredControlTintColor = UIColor(named: "Primary")
present(controller, animated: true) present(controller, animated: true)
} }

8
elpha-ios/Base.lproj/Main.storyboard

@ -1237,10 +1237,10 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" maximumZoomScale="6" translatesAutoresizingMaskIntoConstraints="NO" id="7ll-rV-5Xs"> <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" maximumZoomScale="6" translatesAutoresizingMaskIntoConstraints="NO" id="7ll-rV-5Xs">
<rect key="frame" x="0.0" y="83" width="375" height="464"/>
<rect key="frame" x="0.0" y="83" width="375" height="514"/>
<subviews> <subviews>
<imageView multipleTouchEnabled="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LVW-zt-JUe"> <imageView multipleTouchEnabled="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LVW-zt-JUe">
<rect key="frame" x="0.0" y="0.0" width="375" height="464"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="514"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<gestureRecognizers/> <gestureRecognizers/>
</imageView> </imageView>
@ -1256,11 +1256,11 @@
</constraints> </constraints>
</scrollView> </scrollView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" text="Content" textAlignment="center" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hd1-Nu-84c"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" text="Content" textAlignment="center" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hd1-Nu-84c">
<rect key="frame" x="8" y="562" width="359" height="150"/>
<rect key="frame" x="8" y="612" width="359" height="100"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" name="Secondary"/> <color key="tintColor" name="Secondary"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="150" id="qx0-dd-I7h"/>
<constraint firstAttribute="height" constant="100" id="qx0-dd-I7h"/>
</constraints> </constraints>
<color key="textColor" name="Background Primary"/> <color key="textColor" name="Background Primary"/>
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="17"/> <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="17"/>

39
elpha-ios/CellHeightManager.swift

@ -0,0 +1,39 @@
//
// CellHeightManager.swift
// elpha-ios
//
// Created by Dwayne Harris on 11/10/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import UIKit
class CellHeightManager {
static private var cellHeightsDictionary: NSMutableDictionary = [:]
static func set(statusID: String, height: CGFloat) {
cellHeightsDictionary[statusID] = height
}
static func set(status: StatusMO?, height: CGFloat) {
if let id = status?.id {
set(statusID: id, height: height)
}
}
static func get(statusID: String) -> CGFloat {
if let height = cellHeightsDictionary[statusID] as? CGFloat {
return height
}
return UITableView.automaticDimension
}
static func get(status: StatusMO?) -> CGFloat {
if let id = status?.id {
return get(statusID: id)
}
return UITableView.automaticDimension
}
}

63
elpha-ios/StatusTableViewController.swift

@ -15,12 +15,12 @@ enum StatusType {
case ancestor, status, descendant case ancestor, status, descendant
} }
class StatusTableViewController: UITableViewController, UIGestureRecognizerDelegate {
class StatusTableViewController: AbstractStatusTableViewController, UIGestureRecognizerDelegate {
public var status: StatusMO? = nil public var status: StatusMO? = nil
var ancestors: [StatusMO] = [] var ancestors: [StatusMO] = []
var descendants: [StatusMO] = [] var descendants: [StatusMO] = []
var feedbackGenerator: UINotificationFeedbackGenerator? = nil var feedbackGenerator: UINotificationFeedbackGenerator? = nil
var loading: Bool = false
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -209,6 +209,20 @@ extension StatusTableViewController {
return 3 return 3
} }
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let cell = cell as? StatusTableViewCell {
CellHeightManager.set(status: cell.statusView.status, height: cell.frame.size.height)
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 0: return CellHeightManager.get(status: self.ancestors[indexPath.row])
case 2: return CellHeightManager.get(status: self.descendants[indexPath.row])
default: return UITableView.automaticDimension
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
let height = CGFloat(25) let height = CGFloat(25)
@ -330,44 +344,7 @@ extension StatusTableViewController {
} }
} }
extension StatusTableViewController: StatusViewDelegate {
func accountTapped(account: AccountMO) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "AccountTableViewController") as? AccountTableViewController {
controller.account = account
self.navigationController?.pushViewController(controller, animated: true)
}
}
func statusTapped(status: StatusMO) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let controller = storyboard.instantiateViewController(withIdentifier: "StatusTableViewController") as? StatusTableViewController {
controller.status = status
self.navigationController?.pushViewController(controller, animated: true)
}
}
func attachmentTapped(status: StatusMO, index: Int) {
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AttachmentPageViewController") as? AttachmentPageViewController {
controller.status = status
controller.attachmentIndex = index
present(controller, animated: false)
}
}
func urlTapped(url: URL) {
let controller = SFSafariViewController(url: url)
controller.delegate = self
controller.dismissButtonStyle = .done
// controller.preferredBarTintColor = UIColor(named: "Secondary")
controller.preferredControlTintColor = UIColor(named: "Text")
present(controller, animated: true)
}
extension StatusTableViewController {
func boostTapped() { func boostTapped() {
loadStatuses() loadStatuses()
} }
@ -385,12 +362,6 @@ extension StatusTableViewController: StatusViewDelegate {
} }
} }
extension StatusTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true)
}
}
extension StatusTableViewController: AttachmentManagerDelegate { extension StatusTableViewController: AttachmentManagerDelegate {
func attachmentTapped(index: Int) { func attachmentTapped(index: Int) {
self.attachmentTapped(status: status!, index: index) self.attachmentTapped(status: status!, index: index)

14
elpha-ios/StatusView.swift

@ -63,6 +63,7 @@ class StatusView: UIView {
var delegate: StatusViewDelegate? = nil var delegate: StatusViewDelegate? = nil
var spoilerView: UIVisualEffectView? = nil var spoilerView: UIVisualEffectView? = nil
var attachmentManager: AttachmentManager = AttachmentManager() var attachmentManager: AttachmentManager = AttachmentManager()
var feedbackGenerator: UINotificationFeedbackGenerator? = nil
@IBAction func boostViewTapped(_ sender: Any) { @IBAction func boostViewTapped(_ sender: Any) {
if let delegate = delegate, let status = status { if let delegate = delegate, let status = status {
@ -121,6 +122,8 @@ class StatusView: UIView {
@IBAction func boostTapped(_ sender: Any) { @IBAction func boostTapped(_ sender: Any) {
if let status = status { if let status = status {
feedbackGenerator!.prepare()
if status.reblogged { if status.reblogged {
status.reblogged = false status.reblogged = false
status.reblogsCount = status.reblogsCount - 1 status.reblogsCount = status.reblogsCount - 1
@ -128,10 +131,12 @@ class StatusView: UIView {
MastodonAPI.unreblog(statusID: status.id!) { error in MastodonAPI.unreblog(statusID: status.id!) { error in
guard error == nil else { guard error == nil else {
AlertManager.shared.show(message: error!.localizedDescription, category: .error) AlertManager.shared.show(message: error!.localizedDescription, category: .error)
self.feedbackGenerator!.notificationOccurred(.error)
return return
} }
AlertManager.shared.show(message: "Unboosted", category: .boosted) AlertManager.shared.show(message: "Unboosted", category: .boosted)
self.feedbackGenerator!.notificationOccurred(.success)
} }
} else { } else {
status.reblogged = true status.reblogged = true
@ -140,10 +145,12 @@ class StatusView: UIView {
MastodonAPI.reblog(statusID: status.id!) { error in MastodonAPI.reblog(statusID: status.id!) { error in
guard error == nil else { guard error == nil else {
AlertManager.shared.show(message: error!.localizedDescription, category: .error) AlertManager.shared.show(message: error!.localizedDescription, category: .error)
self.feedbackGenerator!.notificationOccurred(.error)
return return
} }
AlertManager.shared.show(message: "Boosted!", category: .boosted) AlertManager.shared.show(message: "Boosted!", category: .boosted)
self.feedbackGenerator!.notificationOccurred(.success)
} }
} }
@ -154,6 +161,8 @@ class StatusView: UIView {
@IBAction func favoriteTapped(_ sender: Any) { @IBAction func favoriteTapped(_ sender: Any) {
if let status = status { if let status = status {
feedbackGenerator!.prepare()
if status.favorited { if status.favorited {
status.favorited = false status.favorited = false
status.favoritesCount = status.favoritesCount - 1 status.favoritesCount = status.favoritesCount - 1
@ -161,10 +170,12 @@ class StatusView: UIView {
MastodonAPI.unfavorite(statusID: status.id!) { error in MastodonAPI.unfavorite(statusID: status.id!) { error in
guard error == nil else { guard error == nil else {
AlertManager.shared.show(message: error!.localizedDescription, category: .error) AlertManager.shared.show(message: error!.localizedDescription, category: .error)
self.feedbackGenerator!.notificationOccurred(.error)
return return
} }
AlertManager.shared.show(message: "Unfavorited", category: .favorited) AlertManager.shared.show(message: "Unfavorited", category: .favorited)
self.feedbackGenerator!.notificationOccurred(.success)
} }
} else { } else {
status.favorited = true status.favorited = true
@ -173,10 +184,12 @@ class StatusView: UIView {
MastodonAPI.favorite(statusID: status.id!) { error in MastodonAPI.favorite(statusID: status.id!) { error in
guard error == nil else { guard error == nil else {
AlertManager.shared.show(message: error!.localizedDescription, category: .error) AlertManager.shared.show(message: error!.localizedDescription, category: .error)
self.feedbackGenerator!.notificationOccurred(.error)
return return
} }
AlertManager.shared.show(message: "Favorited!", category: .favorited) AlertManager.shared.show(message: "Favorited!", category: .favorited)
self.feedbackGenerator!.notificationOccurred(.success)
} }
} }
@ -210,6 +223,7 @@ class StatusView: UIView {
contentView.frame = self.bounds contentView.frame = self.bounds
attachmentManager.delegate = self attachmentManager.delegate = self
contentTextView.delegate = self contentTextView.delegate = self
feedbackGenerator = UINotificationFeedbackGenerator()
} }
public func update(withStatus status: StatusMO) { public func update(withStatus status: StatusMO) {

109
elpha-ios/TimelineTableViewController.swift

@ -12,18 +12,17 @@ import CoreData
import UIKit import UIKit
import SafariServices import SafariServices
class TimelineTableViewController: UITableViewController {
let fetchLimit = 20
class TimelineTableViewController: AbstractStatusTableViewController {
var feedbackGenerator: UINotificationFeedbackGenerator? = nil var feedbackGenerator: UINotificationFeedbackGenerator? = nil
var fetchedResultsController: NSFetchedResultsController<StatusMO>? = nil var fetchedResultsController: NSFetchedResultsController<StatusMO>? = nil
var loading: Bool = false
var currentPaginationContext: String {
guard let timeline = AuthenticationManager.session?.timeline, let categoryString = timeline.category else {
return ""
}
switch TimelineCategory(rawValue: categoryString)! {
override var currentPaginationContext: String {
get {
guard let timeline = AuthenticationManager.session?.timeline, let categoryString = timeline.category else {
return ""
}
switch TimelineCategory(rawValue: categoryString)! {
case .home: case .home:
return "timeline:home" return "timeline:home"
case .local: case .local:
@ -34,6 +33,11 @@ class TimelineTableViewController: UITableViewController {
return "timeline:tag:\(timeline.subcategory!)" return "timeline:tag:\(timeline.subcategory!)"
case .favorites: case .favorites:
return "timeline:favorites" return "timeline:favorites"
}
}
set {
} }
} }
@ -88,6 +92,20 @@ class TimelineTableViewController: UITableViewController {
} }
} }
override func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {
if let markers = status.markers {
markers.forEach { marker in
if marker.context == self.currentPaginationContext && marker.item.direction == direction {
fetchTimeline(withPagination: marker.item) { error in
if error != nil {
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
}
}
}
}
}
}
@objc func openSettings() { @objc func openSettings() {
} }
@ -96,10 +114,6 @@ class TimelineTableViewController: UITableViewController {
performSegue(withIdentifier: "TimelinesSegue", sender: self) performSegue(withIdentifier: "TimelinesSegue", sender: self)
} }
@objc func compose() {
AlertManager.shared.show(message: "We'll get the compose screen working one day.")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "TimelinesSegue" { if segue.identifier == "TimelinesSegue" {
if let destination = segue.destination as? TimelinesViewController { if let destination = segue.destination as? TimelinesViewController {
@ -108,6 +122,10 @@ class TimelineTableViewController: UITableViewController {
} }
} }
@objc func compose() {
AlertManager.shared.show(message: "We'll get the compose screen working one day.")
}
func createDefaultTimelines(account: AccountMO) { func createDefaultTimelines(account: AccountMO) {
let homeTimeline = TimelineMO(context: CoreDataManager.shared.context) let homeTimeline = TimelineMO(context: CoreDataManager.shared.context)
homeTimeline.name = "Home" homeTimeline.name = "Home"
@ -337,6 +355,16 @@ extension TimelineTableViewController {
return count return count
} }
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let cell = cell as? TimelineTableViewCell {
CellHeightManager.set(status: cell.statusView.status, height: cell.frame.size.height)
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CellHeightManager.get(status: fetchedResultsController?.object(at: indexPath))
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineTableViewCell", for: indexPath) as? TimelineTableViewCell else { guard let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineTableViewCell", for: indexPath) as? TimelineTableViewCell else {
fatalError("Unable to find reusable cell") fatalError("Unable to find reusable cell")
@ -403,58 +431,3 @@ extension TimelineTableViewController: TimelinesViewControllerDelegate {
tableView.reloadData() tableView.reloadData()
} }
} }
extension TimelineTableViewController: StatusViewDelegate {
func accountTapped(account: AccountMO) {
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AccountTableViewController") as? AccountTableViewController {
controller.account = account
self.navigationController?.pushViewController(controller, animated: true)
}
}
func statusTapped(status: StatusMO) {
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "StatusTableViewController") as? StatusTableViewController {
controller.status = status
self.navigationController?.pushViewController(controller, animated: true)
}
}
func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {
if let markers = status.markers {
markers.forEach { marker in
if marker.context == self.currentPaginationContext && marker.item.direction == direction {
fetchTimeline(withPagination: marker.item) { error in
if error != nil {
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
}
}
}
}
}
}
func attachmentTapped(status: StatusMO, index: Int) {
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AttachmentPageViewController") as? AttachmentPageViewController {
controller.status = status
controller.attachmentIndex = index
present(controller, animated: false)
}
}
func urlTapped(url: URL) {
let controller = SFSafariViewController(url: url)
controller.delegate = self
controller.dismissButtonStyle = .done
// controller.preferredBarTintColor = UIColor(named: "Secondary")
controller.preferredControlTintColor = UIColor(named: "Text")
present(controller, animated: true)
}
}
extension TimelineTableViewController: SFSafariViewControllerDelegate {
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
controller.dismiss(animated: true)
}
}

5
elpha-ios/UITextViewFixed.swift

@ -12,7 +12,10 @@ import UIKit
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
textContainerInset = UIEdgeInsets.zero
let inset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
contentInset = inset
textContainerInset = inset
textContainer.lineFragmentPadding = 0 textContainer.lineFragmentPadding = 0
} }
} }
Loading…
Cancel
Save