Browse Source

Development

master
Dwayne Harris 6 years ago
parent
commit
7d5a87e7e4
  1. 4
      elpha-ios.xcodeproj/project.pbxproj
  2. 12
      elpha-ios/Assets.xcassets/Help.imageset/Contents.json
  3. BIN
      elpha-ios/Assets.xcassets/Help.imageset/help-circle.pdf
  4. 346
      elpha-ios/AttachmentsView.swift
  5. 110
      elpha-ios/Base.lproj/Main.storyboard
  6. 2
      elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents
  7. 2
      elpha-ios/MastodonDataManager.swift
  8. 3
      elpha-ios/TimelineTableViewCell.swift
  9. 39
      elpha-ios/TimelineTableViewController.swift

4
elpha-ios.xcodeproj/project.pbxproj

@ -19,6 +19,7 @@
157405B12151A5DA00EEAAEB /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 157405AF2151A5DA00EEAAEB /* README.md */; };
157405B42151A93E00EEAAEB /* InstancesDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157405B32151A93E00EEAAEB /* InstancesDataManager.swift */; };
157405D1215890D700EEAAEB /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 157405C3215890BC00EEAAEB /* Alamofire.framework */; };
1574147321696DB400C841BD /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1574147221696DB400C841BD /* AttachmentsView.swift */; };
159026AE2162CF5600D362DD /* TimelineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159026AD2162CF5600D362DD /* TimelineTableViewCell.swift */; };
159026D02163069600D362DD /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159026CF2163069600D362DD /* Date+TimeAgo.swift */; };
159048AF214F5015004F4014 /* InstancesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159048AE214F5015004F4014 /* InstancesTableViewCell.swift */; };
@ -280,6 +281,7 @@
157405AF2151A5DA00EEAAEB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
157405B32151A93E00EEAAEB /* InstancesDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesDataManager.swift; sourceTree = "<group>"; };
157405B7215890BC00EEAAEB /* Alamofire.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Alamofire.xcodeproj; path = Frameworks/Alamofire/Alamofire.xcodeproj; sourceTree = "<group>"; };
1574147221696DB400C841BD /* AttachmentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentsView.swift; sourceTree = "<group>"; };
159026AD2162CF5600D362DD /* TimelineTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewCell.swift; sourceTree = "<group>"; };
159026CF2163069600D362DD /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
159048AE214F5015004F4014 /* InstancesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesTableViewCell.swift; sourceTree = "<group>"; };
@ -370,6 +372,7 @@
151AD4AE2166DD3500F07403 /* Views */ = {
isa = PBXGroup;
children = (
1574147221696DB400C841BD /* AttachmentsView.swift */,
159048AE214F5015004F4014 /* InstancesTableViewCell.swift */,
159026AD2162CF5600D362DD /* TimelineTableViewCell.swift */,
);
@ -794,6 +797,7 @@
15A79B43215EB959007A326E /* CoreDataManager.swift in Sources */,
15960E822136668500C38CE9 /* TimelinesNavigationController.swift in Sources */,
159026AE2162CF5600D362DD /* TimelineTableViewCell.swift in Sources */,
1574147321696DB400C841BD /* AttachmentsView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

12
elpha-ios/Assets.xcassets/Help.imageset/Contents.json

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "help-circle.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

BIN
elpha-ios/Assets.xcassets/Help.imageset/help-circle.pdf

346
elpha-ios/AttachmentsView.swift

@ -0,0 +1,346 @@
//
// AttachmentsView.swift
// elpha-ios
//
// Created by Dwayne Harris on 10/6/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import AlamofireImage
import UIKit
func getTopConstraint(from: UIView, to: UIView) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: from,
attribute: NSLayoutConstraint.Attribute.top,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: to,
attribute: NSLayoutConstraint.Attribute.top,
multiplier: 1,
constant: 0
)
}
func getBottomConstraint(from: UIView, to: UIView) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: from,
attribute: NSLayoutConstraint.Attribute.bottom,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: to,
attribute: NSLayoutConstraint.Attribute.bottom,
multiplier: 1,
constant: 0
)
}
func getLeadingConstraint(from: UIView, to: UIView) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: from,
attribute: NSLayoutConstraint.Attribute.leading,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: to,
attribute: NSLayoutConstraint.Attribute.leading,
multiplier: 1,
constant: 0
)
}
func getTrailingConstraint(from: UIView, to: UIView) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: from,
attribute: NSLayoutConstraint.Attribute.trailing,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: to,
attribute: NSLayoutConstraint.Attribute.trailing,
multiplier: 1,
constant: 0
)
}
func getWidthConstraint(view: UIView, width: CGFloat) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: view,
attribute: NSLayoutConstraint.Attribute.width,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: nil,
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
multiplier: 1,
constant: width
)
}
func getHeightConstraint(view: UIView, height: CGFloat) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: view,
attribute: NSLayoutConstraint.Attribute.height,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: nil,
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
multiplier: 1,
constant: height
)
}
class AttachmentsView: UIView {
public var attachments: NSOrderedSet? = nil {
didSet {
if let attachments = attachments {
let placeholderImage = UIImage(named: "Help")
print("attachments: \(attachments.count)")
switch attachments.count {
case 0:
self.isHidden = true
case 1:
let filter = AspectScaledToFillSizeFilter(size: CGSize(width: self.frame.width, height: self.frame.width))
let attachment = attachments.firstObject as! AttachmentMO
let imageView = UIImageView()
imageView.af_setImage(
withURL: attachment.url!,
placeholderImage: placeholderImage,
filter: filter
)
self.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
self.addConstraint(getLeadingConstraint(from: imageView, to: self))
self.addConstraint(getTrailingConstraint(from: imageView, to: self))
self.addConstraint(getTopConstraint(from: imageView, to: self))
self.addConstraint(getBottomConstraint(from: imageView, to: self))
self.addConstraint(getWidthConstraint(view: imageView, width: self.frame.width))
self.addConstraint(getHeightConstraint(view: imageView, height: self.frame.width))
case 2:
let filter = AspectScaledToFillSizeFilter(size: CGSize(width: (self.frame.width / 2) - 2, height: self.frame.width))
let firstImageView = UIImageView()
let secondImageView = UIImageView()
firstImageView.af_setImage(
withURL: (attachments[0] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: filter
)
secondImageView.af_setImage(
withURL: (attachments[1] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: filter
)
self.addSubview(firstImageView)
self.addSubview(secondImageView)
[firstImageView, secondImageView].forEach { imageView in
self.addConstraint(getLeadingConstraint(from: imageView, to: self))
self.addConstraint(getTrailingConstraint(from: imageView, to: self))
self.addConstraint(getTopConstraint(from: imageView, to: self))
self.addConstraint(getBottomConstraint(from: imageView, to: self))
self.addConstraint(getHeightConstraint(view: imageView, height: self.frame.width))
self.addConstraint(getWidthConstraint(view: imageView, width: (self.frame.width / 2) - 2))
}
let betweenConstraint = NSLayoutConstraint(
item: firstImageView,
attribute: NSLayoutConstraint.Attribute.trailing,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: secondImageView,
attribute: NSLayoutConstraint.Attribute.leading,
multiplier: 1,
constant: 4
)
self.addConstraint(betweenConstraint)
case 3:
let halfWidth = (self.frame.width / 2) - 2
let primaryFilter = AspectScaledToFillSizeFilter(size: CGSize(width: halfWidth, height: self.frame.width))
let secondaryFilter = AspectScaledToFillSizeFilter(size: CGSize(width: halfWidth, height: halfWidth))
let firstImageView = UIImageView()
let secondImageView = UIImageView()
let thirdImageView = UIImageView()
firstImageView.af_setImage(
withURL: (attachments[0] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: primaryFilter
)
secondImageView.af_setImage(
withURL: (attachments[1] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: secondaryFilter
)
thirdImageView.af_setImage(
withURL: (attachments[2] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: secondaryFilter
)
self.addSubview(firstImageView)
self.addSubview(secondImageView)
self.addSubview(thirdImageView)
self.addConstraint(getLeadingConstraint(from: firstImageView, to: self))
self.addConstraint(getTopConstraint(from: firstImageView, to: self))
self.addConstraint(getBottomConstraint(from: firstImageView, to: self))
self.addConstraint(getHeightConstraint(view: firstImageView, height: self.frame.width))
self.addConstraint(getWidthConstraint(view: firstImageView, width: halfWidth))
self.addConstraint(getTopConstraint(from: secondImageView, to: self))
self.addConstraint(getBottomConstraint(from: thirdImageView, to: self))
[secondImageView, thirdImageView].forEach { imageView in
self.addConstraint(getTrailingConstraint(from: imageView, to: self))
self.addConstraint(getHeightConstraint(view: imageView, height: halfWidth))
self.addConstraint(getWidthConstraint(view: imageView, width: halfWidth))
}
let firstSecondConstraint = NSLayoutConstraint(
item: firstImageView,
attribute: NSLayoutConstraint.Attribute.trailing,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: secondImageView,
attribute: NSLayoutConstraint.Attribute.leading,
multiplier: 1,
constant: 4
)
let firstThirdConstraint = NSLayoutConstraint(
item: firstImageView,
attribute: NSLayoutConstraint.Attribute.trailing,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: thirdImageView,
attribute: NSLayoutConstraint.Attribute.leading,
multiplier: 1,
constant: 4
)
let secondThirdConstraint = NSLayoutConstraint(
item: secondImageView,
attribute: NSLayoutConstraint.Attribute.bottom,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: thirdImageView,
attribute: NSLayoutConstraint.Attribute.top,
multiplier: 1,
constant: 4
)
self.addConstraints([firstSecondConstraint, firstThirdConstraint, secondThirdConstraint])
default:
let halfWidth = (self.frame.width / 2) - 2
let filter = AspectScaledToFillSizeFilter(size: CGSize(width: halfWidth, height: halfWidth))
let firstImageView = UIImageView()
let secondImageView = UIImageView()
let thirdImageView = UIImageView()
let fourthImageView = UIImageView()
firstImageView.af_setImage(
withURL: (attachments[0] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: filter
)
secondImageView.af_setImage(
withURL: (attachments[1] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: filter
)
thirdImageView.af_setImage(
withURL: (attachments[2] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: filter
)
fourthImageView.af_setImage(
withURL: (attachments[3] as! AttachmentMO).url!,
placeholderImage: placeholderImage,
filter: filter
)
self.addSubview(firstImageView)
self.addSubview(secondImageView)
self.addSubview(thirdImageView)
self.addSubview(fourthImageView)
[firstImageView, secondImageView, thirdImageView, fourthImageView].forEach { imageView in
self.addConstraint(getHeightConstraint(view: imageView, height: halfWidth))
self.addConstraint(getWidthConstraint(view: imageView, width: halfWidth))
}
[firstImageView, secondImageView].forEach { imageView in
self.addConstraint(getTopConstraint(from: imageView, to: self))
}
[thirdImageView, fourthImageView].forEach { imageView in
self.addConstraint(getBottomConstraint(from: imageView, to: self))
}
[firstImageView, thirdImageView].forEach { imageView in
self.addConstraint(getLeadingConstraint(from: imageView, to: self))
}
[secondImageView, fourthImageView].forEach { imageView in
self.addConstraint(getTrailingConstraint(from: imageView, to: self))
}
let firstBetweenConstraint = NSLayoutConstraint(
item: firstImageView,
attribute: NSLayoutConstraint.Attribute.trailing,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: secondImageView,
attribute: NSLayoutConstraint.Attribute.leading,
multiplier: 1,
constant: 4
)
let secondBetweenConstraint = NSLayoutConstraint(
item: secondImageView,
attribute: NSLayoutConstraint.Attribute.bottom,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: fourthImageView,
attribute: NSLayoutConstraint.Attribute.top,
multiplier: 1,
constant: 4
)
let thirdBetweenConstraint = NSLayoutConstraint(
item: fourthImageView,
attribute: NSLayoutConstraint.Attribute.leading,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: thirdImageView,
attribute: NSLayoutConstraint.Attribute.trailing,
multiplier: 1,
constant: 4
)
let fourthBetweenConstraint = NSLayoutConstraint(
item: thirdImageView,
attribute: NSLayoutConstraint.Attribute.top,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: firstImageView,
attribute: NSLayoutConstraint.Attribute.bottom,
multiplier: 1,
constant: 4
)
self.addConstraints([
firstBetweenConstraint,
secondBetweenConstraint,
thirdBetweenConstraint,
fourthBetweenConstraint,
])
}
}
}
}
}

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

@ -566,10 +566,10 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="TimelineTableViewCell" rowHeight="500" id="ltf-IW-WJt" customClass="TimelineTableViewCell" customModule="elpha_ios" customModuleProvider="target">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="TimelineTableViewCell" rowHeight="500" id="ltf-IW-WJt" customClass="TimelineTableViewCell" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="414" height="500"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ltf-IW-WJt" id="n6I-gD-BmS">
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ltf-IW-WJt" id="n6I-gD-BmS">
<rect key="frame" x="0.0" y="0.0" width="414" height="500"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
@ -641,13 +641,13 @@
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ukb-MJ-igh">
<rect key="frame" x="56" y="18" width="100.5" height="18"/>
<rect key="frame" x="56" y="18" width="350" height="18"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dvA-pE-bQJ">
<rect key="frame" x="56" y="40" width="62" height="16"/>
<rect key="frame" x="56" y="40" width="350" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -660,7 +660,7 @@
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Boosted" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gXx-Tg-gLN">
<rect key="frame" x="76" y="60" width="47" height="14.5"/>
<rect key="frame" x="76" y="60" width="330" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -670,6 +670,7 @@
<constraints>
<constraint firstItem="IKt-wC-rQf" firstAttribute="leading" secondItem="dvA-pE-bQJ" secondAttribute="leading" id="1Px-vS-dOJ"/>
<constraint firstItem="dvA-pE-bQJ" firstAttribute="leading" secondItem="ocT-ux-M2p" secondAttribute="trailing" constant="8" id="49y-Or-GyX"/>
<constraint firstAttribute="trailing" secondItem="dvA-pE-bQJ" secondAttribute="trailing" constant="8" id="63r-BG-9nt"/>
<constraint firstItem="gXx-Tg-gLN" firstAttribute="top" secondItem="dvA-pE-bQJ" secondAttribute="bottom" constant="4" id="8vA-Cq-EED"/>
<constraint firstAttribute="height" constant="100" id="AsD-s0-pkq"/>
<constraint firstItem="ocT-ux-M2p" firstAttribute="top" secondItem="9fS-a9-pwm" secondAttribute="top" constant="18" id="Bvi-2N-0r3"/>
@ -679,8 +680,10 @@
<constraint firstItem="ukb-MJ-igh" firstAttribute="top" secondItem="9fS-a9-pwm" secondAttribute="top" constant="18" id="ZGu-Y9-Izj"/>
<constraint firstItem="gXx-Tg-gLN" firstAttribute="leading" secondItem="IKt-wC-rQf" secondAttribute="trailing" constant="8" id="avD-BX-C95"/>
<constraint firstItem="8DN-mV-NXI" firstAttribute="leading" secondItem="9fS-a9-pwm" secondAttribute="leading" constant="20" id="eTl-sX-JY6"/>
<constraint firstAttribute="trailing" secondItem="ukb-MJ-igh" secondAttribute="trailing" constant="8" id="ei1-BR-nem"/>
<constraint firstItem="IKt-wC-rQf" firstAttribute="top" secondItem="dvA-pE-bQJ" secondAttribute="bottom" constant="4" id="fMa-hv-fSt"/>
<constraint firstItem="ukb-MJ-igh" firstAttribute="leading" secondItem="ocT-ux-M2p" secondAttribute="trailing" constant="8" id="hDb-E4-iJq"/>
<constraint firstAttribute="trailing" secondItem="gXx-Tg-gLN" secondAttribute="trailing" constant="8" id="poS-0e-gtx"/>
<constraint firstAttribute="trailing" secondItem="8DN-mV-NXI" secondAttribute="trailing" constant="20" id="soR-hM-eq3"/>
</constraints>
</view>
@ -695,7 +698,7 @@
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="In reply to" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BX6-Js-Nhi">
<rect key="frame" x="76" y="18" width="56.5" height="14.5"/>
<rect key="frame" x="76" y="18" width="330" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -708,7 +711,7 @@
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Spo-Jx-UQY">
<rect key="frame" x="56" y="36.5" width="100.5" height="18"/>
<rect key="frame" x="56" y="36.5" width="350" height="18"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -721,7 +724,7 @@
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vCq-bh-CMA">
<rect key="frame" x="56" y="58.5" width="62" height="16"/>
<rect key="frame" x="56" y="58.5" width="350" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -731,6 +734,7 @@
<constraints>
<constraint firstItem="BX6-Js-Nhi" firstAttribute="top" secondItem="xpm-gm-QTe" secondAttribute="top" constant="18" id="1jk-D3-Bsh"/>
<constraint firstAttribute="height" constant="100" id="3ZW-GL-Mj5"/>
<constraint firstAttribute="trailing" secondItem="BX6-Js-Nhi" secondAttribute="trailing" constant="8" id="3oB-JJ-IKK"/>
<constraint firstItem="Spo-Jx-UQY" firstAttribute="leading" secondItem="Z85-Y0-P4Y" secondAttribute="trailing" constant="8" id="5l7-bV-uJQ"/>
<constraint firstItem="o2s-le-wFQ" firstAttribute="top" secondItem="xpm-gm-QTe" secondAttribute="top" constant="20" id="7BG-C0-w5O"/>
<constraint firstItem="Z85-Y0-P4Y" firstAttribute="leading" secondItem="xpm-gm-QTe" secondAttribute="leading" constant="8" id="B1J-au-QNS"/>
@ -740,13 +744,15 @@
<constraint firstItem="vCq-bh-CMA" firstAttribute="leading" secondItem="Spo-Jx-UQY" secondAttribute="leading" id="biR-A0-SVf"/>
<constraint firstItem="vCq-bh-CMA" firstAttribute="top" secondItem="Spo-Jx-UQY" secondAttribute="bottom" constant="4" id="c8u-6u-7Kf"/>
<constraint firstAttribute="bottom" secondItem="4Gf-aV-jSP" secondAttribute="bottom" constant="5" id="dJh-Ld-Doo"/>
<constraint firstAttribute="trailing" secondItem="Spo-Jx-UQY" secondAttribute="trailing" constant="8" id="gUP-f8-pTQ"/>
<constraint firstItem="Spo-Jx-UQY" firstAttribute="top" secondItem="BX6-Js-Nhi" secondAttribute="bottom" constant="4" id="rdh-yu-BHe"/>
<constraint firstItem="Z85-Y0-P4Y" firstAttribute="top" secondItem="xpm-gm-QTe" secondAttribute="top" constant="18" id="sz1-t1-hxY"/>
<constraint firstAttribute="trailing" secondItem="vCq-bh-CMA" secondAttribute="trailing" constant="8" id="ubk-dy-tO8"/>
<constraint firstItem="o2s-le-wFQ" firstAttribute="leading" secondItem="Z85-Y0-P4Y" secondAttribute="trailing" constant="8" id="weK-2y-Ycg"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OwU-e4-gmT">
<rect key="frame" x="0.0" y="255" width="414" height="190"/>
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="OwU-e4-gmT">
<rect key="frame" x="0.0" y="255" width="414" height="129"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AOi-ot-xXa">
<rect key="frame" x="8" y="18" width="45" height="45"/>
@ -756,28 +762,55 @@
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Nsu-8a-xsG">
<rect key="frame" x="61" y="18" width="112" height="20.5"/>
<rect key="frame" x="61" y="18" width="345" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dvJ-7r-JOr">
<rect key="frame" x="61" y="40.5" width="70.5" height="18"/>
<rect key="frame" x="61" y="40.5" width="345" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VmZ-Cs-XbK">
<rect key="frame" x="8" y="78" width="398" height="20.5"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="249" text="Content" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VmZ-Cs-XbK">
<rect key="frame" x="8" y="78" width="398" height="43"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="VmZ-Cs-XbK" secondAttribute="trailing" constant="8" id="32g-8R-k8N"/>
<constraint firstItem="dvJ-7r-JOr" firstAttribute="top" secondItem="Nsu-8a-xsG" secondAttribute="bottom" constant="2" id="KVY-bN-5l0"/>
<constraint firstItem="Nsu-8a-xsG" firstAttribute="top" secondItem="OwU-e4-gmT" secondAttribute="top" constant="18" id="TNR-QZ-3f8"/>
<constraint firstAttribute="trailing" secondItem="Nsu-8a-xsG" secondAttribute="trailing" constant="8" id="URL-d0-869"/>
<constraint firstItem="AOi-ot-xXa" firstAttribute="top" secondItem="OwU-e4-gmT" secondAttribute="top" constant="18" id="VZr-nm-9C5"/>
<constraint firstAttribute="bottom" secondItem="VmZ-Cs-XbK" secondAttribute="bottom" constant="8" id="Vse-j3-LX3"/>
<constraint firstItem="VmZ-Cs-XbK" firstAttribute="leading" secondItem="OwU-e4-gmT" secondAttribute="leading" constant="8" id="awE-TQ-TF0"/>
<constraint firstItem="AOi-ot-xXa" firstAttribute="leading" secondItem="OwU-e4-gmT" secondAttribute="leading" constant="8" id="dZ3-VC-SPP"/>
<constraint firstItem="Nsu-8a-xsG" firstAttribute="leading" secondItem="AOi-ot-xXa" secondAttribute="trailing" constant="8" id="iZn-vn-Xtt"/>
<constraint firstItem="VmZ-Cs-XbK" firstAttribute="top" secondItem="AOi-ot-xXa" secondAttribute="bottom" constant="15" id="kni-Ko-qpY"/>
<constraint firstItem="dvJ-7r-JOr" firstAttribute="leading" secondItem="AOi-ot-xXa" secondAttribute="trailing" constant="8" id="oyQ-0e-9qz"/>
<constraint firstAttribute="trailing" secondItem="dvJ-7r-JOr" secondAttribute="trailing" constant="8" id="u1Y-8l-2XB"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="k2r-TR-ccp" customClass="AttachmentsView" customModule="elpha_ios" customModuleProvider="target">
<rect key="frame" x="0.0" y="384" width="414" height="1"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="9AE-Ni-UAO"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BxY-Mp-TeI">
<rect key="frame" x="0.0" y="385" width="414" height="60"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pGF-ol-Wqu">
<rect key="frame" x="8" y="145" width="100" height="30"/>
<rect key="frame" x="8" y="15" width="194" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Timestamp" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g0I-Zp-Y9h">
<rect key="frame" x="20" y="7" width="67.5" height="16"/>
<rect key="frame" x="20" y="7" width="166" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.090196078430000007" green="0.047058823530000002" blue="0.28627450980000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -793,15 +826,15 @@
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="6cC-Bm-dsh"/>
<constraint firstAttribute="width" constant="100" id="QgS-Ss-UU0"/>
<constraint firstItem="g0I-Zp-Y9h" firstAttribute="centerY" secondItem="pGF-ol-Wqu" secondAttribute="centerY" id="XeP-2L-8Gi"/>
<constraint firstItem="aeb-vM-xuk" firstAttribute="leading" secondItem="pGF-ol-Wqu" secondAttribute="leading" id="Y9E-Kd-bFD"/>
<constraint firstItem="g0I-Zp-Y9h" firstAttribute="leading" secondItem="aeb-vM-xuk" secondAttribute="trailing" constant="5" id="ZrB-fL-WyG"/>
<constraint firstAttribute="trailing" secondItem="g0I-Zp-Y9h" secondAttribute="trailing" constant="8" id="cXG-gt-wOb"/>
<constraint firstItem="aeb-vM-xuk" firstAttribute="centerY" secondItem="pGF-ol-Wqu" secondAttribute="centerY" id="j3V-yK-fuP"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZOn-0n-hPZ">
<rect key="frame" x="346" y="145" width="60" height="30"/>
<rect key="frame" x="346" y="15" width="60" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="100" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jfd-Nt-QbG">
<rect key="frame" x="28" y="6.5" width="24" height="17"/>
@ -828,7 +861,7 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dbI-17-JiR">
<rect key="frame" x="278" y="145" width="60" height="30"/>
<rect key="frame" x="278" y="15" width="60" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="100" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jbL-pa-f8U">
<rect key="frame" x="36" y="6.5" width="24" height="17"/>
@ -855,7 +888,7 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IsJ-nH-idi">
<rect key="frame" x="210" y="145" width="60" height="30"/>
<rect key="frame" x="210" y="15" width="60" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="100" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WWx-tD-ydV">
<rect key="frame" x="36" y="6.5" width="24" height="17"/>
@ -881,33 +914,19 @@
<constraint firstItem="BaX-Vk-itT" firstAttribute="centerY" secondItem="IsJ-nH-idi" secondAttribute="centerY" id="xlm-en-NCW"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="eY8-HB-QXO">
<rect key="frame" x="0.0" y="106.5" width="414" height="30.5"/>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="VmZ-Cs-XbK" secondAttribute="trailing" constant="8" id="32g-8R-k8N"/>
<constraint firstItem="eY8-HB-QXO" firstAttribute="top" secondItem="VmZ-Cs-XbK" secondAttribute="bottom" constant="8" id="8U0-7c-Pnn"/>
<constraint firstAttribute="bottom" secondItem="dbI-17-JiR" secondAttribute="bottom" constant="15" id="976-ZN-32I"/>
<constraint firstAttribute="bottom" secondItem="pGF-ol-Wqu" secondAttribute="bottom" constant="15" id="9Ff-UD-7Ke"/>
<constraint firstAttribute="trailing" secondItem="eY8-HB-QXO" secondAttribute="trailing" id="AsU-r4-iEi"/>
<constraint firstItem="dvJ-7r-JOr" firstAttribute="top" secondItem="Nsu-8a-xsG" secondAttribute="bottom" constant="2" id="KVY-bN-5l0"/>
<constraint firstAttribute="bottom" secondItem="IsJ-nH-idi" secondAttribute="bottom" constant="15" id="KfX-d0-Yfc"/>
<constraint firstItem="Nsu-8a-xsG" firstAttribute="top" secondItem="OwU-e4-gmT" secondAttribute="top" constant="18" id="TNR-QZ-3f8"/>
<constraint firstItem="AOi-ot-xXa" firstAttribute="top" secondItem="OwU-e4-gmT" secondAttribute="top" constant="18" id="VZr-nm-9C5"/>
<constraint firstItem="dbI-17-JiR" firstAttribute="leading" secondItem="IsJ-nH-idi" secondAttribute="trailing" constant="8" id="Wcj-uc-coX"/>
<constraint firstItem="pGF-ol-Wqu" firstAttribute="leading" secondItem="OwU-e4-gmT" secondAttribute="leading" constant="8" id="X1O-8M-ZkZ"/>
<constraint firstItem="VmZ-Cs-XbK" firstAttribute="leading" secondItem="OwU-e4-gmT" secondAttribute="leading" constant="8" id="awE-TQ-TF0"/>
<constraint firstItem="AOi-ot-xXa" firstAttribute="leading" secondItem="OwU-e4-gmT" secondAttribute="leading" constant="8" id="dZ3-VC-SPP"/>
<constraint firstAttribute="bottom" secondItem="ZOn-0n-hPZ" secondAttribute="bottom" constant="15" id="e7x-WD-Jdf"/>
<constraint firstItem="Nsu-8a-xsG" firstAttribute="leading" secondItem="AOi-ot-xXa" secondAttribute="trailing" constant="8" id="iZn-vn-Xtt"/>
<constraint firstItem="VmZ-Cs-XbK" firstAttribute="top" secondItem="AOi-ot-xXa" secondAttribute="bottom" constant="15" id="kni-Ko-qpY"/>
<constraint firstItem="dvJ-7r-JOr" firstAttribute="leading" secondItem="AOi-ot-xXa" secondAttribute="trailing" constant="8" id="oyQ-0e-9qz"/>
<constraint firstAttribute="trailing" secondItem="ZOn-0n-hPZ" secondAttribute="trailing" constant="8" id="q9C-Xy-DDI"/>
<constraint firstItem="ZOn-0n-hPZ" firstAttribute="leading" secondItem="dbI-17-JiR" secondAttribute="trailing" constant="8" id="sII-EP-kkK"/>
<constraint firstItem="pGF-ol-Wqu" firstAttribute="top" secondItem="eY8-HB-QXO" secondAttribute="bottom" constant="8" id="so0-Ep-VbV"/>
<constraint firstItem="eY8-HB-QXO" firstAttribute="leading" secondItem="OwU-e4-gmT" secondAttribute="leading" id="zPq-t1-vzJ"/>
<constraint firstItem="dbI-17-JiR" firstAttribute="centerY" secondItem="BxY-Mp-TeI" secondAttribute="centerY" id="00G-d4-H5e"/>
<constraint firstAttribute="trailing" secondItem="ZOn-0n-hPZ" secondAttribute="trailing" constant="8" id="0h7-8C-X31"/>
<constraint firstItem="IsJ-nH-idi" firstAttribute="leading" secondItem="pGF-ol-Wqu" secondAttribute="trailing" constant="8" id="4X9-uT-pt2"/>
<constraint firstItem="ZOn-0n-hPZ" firstAttribute="leading" secondItem="dbI-17-JiR" secondAttribute="trailing" constant="8" id="JZw-NX-gP8"/>
<constraint firstAttribute="height" constant="60" id="L3p-DT-fAd"/>
<constraint firstItem="pGF-ol-Wqu" firstAttribute="leading" secondItem="BxY-Mp-TeI" secondAttribute="leading" constant="8" id="Msj-vp-7Gn"/>
<constraint firstItem="pGF-ol-Wqu" firstAttribute="centerY" secondItem="BxY-Mp-TeI" secondAttribute="centerY" id="dca-Oo-My0"/>
<constraint firstItem="ZOn-0n-hPZ" firstAttribute="centerY" secondItem="BxY-Mp-TeI" secondAttribute="centerY" id="fO1-B4-Yxd"/>
<constraint firstItem="dbI-17-JiR" firstAttribute="leading" secondItem="IsJ-nH-idi" secondAttribute="trailing" constant="8" id="qAB-2q-VwD"/>
<constraint firstItem="IsJ-nH-idi" firstAttribute="centerY" secondItem="BxY-Mp-TeI" secondAttribute="centerY" id="sDz-Pu-Sbd"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1pv-7u-4nG">
@ -967,7 +986,8 @@
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="attachmentImageView" destination="eY8-HB-QXO" id="Bf8-TY-sQ6"/>
<outlet property="attachmentsHeightConstraint" destination="9AE-Ni-UAO" id="5re-Uh-VwW"/>
<outlet property="attachmentsView" destination="k2r-TR-ccp" id="9gH-U6-mey"/>
<outlet property="avatarImageView" destination="AOi-ot-xXa" id="4Z4-8h-dAo"/>
<outlet property="boostAvatarImageView" destination="ocT-ux-M2p" id="Vfi-vL-ttC"/>
<outlet property="boostDisplayNameLabel" destination="ukb-MJ-igh" id="Ps1-Wf-C1x"/>

2
elpha-ios/Elpha.xcdatamodeld/Elpha.xcdatamodel/contents

@ -123,7 +123,7 @@
<attribute name="visibility" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="account" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Account" inverseName="statuses" inverseEntity="Account" syncable="YES"/>
<relationship name="app" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="App" inverseName="statuses" inverseEntity="App" syncable="YES"/>
<relationship name="attachments" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Attachment" inverseName="status" inverseEntity="Attachment" syncable="YES"/>
<relationship name="attachments" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="Attachment" inverseName="status" inverseEntity="Attachment" syncable="YES"/>
<relationship name="mentions" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Mention" inverseName="status" inverseEntity="Mention" syncable="YES"/>
<relationship name="reblog" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="reblogs" inverseEntity="Status" syncable="YES"/>
<relationship name="reblogs" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="reblog" inverseEntity="Status" syncable="YES"/>

2
elpha-ios/MastodonDataManager.swift

@ -183,7 +183,7 @@ public class MastodonDataManager {
remoteStatus.mediaAttachments.forEach { attachment in
if let attachment = MastodonDataManager.upsertAttachment(attachment) {
status.mutableSetValue(forKey: "attachments").add(attachment)
status.mutableOrderedSetValue(forKey: "attachments").add(attachment)
}
}

3
elpha-ios/TimelineTableViewCell.swift

@ -32,5 +32,6 @@ class TimelineTableViewCell: UITableViewCell {
@IBOutlet var topLoadMoreView: UIView!
@IBOutlet var bottomDividerView: UIView!
@IBOutlet var bottomLoadMoreView: UIView!
@IBOutlet var attachmentImageView: UIImageView!
@IBOutlet var attachmentsView: AttachmentsView!
@IBOutlet var attachmentsHeightConstraint: NSLayoutConstraint!
}

39
elpha-ios/TimelineTableViewController.swift

@ -13,6 +13,7 @@ import UIKit
class TimelineTableViewController: UITableViewController {
let fetchLimit = 50
let cellHeightsDictionary = NSMutableDictionary()
var loading: Bool = false {
didSet {
@ -31,6 +32,9 @@ class TimelineTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 500
let composeButtonItem = UIBarButtonItem(image: UIImage(named: "Compose"), style: .plain, target: self, action: #selector(compose))
navigationItem.rightBarButtonItem = composeButtonItem
navigationItem.title = "Home"
@ -206,6 +210,18 @@ class TimelineTableViewController: UITableViewController {
return getTimelineStatusesCount()
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightsDictionary.setValue(cell.frame.size.height, forKey: String(indexPath.row))
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeightsDictionary.object(forKey: String(indexPath.row)) as? CGFloat {
return height
}
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineTableViewCell", for: indexPath) as? TimelineTableViewCell else {
fatalError("Unable to find reusable cell")
@ -217,7 +233,10 @@ class TimelineTableViewController: UITableViewController {
cell.replyView.isHidden = true
cell.bottomLoadMoreView.isHidden = true
cell.bottomDividerView.isHidden = false
cell.attachmentImageView.isHidden = true
cell.attachmentsView.backgroundColor = UIColor.white
cell.attachmentsHeightConstraint.constant = cell.frame.width
cell.attachmentsView.isHidden = true
if let statuses = getTimelineStatuses() {
let status = statuses[indexPath.row]
@ -255,6 +274,13 @@ class TimelineTableViewController: UITableViewController {
}
}
func setupAttachmentView(attachments: NSOrderedSet?) {
if let attachments = attachments, attachments.count < 0 {
cell.attachmentsView.isHidden = false
cell.attachmentsView.attachments = attachments
}
}
if let reblog = status.reblog {
cell.boostView.isHidden = false
@ -269,12 +295,16 @@ class TimelineTableViewController: UITableViewController {
cell.boostDisplayNameLabel.text = account.displayName
cell.boostUsernameLabel.text = account.acct
}
setupAttachmentView(attachments: reblog.attachments)
} 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
}
setupAttachmentView(attachments: status.attachments)
}
if let replyAccountID = status.inReplyToAccountID {
@ -288,7 +318,7 @@ class TimelineTableViewController: UITableViewController {
if let content = status.content {
do {
let styledContent = "<style>html * { font-size: 15px; color: #170c49; font-family: -apple-system } html, body { margin: 0; padding: 0 }</style> \(content)"
let styledContent = "<style>html * { font-size: 15px; color: #170c49; font-family: -apple-system } p { margin: 0; padding: 0 }</style> \(content)"
let attributedText = try NSAttributedString(
data: styledContent.data(using: String.Encoding.unicode, allowLossyConversion: true)!,
options: [.documentType: NSAttributedString.DocumentType.html],
@ -301,11 +331,6 @@ class TimelineTableViewController: UITableViewController {
}
}
if let attachments = status.attachments, let attachment = attachments.anyObject() as? AttachmentMO {
cell.attachmentImageView.isHidden = false
cell.attachmentImageView.af_setImage(withURL: attachment.url!)
}
cell.timestampLabel.text = status.createdAt!.timeAgo()
cell.repliesLabel.text = "0"
cell.boostsLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.reblogsCount), number: .decimal)

Loading…
Cancel
Save