From 4c6bb677f1924cf007476eb9271167a6eae54e0c Mon Sep 17 00:00:00 2001 From: Dwayne Harris Date: Mon, 12 Nov 2018 23:50:25 -0800 Subject: [PATCH] Add GIF support --- elpha-ios.xcodeproj/project.pbxproj | 8 + .../AbstractStatusTableViewController.swift | 4 + elpha-ios/AccountTableViewController.swift | 13 +- .../Icons/Close White.imageset/Contents.json | 12 + .../Icons/Close White.imageset/x-square.pdf | Bin 0 -> 3927 bytes .../Icons/Close.imageset/x-square.pdf | Bin 3927 -> 3953 bytes .../Icons/Help.imageset/help-circle.pdf | Bin 7064 -> 7075 bytes elpha-ios/AttachmentManager.swift | 42 +-- elpha-ios/AttachmentViewController.swift | 5 +- elpha-ios/Base.lproj/Main.storyboard | 319 +++++++++++++----- elpha-ios/ComposeViewController.swift | 64 ++++ .../FLAnimatedImageView+LoadImageURL.swift | 78 +++++ elpha-ios/MainStatusTableViewCell.swift | 3 +- elpha-ios/SettingsTableViewController.swift | 13 +- elpha-ios/StatusTableViewController.swift | 13 +- elpha-ios/StatusView.swift | 33 +- elpha-ios/StatusView.xib | 15 +- elpha-ios/TimelineTableViewController.swift | 22 +- 18 files changed, 478 insertions(+), 166 deletions(-) create mode 100644 elpha-ios/Assets.xcassets/Icons/Close White.imageset/Contents.json create mode 100644 elpha-ios/Assets.xcassets/Icons/Close White.imageset/x-square.pdf create mode 100644 elpha-ios/ComposeViewController.swift create mode 100644 elpha-ios/FLAnimatedImageView+LoadImageURL.swift diff --git a/elpha-ios.xcodeproj/project.pbxproj b/elpha-ios.xcodeproj/project.pbxproj index fc19a1e..8f0abb7 100644 --- a/elpha-ios.xcodeproj/project.pbxproj +++ b/elpha-ios.xcodeproj/project.pbxproj @@ -24,6 +24,8 @@ 152FBCEE219799FC0079B3E8 /* FLAnimatedImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 152FBCEC219799E50079B3E8 /* FLAnimatedImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 152FBCF2219818AD0079B3E8 /* FieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152FBCF1219818AD0079B3E8 /* FieldTableViewCell.swift */; }; 1539509121894A38009BA6E7 /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1539509021894A38009BA6E7 /* AlertManager.swift */; }; + 156902A0219A7D75002BF61F /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1569029F219A7D75002BF61F /* ComposeViewController.swift */; }; + 156902B3219A8A1C002BF61F /* FLAnimatedImageView+LoadImageURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156902B2219A8A1C002BF61F /* FLAnimatedImageView+LoadImageURL.swift */; }; 156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF014217289380074D9CA /* AccountTableViewCell.swift */; }; 156FF0312174797E0074D9CA /* StatusTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF0302174797E0074D9CA /* StatusTableViewController.swift */; }; 156FF04F2175CDBC0074D9CA /* MainStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156FF04E2175CDBC0074D9CA /* MainStatusTableViewCell.swift */; }; @@ -256,6 +258,8 @@ 152FBCE7219799E50079B3E8 /* FLAnimatedImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = FLAnimatedImage.xcodeproj; path = Frameworks/FLAnimatedImage/FLAnimatedImage.xcodeproj; sourceTree = ""; }; 152FBCF1219818AD0079B3E8 /* FieldTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldTableViewCell.swift; sourceTree = ""; }; 1539509021894A38009BA6E7 /* AlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertManager.swift; sourceTree = ""; }; + 1569029F219A7D75002BF61F /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = ""; }; + 156902B2219A8A1C002BF61F /* FLAnimatedImageView+LoadImageURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FLAnimatedImageView+LoadImageURL.swift"; sourceTree = ""; }; 156FF014217289380074D9CA /* AccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTableViewCell.swift; sourceTree = ""; }; 156FF0302174797E0074D9CA /* StatusTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewController.swift; sourceTree = ""; }; 156FF04E2175CDBC0074D9CA /* MainStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainStatusTableViewCell.swift; sourceTree = ""; }; @@ -378,6 +382,7 @@ isa = PBXGroup; children = ( 159026CF2163069600D362DD /* Date+TimeAgo.swift */, + 156902B2219A8A1C002BF61F /* FLAnimatedImageView+LoadImageURL.swift */, 15B127912192467F00F4EF1D /* String+HtmlAttributed.swift */, 15B127A22192486200F4EF1D /* UIColor+HexString.swift */, ); @@ -500,6 +505,7 @@ 152FB0F7218ADC1A001D6574 /* AttachmentPageViewController.swift */, 152FB0F9218ADDD0001D6574 /* AttachmentViewController.swift */, 15960E7D21329FED00C38CE9 /* AuthenticateViewController.swift */, + 1569029F219A7D75002BF61F /* ComposeViewController.swift */, 1506C5922199768A00EFB483 /* InstancesNavigationController.swift */, 15960E83213774FC00C38CE9 /* InstancesTableViewController.swift */, 157405A72150588A00EEAAEB /* InstanceViewController.swift */, @@ -751,6 +757,7 @@ 156FF0312174797E0074D9CA /* StatusTableViewController.swift in Sources */, 152FB0F8218ADC1A001D6574 /* AttachmentPageViewController.swift in Sources */, 15131EF4216DB8B90092B252 /* AccountTableViewController.swift in Sources */, + 156902A0219A7D75002BF61F /* ComposeViewController.swift in Sources */, 15F998352162C0E8009E58DA /* MastodonDataManager.swift in Sources */, 15960E7A2132387A00C38CE9 /* MainTabBarController.swift in Sources */, 15960E7C213272CD00C38CE9 /* AuthenticationManager.swift in Sources */, @@ -773,6 +780,7 @@ 159026D02163069600D362DD /* Date+TimeAgo.swift in Sources */, 152FBCD2219682E80079B3E8 /* AbstractStatusTableViewController.swift in Sources */, 15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */, + 156902B3219A8A1C002BF61F /* FLAnimatedImageView+LoadImageURL.swift in Sources */, 15BB72AB2171A8D4002F1FA4 /* TimelinesTableViewCell.swift in Sources */, 1574148D2169AD0100C841BD /* AttachmentManager.swift in Sources */, 156FF015217289380074D9CA /* AccountTableViewCell.swift in Sources */, diff --git a/elpha-ios/AbstractStatusTableViewController.swift b/elpha-ios/AbstractStatusTableViewController.swift index e5bda41..8ea8ef3 100644 --- a/elpha-ios/AbstractStatusTableViewController.swift +++ b/elpha-ios/AbstractStatusTableViewController.swift @@ -48,6 +48,10 @@ class AbstractStatusTableViewController: UITableViewController, StatusViewDelega } + func replyTapped(status: StatusMO) { + performSegue(withIdentifier: "ComposeSegue", sender: self) + } + func attachmentTapped(status: StatusMO, index: Int) { let storyboard = UIStoryboard(name: "Main", bundle: nil) diff --git a/elpha-ios/AccountTableViewController.swift b/elpha-ios/AccountTableViewController.swift index 9e88303..486a02f 100644 --- a/elpha-ios/AccountTableViewController.swift +++ b/elpha-ios/AccountTableViewController.swift @@ -8,6 +8,7 @@ import AlamofireImage import CoreData +import FLAnimatedImage import UIKit import SafariServices @@ -65,7 +66,7 @@ class FieldTableViewController: NSObject, UITableViewDelegate, UITableViewDataSo class AccountTableViewController: AbstractStatusTableViewController { @IBOutlet var headerView: UIView! @IBOutlet var headerImageView: UIImageView! - @IBOutlet var avatarImageView: UIImageView! + @IBOutlet var avatarImageView: FLAnimatedImageView! @IBOutlet var displayNameLabel: UILabel! @IBOutlet var usernameLabel: UILabel! @IBOutlet var statusesLabel: UILabel! @@ -101,18 +102,12 @@ class AccountTableViewController: AbstractStatusTableViewController { private func updateHeader(withAccount account: AccountMO) { navigationItem.title = account.displayName - 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) + avatarImageView.loadImageURL(avatarURL) } displayNameLabel.text = account.displayName @@ -148,6 +143,8 @@ class AccountTableViewController: AbstractStatusTableViewController { avatarImageView.layer.shadowOpacity = 0.8 avatarImageView.layer.shadowOffset = CGSize.zero avatarImageView.layer.shadowRadius = 10 + avatarImageView.layer.cornerRadius = 10 + avatarImageView.layer.masksToBounds = true if self.account == nil { if let session = AuthenticationManager.session { diff --git a/elpha-ios/Assets.xcassets/Icons/Close White.imageset/Contents.json b/elpha-ios/Assets.xcassets/Icons/Close White.imageset/Contents.json new file mode 100644 index 0000000..58a1f2d --- /dev/null +++ b/elpha-ios/Assets.xcassets/Icons/Close White.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "x-square.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/elpha-ios/Assets.xcassets/Icons/Close White.imageset/x-square.pdf b/elpha-ios/Assets.xcassets/Icons/Close White.imageset/x-square.pdf new file mode 100644 index 0000000000000000000000000000000000000000..35aead3400b571854e59283884cabb2c75ac7992 GIT binary patch literal 3927 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 dtAYQwT@VBc4g*6Vx`uk-{{s)Uqd5Qo literal 0 HcmV?d00001 diff --git a/elpha-ios/Assets.xcassets/Icons/Close.imageset/x-square.pdf b/elpha-ios/Assets.xcassets/Icons/Close.imageset/x-square.pdf index 35aead3400b571854e59283884cabb2c75ac7992..92f44274a29019eff88ebc5cffe6bce60e3f2f54 100644 GIT binary patch delta 504 zcmcaE_fc*_Kz(SxEnl+%PwV$Nk75_Bl>OwKwk@widBYY_o)ymP@25Lz1x)#2`R~n> zT#1c}54evu|K|NDseh-vKWWB{r7NO}7IoFW2wLGLlO=UyjljCuK^di=Ph~cV&XN?% z_^4$ls&;Gh*7cfYlXN&|=nAMDyKzG8PTUjA$*B?R{?54(rD3dTrs)2n<*$56n6Qz* z&ljD2R~Bf#&nwcnD0A)cyH~3ntS?Nz88dP2-|J~})|el$k-jnEBYR4L>%EDurI{>@ zH*+w0^Kcj%8<-iGni@`y=55q6GgL4D0fjsTE-=Huz{t`9UCh|X&}1?jpIW`SCAyS> zu{ox4LoDh{Ow7>r8XKBom}hKcX^NrF*aRZRkK|5c6GO|%yZG$l4bxH+jnhob%`GgG zk}Q+WO$<#_EsaggOp?Sbb9@p=49>q5#ZTG!&?&ghEGK$;_(pE_9u)8m~RCa=B?d{5K zf6R4mTzJfTwD&#dOD4G;%cd)(mgy8JEfF}jv@~tXDNV;#wo_cab5FfkEd1h#>g6}b z9ruXZc5yl;UD2=fx~0CKEAmv;8S80xcJv$YE@_cj$ZVbdc3qRTQ_<&d*49q!$2XsK zbxm0FU!XW`8qb}HPnrL=S+#Mc=A{&u6s0ESf>`-USzM+H1_~hB(9|3zWHh;-M|86T zqb?7Jfw_UHp@p%@8$!hRk=$u)Y-v3C3ZGqkl7WSBvW0n4ibz80#~bl3_AMt zhw;pvkD9c_4qghdZu$7NN4=)$V{?=H{`>`ZK6JHzoxL%y&#kvu-~0Bf8rCQGgBBzl z{@3V~(DdI_yZC#NNZ!K!H=A`L&vacYG0R+c{@q2cZ_)y*?Mf%iuh(7PJ^gZ@cuwNi zDPb0u8LCwb=PJcsl1~WtirnRuo4hN1<3%a2ch1?4_Emn>i<$Gz_?%Dpuz!P2OAd33&g=BP)|}&C zKV-DnUf+0ed&j)5HAdVL+-XO??{kgFc=6N3>(U;LPbQr!-t*2^(Ybw4C1!f)Wv`oN zp*#6F%idJ;a$71(J>SYwYjB}n;kC^&<>%`f+GeQ5IGmT9!Ot--z{X{|na*ux!~Cy~ ztKTuPvfuqQqvAT(iI0n8GVXTneKF;gi?Y>PSGk{l`U#g_?h1p#U#*>d5R9zR_pP#=eV%?4wwYimT+Y2XbS1{|DprCp5<7?*}u|mBCXPI-P>yB`7 z{{EWNqkb^!x@_Y1l)zo=ksB@=_s9B(9o@Hf(}Ydx|5nXEyYaIbXYjer8D0_JF6`gC zp6B>F>v_jtr&@fipV{~R{qC>fx|-jPnf%JlsIT8pU&Bz|6S-o=Kki{ z_EXyYq)HZC-E7asU%&F6-LLljKCRRLnaEYXeQ)>RY3&!Y>dN@N6XWlv%YW4W!+JH! zZ!#oVOipJPXEfVf&;DCLK+jMiM#HHzGbcsC(89^wbaJPJ9;cz9v4N?9p@I420}_o) zX2z49B~_UW4JKzv`iq$ZQxga%U%WrkGi#85^40aoG@5 gq7bWKXUA1sl2}wyQIwj-WoBY*!KJF|>hHz{06XaF;Q#;t delta 1174 zcmZ2%KEr%N22*{&?mQMno;TmMpRrH-!P-`}yJWfUCq|7RA%Zy`4rcz3zI8a0xz-Wp1foEx=1Z^OaGgRvtIEhWN&l3s#v$oDR1AN zl0Av@7tgyEA!O$xwu6= zK5J*Rgjsz3vFN5w@14#G!J&!y3n%qTKRu~aWph)#FZtKR4?&_&>#saFm@fTBE<9v% z9J36QvH9j2=AVr9*^?I;2ux9!!7z*Kys(JiqqzxAK8v=$oA&>IdF+R+)5=q0>lKgs zR9!N*U3~HXp-l`Mco{aV+5bM`Kv_(O4Zq{{jR(Dt3A8fuJyz*-mN_t;hr1`yVN+75 zx$j;rBcTHyg>wJlT!65b`lw?yXvjf=M|?jB)fF+ zhC81*P$P0*gr)bOYg?-GocyZV3q|#fA?$bai+I+HHVCJfUavY|UZekXp7Flxv#v)z z;9+@YrD?s=_4jA-;N$mqx=gq04&v?F@tV^!gsTf0JG@{d}Y!{BW&(ulv2< z)gBeQ<(tpmdv`tI$@kxuDSx=@8TRt}@^Yo-rA*Femt?fq+{yl1fL|d-!>KegCq==~ z!qM2$aPkxhJx&7yGb3XIBO{Z^rzIMhOpPY{Nvbj#SWYgL^cOR=P%r=ig**i=FvGym z5UA~zq*|aEhLnMY1%{ZRrI9(h5ynOqM(AQ@2Bwn(rG#w_EYW2QEe$YCFfuU5P-kpp zHhCe?1VaoNGXrB2bW_a?&5bd{jEpCLloDn#G?>gLZ5MB7X=$8jnQW3|keFg - + @@ -807,7 +807,7 @@ - + @@ -1059,99 +1059,251 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + @@ -1199,6 +1351,7 @@ + @@ -1224,7 +1377,7 @@ - + @@ -1543,7 +1696,7 @@ - + diff --git a/elpha-ios/ComposeViewController.swift b/elpha-ios/ComposeViewController.swift new file mode 100644 index 0000000..fc651ea --- /dev/null +++ b/elpha-ios/ComposeViewController.swift @@ -0,0 +1,64 @@ +// +// ComposeViewController.swift +// elpha-ios +// +// Created by Dwayne Harris on 11/12/18. +// Copyright © 2018 Elpha. All rights reserved. +// + +import FLAnimatedImage +import UIKit + +class ComposeViewController: UIViewController { + @IBOutlet var replyToView: UIView! + @IBOutlet var replyToAvatarImageView: FLAnimatedImageView! + @IBOutlet var replyToDisplayNameLabel: UILabel! + @IBOutlet var replyToUsernameLabel: UILabel! + @IBOutlet var replyToContentTextView: UITextViewFixed! + @IBOutlet var statusTextField: UITextField! + @IBOutlet var statusCharacterCountLabel: UILabel! + @IBOutlet var contentWarningTextField: UITextField! + @IBOutlet var tootButton: UIButton! + + var replyToStatus: StatusMO? = nil + + override func viewDidLoad() { + super.viewDidLoad() + + if let replyToStatus = replyToStatus { + replyToView.isHidden = false + + if let reblog = replyToStatus.reblog { + self.setupReplyTo(status: reblog) + } else { + self.setupReplyTo(status: replyToStatus) + } + } else { + replyToView.isHidden = true + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + statusTextField.becomeFirstResponder() + } + + func setupReplyTo(status: StatusMO) { + if let account = status.account { + replyToAvatarImageView.loadImageURL(account.avatarURL!) + replyToDisplayNameLabel.text = account.displayName + replyToUsernameLabel.text = "@\(account.acct!)" + } + + replyToContentTextView.attributedText = status.content?.htmlAttributed(size: 15.0) + } + + @IBAction func statusTextFieldEdited(_ sender: Any) { + let characters = statusTextField.text!.count + statusCharacterCountLabel.text = String(500 - characters) + } + + @IBAction func dismissTapped(_ sender: Any) { + dismiss(animated: true) + } +} diff --git a/elpha-ios/FLAnimatedImageView+LoadImageURL.swift b/elpha-ios/FLAnimatedImageView+LoadImageURL.swift new file mode 100644 index 0000000..93371e3 --- /dev/null +++ b/elpha-ios/FLAnimatedImageView+LoadImageURL.swift @@ -0,0 +1,78 @@ +// +// FLAnimatedImage+LoadImageURL.swift +// elpha-ios +// +// Created by Dwayne Harris on 11/12/18. +// Copyright © 2018 Elpha. All rights reserved. +// + +import Alamofire +import AlamofireImage +import FLAnimatedImage +import Foundation + +class ImageCache { + static var cache: NSCache = NSCache() + + static func set(string: String, data: Data) { + ImageCache.cache.setObject(data as AnyObject, forKey: string as AnyObject) + } + + static func set(url: URL, data: Data) { + set(string: url.absoluteString, data: data) + } + + static func set(request: URLRequest, data: Data) { + set(url: request.url!, data: data) + } + + static func get(string: String) -> Data? { + if let data = ImageCache.cache.object(forKey: string as AnyObject) as? Data { + return data + } else { + return nil + } + } + + static func get(url: URL) -> Data? { + return get(string: url.absoluteString) + } + + static func get(request: URLRequest) -> Data? { + return get(url: request.url!) + } +} + +extension FLAnimatedImageView { + func setPlaceholder() { + self.contentMode = .center + self.image = UIImage(named: "Help") + } + + func loadImageURL(_ url: URL) { + if let data = ImageCache.get(url: url) { + if url.absoluteString.hasSuffix(".gif") { + self.animatedImage = FLAnimatedImage(animatedGIFData: data) + } else { + self.image = UIImage(data: data) + } + } else { + setPlaceholder() + + Alamofire.request(url).responseImage { response in + if let data = response.data { + DispatchQueue.main.async { + ImageCache.set(url: url, data: data) + self.contentMode = .scaleAspectFit + + if url.absoluteString.hasSuffix(".gif") { + self.animatedImage = FLAnimatedImage(animatedGIFData: data) + } else { + self.image = UIImage(data: data) + } + } + } + } + } + } +} diff --git a/elpha-ios/MainStatusTableViewCell.swift b/elpha-ios/MainStatusTableViewCell.swift index edd05e5..c5a27c2 100644 --- a/elpha-ios/MainStatusTableViewCell.swift +++ b/elpha-ios/MainStatusTableViewCell.swift @@ -6,10 +6,11 @@ // Copyright © 2018 Elpha. All rights reserved. // +import FLAnimatedImage import UIKit class MainStatusTableViewCell: UITableViewCell { - @IBOutlet var avatarImageView: UIImageView! + @IBOutlet var avatarImageView: FLAnimatedImageView! @IBOutlet var displayNameLabel: UILabel! @IBOutlet var usernameLabel: UILabel! @IBOutlet var repliesImageView: UIImageView! diff --git a/elpha-ios/SettingsTableViewController.swift b/elpha-ios/SettingsTableViewController.swift index ac72db6..e5a130f 100644 --- a/elpha-ios/SettingsTableViewController.swift +++ b/elpha-ios/SettingsTableViewController.swift @@ -7,11 +7,12 @@ // import AlamofireImage +import FLAnimatedImage import UIKit class SettingsTableViewController: UITableViewController { @IBOutlet var headerImageView: UIImageView! - @IBOutlet var avatarImageView: UIImageView! + @IBOutlet var avatarImageView: FLAnimatedImageView! @IBOutlet var displayNameLabel: UILabel! @IBOutlet var usernameLabel: UILabel! @@ -20,20 +21,16 @@ class SettingsTableViewController: UITableViewController { navigationItem.title = "Settings" - let filter = AspectScaledToFillSizeWithRoundedCornersFilter( - size: CGSize(width: 70.0, height: 70.0), - radius: 20.0, - divideRadiusByImageScale: true - ) - avatarImageView.layer.shadowColor = UIColor.black.cgColor avatarImageView.layer.shadowOpacity = 0.8 avatarImageView.layer.shadowOffset = CGSize.zero avatarImageView.layer.shadowRadius = 10 + avatarImageView.layer.cornerRadius = 10 + avatarImageView.layer.masksToBounds = true if let account = AuthenticationManager.session?.account { headerImageView.af_setImage(withURL: account.headerURL!) - avatarImageView.af_setImage(withURL: account.avatarURL!, filter: filter) + avatarImageView.loadImageURL(account.avatarURL!) displayNameLabel.text = account.displayName usernameLabel.text = "@\(account.acct!)" } diff --git a/elpha-ios/StatusTableViewController.swift b/elpha-ios/StatusTableViewController.swift index a692666..eb791aa 100644 --- a/elpha-ios/StatusTableViewController.swift +++ b/elpha-ios/StatusTableViewController.swift @@ -262,15 +262,16 @@ extension StatusTableViewController { fatalError("Unable to find reusable cell") } - let avatarFilter = AspectScaledToFillSizeWithRoundedCornersFilter( - size: CGSize(width: 40.0, height: 40.0), - radius: 30.0, - divideRadiusByImageScale: true - ) + cell.avatarImageView.layer.shadowColor = UIColor.black.cgColor + cell.avatarImageView.layer.shadowOpacity = 0.8 + cell.avatarImageView.layer.shadowOffset = CGSize.zero + cell.avatarImageView.layer.shadowRadius = 10 + cell.avatarImageView.layer.cornerRadius = 10 + cell.avatarImageView.layer.masksToBounds = true func updateAccountView(status: StatusMO) { if let account = status.account { - cell.avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + cell.avatarImageView.loadImageURL(account.avatarURL!) cell.displayNameLabel.text = account.displayName cell.usernameLabel.text = "@\(account.acct!)" } diff --git a/elpha-ios/StatusView.swift b/elpha-ios/StatusView.swift index f94ce60..6c7d3e9 100644 --- a/elpha-ios/StatusView.swift +++ b/elpha-ios/StatusView.swift @@ -7,6 +7,7 @@ // import AlamofireImage +import FLAnimatedImage import UIKit protocol StatusViewDelegate { @@ -17,6 +18,7 @@ protocol StatusViewDelegate { func urlTapped(url: URL) func boostTapped() func favoriteTapped() + func replyTapped(status: StatusMO) func revealTapped() func hideTapped() } @@ -25,6 +27,7 @@ extension StatusViewDelegate { func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {} func boostTapped() {} func favoriteTapped() {} + func replyTapped(status: StatusMO) {} func revealTapped() {} func hideTapped() {} } @@ -32,14 +35,14 @@ extension StatusViewDelegate { class StatusView: UIView { @IBOutlet var contentView: UIView! @IBOutlet var boostView: UIView! - @IBOutlet var boostAvatarImageView: UIImageView! + @IBOutlet var boostAvatarImageView: FLAnimatedImageView! @IBOutlet var boostDisplayNameLabel: UILabel! @IBOutlet var boostUsernameLabel: UILabel! @IBOutlet var replyView: UIView! - @IBOutlet var replyAvatarImageView: UIImageView! + @IBOutlet var replyAvatarImageView: FLAnimatedImageView! @IBOutlet var replyDisplayNameLabel: UILabel! @IBOutlet var replyUsernameLabel: UILabel! - @IBOutlet var avatarImageView: UIImageView! + @IBOutlet var avatarImageView: FLAnimatedImageView! @IBOutlet var displayNameLabel: UILabel! @IBOutlet var usernameLabel: UILabel! @IBOutlet var timestampLabel: UILabel! @@ -198,6 +201,9 @@ class StatusView: UIView { } } + @IBAction func replyTapped(_ sender: Any) { + delegate?.replyTapped(status: status!) + } @objc func reveal(sender: UITapGestureRecognizer) { if let status = status { @@ -224,6 +230,13 @@ class StatusView: UIView { attachmentManager.delegate = self contentTextView.delegate = self feedbackGenerator = UINotificationFeedbackGenerator() + + avatarImageView.layer.cornerRadius = 10 + avatarImageView.layer.masksToBounds = true + boostAvatarImageView.layer.cornerRadius = 10 + boostAvatarImageView.layer.masksToBounds = true + replyAvatarImageView.layer.cornerRadius = 10 + replyAvatarImageView.layer.masksToBounds = true } public func update(withStatus status: StatusMO) { @@ -235,15 +248,9 @@ class StatusView: UIView { attachmentsView.isHidden = true spoilerImageView.isHidden = true - let avatarFilter = AspectScaledToFillSizeWithRoundedCornersFilter( - size: CGSize(width: 40.0, height: 40.0), - radius: 20.0, - divideRadiusByImageScale: true - ) - func updateStatusContent(_ status: StatusMO) { if let account = status.account { - avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + avatarImageView.loadImageURL(account.avatarURL!) displayNameLabel.text = account.displayName usernameLabel.text = "@\(account.acct!)" } @@ -326,7 +333,7 @@ class StatusView: UIView { boostView.isHidden = false if let account = status.account { - boostAvatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + boostAvatarImageView.loadImageURL(account.avatarURL!) boostDisplayNameLabel.text = account.displayName boostUsernameLabel.text = "@\(account.acct!)" } @@ -334,7 +341,7 @@ class StatusView: UIView { updateStatusContent(reblog) } else { if let account = status.account { - avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter) + avatarImageView.loadImageURL(account.avatarURL!) displayNameLabel.text = account.displayName usernameLabel.text = "@\(account.acct!)" } @@ -345,7 +352,7 @@ class StatusView: UIView { if let replyAccountID = status.inReplyToAccountID { if let replyAccount = MastodonDataManager.account(id: replyAccountID) { replyView.isHidden = false - replyAvatarImageView.af_setImage(withURL: replyAccount.avatarURL!, filter: avatarFilter) + replyAvatarImageView.loadImageURL(replyAccount.avatarURL!) replyDisplayNameLabel.text = replyAccount.displayName replyUsernameLabel.text = "@\(replyAccount.acct!)" } diff --git a/elpha-ios/StatusView.xib b/elpha-ios/StatusView.xib index ea369d5..87a936c 100644 --- a/elpha-ios/StatusView.xib +++ b/elpha-ios/StatusView.xib @@ -91,7 +91,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -430,6 +430,7 @@ + @@ -438,6 +439,9 @@ + + + @@ -556,6 +560,11 @@ + + + + + diff --git a/elpha-ios/TimelineTableViewController.swift b/elpha-ios/TimelineTableViewController.swift index 5635df2..339cf04 100644 --- a/elpha-ios/TimelineTableViewController.swift +++ b/elpha-ios/TimelineTableViewController.swift @@ -16,6 +16,8 @@ class TimelineTableViewController: AbstractStatusTableViewController { var feedbackGenerator: UINotificationFeedbackGenerator? = nil var fetchedResultsController: NSFetchedResultsController? = nil + var replyToStatus: StatusMO? = nil + override var currentPaginationContext: String { get { guard let timeline = AuthenticationManager.session?.timeline, let categoryString = timeline.category else { @@ -99,6 +101,11 @@ class TimelineTableViewController: AbstractStatusTableViewController { } } + override func replyTapped(status: StatusMO) { + replyToStatus = status + performSegue(withIdentifier: "ComposeSegue", sender: self) + } + @objc func openSettings() { let storyboard = UIStoryboard(name: "Main", bundle: nil) @@ -111,16 +118,23 @@ class TimelineTableViewController: AbstractStatusTableViewController { performSegue(withIdentifier: "TimelinesSegue", sender: self) } + @objc func compose() { + replyToStatus = nil + performSegue(withIdentifier: "ComposeSegue", sender: self) + } + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "TimelinesSegue" { if let destination = segue.destination as? TimelinesViewController { destination.delegate = self } } - } - - @objc func compose() { - AlertManager.shared.show(message: "We'll get the compose screen working one day.") + + if segue.identifier == "ComposeSegue" { + if let destination = segue.destination as? ComposeViewController { + destination.replyToStatus = replyToStatus + } + } } func createDefaultTimelines(account: AccountMO) {