From dd71c0625748f155838e0d4b7c12e7b85e12830b Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 9 Jan 2022 18:34:17 -0500 Subject: [PATCH] Add item cell --- Reader.xcodeproj/project.pbxproj | 31 ++++++++ .../Items/ItemCollectionViewCell.swift | 70 +++++++++++++++++++ .../Screens/Items/ItemsViewController.swift | 12 ++-- 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 Reader/Screens/Items/ItemCollectionViewCell.swift diff --git a/Reader.xcodeproj/project.pbxproj b/Reader.xcodeproj/project.pbxproj index 78569af..633e429 100644 --- a/Reader.xcodeproj/project.pbxproj +++ b/Reader.xcodeproj/project.pbxproj @@ -40,6 +40,8 @@ D6E2435E278B97240005E546 /* Item+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E2435A278B97240005E546 /* Item+CoreDataProperties.swift */; }; D6E2435F278B97240005E546 /* Group+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E2435B278B97240005E546 /* Group+CoreDataClass.swift */; }; D6E24360278B97240005E546 /* Group+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E2435C278B97240005E546 /* Group+CoreDataProperties.swift */; }; + D6E24363278BA1410005E546 /* ItemCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E24361278BA1410005E546 /* ItemCollectionViewCell.swift */; }; + D6E24367278BA2660005E546 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = D6E24366278BA2660005E546 /* SwiftSoup */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -117,6 +119,7 @@ D6E2435A278B97240005E546 /* Item+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Item+CoreDataProperties.swift"; sourceTree = ""; }; D6E2435B278B97240005E546 /* Group+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Group+CoreDataClass.swift"; sourceTree = ""; }; D6E2435C278B97240005E546 /* Group+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Group+CoreDataProperties.swift"; sourceTree = ""; }; + D6E24361278BA1410005E546 /* ItemCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCollectionViewCell.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +128,7 @@ buildActionMask = 2147483647; files = ( D6C68829272CD2BA00874C10 /* Fervor.framework in Frameworks */, + D6E24367278BA2660005E546 /* SwiftSoup in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -270,6 +274,7 @@ isa = PBXGroup; children = ( D6E2434B278B456A0005E546 /* ItemsViewController.swift */, + D6E24361278BA1410005E546 /* ItemCollectionViewCell.swift */, ); path = Items; sourceTree = ""; @@ -303,6 +308,9 @@ D6C68828272CD2BA00874C10 /* PBXTargetDependency */, ); name = Reader; + packageProductDependencies = ( + D6E24366278BA2660005E546 /* SwiftSoup */, + ); productName = Reader; productReference = D6C687E8272CD27600874C10 /* Reader.app */; productType = "com.apple.product-type.application"; @@ -397,6 +405,9 @@ Base, ); mainGroup = D6C687DF272CD27600874C10; + packageReferences = ( + D6E24365278BA2660005E546 /* XCRemoteSwiftPackageReference "SwiftSoup" */, + ); productRefGroup = D6C687E9272CD27600874C10 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -460,6 +471,7 @@ D6E24358278B96E40005E546 /* Feed+CoreDataProperties.swift in Sources */, D65B18BE275051A1004A9448 /* LocalData.swift in Sources */, D65B18B22750469D004A9448 /* LoginViewController.swift in Sources */, + D6E24363278BA1410005E546 /* ItemCollectionViewCell.swift in Sources */, D65B18C127505348004A9448 /* HomeViewController.swift in Sources */, D6C687EE272CD27600874C10 /* SceneDelegate.swift in Sources */, ); @@ -896,6 +908,25 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + D6E24365278BA2660005E546 /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/scinfu/SwiftSoup"; + requirement = { + kind = upToNextMinorVersion; + minimumVersion = 2.3.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + D6E24366278BA2660005E546 /* SwiftSoup */ = { + isa = XCSwiftPackageProductDependency; + package = D6E24365278BA2660005E546 /* XCRemoteSwiftPackageReference "SwiftSoup" */; + productName = SwiftSoup; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ D6C687F4272CD27600874C10 /* Reader.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/Reader/Screens/Items/ItemCollectionViewCell.swift b/Reader/Screens/Items/ItemCollectionViewCell.swift new file mode 100644 index 0000000..fcadd68 --- /dev/null +++ b/Reader/Screens/Items/ItemCollectionViewCell.swift @@ -0,0 +1,70 @@ +// +// ItemCollectionViewCell.swift +// Reader +// +// Created by Shadowfacts on 1/9/22. +// + +import UIKit +import SwiftSoup + +class ItemCollectionViewCell: UICollectionViewCell { + + private let titleLabel = UILabel() + private let feedTitleLabel = UILabel() + private let contentLabel = UILabel() + + override init(frame: CGRect) { + super.init(frame: frame) + + let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title3).withSymbolicTraits(.traitBold)!.withDesign(.serif)! + titleLabel.font = UIFont(descriptor: descriptor, size: 0) + titleLabel.numberOfLines = 0 + + feedTitleLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .subheadline), size: 0) + feedTitleLabel.textColor = .tintColor + + contentLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).withDesign(.serif)!, size: 0) + contentLabel.textColor = UIColor(dynamicProvider: { traitCollection in + if traitCollection.userInterfaceStyle == .dark { + return .lightGray + } else { + return .darkGray + } + }) + contentLabel.numberOfLines = 0 + + let stack = UIStackView(arrangedSubviews: [ + titleLabel, + feedTitleLabel, + contentLabel, + ]) + stack.translatesAutoresizingMaskIntoConstraints = false + stack.spacing = 8 + stack.axis = .vertical + addSubview(stack) + NSLayoutConstraint.activate([ + stack.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + stack.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + stack.topAnchor.constraint(equalTo: topAnchor, constant: 8), + stack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func updateUI(item: Item) { + titleLabel.text = item.title + feedTitleLabel.text = item.feed!.title ?? item.feed!.url?.host + if let content = item.content { + let doc = try! SwiftSoup.parse(content) + contentLabel.text = try! doc.select("p").first()?.text() + } else { + contentLabel.text = "" + } + contentLabel.isHidden = contentLabel.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true + } + +} diff --git a/Reader/Screens/Items/ItemsViewController.swift b/Reader/Screens/Items/ItemsViewController.swift index 8ef89ba..6555d69 100644 --- a/Reader/Screens/Items/ItemsViewController.swift +++ b/Reader/Screens/Items/ItemsViewController.swift @@ -35,6 +35,7 @@ class ItemsViewController: UIViewController { let layout = UICollectionViewCompositionalLayout.list(using: configuration) collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout) collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + collectionView.register(ItemCollectionViewCell.self, forCellWithReuseIdentifier: "itemCell") view.addSubview(collectionView) dataSource = createDataSource() @@ -50,15 +51,10 @@ class ItemsViewController: UIViewController { } private func createDataSource() -> UICollectionViewDiffableDataSource { - let listCell = UICollectionView.CellRegistration { cell, indexPath, item in - var config = cell.defaultContentConfiguration() - config.text = item.title - cell.contentConfiguration = config - - cell.accessories = [.disclosureIndicator()] - } let dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in - return collectionView.dequeueConfiguredReusableCell(using: listCell, for: indexPath, item: item) + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "itemCell", for: indexPath) as! ItemCollectionViewCell + cell.updateUI(item: item) + return cell } return dataSource }