From 4426f84df431ec6f3461d204af334aea99218d7b Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Thu, 7 Jan 2021 22:11:33 -0800 Subject: [PATCH] Refactoring --- .../CompositionAttachmentsDataSource.swift | 34 ------ Metatext.xcodeproj/project.pbxproj | 48 +++----- View Controllers/TableViewController.swift | 60 ++-------- .../ViewModels/AttachmentViewModel.swift | 18 ++- .../AttachmentsRenderingViewModel.swift | 23 ++++ .../CompositionAttachmentViewModel.swift | 14 --- .../ViewModels/CompositionViewModel.swift | 22 ++-- .../Sources/ViewModels/StatusViewModel.swift | 4 +- ...achmentView.swift => AttachmentView.swift} | 50 ++++++-- ...hmentsView.swift => AttachmentsView.swift} | 52 ++++---- ...positionAttachmentCollectionViewCell.swift | 19 --- ...sitionAttachmentContentConfiguration.swift | 19 --- Views/CompositionAttachmentView.swift | 112 ------------------ Views/CompositionView.swift | 44 +------ Views/Status/StatusBodyView.swift | 2 +- 15 files changed, 142 insertions(+), 379 deletions(-) delete mode 100644 Data Sources/CompositionAttachmentsDataSource.swift create mode 100644 ViewModels/Sources/ViewModels/AttachmentsRenderingViewModel.swift delete mode 100644 ViewModels/Sources/ViewModels/CompositionAttachmentViewModel.swift rename Views/{Status/StatusAttachmentView.swift => AttachmentView.swift} (78%) rename Views/{Status/StatusAttachmentsView.swift => AttachmentsView.swift} (78%) delete mode 100644 Views/CompositionAttachmentCollectionViewCell.swift delete mode 100644 Views/CompositionAttachmentContentConfiguration.swift delete mode 100644 Views/CompositionAttachmentView.swift diff --git a/Data Sources/CompositionAttachmentsDataSource.swift b/Data Sources/CompositionAttachmentsDataSource.swift deleted file mode 100644 index 822775e..0000000 --- a/Data Sources/CompositionAttachmentsDataSource.swift +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Mastodon -import UIKit -import ViewModels - -final class CompositionAttachmentsDataSource: UICollectionViewDiffableDataSource { - private let updateQueue = - DispatchQueue(label: "com.metabolist.metatext.composition-attachments-data-source.update-queue") - - init(collectionView: UICollectionView, - viewModelProvider: @escaping (IndexPath) -> (CompositionAttachmentViewModel, CompositionViewModel)) { - let registration = UICollectionView.CellRegistration - { - $0.viewModel = $2.0 - $0.parentViewModel = $2.1 - } - - super.init(collectionView: collectionView) { collectionView, indexPath, _ in - collectionView.dequeueConfiguredReusableCell( - using: registration, - for: indexPath, - item: viewModelProvider(indexPath)) - } - } - - override func apply(_ snapshot: NSDiffableDataSourceSnapshot, - animatingDifferences: Bool = true, - completion: (() -> Void)? = nil) { - updateQueue.async { - super.apply(snapshot, animatingDifferences: animatingDifferences, completion: completion) - } - } -} diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index b2b0713..721f891 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -14,10 +14,14 @@ D007023E25562A2800F38136 /* ConversationAvatarsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007023D25562A2800F38136 /* ConversationAvatarsView.swift */; }; D0070252255921B100F38136 /* AccountFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0070251255921B100F38136 /* AccountFieldView.swift */; }; D00CB2ED2533ACC00080096B /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00CB2EC2533ACC00080096B /* StatusView.swift */; }; + D015B13525A812DD006D88A8 /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* AttachmentsView.swift */; }; + D015B13A25A812E6006D88A8 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; }; + D015B13F25A812EC006D88A8 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FE1C8E253686F9003EF1EB /* PlayerView.swift */; }; + D015B14425A812F6006D88A8 /* PlayerCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FE1C9725368A9D003EF1EB /* PlayerCache.swift */; }; D01C6FAC252024BD003D0300 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C6FAB252024BD003D0300 /* Array+Extensions.swift */; }; D01EF22425182B1F00650C6B /* AccountHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01EF22325182B1F00650C6B /* AccountHeaderView.swift */; }; D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; }; - D01F41E424F8889700D55A2D /* StatusAttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* StatusAttachmentsView.swift */; }; + D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* AttachmentsView.swift */; }; D02E1F95250B13210071AD56 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02E1F94250B13210071AD56 /* SafariView.swift */; }; D036AA02254B6101009094DF /* NotificationListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036AA01254B6101009094DF /* NotificationListCell.swift */; }; D036AA07254B6118009094DF /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036AA06254B6118009094DF /* NotificationView.swift */; }; @@ -34,15 +38,7 @@ D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D04F9E8D259E9C950081B0C9 /* ViewModels */; }; D0625E59250F092900502611 /* StatusListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E58250F092900502611 /* StatusListCell.swift */; }; D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */; }; - D065965B25899DAE0096AC5D /* CompositionAttachmentsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D065965A25899DAE0096AC5D /* CompositionAttachmentsDataSource.swift */; }; - D065966125899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D065966025899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift */; }; - D065966225899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D065966025899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift */; }; - D065966725899E910096AC5D /* CompositionAttachmentsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D065965A25899DAE0096AC5D /* CompositionAttachmentsDataSource.swift */; }; D06BC5E625202AD90079541D /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06BC5E525202AD90079541D /* ProfileViewController.swift */; }; - D0804133258D902900AD6139 /* CompositionAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0804132258D902900AD6139 /* CompositionAttachmentView.swift */; }; - D0804134258D902900AD6139 /* CompositionAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0804132258D902900AD6139 /* CompositionAttachmentView.swift */; }; - D080413E258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D080413D258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift */; }; - D080413F258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D080413D258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift */; }; D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0849C7E25903C4900A5EBCC /* Status+Extensions.swift */; }; D08B8D3D253F929E00B1EBEF /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B8D3C253F929E00B1EBEF /* ImageViewController.swift */; }; D08B8D42253F92B600B1EBEF /* ImagePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B8D41253F92B600B1EBEF /* ImagePageViewController.swift */; }; @@ -69,7 +65,7 @@ D0B32F50250B373600311912 /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B32F4F250B373600311912 /* RegistrationView.swift */; }; D0B5FE9B251583DB00478838 /* ProfileCollection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */; }; D0B8510C25259E56004E0744 /* LoadMoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8510B25259E56004E0744 /* LoadMoreCell.swift */; }; - D0BEB1F324F8EE8C001B0F04 /* StatusAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */; }; + D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; }; D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; }; D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1FE24F9E5BB001B0F04 /* ListsView.swift */; }; D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20424FA1107001B0F04 /* FiltersView.swift */; }; @@ -176,7 +172,7 @@ D01C6FAB252024BD003D0300 /* Array+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = ""; }; D01EF22325182B1F00650C6B /* AccountHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountHeaderView.swift; sourceTree = ""; }; D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchFallthroughTextView.swift; sourceTree = ""; }; - D01F41E224F8889700D55A2D /* StatusAttachmentsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusAttachmentsView.swift; sourceTree = ""; }; + 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 = ""; }; D036AA01254B6101009094DF /* NotificationListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationListCell.swift; sourceTree = ""; }; D036AA06254B6118009094DF /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; @@ -187,13 +183,9 @@ 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 = ""; }; - D065965A25899DAE0096AC5D /* CompositionAttachmentsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionAttachmentsDataSource.swift; sourceTree = ""; }; - D065966025899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionAttachmentCollectionViewCell.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 = ""; }; D06BC5E525202AD90079541D /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; - D0804132258D902900AD6139 /* CompositionAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionAttachmentView.swift; sourceTree = ""; }; - D080413D258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionAttachmentContentConfiguration.swift; sourceTree = ""; }; D0849C7E25903C4900A5EBCC /* Status+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Status+Extensions.swift"; sourceTree = ""; }; D085C3BB25008DEC008A6C5E /* DB */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DB; sourceTree = ""; }; D08B8D3C253F929E00B1EBEF /* ImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewController.swift; sourceTree = ""; }; @@ -222,7 +214,7 @@ D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileCollection+Extensions.swift"; sourceTree = ""; }; D0B8510B25259E56004E0744 /* LoadMoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreCell.swift; sourceTree = ""; }; D0BDF66524FD7A6400C7FA1C /* ServiceLayer */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ServiceLayer; sourceTree = ""; }; - D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusAttachmentView.swift; sourceTree = ""; }; + D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = ""; }; D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingTableFooterView.swift; sourceTree = ""; }; D0BEB1FE24F9E5BB001B0F04 /* ListsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsView.swift; sourceTree = ""; }; D0BEB20424FA1107001B0F04 /* FiltersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersView.swift; sourceTree = ""; }; @@ -366,8 +358,6 @@ isa = PBXGroup; children = ( D0EA593F2522AC8700804347 /* CardView.swift */, - D01F41E224F8889700D55A2D /* StatusAttachmentsView.swift */, - D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */, D036AA16254CA823009094DF /* StatusBodyView.swift */, D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */, D0625E58250F092900502611 /* StatusListCell.swift */, @@ -419,7 +409,6 @@ isa = PBXGroup; children = ( D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */, - D065965A25899DAE0096AC5D /* CompositionAttachmentsDataSource.swift */, ); path = "Data Sources"; sourceTree = ""; @@ -442,10 +431,9 @@ D0F0B125251A90F400942152 /* AccountListCell.swift */, D0F0B10D251A868200942152 /* AccountView.swift */, D0C7D42424F76169001EBDBB /* AddIdentityView.swift */, + D01F41E224F8889700D55A2D /* AttachmentsView.swift */, D0CE9F86258B076900E3A6B6 /* AttachmentUploadView.swift */, - D065966025899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift */, - D080413D258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift */, - D0804132258D902900AD6139 /* CompositionAttachmentView.swift */, + D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */, D0E9F9A9258450B300EF503D /* CompositionInputAccessoryView.swift */, D08E52ED257D757100FA2C5F /* CompositionView.swift */, D007023D25562A2800F38136 /* ConversationAvatarsView.swift */, @@ -767,7 +755,6 @@ D0C7D49C24F7616A001EBDBB /* RootView.swift in Sources */, D0F0B126251A90F400942152 /* AccountListCell.swift in Sources */, D0B32F50250B373600311912 /* RegistrationView.swift in Sources */, - D0804133258D902900AD6139 /* CompositionAttachmentView.swift in Sources */, D08B8D612540DE3B00B1EBEF /* ZoomDismissalInteractionController.swift in Sources */, D036AA07254B6118009094DF /* NotificationView.swift in Sources */, D08E52EE257D757100FA2C5F /* CompositionView.swift in Sources */, @@ -777,7 +764,7 @@ D007023E25562A2800F38136 /* ConversationAvatarsView.swift in Sources */, D0E7AD3925870B13005F5E2D /* UIVIewController+Extensions.swift in Sources */, D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */, - D0BEB1F324F8EE8C001B0F04 /* StatusAttachmentView.swift in Sources */, + D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */, D0C7D49A24F7616A001EBDBB /* TableView.swift in Sources */, D08B8D622540DE3B00B1EBEF /* ZoomTransitionController.swift in Sources */, D0F0B12E251A97E400942152 /* TableViewController.swift in Sources */, @@ -791,7 +778,6 @@ D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */, D0E9F9AA258450B300EF503D /* CompositionInputAccessoryView.swift in Sources */, D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */, - D080413E258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift in Sources */, D0625E59250F092900502611 /* StatusListCell.swift in Sources */, D0E569DB2529319100FA1D72 /* LoadMoreView.swift in Sources */, D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */, @@ -818,16 +804,14 @@ D036AA17254CA824009094DF /* StatusBodyView.swift in Sources */, D08E512125786A6600FA2C5F /* UIButton+Extensions.swift in Sources */, D0EA59482522B8B600804347 /* ViewConstants.swift in Sources */, - D065965B25899DAE0096AC5D /* CompositionAttachmentsDataSource.swift in Sources */, D04226FD2546AC0B000980A3 /* StartupAndSyncingPreferencesView.swift in Sources */, D036AA0C254B612B009094DF /* NotificationContentConfiguration.swift in Sources */, D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */, D08B8D3D253F929E00B1EBEF /* ImageViewController.swift in Sources */, D0B8510C25259E56004E0744 /* LoadMoreCell.swift in Sources */, D08E52612579D2E100FA2C5F /* DomainBlocksView.swift in Sources */, - D01F41E424F8889700D55A2D /* StatusAttachmentsView.swift in Sources */, + D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */, D00702312555F4AE00F38136 /* ConversationView.swift in Sources */, - D065966125899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift in Sources */, D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */, D08B8D4A253FC36500B1EBEF /* ImageNavigationController.swift in Sources */, D0070252255921B100F38136 /* AccountFieldView.swift in Sources */, @@ -866,16 +850,16 @@ D038273C259EA38F00056E0F /* NewStatusView.swift in Sources */, D08E52EF257D757100FA2C5F /* CompositionView.swift in Sources */, D0CE9F88258B076900E3A6B6 /* AttachmentUploadView.swift in Sources */, - D080413F258D904400AD6139 /* CompositionAttachmentContentConfiguration.swift in Sources */, D08E52C7257C7AEE00FA2C5F /* ShareErrorViewController.swift in Sources */, + D015B14425A812F6006D88A8 /* PlayerCache.swift in Sources */, + D015B13F25A812EC006D88A8 /* PlayerView.swift in Sources */, + D015B13A25A812E6006D88A8 /* AttachmentView.swift in Sources */, D08E52F8257D78BE00FA2C5F /* ViewConstants.swift in Sources */, D036EBC2259FE2AD00EC1CFC /* UIVIewController+Extensions.swift in Sources */, - D065966725899E910096AC5D /* CompositionAttachmentsDataSource.swift in Sources */, + D015B13525A812DD006D88A8 /* AttachmentsView.swift in Sources */, D0FCC106259C4E62000B67DF /* NewStatusViewController.swift in Sources */, D036EBBD259FE2A100EC1CFC /* Array+Extensions.swift in Sources */, D036EBB3259FE28800EC1CFC /* UIColor+Extensions.swift in Sources */, - D0804134258D902900AD6139 /* CompositionAttachmentView.swift in Sources */, - D065966225899E890096AC5D /* CompositionAttachmentCollectionViewCell.swift in Sources */, D036EBB8259FE29800EC1CFC /* Status+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/View Controllers/TableViewController.swift b/View Controllers/TableViewController.swift index a87445c..7fe6850 100644 --- a/View Controllers/TableViewController.swift +++ b/View Controllers/TableViewController.swift @@ -6,7 +6,6 @@ import SafariServices import SwiftUI import ViewModels -// swiftlint:disable file_length class TableViewController: UITableViewController { var transitionViewTag = -1 @@ -16,6 +15,7 @@ class TableViewController: UITableViewController { private let webfingerIndicatorView = WebfingerIndicatorView() private var cancellables = Set() private var cellHeightCaches = [CGFloat: [CollectionItem: CGFloat]]() + private var shouldKeepPlayingVideoAfterDismissal = false private lazy var dataSource: TableViewDataSource = { .init(tableView: tableView, viewModelProvider: viewModel.viewModel(indexPath:)) @@ -59,18 +59,6 @@ class TableViewController: UITableViewController { viewModel.request(maxId: nil, minId: nil) } - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - updateAutoplayViews() - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - updateAutoplayViews() - } - override func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView.isDragging else { return } @@ -79,8 +67,6 @@ class TableViewController: UITableViewController { for loadMoreView in visibleLoadMoreViews { loadMoreView.directionChanged(up: up) } - - updateAutoplayViews() } override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { @@ -124,10 +110,6 @@ class TableViewController: UITableViewController { } extension TableViewController { - static let autoplayableAttachmentsView = PassthroughSubject() - static let autoplayableAttachmentsViewNotification = - Notification.Name("com.metabolist.metatext.attachment-view-became-autoplayable") - func report(viewModel: ReportViewModel) { let reportViewController = ReportViewController(viewModel: viewModel) let navigationController = UINavigationController(rootViewController: reportViewController) @@ -188,7 +170,12 @@ extension TableViewController: AVPlayerViewControllerDelegate { willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { try? AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default) playerViewController.player?.isMuted = true - updateAutoplayViews() + + coordinator.animate(alongsideTransition: nil) { _ in + if self.shouldKeepPlayingVideoAfterDismissal { + playerViewController.player?.play() + } + } } } @@ -267,17 +254,6 @@ private extension TableViewController { .compactMap { [weak self] _ in self?.tableView.indexPathsForVisibleRows?.first } .sink { [weak self] in self?.viewModel.viewedAtTop(indexPath: $0) } .store(in: &cancellables) - - Self.autoplayableAttachmentsView - .removeDuplicates() - .sink { - let notification = Notification( - name: Self.autoplayableAttachmentsViewNotification, - object: $0, - userInfo: nil) - NotificationCenter.default.post(notification) - } - .store(in: &cancellables) } func update(_ update: CollectionUpdate) { @@ -313,8 +289,6 @@ private extension TableViewController { self.tableView.contentOffset.y -= offsetFromNavigationBar } } - - self.updateAutoplayViews() } } @@ -369,6 +343,8 @@ private extension TableViewController { playerViewController.delegate = self playerViewController.player = player + shouldKeepPlayingVideoAfterDismissal = attachmentViewModel.shouldAutoplay + present(playerViewController, animated: true) { try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) player.isMuted = false @@ -411,22 +387,4 @@ private extension TableViewController { present(activityViewController, animated: true, completion: nil) } - - func updateAutoplayViews() { - if let visibleView = navigationController?.visibleViewController?.view, - view.isDescendant(of: visibleView), - let superview = view.superview, - let attachmentsViewClosestToCenter = tableView.visibleCells - .compactMap({ ($0.contentView as? StatusView)?.bodyView.attachmentsView }) - .filter(\.shouldAutoplay) - .min(by: { - abs(superview.convert($0.frame, from: $0.superview).midY - view.frame.midY) - < abs(superview.convert($1.frame, from: $1.superview).midY - view.frame.midY) - }) { - Self.autoplayableAttachmentsView.send(attachmentsViewClosestToCenter) - } else { - Self.autoplayableAttachmentsView.send(nil) - } - } } -// swiftlint:enable file_length diff --git a/ViewModels/Sources/ViewModels/AttachmentViewModel.swift b/ViewModels/Sources/ViewModels/AttachmentViewModel.swift index 56b4f33..7b959fd 100644 --- a/ViewModels/Sources/ViewModels/AttachmentViewModel.swift +++ b/ViewModels/Sources/ViewModels/AttachmentViewModel.swift @@ -4,22 +4,22 @@ import Foundation import Mastodon import Network -public struct AttachmentViewModel { +public final class AttachmentViewModel: ObservableObject { public let attachment: Attachment - private let status: Status private let identification: Identification + private let status: Status? - init(attachment: Attachment, status: Status, identification: Identification) { + init(attachment: Attachment, identification: Identification, status: Status? = nil) { self.attachment = attachment - self.status = status self.identification = identification + self.status = status } } public extension AttachmentViewModel { var tag: Int { - attachment.id.appending(status.id).hashValue + attachment.id.appending(status?.id ?? "").hashValue } var shouldAutoplay: Bool { @@ -38,5 +38,11 @@ public extension AttachmentViewModel { } private extension AttachmentViewModel { - static let wifiMonitor = NWPathMonitor(requiredInterfaceType: .wifi) + static var wifiMonitor: NWPathMonitor = { + let monitor = NWPathMonitor(requiredInterfaceType: .wifi) + + monitor.start(queue: .main) + + return monitor + }() } diff --git a/ViewModels/Sources/ViewModels/AttachmentsRenderingViewModel.swift b/ViewModels/Sources/ViewModels/AttachmentsRenderingViewModel.swift new file mode 100644 index 0000000..3b00c5d --- /dev/null +++ b/ViewModels/Sources/ViewModels/AttachmentsRenderingViewModel.swift @@ -0,0 +1,23 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +public protocol AttachmentsRenderingViewModel { + var attachmentViewModels: [AttachmentViewModel] { get } + var shouldShowAttachments: Bool { get } + var shouldShowHideAttachmentsButton: Bool { get } + var sensitive: Bool { get } + var canRemoveAttachments: Bool { get } + func attachmentSelected(viewModel: AttachmentViewModel) + func removeAttachment(viewModel: AttachmentViewModel) + func toggleShowAttachments() +} + +public extension AttachmentsRenderingViewModel { + var shouldShowAttachments: Bool { true } + var shouldShowHideAttachmentsButton: Bool { false } + var sensitive: Bool { false } + var canRemoveAttachments: Bool { false } + func removeAttachment(viewModel: AttachmentViewModel) {} + func toggleShowAttachments() {} +} diff --git a/ViewModels/Sources/ViewModels/CompositionAttachmentViewModel.swift b/ViewModels/Sources/ViewModels/CompositionAttachmentViewModel.swift deleted file mode 100644 index c6c06e4..0000000 --- a/ViewModels/Sources/ViewModels/CompositionAttachmentViewModel.swift +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Combine -import Foundation -import Mastodon -import ServiceLayer - -public final class CompositionAttachmentViewModel: ObservableObject { - public let attachment: Attachment - - init(attachment: Attachment) { - self.attachment = attachment - } -} diff --git a/ViewModels/Sources/ViewModels/CompositionViewModel.swift b/ViewModels/Sources/ViewModels/CompositionViewModel.swift index 02c22b9..081ea79 100644 --- a/ViewModels/Sources/ViewModels/CompositionViewModel.swift +++ b/ViewModels/Sources/ViewModels/CompositionViewModel.swift @@ -5,18 +5,19 @@ import Foundation import Mastodon import ServiceLayer -public final class CompositionViewModel: ObservableObject, Identifiable { +public final class CompositionViewModel: AttachmentsRenderingViewModel, ObservableObject, Identifiable { public let id = Id() public var isPosted = false @Published public var text = "" @Published public var contentWarning = "" @Published public var displayContentWarning = false - @Published public private(set) var attachmentViewModels = [CompositionAttachmentViewModel]() + @Published public private(set) var attachmentViewModels = [AttachmentViewModel]() @Published public private(set) var attachmentUpload: AttachmentUpload? @Published public private(set) var isPostable = false @Published public private(set) var canAddAttachment = true @Published public private(set) var canAddNonImageAttachment = true @Published public private(set) var remainingCharacters = CompositionViewModel.maxCharacters + public let canRemoveAttachments = true private var attachmentUploadCancellable: AnyCancellable? @@ -42,6 +43,14 @@ public final class CompositionViewModel: ObservableObject, Identifiable { .map { Self.maxCharacters - ($0 + ($1 ? $2.count : 0)) } .assign(to: &$remainingCharacters) } + + public func attachmentSelected(viewModel: AttachmentViewModel) { + + } + + public func removeAttachment(viewModel: AttachmentViewModel) { + attachmentViewModels.removeAll { $0 === viewModel } + } } public extension CompositionViewModel { @@ -64,10 +73,6 @@ public extension CompositionViewModel { visibility: visibility) } - func remove(attachmentViewModel: CompositionAttachmentViewModel) { - attachmentViewModels.removeAll { $0 === attachmentViewModel } - } - func cancelUpload() { attachmentUploadCancellable?.cancel() } @@ -96,7 +101,10 @@ extension CompositionViewModel { .sink { [weak self] _ in self?.attachmentUpload = nil } receiveValue: { [weak self] in - self?.attachmentViewModels.append(CompositionAttachmentViewModel(attachment: $0)) + self?.attachmentViewModels.append( + AttachmentViewModel( + attachment: $0, + identification: parentViewModel.identification)) } } } diff --git a/ViewModels/Sources/ViewModels/StatusViewModel.swift b/ViewModels/Sources/ViewModels/StatusViewModel.swift index f52900f..ffb0800 100644 --- a/ViewModels/Sources/ViewModels/StatusViewModel.swift +++ b/ViewModels/Sources/ViewModels/StatusViewModel.swift @@ -5,7 +5,7 @@ import Foundation import Mastodon import ServiceLayer -public final class StatusViewModel: CollectionItemViewModel, ObservableObject { +public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderingViewModel, ObservableObject { public let content: NSAttributedString public let contentEmoji: [Emoji] public let displayName: String @@ -40,7 +40,7 @@ public final class StatusViewModel: CollectionItemViewModel, ObservableObject { : statusService.status.account.displayName rebloggedByDisplayNameEmoji = statusService.status.account.emojis attachmentViewModels = statusService.status.displayStatus.mediaAttachments - .map { AttachmentViewModel(attachment: $0, status: statusService.status, identification: identification) } + .map { AttachmentViewModel(attachment: $0, identification: identification, status: statusService.status) } pollEmoji = statusService.status.displayStatus.poll?.emojis ?? [] events = eventsSubject.eraseToAnyPublisher() } diff --git a/Views/Status/StatusAttachmentView.swift b/Views/AttachmentView.swift similarity index 78% rename from Views/Status/StatusAttachmentView.swift rename to Views/AttachmentView.swift index 8de86da..da43827 100644 --- a/Views/Status/StatusAttachmentView.swift +++ b/Views/AttachmentView.swift @@ -5,10 +5,11 @@ import Kingfisher import UIKit import ViewModels -final class StatusAttachmentView: UIView { +final class AttachmentView: UIView { let playerView = PlayerView() let imageView = AnimatedImageView() - let button = UIButton() + let removeButton = UIButton(type: .close) + let selectionButton = UIButton() var playing: Bool = false { didSet { @@ -25,10 +26,12 @@ final class StatusAttachmentView: UIView { } private let viewModel: AttachmentViewModel + private let parentViewModel: AttachmentsRenderingViewModel private var playerLooper: AVPlayerLooper? - init(viewModel: AttachmentViewModel) { + init(viewModel: AttachmentViewModel, parentViewModel: AttachmentsRenderingViewModel) { self.viewModel = viewModel + self.parentViewModel = parentViewModel super.init(frame: .zero) @@ -72,7 +75,7 @@ final class StatusAttachmentView: UIView { } } -extension StatusAttachmentView { +extension AttachmentView { func play() { let player = PlayerCache.shared.player(url: viewModel.attachment.url) @@ -105,7 +108,7 @@ extension StatusAttachmentView { } } -private extension StatusAttachmentView { +private extension AttachmentView { static var playerLooperCache = [AVQueuePlayer: AVPlayerLooper]() // swiftlint:disable:next function_body_length @@ -139,9 +142,30 @@ private extension StatusAttachmentView { playerView.videoGravity = .resizeAspectFill playerView.isHidden = true - addSubview(button) - button.translatesAutoresizingMaskIntoConstraints = false - button.setBackgroundImage(.highlightedButtonBackground, for: .highlighted) + addSubview(selectionButton) + selectionButton.translatesAutoresizingMaskIntoConstraints = false + selectionButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted) + selectionButton.addAction( + UIAction { [weak self] _ in + guard let self = self else { return } + + self.parentViewModel.attachmentSelected(viewModel: self.viewModel) + }, + for: .touchUpInside) + + addSubview(removeButton) + removeButton.translatesAutoresizingMaskIntoConstraints = false + removeButton.showsMenuAsPrimaryAction = true + removeButton.menu = UIMenu( + children: [ + UIAction( + title: NSLocalizedString("remove", comment: ""), + image: UIImage(systemName: "trash"), + attributes: .destructive) { [weak self] _ in + guard let self = self else { return } + + self.parentViewModel.removeAttachment(viewModel: self.viewModel) + }]) switch viewModel.attachment.type { case .image, .video, .gifv: @@ -183,10 +207,12 @@ private extension StatusAttachmentView { equalTo: playView.topAnchor, constant: .compactSpacing), playImageView.leadingAnchor.constraint( equalTo: playView.leadingAnchor, constant: .compactSpacing), - button.leadingAnchor.constraint(equalTo: leadingAnchor), - button.trailingAnchor.constraint(equalTo: trailingAnchor), - button.topAnchor.constraint(equalTo: topAnchor), - button.bottomAnchor.constraint(equalTo: bottomAnchor) + selectionButton.leadingAnchor.constraint(equalTo: leadingAnchor), + selectionButton.trailingAnchor.constraint(equalTo: trailingAnchor), + selectionButton.topAnchor.constraint(equalTo: topAnchor), + selectionButton.bottomAnchor.constraint(equalTo: bottomAnchor), + removeButton.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor), + removeButton.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor) ]) } } diff --git a/Views/Status/StatusAttachmentsView.swift b/Views/AttachmentsView.swift similarity index 78% rename from Views/Status/StatusAttachmentsView.swift rename to Views/AttachmentsView.swift index 2d915c7..d17a204 100644 --- a/Views/Status/StatusAttachmentsView.swift +++ b/Views/AttachmentsView.swift @@ -4,7 +4,7 @@ import Combine import UIKit import ViewModels -final class StatusAttachmentsView: UIView { +final class AttachmentsView: UIView { private let containerStackView = UIStackView() private let leftStackView = UIStackView() private let rightStackView = UIStackView() @@ -15,7 +15,7 @@ final class StatusAttachmentsView: UIView { private var aspectRatioConstraint: NSLayoutConstraint? private var cancellables = Set() - var viewModel: StatusViewModel? { + var viewModel: AttachmentsRenderingViewModel? { didSet { for stackView in [leftStackView, rightStackView] { for view in stackView.arrangedSubviews { @@ -24,21 +24,18 @@ final class StatusAttachmentsView: UIView { } } - let attachmentViewModels = viewModel?.attachmentViewModels ?? [] - let attachmentCount = attachmentViewModels.count + guard let viewModel = viewModel else { return } - rightStackView.isHidden = attachmentCount == 1 + rightStackView.isHidden = viewModel.attachmentViewModels.count == 1 - for (index, attachmentViewModel) in attachmentViewModels.enumerated() { - let attachmentView = StatusAttachmentView(viewModel: attachmentViewModel) + for (index, attachmentViewModel) in viewModel.attachmentViewModels.enumerated() { + let attachmentView = AttachmentView(viewModel: attachmentViewModel, parentViewModel: viewModel) + attachmentView.playing = viewModel.shouldShowAttachments && attachmentViewModel.shouldAutoplay + attachmentView.removeButton.isHidden = !viewModel.canRemoveAttachments - attachmentView.button.addAction( - UIAction { [weak self] _ in self?.viewModel?.attachmentSelected(viewModel: attachmentViewModel) }, - for: .touchUpInside) - - if attachmentCount == 2 && index == 1 - || attachmentCount == 3 && index != 0 - || attachmentCount > 3 && index % 2 != 0 { + if viewModel.attachmentViewModels.count == 2 && index == 1 + || viewModel.attachmentViewModels.count == 3 && index != 0 + || viewModel.attachmentViewModels.count > 3 && index % 2 != 0 { rightStackView.addArrangedSubview(attachmentView) } else { leftStackView.addArrangedSubview(attachmentView) @@ -47,7 +44,8 @@ final class StatusAttachmentsView: UIView { let newAspectRatio: CGFloat - if attachmentCount == 1, let aspectRatio = attachmentViewModels.first?.attachment.aspectRatio { + if viewModel.attachmentViewModels.count == 1, + let aspectRatio = viewModel.attachmentViewModels.first?.attachment.aspectRatio { newAspectRatio = max(CGFloat(aspectRatio), 16 / 9) } else { newAspectRatio = 16 / 9 @@ -58,14 +56,14 @@ final class StatusAttachmentsView: UIView { aspectRatioConstraint?.priority = .justBelowMax aspectRatioConstraint?.isActive = true - curtain.isHidden = viewModel?.shouldShowAttachments ?? false + curtain.isHidden = viewModel.shouldShowAttachments curtainButton.setTitle( - NSLocalizedString((viewModel?.sensitive ?? false) + NSLocalizedString((viewModel.sensitive) ? "attachment.sensitive-content" : "attachment.media-hidden", comment: ""), for: .normal) - hideButtonBackground.isHidden = !(viewModel?.shouldShowHideAttachmentsButton ?? false) + hideButtonBackground.isHidden = !viewModel.shouldShowHideAttachmentsButton } } @@ -81,7 +79,7 @@ final class StatusAttachmentsView: UIView { } } -extension StatusAttachmentsView { +extension AttachmentsView { var shouldAutoplay: Bool { guard !isHidden, let viewModel = viewModel, viewModel.shouldShowAttachments else { return false } @@ -89,7 +87,7 @@ extension StatusAttachmentsView { } } -private extension StatusAttachmentsView { +private extension AttachmentsView { // swiftlint:disable:next function_body_length func initialSetup() { backgroundColor = .clear @@ -161,20 +159,10 @@ private extension StatusAttachmentsView { curtainButton.trailingAnchor.constraint(equalTo: curtain.contentView.trailingAnchor), curtainButton.bottomAnchor.constraint(equalTo: curtain.contentView.bottomAnchor) ]) - - NotificationCenter.default.publisher(for: TableViewController.autoplayableAttachmentsViewNotification) - .sink { [weak self] in - guard let self = self else { return } - - for attachmentView in self.attachmentViews { - attachmentView.playing = $0.object as? Self === self - } - } - .store(in: &cancellables) } - var attachmentViews: [StatusAttachmentView] { + var attachmentViews: [AttachmentView] { (leftStackView.arrangedSubviews + rightStackView.arrangedSubviews) - .compactMap { $0 as? StatusAttachmentView } + .compactMap { $0 as? AttachmentView } } } diff --git a/Views/CompositionAttachmentCollectionViewCell.swift b/Views/CompositionAttachmentCollectionViewCell.swift deleted file mode 100644 index 1584f8a..0000000 --- a/Views/CompositionAttachmentCollectionViewCell.swift +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import UIKit -import ViewModels - -class CompositionAttachmentCollectionViewCell: UICollectionViewCell { - var viewModel: CompositionAttachmentViewModel? - var parentViewModel: CompositionViewModel? - - override func updateConfiguration(using state: UICellConfigurationState) { - guard let viewModel = viewModel, let parentViewModel = parentViewModel else { return } - - contentConfiguration = CompositionAttachmentContentConfiguration( - viewModel: viewModel, - parentViewModel: parentViewModel) - .updated(for: state) - backgroundConfiguration = UIBackgroundConfiguration.clear().updated(for: state) - } -} diff --git a/Views/CompositionAttachmentContentConfiguration.swift b/Views/CompositionAttachmentContentConfiguration.swift deleted file mode 100644 index 8105799..0000000 --- a/Views/CompositionAttachmentContentConfiguration.swift +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import UIKit -import ViewModels - -struct CompositionAttachmentContentConfiguration { - let viewModel: CompositionAttachmentViewModel - let parentViewModel: CompositionViewModel -} - -extension CompositionAttachmentContentConfiguration: UIContentConfiguration { - func makeContentView() -> UIView & UIContentView { - CompositionAttachmentView(configuration: self) - } - - func updated(for state: UIConfigurationState) -> CompositionAttachmentContentConfiguration { - self - } -} diff --git a/Views/CompositionAttachmentView.swift b/Views/CompositionAttachmentView.swift deleted file mode 100644 index 087537d..0000000 --- a/Views/CompositionAttachmentView.swift +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Kingfisher -import UIKit -import ViewModels - -class CompositionAttachmentView: UIView { - let imageView = UIImageView() - let removeButton = UIButton() - let editButton = UIButton() - private var compositionAttachmentConfiguration: CompositionAttachmentContentConfiguration - private var aspectRatioConstraint: NSLayoutConstraint - - init(configuration: CompositionAttachmentContentConfiguration) { - self.compositionAttachmentConfiguration = configuration - - aspectRatioConstraint = imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: 2) - - super.init(frame: .zero) - - initialSetup() - applyCompositionAttachmentConfiguration() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -extension CompositionAttachmentView: UIContentView { - var configuration: UIContentConfiguration { - get { compositionAttachmentConfiguration } - set { - guard let compositionAttachmentConfiguration = newValue as? CompositionAttachmentContentConfiguration - else { return } - - self.compositionAttachmentConfiguration = compositionAttachmentConfiguration - - applyCompositionAttachmentConfiguration() - } - } -} - -private extension CompositionAttachmentView { - // swiftlint:disable:next function_body_length - func initialSetup() { - backgroundColor = .secondarySystemBackground - layer.cornerRadius = .defaultCornerRadius - clipsToBounds = true - - addSubview(imageView) - imageView.translatesAutoresizingMaskIntoConstraints = false - imageView.contentMode = .scaleAspectFill - imageView.kf.indicatorType = .activity - - addSubview(removeButton) - removeButton.translatesAutoresizingMaskIntoConstraints = false - removeButton.setImage( - UIImage( - systemName: "xmark.circle.fill", - withConfiguration: UIImage.SymbolConfiguration(scale: .large)), - for: .normal) - removeButton.showsMenuAsPrimaryAction = true - removeButton.menu = UIMenu( - children: [ - UIAction( - title: NSLocalizedString("remove", comment: ""), - image: UIImage(systemName: "trash"), - attributes: .destructive, handler: { [weak self] _ in - guard let self = self else { return } - - self.compositionAttachmentConfiguration.parentViewModel.remove( - attachmentViewModel: self.compositionAttachmentConfiguration.viewModel) - })]) - - addSubview(editButton) - editButton.translatesAutoresizingMaskIntoConstraints = false - editButton.setImage( - UIImage( - systemName: "pencil.circle.fill", - withConfiguration: UIImage.SymbolConfiguration(scale: .large)), - for: .normal) - editButton.addAction(UIAction { [weak self] _ in }, for: .touchUpInside) - - NSLayoutConstraint.activate([ - aspectRatioConstraint, - imageView.leadingAnchor.constraint(equalTo: leadingAnchor), - imageView.topAnchor.constraint(equalTo: topAnchor), - imageView.trailingAnchor.constraint(equalTo: trailingAnchor), - imageView.bottomAnchor.constraint(equalTo: bottomAnchor), - removeButton.topAnchor.constraint(equalTo: topAnchor), - removeButton.trailingAnchor.constraint(equalTo: trailingAnchor), - removeButton.heightAnchor.constraint(equalToConstant: .minimumButtonDimension), - removeButton.widthAnchor.constraint(equalToConstant: .minimumButtonDimension), - editButton.trailingAnchor.constraint(equalTo: trailingAnchor), - editButton.bottomAnchor.constraint(equalTo: bottomAnchor), - editButton.heightAnchor.constraint(equalToConstant: .minimumButtonDimension), - editButton.widthAnchor.constraint(equalToConstant: .minimumButtonDimension) - ]) - } - - func applyCompositionAttachmentConfiguration() { - imageView.kf.setImage(with: compositionAttachmentConfiguration.viewModel.attachment.previewUrl) - aspectRatioConstraint.isActive = false - aspectRatioConstraint = imageView.widthAnchor.constraint( - equalTo: imageView.heightAnchor, - multiplier: CGFloat(compositionAttachmentConfiguration.viewModel.attachment.aspectRatio ?? 1)) - aspectRatioConstraint.priority = .justBelowMax - aspectRatioConstraint.isActive = true - } -} diff --git a/Views/CompositionView.swift b/Views/CompositionView.swift index 2afdf31..a4ada95 100644 --- a/Views/CompositionView.swift +++ b/Views/CompositionView.swift @@ -10,46 +10,17 @@ final class CompositionView: UIView { let spoilerTextField = UITextField() let textView = UITextView() let textViewPlaceholder = UILabel() - let attachmentsCollectionView: UICollectionView + let attachmentsView = AttachmentsView() let attachmentUploadView: AttachmentUploadView private let viewModel: CompositionViewModel private let parentViewModel: NewStatusViewModel private var cancellables = Set() - private lazy var attachmentsDataSource: CompositionAttachmentsDataSource = { - let vm = viewModel - - return .init(collectionView: attachmentsCollectionView) { - (vm.attachmentViewModels[$0.item], vm) - } - }() - init(viewModel: CompositionViewModel, parentViewModel: NewStatusViewModel) { self.viewModel = viewModel self.parentViewModel = parentViewModel - let itemSize = NSCollectionLayoutSize( - widthDimension: .estimated(Self.attachmentCollectionViewHeight), - heightDimension: .fractionalHeight(1)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - let groupSize = NSCollectionLayoutSize( - widthDimension: .estimated(Self.attachmentCollectionViewHeight), - heightDimension: .fractionalHeight(1)) - let group = NSCollectionLayoutGroup.horizontal( - layoutSize: groupSize, - subitems: [item]) - let section = NSCollectionLayoutSection(group: group) - - section.interGroupSpacing = .defaultSpacing - - let configuration = UICollectionViewCompositionalLayoutConfiguration() - - configuration.scrollDirection = .horizontal - - let attachmentsLayout = UICollectionViewCompositionalLayout(section: section, configuration: configuration) - - attachmentsCollectionView = UICollectionView(frame: .zero, collectionViewLayout: attachmentsLayout) attachmentUploadView = AttachmentUploadView(viewModel: viewModel) super.init(frame: .zero) @@ -126,10 +97,7 @@ private extension CompositionView { textViewPlaceholder.textColor = .secondaryLabel textViewPlaceholder.text = NSLocalizedString("compose.prompt", comment: "") - stackView.addArrangedSubview(attachmentsCollectionView) - attachmentsCollectionView.dataSource = attachmentsDataSource - attachmentsCollectionView.backgroundColor = .clear - + stackView.addArrangedSubview(attachmentsView) stackView.addArrangedSubview(attachmentUploadView) textView.text = viewModel.text @@ -163,9 +131,10 @@ private extension CompositionView { .store(in: &cancellables) viewModel.$attachmentViewModels + .receive(on: RunLoop.main) .sink { [weak self] in - self?.attachmentsDataSource.apply($0.map(\.attachment).snapshot()) - self?.attachmentsCollectionView.isHidden = $0.isEmpty + self?.attachmentsView.viewModel = self?.viewModel + self?.attachmentsView.isHidden = $0.isEmpty } .store(in: &cancellables) @@ -182,8 +151,7 @@ private extension CompositionView { stackView.bottomAnchor.constraint(lessThanOrEqualTo: guide.bottomAnchor), textViewPlaceholder.leadingAnchor.constraint(equalTo: textView.leadingAnchor), textViewPlaceholder.topAnchor.constraint(equalTo: textView.topAnchor), - textViewPlaceholder.trailingAnchor.constraint(equalTo: textView.trailingAnchor), - attachmentsCollectionView.heightAnchor.constraint(equalToConstant: Self.attachmentCollectionViewHeight) + textViewPlaceholder.trailingAnchor.constraint(equalTo: textView.trailingAnchor) ] if UIDevice.current.userInterfaceIdiom == .pad { diff --git a/Views/Status/StatusBodyView.swift b/Views/Status/StatusBodyView.swift index 73fafaf..4a8497d 100644 --- a/Views/Status/StatusBodyView.swift +++ b/Views/Status/StatusBodyView.swift @@ -7,7 +7,7 @@ final class StatusBodyView: UIView { let spoilerTextLabel = UILabel() let toggleShowContentButton = UIButton(type: .system) let contentTextView = TouchFallthroughTextView() - let attachmentsView = StatusAttachmentsView() + let attachmentsView = AttachmentsView() let pollView = PollView() let cardView = CardView()