Compare commits

...

2 Commits

9 changed files with 330 additions and 9 deletions

View File

@ -148,6 +148,10 @@
D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC7B232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib */; };
D6A3BC802321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7E2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift */; };
D6A3BC812321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC7F2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib */; };
D6A3BC852321F6C100FD64D5 /* AccountListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC832321F6C100FD64D5 /* AccountListTableViewController.swift */; };
D6A3BC862321F6C100FD64D5 /* AccountListTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC842321F6C100FD64D5 /* AccountListTableViewController.xib */; };
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC882321F79B00FD64D5 /* AccountTableViewCell.swift */; };
D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC892321F79B00FD64D5 /* AccountTableViewCell.xib */; };
D6A5FAF1217B7E05003DB2D9 /* ComposeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A5FAF0217B7E05003DB2D9 /* ComposeViewController.xib */; };
D6A5FAFB217B86CE003DB2D9 /* OnboardingViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A5FAFA217B86CE003DB2D9 /* OnboardingViewController.xib */; };
D6AEBB3E2321638100E5038B /* UIActivity+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */; };
@ -389,6 +393,10 @@
D6A3BC7B232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ActionNotificationGroupTableViewCell.xib; sourceTree = "<group>"; };
D6A3BC7E2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowNotificationGroupTableViewCell.swift; sourceTree = "<group>"; };
D6A3BC7F2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FollowNotificationGroupTableViewCell.xib; sourceTree = "<group>"; };
D6A3BC832321F6C100FD64D5 /* AccountListTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountListTableViewController.swift; sourceTree = "<group>"; };
D6A3BC842321F6C100FD64D5 /* AccountListTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountListTableViewController.xib; sourceTree = "<group>"; };
D6A3BC882321F79B00FD64D5 /* AccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTableViewCell.swift; sourceTree = "<group>"; };
D6A3BC892321F79B00FD64D5 /* AccountTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountTableViewCell.xib; sourceTree = "<group>"; };
D6A5FAF0217B7E05003DB2D9 /* ComposeViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ComposeViewController.xib; sourceTree = "<group>"; };
D6A5FAFA217B86CE003DB2D9 /* OnboardingViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OnboardingViewController.xib; sourceTree = "<group>"; };
D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIActivity+Types.swift"; sourceTree = "<group>"; };
@ -674,6 +682,7 @@
D641C788213DD86D004B4513 /* Large Image */,
0411610422B4571E0030A9B7 /* Attachment */,
0411610522B457290030A9B7 /* Gallery */,
D6A3BC822321F69400FD64D5 /* Account List */,
D641C789213DD87E004B4513 /* Preferences */,
);
path = Screens;
@ -941,6 +950,24 @@
path = Utilities;
sourceTree = "<group>";
};
D6A3BC822321F69400FD64D5 /* Account List */ = {
isa = PBXGroup;
children = (
D6A3BC832321F6C100FD64D5 /* AccountListTableViewController.swift */,
D6A3BC842321F6C100FD64D5 /* AccountListTableViewController.xib */,
);
path = "Account List";
sourceTree = "<group>";
};
D6A3BC872321F78000FD64D5 /* Account Cell */ = {
isa = PBXGroup;
children = (
D6A3BC882321F79B00FD64D5 /* AccountTableViewCell.swift */,
D6A3BC892321F79B00FD64D5 /* AccountTableViewCell.xib */,
);
path = "Account Cell";
sourceTree = "<group>";
};
D6AEBB3F2321640F00E5038B /* Activities */ = {
isa = PBXGroup;
children = (
@ -977,6 +1004,7 @@
D6C7D27B22B6EBE200071952 /* Attachments */,
D641C78B213DD92F004B4513 /* Profile Header */,
D641C78C213DD937004B4513 /* Notifications */,
D6A3BC872321F78000FD64D5 /* Account Cell */,
);
path = Views;
sourceTree = "<group>";
@ -1338,6 +1366,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D6A3BC862321F6C100FD64D5 /* AccountListTableViewController.xib in Resources */,
D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */,
D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */,
D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */,
D667E5E921349EE50057A976 /* ProfileHeaderTableViewCell.xib in Resources */,
@ -1453,6 +1483,7 @@
D6C693F92162E4DB007D6A6D /* StatusContentLabel.swift in Sources */,
D6D58DF922074B74009C8DD9 /* LinkLabel.swift in Sources */,
0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */,
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */,
D667E5F52135BCD50057A976 /* ConversationTableViewController.swift in Sources */,
D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */,
@ -1465,6 +1496,7 @@
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */,
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
D6A3BC852321F6C100FD64D5 /* AccountListTableViewController.swift in Sources */,
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */,
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,

View File

@ -0,0 +1,57 @@
//
// AccountListTableViewController.swift
// Tusker
//
// Created by Shadowfacts on 9/5/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import UIKit
class AccountListTableViewController: UITableViewController {
private let accountCell = "accountCell"
let accountIDs: [String]
init(accountIDs: [String]) {
self.accountIDs = accountIDs
super.init(nibName: "AccountListTableViewController", bundle: .main)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "AccountTableViewCell", bundle: .main), forCellReuseIdentifier: accountCell)
tableView.rowHeight = 66
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return accountIDs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as? AccountTableViewCell else { fatalError() }
let id = accountIDs[indexPath.row]
cell.updateUI(accountID: id)
cell.delegate = self
return cell
}
}
extension AccountListTableViewController: TuskerNavigationDelegate {}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AccountListTableViewController" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableView opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" bouncesZoom="NO" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="vLr-E1-eTs"/>
<connections>
<outlet property="dataSource" destination="-1" id="Tng-2m-Rnh"/>
<outlet property="delegate" destination="-1" id="9aC-8N-iBw"/>
</connections>
</tableView>
</objects>
</document>

View File

@ -41,6 +41,8 @@ protocol TuskerNavigationDelegate {
func showMoreOptions(forStatus statusID: String)
func showMoreOptions(forURL url: URL)
func showFollowedByList(accountIDs: [String])
}
extension TuskerNavigationDelegate where Self: UIViewController {
@ -169,4 +171,10 @@ extension TuskerNavigationDelegate where Self: UIViewController {
present(moreOptions(forURL: url), animated: true)
}
func showFollowedByList(accountIDs: [String]) {
let vc = AccountListTableViewController(accountIDs: accountIDs)
vc.title = NSLocalizedString("Followed By", comment: "followed by accounts list title")
show(vc, sender: self)
}
}

View File

@ -0,0 +1,66 @@
//
// AccountTableViewCell.swift
// Tusker
//
// Created by Shadowfacts on 9/5/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import UIKit
class AccountTableViewCell: UITableViewCell {
var delegate: TuskerNavigationDelegate?
@IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var displayNameLabel: UILabel!
@IBOutlet weak var usernameLabel: UILabel!
var accountID: String!
var avatarURL: URL?
override func awakeFromNib() {
super.awakeFromNib()
avatarImageView.layer.masksToBounds = true
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPrefrences), name: .preferencesChanged, object: nil)
}
@objc func updateUIForPrefrences() {
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
guard let account = MastodonCache.account(for: accountID) else {
fatalError("Missing cached account \(accountID!)")
}
displayNameLabel.text = account.realDisplayName
}
func updateUI(accountID: String) {
self.accountID = accountID
guard let account = MastodonCache.account(for: accountID) else {
fatalError("Missing cached account \(accountID)")
}
self.avatarURL = account.avatar
ImageCache.avatars.get(account.avatar) { (data) in
guard let data = data, self.avatarURL == account.avatar else { return }
DispatchQueue.main.async {
self.avatarImageView.image = UIImage(data: data)
}
}
displayNameLabel.text = account.realDisplayName
usernameLabel.text = "@\(account.acct)"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if selected {
delegate?.selected(account: accountID)
}
}
}

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="66" id="KGk-i7-Jjw" customClass="AccountTableViewCell" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="66"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Rp2-O5-Vew">
<rect key="frame" x="16" y="8" width="50" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="NqI-m0-owe"/>
<constraint firstAttribute="width" constant="50" id="lar-P0-gRh"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Iif-9m-vM5">
<rect key="frame" x="74" y="11" width="230" height="44"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fhc-bZ-lkB">
<rect key="frame" x="0.0" y="0.0" width="230" height="26"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JMo-QH-1is">
<rect key="frame" x="0.0" y="26" width="230" height="18"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="Rp2-O5-Vew" secondAttribute="bottom" constant="8" id="Vw1-OF-tnw"/>
<constraint firstAttribute="bottomMargin" secondItem="Iif-9m-vM5" secondAttribute="bottom" id="dV0-Vm-DUb"/>
<constraint firstItem="Iif-9m-vM5" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="ihr-er-kLO"/>
<constraint firstAttribute="trailingMargin" secondItem="Iif-9m-vM5" secondAttribute="trailing" id="q7a-DT-WPF"/>
<constraint firstItem="Iif-9m-vM5" firstAttribute="leading" secondItem="Rp2-O5-Vew" secondAttribute="trailing" constant="8" id="sk1-KY-Ttj"/>
<constraint firstItem="Rp2-O5-Vew" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="8" id="xpB-wY-5d6"/>
<constraint firstItem="Rp2-O5-Vew" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="yd4-AU-qbj"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="avatarImageView" destination="Rp2-O5-Vew" id="3Gw-Xg-bd5"/>
<outlet property="displayNameLabel" destination="Fhc-bZ-lkB" id="1b0-3k-KR8"/>
<outlet property="usernameLabel" destination="JMo-QH-1is" id="ElX-ua-xcQ"/>
</connections>
<point key="canvasLocation" x="173.91304347826087" y="24.107142857142858"/>
</tableViewCell>
</objects>
</document>

View File

@ -94,7 +94,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell {
func updateTimestamp() {
guard let id = group.notificationIDs.first,
let notification = MastodonCache.notification(for: id) else {
fatalError("Missing cached status")
fatalError("Missing cached notification")
}
timestampLabel.text = notification.createdAt.timeAgoString()

View File

@ -14,10 +14,13 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
var delegate: TuskerNavigationDelegate?
@IBOutlet weak var avatarStackView: UIStackView!
@IBOutlet weak var timestampLabel: UILabel!
@IBOutlet weak var actionLabel: UILabel!
var group: NotificationGroup!
var updateTimestampWorkItem: DispatchWorkItem?
override func awakeFromNib() {
super.awakeFromNib()
@ -39,6 +42,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account }
updateActionLabel(people: people)
updateTimestamp()
avatarStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
for account in people {
@ -63,7 +67,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
func updateActionLabel(people: [Account]) {
// todo: figure out how to localize this
let peopleStr: String
switch (people.count) {
switch people.count {
case 1:
peopleStr = people.first!.realDisplayName
case 2:
@ -75,4 +79,54 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
actionLabel.text = "Followed by \(peopleStr)"
}
func updateTimestamp() {
guard let id = group.notificationIDs.first,
let notification = MastodonCache.notification(for: id) else {
fatalError("Missing cached notification")
}
timestampLabel.text = notification.createdAt.timeAgoString()
let delay: DispatchTimeInterval?
switch notification.createdAt.timeAgo().1 {
case .second:
delay = .seconds(10)
case .minute:
delay = .seconds(60)
default:
delay = nil
}
if let delay = delay {
updateTimestampWorkItem = DispatchWorkItem {
self.updateTimestamp()
}
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: updateTimestampWorkItem!)
} else {
updateTimestampWorkItem = nil
}
}
override func prepareForReuse() {
super.prepareForReuse()
updateTimestampWorkItem?.cancel()
updateTimestampWorkItem = nil
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if selected {
let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account.id }
switch people.count {
case 0:
return
case 1:
delegate?.selected(account: people.first!)
default:
delegate?.showFollowedByList(accountIDs: people)
}
}
}
}

View File

@ -16,17 +16,31 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="98"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" translatesAutoresizingMaskIntoConstraints="NO" id="g8L-M7-dD6">
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="g8L-M7-dD6">
<rect key="frame" x="74" y="11" width="230" height="76"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="xyB-aZ-YhR">
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7lu-x4-ldA">
<rect key="frame" x="0.0" y="0.0" width="230" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="3ns-8D-P1Q"/>
</constraints>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="xyB-aZ-YhR">
<rect key="frame" x="0.0" y="0.0" width="205.5" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="3ns-8D-P1Q"/>
</constraints>
</stackView>
<view contentMode="scaleToFill" horizontalHuggingPriority="249" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eEp-GR-rtF">
<rect key="frame" x="205.5" y="0.0" width="0.0" height="30"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Iub-HC-orP">
<rect key="frame" x="205.5" y="0.0" width="24.5" height="30"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Followed by Person 1 and Person 2" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bHA-9x-pcO">
<rect key="frame" x="0.0" y="30" width="198" height="46"/>
<rect key="frame" x="0.0" y="30" width="230" height="46"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -54,6 +68,7 @@
<connections>
<outlet property="actionLabel" destination="bHA-9x-pcO" id="Woa-25-hgd"/>
<outlet property="avatarStackView" destination="xyB-aZ-YhR" id="DDp-5c-Qdo"/>
<outlet property="timestampLabel" destination="Iub-HC-orP" id="OCV-mm-LXF"/>
</connections>
<point key="canvasLocation" x="131.8840579710145" y="171.42857142857142"/>
</tableViewCell>