forked from shadowfacts/Tusker
parent
af65aa88e0
commit
c91a7baaa6
|
@ -22,6 +22,13 @@ class ProfileTableViewController: EnhancedTableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
var pinnedStatusIDs: [String] = [] {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
var timelineSegments: [TimelineSegment<Status>] = [] {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
|
@ -98,6 +105,13 @@ class ProfileTableViewController: EnhancedTableViewController {
|
|||
|
||||
updateUIForPreferences()
|
||||
|
||||
getStatuses(onlyPinned: true) { (response) in
|
||||
guard case let .success(statuses, _) = response else { fatalError() }
|
||||
|
||||
MastodonCache.addAll(statuses: statuses)
|
||||
self.pinnedStatusIDs = statuses.map { $0.id }
|
||||
}
|
||||
|
||||
getStatuses() { response in
|
||||
guard case let .success(statuses, pagination) = response else { fatalError() }
|
||||
|
||||
|
@ -114,8 +128,8 @@ class ProfileTableViewController: EnhancedTableViewController {
|
|||
navigationItem.title = account.realDisplayName
|
||||
}
|
||||
|
||||
func getStatuses(for range: RequestRange = .default, completion: @escaping Client.Callback<[Status]>) {
|
||||
let request = Account.getStatuses(accountID, range: range, onlyMedia: false, pinned: false, excludeReplies: !Preferences.shared.showRepliesInProfiles)
|
||||
func getStatuses(for range: RequestRange = .default, onlyPinned: Bool = false, completion: @escaping Client.Callback<[Status]>) {
|
||||
let request = Account.getStatuses(accountID, range: range, onlyMedia: false, pinned: onlyPinned, excludeReplies: !Preferences.shared.showRepliesInProfiles)
|
||||
MastodonController.client.run(request, completion: completion)
|
||||
}
|
||||
|
||||
|
@ -128,27 +142,38 @@ class ProfileTableViewController: EnhancedTableViewController {
|
|||
// MARK: - Table view data source
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return 1 + timelineSegments.count
|
||||
// 1 section for header, 1 section for pinned, rest for timeline
|
||||
return 2 + timelineSegments.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
if section == 0 {
|
||||
return accountID == nil || MastodonCache.account(for: accountID) == nil ? 0 : 1
|
||||
} else if section == 1 {
|
||||
return pinnedStatusIDs.count
|
||||
} else {
|
||||
return timelineSegments[section - 1].count
|
||||
return timelineSegments[section - 2].count
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
if indexPath.section == 0 {
|
||||
switch indexPath.section {
|
||||
case 0:
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "headerCell", for: indexPath) as? ProfileHeaderTableViewCell else { fatalError() }
|
||||
cell.selectionStyle = .none
|
||||
cell.delegate = self
|
||||
cell.updateUI(for: accountID)
|
||||
return cell
|
||||
} else {
|
||||
case 1:
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
||||
let statusID = timelineSegments[indexPath.section - 1][indexPath.row]
|
||||
let statusID = pinnedStatusIDs[indexPath.row]
|
||||
cell.showPinned = true
|
||||
cell.updateUI(statusID: statusID)
|
||||
cell.delegate = self
|
||||
return cell
|
||||
default:
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
||||
let statusID = timelineSegments[indexPath.section - 2][indexPath.row]
|
||||
cell.updateUI(statusID: statusID)
|
||||
cell.delegate = self
|
||||
return cell
|
||||
|
@ -156,14 +181,14 @@ class ProfileTableViewController: EnhancedTableViewController {
|
|||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
if timelineSegments.count > 0 && indexPath.section == timelineSegments.count && indexPath.row == timelineSegments[indexPath.section - 1].count - 1 {
|
||||
if timelineSegments.count > 0 && indexPath.section - 1 == timelineSegments.count && indexPath.row == timelineSegments[indexPath.section - 2].count - 1 {
|
||||
guard let older = older else { return }
|
||||
|
||||
getStatuses(for: older) { response in
|
||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||
|
||||
MastodonCache.addAll(statuses: newStatuses)
|
||||
self.timelineSegments[indexPath.section - 1].append(objects: newStatuses)
|
||||
self.timelineSegments[indexPath.section - 2].append(objects: newStatuses)
|
||||
|
||||
self.older = pagination?.older
|
||||
}
|
||||
|
@ -246,8 +271,8 @@ extension ProfileTableViewController: ProfileHeaderTableViewCellDelegate {
|
|||
|
||||
extension ProfileTableViewController: UITableViewDataSourcePrefetching {
|
||||
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
||||
for indexPath in indexPaths where indexPath.section > 0 {
|
||||
let statusID = timelineSegments[indexPath.section - 1][indexPath.row]
|
||||
for indexPath in indexPaths where indexPath.section > 1 {
|
||||
let statusID = timelineSegments[indexPath.section - 2][indexPath.row]
|
||||
guard let status = MastodonCache.status(for: statusID) else { continue }
|
||||
ImageCache.avatars.get(status.account.avatar, completion: nil)
|
||||
for attachment in status.attachments {
|
||||
|
@ -257,8 +282,8 @@ extension ProfileTableViewController: UITableViewDataSourcePrefetching {
|
|||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
|
||||
for indexPath in indexPaths where indexPath.section > 0 {
|
||||
let statusID = timelineSegments[indexPath.section - 1][indexPath.row]
|
||||
for indexPath in indexPaths where indexPath.section > 1 {
|
||||
let statusID = timelineSegments[indexPath.section - 2][indexPath.row]
|
||||
guard let status = MastodonCache.status(for: statusID) else { continue }
|
||||
ImageCache.avatars.cancel(status.account.avatar)
|
||||
for attachment in status.attachments {
|
||||
|
|
|
@ -42,6 +42,7 @@ class StatusTableViewCell: UITableViewCell {
|
|||
@IBOutlet weak var favoriteButton: UIButton!
|
||||
@IBOutlet weak var reblogButton: UIButton!
|
||||
@IBOutlet weak var moreButton: UIButton!
|
||||
@IBOutlet weak var pinnedStackView: UIStackView!
|
||||
|
||||
var statusID: String!
|
||||
var accountID: String!
|
||||
|
@ -58,6 +59,7 @@ class StatusTableViewCell: UITableViewCell {
|
|||
reblogButton.tintColor = reblogged ? UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1) : tintColor
|
||||
}
|
||||
}
|
||||
var showPinned: Bool = false
|
||||
|
||||
var collapsible = false {
|
||||
didSet {
|
||||
|
@ -153,6 +155,9 @@ class StatusTableViewCell: UITableViewCell {
|
|||
setCollapsed(collapsible, animated: false)
|
||||
contentWarningLabel.text = status.spoilerText
|
||||
contentWarningLabel.isHidden = status.spoilerText.isEmpty
|
||||
|
||||
let pinned = status.pinned ?? false
|
||||
pinnedStackView.isHidden = !(pinned && showPinned)
|
||||
}
|
||||
|
||||
private func updateStatusState(status: Status) {
|
||||
|
@ -226,6 +231,7 @@ class StatusTableViewCell: UITableViewCell {
|
|||
updateTimestampWorkItem?.cancel()
|
||||
updateTimestampWorkItem = nil
|
||||
attachmentsView.subviews.forEach { $0.removeFromSuperview() }
|
||||
showPinned = false
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -16,6 +16,21 @@
|
|||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="yNh-ac-v6c">
|
||||
<rect key="frame" x="16" y="8" width="343" height="224"/>
|
||||
<subviews>
|
||||
<stackView hidden="YES" opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="3aF-uU-owK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="77" height="0.0"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="pin.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="LRh-Cc-1br">
|
||||
<rect key="frame" x="0.0" y="-0.5" width="20" height="1.5"/>
|
||||
<color key="tintColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pinned" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="meL-En-2jB">
|
||||
<rect key="frame" x="24" y="0.0" width="53" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" 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" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" verticalCompressionResistancePriority="751" text="Reblogged by Person" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lDH-50-AJZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="163.5" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
@ -23,7 +38,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="ve3-Y1-NQH">
|
||||
<rect key="frame" x="0.0" y="28.5" width="343" height="165.5"/>
|
||||
<rect key="frame" x="0.0" y="28.5" width="343" height="103.5"/>
|
||||
<subviews>
|
||||
<imageView contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QMP-j2-HLn">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||
|
@ -37,7 +52,7 @@
|
|||
</constraints>
|
||||
</imageView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="751" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="gIY-Wp-RSk">
|
||||
<rect key="frame" x="58" y="0.0" width="277" height="165.5"/>
|
||||
<rect key="frame" x="58" y="0.0" width="277" height="103.5"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3Sm-P0-ySf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="277" height="20.5"/>
|
||||
|
@ -101,7 +116,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HrJ-t9-KcD" customClass="StatusContentLabel" customModule="Tusker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="83" width="277" height="82.5"/>
|
||||
<rect key="frame" x="0.0" y="83" width="277" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -120,17 +135,17 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" verticalCompressionResistancePriority="1" translatesAutoresizingMaskIntoConstraints="NO" id="nbq-yr-2mA" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="198" width="343" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="136" width="343" height="0.0"/>
|
||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" priority="999" constant="200" id="J42-49-2MU"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" distribution="equalSpacing" alignment="bottom" translatesAutoresizingMaskIntoConstraints="NO" id="Zlb-yt-NTw">
|
||||
<rect key="frame" x="0.0" y="202" width="343" height="22"/>
|
||||
<rect key="frame" x="0.0" y="140" width="343" height="84"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rKF-yF-KIa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="21" height="22"/>
|
||||
<rect key="frame" x="0.0" y="62" width="21" height="22"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Reply"/>
|
||||
<state key="normal" image="arrowshape.turn.up.left.fill" catalog="system"/>
|
||||
<connections>
|
||||
|
@ -138,7 +153,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="x0t-TR-jJ4">
|
||||
<rect key="frame" x="107" y="0.0" width="22" height="22"/>
|
||||
<rect key="frame" x="107" y="62" width="22" height="22"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Favorite"/>
|
||||
<state key="normal" image="star.fill" catalog="system"/>
|
||||
<connections>
|
||||
|
@ -146,7 +161,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6tW-z8-Qh9">
|
||||
<rect key="frame" x="215.5" y="0.0" width="22.5" height="22"/>
|
||||
<rect key="frame" x="215.5" y="62" width="22.5" height="22"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Reblog"/>
|
||||
<state key="normal" image="repeat" catalog="system"/>
|
||||
<connections>
|
||||
|
@ -154,7 +169,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="982-J4-NGl">
|
||||
<rect key="frame" x="324" y="0.0" width="19" height="22"/>
|
||||
<rect key="frame" x="324" y="62" width="19" height="22"/>
|
||||
<accessibility key="accessibilityConfiguration" label="More Actions"/>
|
||||
<state key="normal" image="ellipsis" catalog="system"/>
|
||||
<connections>
|
||||
|
@ -189,6 +204,7 @@
|
|||
<outlet property="displayNameLabel" destination="gll-xe-FSr" id="63y-He-xy1"/>
|
||||
<outlet property="favoriteButton" destination="x0t-TR-jJ4" id="Ohz-bs-Ebr"/>
|
||||
<outlet property="moreButton" destination="982-J4-NGl" id="Xga-I4-CzK"/>
|
||||
<outlet property="pinnedStackView" destination="3aF-uU-owK" id="O71-WE-G6U"/>
|
||||
<outlet property="reblogButton" destination="6tW-z8-Qh9" id="i9h-QA-ZPd"/>
|
||||
<outlet property="reblogLabel" destination="lDH-50-AJZ" id="uJf-Pt-cEP"/>
|
||||
<outlet property="replyButton" destination="rKF-yF-KIa" id="rul-lk-bIR"/>
|
||||
|
@ -202,6 +218,7 @@
|
|||
<image name="arrowshape.turn.up.left.fill" catalog="system" width="64" height="52"/>
|
||||
<image name="chevron.down" catalog="system" width="64" height="36"/>
|
||||
<image name="ellipsis" catalog="system" width="64" height="18"/>
|
||||
<image name="pin.fill" catalog="system" width="58" height="64"/>
|
||||
<image name="repeat" catalog="system" width="64" height="48"/>
|
||||
<image name="star.fill" catalog="system" width="64" height="58"/>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue