From c1671bb23bc91189989f412def9f09b360750faa Mon Sep 17 00:00:00 2001 From: Dwayne Harris Date: Wed, 10 Oct 2018 01:14:34 -0700 Subject: [PATCH] Development --- elpha-ios.xcodeproj/project.pbxproj | 26 +- elpha-ios/AccountNavigationController.swift | 13 + elpha-ios/AccountTableViewController.swift | 105 +++ .../Account.imageset/Contents.json | 12 + .../Account.imageset/user-circle.pdf | Bin 0 -> 4185 bytes .../Comments.imageset/Contents.json | 12 + .../Comments.imageset/comments.pdf | Bin 0 -> 4345 bytes elpha-ios/Base.lproj/Main.storyboard | 722 ++++++------------ elpha-ios/NewStatusesView.swift | 13 +- elpha-ios/NewStatusesView.xib | 18 +- elpha-ios/StatusView.swift | 55 ++ elpha-ios/StatusView.xib | 473 ++++++++++++ elpha-ios/TimelineTableViewCell.swift | 26 +- elpha-ios/TimelineTableViewController.swift | 96 +-- elpha-ios/TimelinesNavigationController.swift | 5 +- 15 files changed, 982 insertions(+), 594 deletions(-) create mode 100644 elpha-ios/AccountNavigationController.swift create mode 100644 elpha-ios/AccountTableViewController.swift create mode 100644 elpha-ios/Assets.xcassets/Account.imageset/Contents.json create mode 100644 elpha-ios/Assets.xcassets/Account.imageset/user-circle.pdf create mode 100644 elpha-ios/Assets.xcassets/Comments.imageset/Contents.json create mode 100644 elpha-ios/Assets.xcassets/Comments.imageset/comments.pdf create mode 100644 elpha-ios/StatusView.swift create mode 100644 elpha-ios/StatusView.xib diff --git a/elpha-ios.xcodeproj/project.pbxproj b/elpha-ios.xcodeproj/project.pbxproj index 512988f..0d47920 100644 --- a/elpha-ios.xcodeproj/project.pbxproj +++ b/elpha-ios.xcodeproj/project.pbxproj @@ -7,13 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - 151AD4D8216899AD00F07403 /* AlamofireImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1517EA842159D72200DE80D6 /* AlamofireImage.framework */; }; + 15131ED8216D8C680092B252 /* StatusView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15131ED7216D8C680092B252 /* StatusView.xib */; }; + 15131EF2216D8D570092B252 /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15131EF1216D8D570092B252 /* StatusView.swift */; }; + 15131EF4216DB8B90092B252 /* AccountTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15131EF3216DB8B90092B252 /* AccountTableViewController.swift */; }; + 15131EF6216DBA820092B252 /* AccountNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15131EF5216DBA820092B252 /* AccountNavigationController.swift */; }; 151AD4D9216899AD00F07403 /* AlamofireImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1517EA842159D72200DE80D6 /* AlamofireImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 151AD4DD216899E000F07403 /* OAuthSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A79B13215B438C007A326E /* OAuthSwift.framework */; }; 151AD4DE216899E000F07403 /* OAuthSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 15A79B13215B438C007A326E /* OAuthSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 151AD4E1216899F900F07403 /* MastodonKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A79B02215B3CC5007A326E /* MastodonKit.framework */; }; 151AD4E2216899F900F07403 /* MastodonKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 15A79B02215B3CC5007A326E /* MastodonKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 151AD4E521689A0F00F07403 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 157405C3215890BC00EEAAEB /* Alamofire.framework */; }; 151AD4E621689A0F00F07403 /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 157405C3215890BC00EEAAEB /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 157405A82150588A00EEAAEB /* InstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405A72150588A00EEAAEB /* InstanceViewController.swift */; }; 157405B12151A5DA00EEAAEB /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 157405AF2151A5DA00EEAAEB /* README.md */; }; @@ -37,8 +39,6 @@ 15960E7E21329FED00C38CE9 /* AuthenticateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E7D21329FED00C38CE9 /* AuthenticateViewController.swift */; }; 15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E812136668500C38CE9 /* TimelinesNavigationController.swift */; }; 15960E84213774FC00C38CE9 /* InstancesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */; }; - 15A79B07215B3CD5007A326E /* MastodonKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A79B02215B3CC5007A326E /* MastodonKit.framework */; }; - 15A79B20215B439A007A326E /* OAuthSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A79B13215B438C007A326E /* OAuthSwift.framework */; }; 15A79B2E215C63B6007A326E /* AlamofireImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1517EA842159D72200DE80D6 /* AlamofireImage.framework */; }; 15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A79B42215EB959007A326E /* CoreDataManager.swift */; }; 15C91A02216AB2D600D97DC3 /* NewStatusesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15C91A01216AB2D600D97DC3 /* NewStatusesView.xib */; }; @@ -278,6 +278,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 15131ED7216D8C680092B252 /* StatusView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StatusView.xib; sourceTree = ""; }; + 15131EF1216D8D570092B252 /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = ""; }; + 15131EF3216DB8B90092B252 /* AccountTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTableViewController.swift; sourceTree = ""; }; + 15131EF5216DBA820092B252 /* AccountNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountNavigationController.swift; sourceTree = ""; }; 1517EA6F2159D72200DE80D6 /* AlamofireImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AlamofireImage.xcodeproj; path = Frameworks/AlamofireImage/AlamofireImage.xcodeproj; sourceTree = ""; }; 157405A72150588A00EEAAEB /* InstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceViewController.swift; sourceTree = ""; }; 157405AF2151A5DA00EEAAEB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -318,13 +322,9 @@ buildActionMask = 2147483647; files = ( 15A79B2E215C63B6007A326E /* AlamofireImage.framework in Frameworks */, - 151AD4D8216899AD00F07403 /* AlamofireImage.framework in Frameworks */, 151AD4DD216899E000F07403 /* OAuthSwift.framework in Frameworks */, 151AD4E1216899F900F07403 /* MastodonKit.framework in Frameworks */, - 15A79B20215B439A007A326E /* OAuthSwift.framework in Frameworks */, - 15A79B07215B3CD5007A326E /* MastodonKit.framework in Frameworks */, 157405D1215890D700EEAAEB /* Alamofire.framework in Frameworks */, - 151AD4E521689A0F00F07403 /* Alamofire.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -372,6 +372,8 @@ children = ( 15C91A01216AB2D600D97DC3 /* NewStatusesView.xib */, 15C91A03216AB32500D97DC3 /* NewStatusesView.swift */, + 15131ED7216D8C680092B252 /* StatusView.xib */, + 15131EF1216D8D570092B252 /* StatusView.swift */, ); name = "Reusable Views"; sourceTree = ""; @@ -467,6 +469,8 @@ 15960E782132383600C38CE9 /* View Controllers */ = { isa = PBXGroup; children = ( + 15131EF5216DBA820092B252 /* AccountNavigationController.swift */, + 15131EF3216DB8B90092B252 /* AccountTableViewController.swift */, 15960E7D21329FED00C38CE9 /* AuthenticateViewController.swift */, 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */, 157405A72150588A00EEAAEB /* InstanceViewController.swift */, @@ -535,7 +539,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0940; - LastUpgradeCheck = 0940; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = Elpha; TargetAttributes = { 15960E56213145E100C38CE9 = { @@ -775,6 +779,7 @@ 15960E64213145E200C38CE9 /* Assets.xcassets in Resources */, 157405B12151A5DA00EEAAEB /* README.md in Resources */, 15960E62213145E100C38CE9 /* Main.storyboard in Resources */, + 15131ED8216D8C680092B252 /* StatusView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -790,14 +795,17 @@ 15960E7021321FA500C38CE9 /* Elpha.xcdatamodeld in Sources */, 15F9981721629965009E58DA /* TimelineTableViewController.swift in Sources */, 157405B42151A93E00EEAAEB /* InstancesDataManager.swift in Sources */, + 15131EF4216DB8B90092B252 /* AccountTableViewController.swift in Sources */, 15960E5F213145E100C38CE9 /* SecondViewController.swift in Sources */, 15F998352162C0E8009E58DA /* MastodonDataManager.swift in Sources */, 15960E7A2132387A00C38CE9 /* MainTabBarController.swift in Sources */, 15960E7C213272CD00C38CE9 /* AuthenticationManager.swift in Sources */, 15960E7E21329FED00C38CE9 /* AuthenticateViewController.swift in Sources */, 15960E5B213145E100C38CE9 /* AppDelegate.swift in Sources */, + 15131EF2216D8D570092B252 /* StatusView.swift in Sources */, 15960E7721322C6F00C38CE9 /* Configuration.swift in Sources */, 15C91A04216AB32500D97DC3 /* NewStatusesView.swift in Sources */, + 15131EF6216DBA820092B252 /* AccountNavigationController.swift in Sources */, 15960E7521322BF800C38CE9 /* KeychainWrapper.swift in Sources */, 157405A82150588A00EEAAEB /* InstanceViewController.swift in Sources */, 15960E7321322BC700C38CE9 /* KeychainItemAccessibility.swift in Sources */, diff --git a/elpha-ios/AccountNavigationController.swift b/elpha-ios/AccountNavigationController.swift new file mode 100644 index 0000000..c93aebc --- /dev/null +++ b/elpha-ios/AccountNavigationController.swift @@ -0,0 +1,13 @@ +// +// AccountNavigationController.swift +// elpha-ios +// +// Created by Dwayne Harris on 10/9/18. +// Copyright © 2018 Elpha. All rights reserved. +// + +import UIKit + +class AccountNavigationController: UINavigationController { + +} diff --git a/elpha-ios/AccountTableViewController.swift b/elpha-ios/AccountTableViewController.swift new file mode 100644 index 0000000..3d1bc91 --- /dev/null +++ b/elpha-ios/AccountTableViewController.swift @@ -0,0 +1,105 @@ +// +// AccountTableView.swift +// elpha-ios +// +// Created by Dwayne Harris on 10/9/18. +// Copyright © 2018 Elpha. All rights reserved. +// + +import AlamofireImage +import MastodonKit +import UIKit + +class AccountTableViewController: UITableViewController { + @IBOutlet var headerImageView: UIImageView! + @IBOutlet var avatarImageView: UIImageView! + @IBOutlet var displayNameLabel: UILabel! + @IBOutlet var usernameLabel: UILabel! + @IBOutlet var contentLabel: UILabel! + @IBOutlet var statusesLabel: UILabel! + @IBOutlet var followingLabel: UILabel! + @IBOutlet var followersLabel: UILabel! + + public var account: AccountMO? = nil + + private func setAccount(_ account: AccountMO) { + let avatarFilter = AspectScaledToFillSizeWithRoundedCornersFilter( + size: CGSize(width: 70.0, height: 70.0), + radius: 20.0, + divideRadiusByImageScale: true + ) + + if let headerURL = account.headerURL { + headerImageView.af_setImage(withURL: headerURL) + } + + if let avatarURL = account.avatarURL { + avatarImageView.af_setImage(withURL: avatarURL, filter: avatarFilter) + } + + displayNameLabel.text = account.displayName + usernameLabel.text = account.acct + + if let note = account.note { + do { + let styledContent = " \(note)" + let attributedText = try NSAttributedString( + data: styledContent.data(using: String.Encoding.unicode, allowLossyConversion: true)!, + options: [.documentType: NSAttributedString.DocumentType.html], + documentAttributes: nil + ) + + contentLabel.attributedText = attributedText + } catch { + print("\(error)") + } + } + + statusesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: account.statusesCount), number: .decimal) + followingLabel.text = NumberFormatter.localizedString(from: NSNumber(value: account.followingCount), number: .decimal) + followersLabel.text = NumberFormatter.localizedString(from: NSNumber(value: account.followersCount), number: .decimal) + } + + override func viewDidLoad() { + super.viewDidLoad() + + if let navigationController = navigationController { + navigationController.view.backgroundColor = .clear + } + + if self.account == nil { + if let session = AuthenticationManager.shared.selectedSession { + self.account = session.account + } + } + + if let account = account { + setAccount(account) + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if let account = self.account { + if let client = AuthenticationManager.shared.mkClientForSelectedSession() { + let request = Accounts.account(id: account.id!) + + client.run(request) { result in + switch result { + case .success(let remoteAccount, _): + self.account = MastodonDataManager.upsertAccount(remoteAccount) + + if let account = self.account { + DispatchQueue.main.async { + self.setAccount(account) + } + } + case .failure(let error): + print("\(error)") + } + } + } + } + } +} diff --git a/elpha-ios/Assets.xcassets/Account.imageset/Contents.json b/elpha-ios/Assets.xcassets/Account.imageset/Contents.json new file mode 100644 index 0000000..d44748b --- /dev/null +++ b/elpha-ios/Assets.xcassets/Account.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "user-circle.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/elpha-ios/Assets.xcassets/Account.imageset/user-circle.pdf b/elpha-ios/Assets.xcassets/Account.imageset/user-circle.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b40b54c20256981eef173ba08543100fd4c26328 GIT binary patch literal 4185 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 - + @@ -472,42 +472,189 @@ - - + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -522,7 +669,7 @@ - + @@ -530,34 +677,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -594,454 +713,27 @@ - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1087,18 +779,32 @@ + + + + + + + + + + + + + + + + + + + + - - - + - - - - diff --git a/elpha-ios/NewStatusesView.swift b/elpha-ios/NewStatusesView.swift index 5a0a0ab..0391cf7 100644 --- a/elpha-ios/NewStatusesView.swift +++ b/elpha-ios/NewStatusesView.swift @@ -14,15 +14,15 @@ import UIKit override init(frame: CGRect) { super.init(frame: frame) - commonInit() + setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - commonInit() + setup() } - private func commonInit() { + private func setup() { Bundle.main.loadNibNamed("NewStatusesView", owner: self, options: nil) addSubview(contentView) contentView.frame = self.bounds @@ -30,6 +30,11 @@ import UIKit } public func setCount(_ count: Int) { - mainLabel.text = "\(count) New Toots" + switch count { + case 1: + mainLabel.text = "1 New Toot" + default: + mainLabel.text = "\(count) New Toots" + } } } diff --git a/elpha-ios/NewStatusesView.xib b/elpha-ios/NewStatusesView.xib index 56c144b..decd370 100644 --- a/elpha-ios/NewStatusesView.xib +++ b/elpha-ios/NewStatusesView.xib @@ -21,16 +21,25 @@ + + + + + + + - + + + @@ -39,4 +48,7 @@ + + + diff --git a/elpha-ios/StatusView.swift b/elpha-ios/StatusView.swift new file mode 100644 index 0000000..102ca44 --- /dev/null +++ b/elpha-ios/StatusView.swift @@ -0,0 +1,55 @@ +// +// StatusStackView.swift +// elpha-ios +// +// Created by Dwayne Harris on 10/9/18. +// Copyright © 2018 Elpha. All rights reserved. +// + +import UIKit + +class StatusView: UIView { + @IBOutlet var contentView: UIView! + @IBOutlet var boostView: UIView! + @IBOutlet var boostAvatarImageView: UIImageView! + @IBOutlet var boostDisplayNameLabel: UILabel! + @IBOutlet var boostUsernameLabel: UILabel! + @IBOutlet var replyView: UIView! + @IBOutlet var replyAvatarImageView: UIImageView! + @IBOutlet var replyDisplayNameLabel: UILabel! + @IBOutlet var replyUsernameLabel: UILabel! + @IBOutlet var avatarImageView: UIImageView! + @IBOutlet var displayNameLabel: UILabel! + @IBOutlet var usernameLabel: UILabel! + @IBOutlet var contentLabel: UILabel! + @IBOutlet var timestampLabel: UILabel! + @IBOutlet var repliesImageView: UIImageView! + @IBOutlet var repliesLabel: UILabel! + @IBOutlet var boostsImageView: UIImageView! + @IBOutlet var boostsLabel: UILabel! + @IBOutlet var favoritesImageView: UIImageView! + @IBOutlet var favoritesLabel: UILabel! + @IBOutlet var topDividerView: UIView! + @IBOutlet var topLoadMoreView: UIView! + @IBOutlet var bottomDividerView: UIView! + @IBOutlet var bottomLoadMoreView: UIView! + @IBOutlet var attachmentsView: UIView! + @IBOutlet var attachmentsHeightConstraint: NSLayoutConstraint! + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + private func setup() { + Bundle.main.loadNibNamed("StatusView", owner: self, options: nil) + addSubview(contentView) + contentView.frame = self.bounds + contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + } +} diff --git a/elpha-ios/StatusView.xib b/elpha-ios/StatusView.xib new file mode 100644 index 0000000..0fc6875 --- /dev/null +++ b/elpha-ios/StatusView.xib @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/elpha-ios/TimelineTableViewCell.swift b/elpha-ios/TimelineTableViewCell.swift index 95812ce..417e8f4 100644 --- a/elpha-ios/TimelineTableViewCell.swift +++ b/elpha-ios/TimelineTableViewCell.swift @@ -9,29 +9,5 @@ import UIKit class TimelineTableViewCell: UITableViewCell { - @IBOutlet var boostView: UIView! - @IBOutlet var boostAvatarImageView: UIImageView! - @IBOutlet var boostDisplayNameLabel: UILabel! - @IBOutlet var boostUsernameLabel: UILabel! - @IBOutlet var replyView: UIView! - @IBOutlet var replyAvatarImageView: UIImageView! - @IBOutlet var replyDisplayNameLabel: UILabel! - @IBOutlet var replyUsernameLabel: UILabel! - @IBOutlet var avatarImageView: UIImageView! - @IBOutlet var displayNameLabel: UILabel! - @IBOutlet var usernameLabel: UILabel! - @IBOutlet var contentLabel: UILabel! - @IBOutlet var timestampLabel: UILabel! - @IBOutlet var repliesImageView: UIImageView! - @IBOutlet var repliesLabel: UILabel! - @IBOutlet var boostsImageView: UIImageView! - @IBOutlet var boostsLabel: UILabel! - @IBOutlet var favoritesImageView: UIImageView! - @IBOutlet var favoritesLabel: UILabel! - @IBOutlet var topDividerView: UIView! - @IBOutlet var topLoadMoreView: UIView! - @IBOutlet var bottomDividerView: UIView! - @IBOutlet var bottomLoadMoreView: UIView! - @IBOutlet var attachmentsView: UIView! - @IBOutlet var attachmentsHeightConstraint: NSLayoutConstraint! + @IBOutlet var statusView: StatusView! } diff --git a/elpha-ios/TimelineTableViewController.swift b/elpha-ios/TimelineTableViewController.swift index ca119e0..d24f1c5 100644 --- a/elpha-ios/TimelineTableViewController.swift +++ b/elpha-ios/TimelineTableViewController.swift @@ -197,11 +197,19 @@ class TimelineTableViewController: UITableViewController { } let newStatuses = statuses.filter { $0.new } - DispatchQueue.main.async { - if let navigationController = self.navigationController as? TimelinesNavigationController, - let newStatusesView = navigationController.newStatusesView { - newStatusesView.isHidden = false - newStatusesView.setCount(newStatuses.count) + if newStatuses.count > -1 { + DispatchQueue.main.async { + if let navigationController = self.navigationController as? TimelinesNavigationController, + let newStatusesView = navigationController.newStatusesView { + newStatusesView.setCount(newStatuses.count) + newStatusesView.isHidden = false + self.view.layoutIfNeeded() + + UIView.animate(withDuration: 2.0, animations: { () -> Void in + navigationController.bottomLayoutConstraint?.constant = -20 + self.view.layoutIfNeeded() + }) + } } } @@ -286,16 +294,16 @@ extension TimelineTableViewController { fatalError("Unable to find reusable cell") } - cell.topDividerView.isHidden = false - cell.topLoadMoreView.isHidden = true - cell.boostView.isHidden = true - cell.replyView.isHidden = true - cell.bottomLoadMoreView.isHidden = true - cell.bottomDividerView.isHidden = false + cell.statusView.topDividerView.isHidden = false + cell.statusView.topLoadMoreView.isHidden = true + cell.statusView.boostView.isHidden = true + cell.statusView.replyView.isHidden = true + cell.statusView.bottomLoadMoreView.isHidden = true + cell.statusView.bottomDividerView.isHidden = false - cell.attachmentsView.backgroundColor = UIColor.white - cell.attachmentsHeightConstraint.constant = cell.frame.width - cell.attachmentsView.isHidden = true + cell.statusView.attachmentsView.backgroundColor = UIColor.white + cell.statusView.attachmentsHeightConstraint.constant = cell.frame.width + cell.statusView.attachmentsView.isHidden = true if let statuses = timelineStatuses() { let status = statuses[indexPath.row] @@ -313,14 +321,14 @@ extension TimelineTableViewController { let previousStatus = statuses[indexPath.row - 1] if let previousBoundary = boundaries.filtered(using: NSPredicate(format: "statusID = %@", previousStatus.id!)).first as? TimelineBoundaryMO { if !previousBoundary.start { - cell.topDividerView.isHidden = true - cell.topLoadMoreView.isHidden = false + cell.statusView.topDividerView.isHidden = true + cell.statusView.topLoadMoreView.isHidden = false } } } } } else { - cell.topDividerView.isHidden = true + cell.statusView.topDividerView.isHidden = true } if indexPath.row < statuses.count - 1 { @@ -329,8 +337,8 @@ extension TimelineTableViewController { let nextStatus = statuses[indexPath.row + 1] if let nextBoundary = boundaries.filtered(using: NSPredicate(format: "statusID = %@", nextStatus.id!)).first as? TimelineBoundaryMO { if nextBoundary.start { - cell.bottomDividerView.isHidden = true - cell.bottomLoadMoreView.isHidden = false + cell.statusView.bottomDividerView.isHidden = true + cell.statusView.bottomLoadMoreView.isHidden = false } } } @@ -339,14 +347,14 @@ extension TimelineTableViewController { func setStatusContent(_ status: StatusMO) { if let account = status.account { - cell.avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) - cell.displayNameLabel.text = account.displayName - cell.usernameLabel.text = account.acct + cell.statusView.avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + cell.statusView.displayNameLabel.text = account.displayName + cell.statusView.usernameLabel.text = account.acct } if let attachments = status.attachments, attachments.count > 0 { - cell.attachmentsView.isHidden = false - AttachmentsManager.setupAttachmentsView(cell.attachmentsView, withAttachments: attachments) + cell.statusView.attachmentsView.isHidden = false + AttachmentsManager.setupAttachmentsView(cell.statusView.attachmentsView, withAttachments: attachments) } if let content = status.content { @@ -358,45 +366,45 @@ extension TimelineTableViewController { documentAttributes: nil ) - cell.contentLabel.attributedText = attributedText + cell.statusView.contentLabel.attributedText = attributedText } catch { print("\(error)") } } - cell.timestampLabel.text = status.createdAt!.timeAgo() - cell.repliesLabel.text = "0" - cell.boostsLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.reblogsCount), number: .decimal) - cell.favoritesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.favouritesCount), number: .decimal) + cell.statusView.timestampLabel.text = status.createdAt!.timeAgo() + cell.statusView.repliesLabel.text = "0" + cell.statusView.boostsLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.reblogsCount), number: .decimal) + cell.statusView.favoritesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.favouritesCount), number: .decimal) if status.reblogged { - cell.boostsImageView.image = UIImage(named: "Boost Bold") + cell.statusView.boostsImageView.image = UIImage(named: "Boost Bold") } else { - cell.boostsImageView.image = UIImage(named: "Boost Regular") + cell.statusView.boostsImageView.image = UIImage(named: "Boost Regular") } if status.favourited { - cell.favoritesImageView.image = UIImage(named: "Star Filled") + cell.statusView.favoritesImageView.image = UIImage(named: "Star Filled") } else { - cell.favoritesImageView.image = UIImage(named: "Star Regular") + cell.statusView.favoritesImageView.image = UIImage(named: "Star Regular") } } if let reblog = status.reblog { - cell.boostView.isHidden = false + cell.statusView.boostView.isHidden = false if let account = status.account { - cell.boostAvatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) - cell.boostDisplayNameLabel.text = account.displayName - cell.boostUsernameLabel.text = account.acct + cell.statusView.boostAvatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + cell.statusView.boostDisplayNameLabel.text = account.displayName + cell.statusView.boostUsernameLabel.text = account.acct } setStatusContent(reblog) } else { if let account = status.account { - cell.avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) - cell.displayNameLabel.text = account.displayName - cell.usernameLabel.text = account.acct + cell.statusView.avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + cell.statusView.displayNameLabel.text = account.displayName + cell.statusView.usernameLabel.text = account.acct } setStatusContent(status) @@ -404,10 +412,10 @@ extension TimelineTableViewController { if let replyAccountID = status.inReplyToAccountID { if let replyAccount = MastodonDataManager.getAccountByID(replyAccountID) { - cell.replyView.isHidden = false - cell.replyAvatarImageView.af_setImage(withURL: replyAccount.avatarURL!, filter: avatarFilter) - cell.replyDisplayNameLabel.text = replyAccount.displayName - cell.replyUsernameLabel.text = replyAccount.acct + cell.statusView.replyView.isHidden = false + cell.statusView.replyAvatarImageView.af_setImage(withURL: replyAccount.avatarURL!, filter: avatarFilter) + cell.statusView.replyDisplayNameLabel.text = replyAccount.displayName + cell.statusView.replyUsernameLabel.text = replyAccount.acct } } diff --git a/elpha-ios/TimelinesNavigationController.swift b/elpha-ios/TimelinesNavigationController.swift index 1e1f2b1..0bffa5c 100644 --- a/elpha-ios/TimelinesNavigationController.swift +++ b/elpha-ios/TimelinesNavigationController.swift @@ -10,6 +10,7 @@ import UIKit class TimelinesNavigationController: UINavigationController { public var newStatusesView: NewStatusesView? = nil + public var bottomLayoutConstraint: NSLayoutConstraint? = nil override func viewDidLoad() { super.viewDidLoad() @@ -32,11 +33,13 @@ class TimelinesNavigationController: UINavigationController { view.addSubview(blurEffectView) + bottomLayoutConstraint = blurEffectView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 50) + NSLayoutConstraint.activate([ blurEffectView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), blurEffectView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - blurEffectView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20), blurEffectView.heightAnchor.constraint(equalToConstant: 50), + bottomLayoutConstraint!, ]) self.newStatusesView = newStatusesView