From fb3a5be6fd3d55be1f0ac0ad7800273adda7a253 Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Mon, 14 Sep 2020 00:20:25 -0700 Subject: [PATCH] content configuration wip --- Metatext.xcodeproj/project.pbxproj | 20 ++++++ .../StatusListViewController.swift | 14 ++-- Views/Status/StatusContentConfiguration.swift | 19 +++++ Views/Status/StatusListCell.swift | 20 ++++++ Views/Status/StatusView.swift | 69 +++++++++++++++++++ 5 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 Views/Status/StatusContentConfiguration.swift create mode 100644 Views/Status/StatusListCell.swift create mode 100644 Views/Status/StatusView.swift diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index bc4dadd..5454b56 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -13,6 +13,9 @@ D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; }; D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* AttachmentsView.swift */; }; D02E1F95250B13210071AD56 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02E1F94250B13210071AD56 /* SafariView.swift */; }; + D0625E59250F092900502611 /* StatusListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E58250F092900502611 /* StatusListCell.swift */; }; + D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */; }; + D0625E5F250F0CFF00502611 /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5E250F0CFF00502611 /* StatusView.swift */; }; D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; }; D0B32F50250B373600311912 /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B32F4F250B373600311912 /* RegistrationView.swift */; }; D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; }; @@ -88,6 +91,9 @@ D01F41E224F8889700D55A2D /* AttachmentsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentsView.swift; sourceTree = ""; }; D02E1F94250B13210071AD56 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = ""; }; D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D0625E58250F092900502611 /* StatusListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusListCell.swift; sourceTree = ""; }; + D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentConfiguration.swift; sourceTree = ""; }; + D0625E5E250F0CFF00502611 /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = ""; }; D0666A2124C677B400F3F04B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D0666A2524C677B400F3F04B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D085C3BB25008DEC008A6C5E /* DB */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DB; sourceTree = ""; }; @@ -221,6 +227,16 @@ name = Products; sourceTree = ""; }; + D0625E55250F086B00502611 /* Status */ = { + isa = PBXGroup; + children = ( + D0625E58250F092900502611 /* StatusListCell.swift */, + D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */, + D0625E5E250F0CFF00502611 /* StatusView.swift */, + ); + path = Status; + sourceTree = ""; + }; D0666A2224C677B400F3F04B /* Tests */ = { isa = PBXGroup; children = ( @@ -248,6 +264,7 @@ D0C7D42024F76169001EBDBB /* Views */ = { isa = PBXGroup; children = ( + D0625E55250F086B00502611 /* Status */, D0C7D42424F76169001EBDBB /* AddIdentityView.swift */, D01F41E024F8885900D55A2D /* Attachments */, D0C7D42324F76169001EBDBB /* CustomEmojiText.swift */, @@ -491,11 +508,14 @@ D02E1F95250B13210071AD56 /* SafariView.swift in Sources */, D0C7D49C24F7616A001EBDBB /* RootView.swift in Sources */, D0B32F50250B373600311912 /* RegistrationView.swift in Sources */, + D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */, D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */, D0C7D49A24F7616A001EBDBB /* StatusListView.swift in Sources */, D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */, D0C7D4A524F7616A001EBDBB /* StatusListViewController.swift in Sources */, D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */, + D0625E5F250F0CFF00502611 /* StatusView.swift in Sources */, + D0625E59250F092900502611 /* StatusListCell.swift in Sources */, D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */, D0C7D49E24F7616A001EBDBB /* SecondaryNavigationView.swift in Sources */, D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */, diff --git a/View Controllers/StatusListViewController.swift b/View Controllers/StatusListViewController.swift index ac5a811..1c0f934 100644 --- a/View Controllers/StatusListViewController.swift +++ b/View Controllers/StatusListViewController.swift @@ -17,12 +17,12 @@ final class StatusListViewController: UITableViewController { guard let self = self, let cell = tableView.dequeueReusableCell( - withIdentifier: String(describing: StatusTableViewCell.self), - for: indexPath) as? StatusTableViewCell + withIdentifier: String(describing: StatusListCell.self), + for: indexPath) as? StatusListCell else { return nil } cell.viewModel = self.viewModel.statusViewModel(id: statusID) - cell.delegate = self +// cell.delegate = self return cell } @@ -42,17 +42,11 @@ final class StatusListViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() - for cellClass in [StatusTableViewCell.self] { - let classString = String(describing: cellClass) - tableView.register( - UINib(nibName: classString, bundle: nil), - forCellReuseIdentifier: classString) - } + tableView.register(StatusListCell.self, forCellReuseIdentifier: String(describing: StatusListCell.self)) tableView.dataSource = dataSource tableView.prefetchDataSource = self tableView.cellLayoutMarginsFollowReadableWidth = true - tableView.separatorInset = .zero tableView.tableFooterView = UIView() viewModel.$statusIDs diff --git a/Views/Status/StatusContentConfiguration.swift b/Views/Status/StatusContentConfiguration.swift new file mode 100644 index 0000000..51cc70a --- /dev/null +++ b/Views/Status/StatusContentConfiguration.swift @@ -0,0 +1,19 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import UIKit +import ViewModels + +struct StatusContentConfiguration { + let viewModel: StatusViewModel +} + +extension StatusContentConfiguration: UIContentConfiguration { + func makeContentView() -> UIView & UIContentView { + StatusView(configuration: self) + } + + func updated(for state: UIConfigurationState) -> StatusContentConfiguration { + // TODO: Update stuff? + self + } +} diff --git a/Views/Status/StatusListCell.swift b/Views/Status/StatusListCell.swift new file mode 100644 index 0000000..70c478a --- /dev/null +++ b/Views/Status/StatusListCell.swift @@ -0,0 +1,20 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import UIKit +import ViewModels + +class StatusListCell: UITableViewCell { + var viewModel: StatusViewModel? + + override func updateConfiguration(using state: UICellConfigurationState) { + guard let viewModel = viewModel else { return } + + contentConfiguration = StatusContentConfiguration(viewModel: viewModel).updated(for: state) + } + + override func layoutSubviews() { + super.layoutSubviews() + + separatorInset.left = UIDevice.current.userInterfaceIdiom == .phone ? 0 : layoutMargins.left + } +} diff --git a/Views/Status/StatusView.swift b/Views/Status/StatusView.swift new file mode 100644 index 0000000..b0458fd --- /dev/null +++ b/Views/Status/StatusView.swift @@ -0,0 +1,69 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import UIKit + +class StatusView: UIView { + private var statusConfiguration: StatusContentConfiguration + + private let content = TouchFallthroughTextView() + + init(configuration: StatusContentConfiguration) { + self.statusConfiguration = configuration + + super.init(frame: .zero) + + setup() + applyStatusConfiguration() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension StatusView: UIContentView { + var configuration: UIContentConfiguration { + get { statusConfiguration } + set { + guard let statusConfiguration = newValue as? StatusContentConfiguration else { return } + + self.statusConfiguration = statusConfiguration + + applyStatusConfiguration() + } + } +} + +private extension StatusView { + func setup() { + addSubview(content) + content.translatesAutoresizingMaskIntoConstraints = false + content.isScrollEnabled = false + content.isEditable = false + content.backgroundColor = .clear + NSLayoutConstraint.activate([ + content.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor), + content.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), + content.topAnchor.constraint(equalTo: readableContentGuide.topAnchor), + content.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor) + ]) + } + + func applyStatusConfiguration() { + let viewModel = statusConfiguration.viewModel + let mutableContent = NSMutableAttributedString(attributedString: viewModel.content) + let contentFont = UIFont.preferredFont(forTextStyle: viewModel.isContextParent ? .title3 : .callout) + + let contentRange = NSRange(location: 0, length: mutableContent.length) + mutableContent.removeAttribute(.font, range: contentRange) + mutableContent.addAttributes( + [.font: contentFont as Any, + .foregroundColor: UIColor.label], + range: contentRange) + mutableContent.insert(emoji: viewModel.contentEmoji, view: content) + mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight) + content.attributedText = mutableContent +// content.isHidden = contentTextView.text == "" + } +}