Skip to content

Commit

Permalink
Merge branch 'master' of github.com:weiran/Hackers into text
Browse files Browse the repository at this point in the history
# Conflicts:
#	App/Main.storyboard
  • Loading branch information
weiran committed Jul 16, 2023
2 parents ee031e7 + 626a623 commit 99093c6
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 19 deletions.
20 changes: 3 additions & 17 deletions App/Comments/CommentTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class CommentTableViewCell: SwipeTableViewCell {
if let commentTextView = commentTextView, comment.visibility == .visible {
// only for expanded comments
let commentFont = UIFont.preferredFont(forTextStyle: .subheadline)
let commentAttributedString = parseToAttributedString(comment.text)
let commentAttributedString = comment.text.parseToAttributedString()
let commentRange = NSRange(location: 0, length: commentAttributedString.length)

commentAttributedString.addAttribute(NSAttributedString.Key.font,
Expand All @@ -83,20 +83,6 @@ class CommentTableViewCell: SwipeTableViewCell {
commentTextView.attributedText = commentAttributedString
}
}

private func parseToAttributedString(_ html: String) -> NSMutableAttributedString {
let paragraphIdentifier = "PARAGRAPH_NEED_NEW_LINES_HERE"

// swiftlint:disable unused_optional_binding
guard let document = try? SwiftSoup.parse(html),
let _ = try? document.select("p").before(paragraphIdentifier),
let text = try? document.text() else {
return NSMutableAttributedString()
}
// swiftlint:enable unused_optional_binding

return NSMutableAttributedString(string: text.replacingOccurrences(of: paragraphIdentifier + " ", with: "\n\n"))
}
}

extension CommentTableViewCell: UITextViewDelegate {
Expand Down Expand Up @@ -138,12 +124,12 @@ extension CommentTableViewCell: UITextViewDelegate {
extension CommentTableViewCell {
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
selected ? setSelectedBackground() : setUnselectedBackground()
if selected { setSelectedBackground() } else { setUnselectedBackground() }
}

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
highlighted ? setSelectedBackground() : setUnselectedBackground()
if highlighted { setSelectedBackground() } else { setUnselectedBackground() }
}

private func setSelectedBackground() {
Expand Down
41 changes: 40 additions & 1 deletion App/Comments/CommentsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class CommentsViewController: UITableViewController {
return self.loadComments(for: post)
}.done { comments in
self.comments = comments
self.post?.commentsCount = comments.count
self.tableView.reloadData()
}.catch { error in
UINotifications.showError()
Expand Down Expand Up @@ -267,10 +268,26 @@ extension CommentsViewController {
self?.shareComment(at: indexPath)
}

let copy = UIAction(
title: "Copy",
image: UIImage(systemName: "doc.on.doc"),
identifier: UIAction.Identifier(rawValue: "copy.comment")
) { [weak self] _ in
self?.copyComment(at: indexPath)
}

let selectText = UIAction(
title: "Select Text",
image: UIImage(systemName: "selection.pin.in.out"),
identifier: UIAction.Identifier(rawValue: "select.comment")
) { [weak self] _ in
self?.selectCommentText(at: indexPath)
}

let voteMenu = upvoted ? unvote : upvote
let shareMenu = UIMenu(title: "", options: .displayInline, children: [share])

return UIMenu(title: "", image: nil, identifier: nil, children: [voteMenu, shareMenu])
return UIMenu(title: "", image: nil, identifier: nil, children: [voteMenu, copy, selectText, shareMenu])
}
}

Expand Down Expand Up @@ -397,6 +414,17 @@ extension CommentsViewController: SwipeTableViewCellDelegate {
self.present(activityViewController, animated: true, completion: nil)
}

private func selectCommentText(at indexPath: IndexPath) {
let comment = self.commentsController.visibleComments[indexPath.row]
performSegue(withIdentifier: "ShowTextSelectionSegue", sender: comment.text)
}

private func copyComment(at indexPath: IndexPath) {
let comment = self.commentsController.visibleComments[indexPath.row]
let pasteboard = UIPasteboard.general
pasteboard.string = comment.text.parseToAttributedString().string
}

private func collapseAction() -> SwipeAction {
let collapseAction = SwipeAction(style: .default, title: "Collapse") { _, indexPath in
let comment = self.commentsController.visibleComments[indexPath.row]
Expand Down Expand Up @@ -517,3 +545,14 @@ extension CommentsViewController {
userActivity?.invalidate()
}
}

extension CommentsViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let comment = sender as? String,
segue.identifier == "ShowTextSelectionSegue",
let navVC = segue.destination as? UINavigationController,
let textSelectionViewController = navVC.children.first as? TextSelectionViewController {
textSelectionViewController.comment = comment
}
}
}
56 changes: 56 additions & 0 deletions App/Comments/TextSelectionViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// TextSelectionViewController.swift
// Hackers
//
// Created by Peter Ajayi on 08/07/2023.
// Copyright © 2023 Glass Umbrella. All rights reserved.
//

import UIKit

final class TextSelectionViewController: UIViewController {

var comment: String?

@IBOutlet private var commentTextView: UITextView!

override func viewDidLoad() {
super.viewDidLoad()
setup()
}

private func setup() {
view.backgroundColor = AppTheme.default.backgroundColor
setupCommentTextView()
}

private func setupCommentTextView() {
commentTextView.attributedText = attributedComment()
commentTextView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
commentTextView.textColor = AppTheme.default.textColor
commentTextView.selectAll(nil)
}

private func attributedComment() -> NSAttributedString? {
guard let comment = comment else { return nil }

let attributedString = comment.parseToAttributedString()

let commentRange = NSRange(location: 0, length: attributedString.length)
let commentFont = UIFont.preferredFont(forTextStyle: .subheadline)

attributedString.addAttribute(NSAttributedString.Key.font,
value: commentFont,
range: commentRange)

attributedString.addAttribute(NSAttributedString.Key.foregroundColor,
value: AppTheme.default.textColor,
range: commentRange)

return attributedString
}

@IBAction private func didPressDone(_ sender: Any) {
dismiss(animated: true)
}
}
15 changes: 15 additions & 0 deletions App/Extensions/StringExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import SwiftSoup

extension String {
subscript(value: PartialRangeUpTo<Int>) -> Substring {
Expand All @@ -20,4 +21,18 @@ extension String {
subscript(value: PartialRangeFrom<Int>) -> Substring {
return self[index(startIndex, offsetBy: value.lowerBound)...]
}

func parseToAttributedString() -> NSMutableAttributedString {
let paragraphIdentifier = "PARAGRAPH_NEED_NEW_LINES_HERE"

// swiftlint:disable unused_optional_binding
guard let document = try? SwiftSoup.parse(self),
let _ = try? document.select("p").before(paragraphIdentifier),
let text = try? document.text() else {
return NSMutableAttributedString()
}
// swiftlint:enable unused_optional_binding

return NSMutableAttributedString(string: text.replacingOccurrences(of: paragraphIdentifier + " ", with: "\n\n"))
}
}
68 changes: 68 additions & 0 deletions App/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,76 @@
</connections>
</barButtonItem>
</navigationItem>
<connections>
<segue destination="ozE-fK-sDZ" kind="presentation" identifier="ShowTextSelectionSegue" id="IIR-lL-SMT"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ZK9-xq-FV6" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4074" y="546"/>
</scene>
<!--Select Text Navigation Controller-->
<scene sceneID="x8d-A2-KEL">
<objects>
<navigationController title="Select Text" id="ozE-fK-sDZ" userLabel="Select Text Navigation Controller" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="vl6-C0-1Os">
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="iMC-4m-ZPQ" kind="relationship" relationship="rootViewController" id="mSf-15-Jv5"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="UQC-fj-N50" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4073" y="1397"/>
</scene>
<!--Text Selection View Controller-->
<scene sceneID="Kxi-mw-q0c">
<objects>
<viewController id="iMC-4m-ZPQ" customClass="TextSelectionViewController" customModule="Hackers" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="qem-z7-MD4">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" layoutMarginsFollowReadableWidth="YES" contentInsetAdjustmentBehavior="always" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ex9-nV-QsL">
<rect key="frame" x="0.0" y="56" width="375" height="591"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" name="appTintColor"/>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</string>
<color key="textColor" name="titleTextColor"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<viewLayoutGuide key="safeArea" id="6GH-Me-8qr"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="ex9-nV-QsL" firstAttribute="top" secondItem="6GH-Me-8qr" secondAttribute="top" id="28R-Oy-9el"/>
<constraint firstItem="6GH-Me-8qr" firstAttribute="trailing" secondItem="ex9-nV-QsL" secondAttribute="trailing" id="8M0-uA-971"/>
<constraint firstItem="6GH-Me-8qr" firstAttribute="bottom" secondItem="ex9-nV-QsL" secondAttribute="bottom" id="8cC-rF-95T"/>
<constraint firstItem="ex9-nV-QsL" firstAttribute="leading" secondItem="6GH-Me-8qr" secondAttribute="leading" id="sBQ-UH-2BG"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="as6-0R-MHp">
<barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="vLV-wD-oKW">
<color key="tintColor" name="titleTextColor"/>
<connections>
<action selector="didPressDone:" destination="iMC-4m-ZPQ" id="mLe-QH-ihC"/>
</connections>
</barButtonItem>
</navigationItem>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="title" value="Select Text"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="commentTextView" destination="ex9-nV-QsL" id="7Xb-R8-d1q"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="T4Z-We-8aE" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4916" y="1397"/>
</scene>
<!--Settings Navigation Controller-->
<scene sceneID="CQx-j9-MSt">
<objects>
Expand Down Expand Up @@ -728,6 +793,9 @@
<image name="PointsIcon" width="14" height="14"/>
<image name="gear" catalog="system" width="128" height="122"/>
<image name="safari" catalog="system" width="128" height="123"/>
<namedColor name="appTintColor">
<color red="0.396078431372549" green="0.074509803921568626" blue="0.89803921568627454" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="groupedTableViewBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
Expand Down
4 changes: 4 additions & 0 deletions Hackers.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
24FF021D226C9BEA002EF8DD /* SwinjectStoryboardExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FF021C226C9BEA002EF8DD /* SwinjectStoryboardExtensions.swift */; };
24FFFF5A23362C7800D009EF /* HackersKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFFF5923362C7800D009EF /* HackersKitExtensions.swift */; };
698FE7B523EE5FE300F5828C /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 698FE7B423EE5FE300F5828C /* Colors.xcassets */; };
8B782E032A5AB01C00FD6B39 /* TextSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B782E022A5AB01C00FD6B39 /* TextSelectionViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -219,6 +220,7 @@
24FF021C226C9BEA002EF8DD /* SwinjectStoryboardExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwinjectStoryboardExtensions.swift; sourceTree = "<group>"; };
24FFFF5923362C7800D009EF /* HackersKitExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackersKitExtensions.swift; sourceTree = "<group>"; };
698FE7B423EE5FE300F5828C /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
8B782E022A5AB01C00FD6B39 /* TextSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSelectionViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -444,6 +446,7 @@
2454B9031F655426005A98C7 /* EmptyViewController.swift */,
24D811A41FF90A58000951C3 /* TouchableTextView.swift */,
24191F8C1944C991003C0D98 /* CommentsController.swift */,
8B782E022A5AB01C00FD6B39 /* TextSelectionViewController.swift */,
);
path = Comments;
sourceTree = "<group>";
Expand Down Expand Up @@ -878,6 +881,7 @@
249B8F8322A2A48B002A9EC5 /* NotificationToken.swift in Sources */,
2481BD61247C11AE0088CA2B /* HackersKit+CommentVoting.swift in Sources */,
24D330CA248BAC4C00A2AA10 /* HackersKit+Authentication.swift in Sources */,
8B782E032A5AB01C00FD6B39 /* TextSelectionViewController.swift in Sources */,
24C20D391A7E42D5005B759B /* MainSplitViewController.swift in Sources */,
2464D21F209E27FE00C7F8FC /* UserDefaultsExtensions.swift in Sources */,
24CE5FF819435A90009D2677 /* PostCell.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Shared Frameworks/HackersKit/Models/Models.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Post: Hashable {
let url: URL
let title: String
let age: String
let commentsCount: Int
var commentsCount: Int
let by: String
var score: Int
let postType: PostType
Expand Down

0 comments on commit 99093c6

Please sign in to comment.