Skip to content
34 changes: 34 additions & 0 deletions WordPress/Classes/Extensions/SwiftUI/View+ReadSize.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import SwiftUI

private struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero

static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}

private struct SizeModifier: ViewModifier {
let size: (CGSize) -> Void

private var sizeView: some View {
GeometryReader { geometry in
Color.clear.preference(key: SizePreferenceKey.self, value: geometry.size)
}
}

func body(content: Content) -> some View {
content.background(
sizeView
.onPreferenceChange(SizePreferenceKey.self, perform: { value in
size(value)
})
)
}
}

extension View {
func readSize(_ size: @escaping (CGSize) -> Void) -> some View {
modifier(SizeModifier(size: size))
}
}
Comment thread
salimbraksa marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,7 @@ class CommentDetailViewController: UIViewController, NoResultsViewHost {
override func viewDidLoad() {
super.viewDidLoad()
configureView()
configureReplyView()
setupKeyboardManager()
configureSuggestionsView()
configureNavigationBar()
configureTable()
configureSections()
Expand Down Expand Up @@ -290,18 +288,28 @@ private extension CommentDetailViewController {
}

func configureView() {
containerStackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(containerStackView)
containerStackView.axis = .vertical
containerStackView.addArrangedSubview(tableView)
if comment.allowsModeration() {
let commentModerationView = CommentModerationView(
viewModel: commentModerationViewModel
)
let hostingController = UIHostingController(rootView: commentModerationView)
containerStackView.addArrangedSubview(hostingController.view)
self.configureTableView()
self.configureModerationView()
}

func configureTableView() {
self.tableView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(tableView)
self.view.pinSubviewToAllEdges(tableView)
}

func configureModerationView() {
guard comment.allowsModeration() else {
return
}
view.pinSubviewToAllEdges(containerStackView)
let moderationView = CommentModerationSheetHostingView(viewModel: commentModerationViewModel, parent: self) { [weak self] size in
let bottomInset = size.height
self?.tableView.contentInset.bottom = bottomInset
self?.tableView.verticalScrollIndicatorInsets.bottom = bottomInset
}
moderationView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(moderationView)
self.view.pinSubviewToAllEdges(moderationView)
}

func createCommentModerationViewModel() -> CommentModerationViewModel {
Expand Down Expand Up @@ -334,9 +342,6 @@ private extension CommentDetailViewController {
tableView.separatorInsetReference = .fromAutomaticInsets
tableView.separatorStyle = .none

// get rid of the separator line for the last cell.
tableView.tableFooterView = UIView(frame: .init(x: 0, y: 0, width: tableView.frame.size.width, height: Constants.tableBottomMargin))

// assign 20pt leading inset to the table view, as per the design.
tableView.directionalLayoutMargins = .init(top: tableView.directionalLayoutMargins.top,
leading: Constants.tableHorizontalInset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ private extension CommentDetailContentTableViewCell {
hostingController.rootView = content
} else {
let hostingController = UIHostingController<CommentContentHeaderView>(rootView: content)
hostingController.view.setContentCompressionResistancePriority(.required, for: .vertical)
Copy link
Copy Markdown
Contributor Author

@salimbraksa salimbraksa May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes the comment cell header is compressed ( height is 0 ) and a constraints ambiguity warning is thrown in the console. Setting the compression resistance fixed this issue.

This change is not part of the fix, but I thought of including in this PR because it's just a 1 line.

hostingController.view.backgroundColor = .clear
hostingController.willMove(toParent: parent)
stackView.insertArrangedSubview(hostingController.view, at: 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class WebCommentContentRenderer: NSObject, CommentContentRenderer {
webView.scrollView.bounces = false
webView.scrollView.showsVerticalScrollIndicator = false
webView.scrollView.backgroundColor = .clear
webView.scrollView.isScrollEnabled = false
webView.configuration.allowsInlineMediaPlayback = true
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import UIKit
import SwiftUI

final class CommentModerationSheetHostingView: UIView {
Copy link
Copy Markdown
Contributor Author

@salimbraksa salimbraksa May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the view that fixes this bug.

For context, the bug was occurring because the moderation hosting view was not resizing automatically when its content changed. This is a known issue in UIKit and SwiftUI integration, where the hosting view doesn't resize when the SwiftUI view's size changes.

While it's possible to resize the hosting view by calling hostingView.invalidateIntrinsicContentSize, the resize will occur without animation which might break the moderation view animation.

There is a workaround to resolve this issue and it works as following:

  1. Constrain the moderation hosting view to the edges of viewController.view so that it matches the size of its parent view.
  2. By default, the Hosting View will prevent touches from passing through. To allow touches outside the moderation view to pass through, we are overriding the hosting view hitTest method.
  3. Make the Hosting View transparent.
  4. Now the Bottom Sheet can resize freely, and the user doesn't see the “Hosting View”.


private var hostingController: UIHostingController<Content>?
private var intrinsicContentSizeChangeObservation: NSKeyValueObservation?

init(viewModel: CommentModerationViewModel,
parent: UIViewController,
sizeChanged: @escaping (CGSize) -> Void) {
super.init(frame: .zero)
self.setup(
with: viewModel,
sizeChanged: sizeChanged,
parent: parent
)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setup(
with viewModel: CommentModerationViewModel,
sizeChanged: @escaping (CGSize) -> Void,
parent: UIViewController
) {
self.backgroundColor = .clear
let content = Content(viewModel: viewModel, sizeChanged: sizeChanged)
let controller = UIHostingController(rootView: content)
controller.view.translatesAutoresizingMaskIntoConstraints = false
controller.view.backgroundColor = .clear
controller.willMove(toParent: parent)
self.addSubview(controller.view)
self.pinSubviewToAllEdges(controller.view)
parent.addChild(controller)
controller.didMove(toParent: parent)
self.hostingController = controller
}

/// There was a bug where the moderation view did not resize correctly when the moderation view state changed,
/// resulting in an incorrect view height after state transitions.
///
/// To address this bug, the hosting view was laid out to the edges of `viewController.view` to provide enough space
/// for the moderation view to animate smoothly. However, this setup caused the hosting view to intercept touch events,
/// preventing them from passing through to underlying views.
///
/// This custom `hitTest` method resolves the touch event handling issue by ensuring that touch events are forwarded to
/// the appropriate subview or parent view.
///
/// This method has unit tests to verify its functionality.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ I'm planning to unit test this method.

Copy link
Copy Markdown
Contributor Author

@salimbraksa salimbraksa May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 7832ce2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a short documentation to this would make sense I think as it isn't very obvious why it is needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 304dfc9

guard let hitView = super.hitTest(point, with: event),
let hostingView = self.hostingController?.view,
let parent = superview,
hitView === hostingView
else {
return super.hitTest(point, with: event)
}
Copy link
Copy Markdown
Contributor Author

@salimbraksa salimbraksa May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the touch happens inside the moderation view (for example, if the user taps the Approve button or any other button), then everything will proceed as normal.


// Iterate through the parent's subviews to find the view that should respond to the touch event
for subview in parent.subviews where subview !== self {
let point = convert(point, to: subview)
if let respondingView = subview.hitTest(point, with: event) {
return respondingView
}
}
Copy link
Copy Markdown
Contributor Author

@salimbraksa salimbraksa May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the hosting view is tapped, the touch is forwarded to one of the hosting view's siblings. In the case of the CommentDetailViewController, the viewController.view has two subviews: the tableView and the hostingView. Therefore, the touch is forward to the tableView.


// If no subviews are hit, return the parent view
return parent
}

private struct Content: View {
let viewModel: CommentModerationViewModel
let sizeChanged: (CGSize) -> Void

var body: some View {
VStack(spacing: 0) {
Spacer()
CommentModerationView(viewModel: viewModel)
.readSize(sizeChanged)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct CommentModerationView: View {
}
.padding(.horizontal, .DS.Padding.double)
}
.background(Color.DS.Background.primary)
.animation(.smooth, value: viewModel.state)
}
}
Expand Down Expand Up @@ -234,7 +235,9 @@ private struct TrashSpam: View {
) {
self.viewModel.didTapPrimaryCTA()
}
}.onChange(of: viewModel.state) { state in
}
.padding(.bottom, .DS.Padding.double)
.onChange(of: viewModel.state) { state in
if let title = Self.title(for: state) {
self.title = title
}
Expand Down
34 changes: 33 additions & 1 deletion WordPress/WordPress.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3876,6 +3876,7 @@
F465980C28E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F465980728E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png */; };
F478B152292FC1BC00AA8645 /* MigrationAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = F478B151292FC1BC00AA8645 /* MigrationAppearance.swift */; };
F479995F2AFD241E0023F4FB /* RegisterDomainTransferFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F479995D2AFD241E0023F4FB /* RegisterDomainTransferFooterView.swift */; };
F47A36D22C08DE8800A2A433 /* CommentModerationSheetHostingViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47A36D12C08DE8800A2A433 /* CommentModerationSheetHostingViewTests.swift */; };
F47E154A29E84A9300B6E426 /* SiteCreationPurchasingWebFlowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47E154929E84A9300B6E426 /* SiteCreationPurchasingWebFlowController.swift */; };
F47E154B29E84A9300B6E426 /* SiteCreationPurchasingWebFlowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47E154929E84A9300B6E426 /* SiteCreationPurchasingWebFlowController.swift */; };
F47FE1052BE3BA8D0057D159 /* CommentDetailContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47FE1042BE3BA8D0057D159 /* CommentDetailContentView.swift */; };
Expand All @@ -3893,6 +3894,10 @@
F48EBF8B2B2F94DD004CD561 /* BlogDashboardAnalyticPropertiesProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48EBF892B2F94DD004CD561 /* BlogDashboardAnalyticPropertiesProviding.swift */; };
F48EBF942B333550004CD561 /* dashboard-200-with-only-one-dynamic-card.json in Resources */ = {isa = PBXBuildFile; fileRef = F48EBF912B333111004CD561 /* dashboard-200-with-only-one-dynamic-card.json */; };
F48EBF952B333B31004CD561 /* dashboard-200-with-multiple-dynamic-cards.json in Resources */ = {isa = PBXBuildFile; fileRef = F48EBF8C2B3262D5004CD561 /* dashboard-200-with-multiple-dynamic-cards.json */; };
F48EE3042C072E570068EA92 /* View+ReadSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48EE3032C072E570068EA92 /* View+ReadSize.swift */; };
F48EE3052C072F8C0068EA92 /* View+ReadSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48EE3032C072E570068EA92 /* View+ReadSize.swift */; };
F48EE3072C0747520068EA92 /* CommentModerationSheetHostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48EE3062C0747520068EA92 /* CommentModerationSheetHostingView.swift */; };
F48EE3082C07478C0068EA92 /* CommentModerationSheetHostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48EE3062C0747520068EA92 /* CommentModerationSheetHostingView.swift */; };
F499CFB32BD978340072FB00 /* DynamicDashboardCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F499CFB22BD978340072FB00 /* DynamicDashboardCard.swift */; };
F499CFB42BD978340072FB00 /* DynamicDashboardCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F499CFB22BD978340072FB00 /* DynamicDashboardCard.swift */; };
F49B99FF2937C9B4000CEFCE /* MigrationEmailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49B99FE2937C9B4000CEFCE /* MigrationEmailService.swift */; };
Expand Down Expand Up @@ -9318,6 +9323,7 @@
F465980728E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "white-on-blue-icon-app-83.5@2x.png"; sourceTree = "<group>"; };
F478B151292FC1BC00AA8645 /* MigrationAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationAppearance.swift; sourceTree = "<group>"; };
F479995D2AFD241E0023F4FB /* RegisterDomainTransferFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterDomainTransferFooterView.swift; sourceTree = "<group>"; };
F47A36D12C08DE8800A2A433 /* CommentModerationSheetHostingViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentModerationSheetHostingViewTests.swift; sourceTree = "<group>"; };
F47E154929E84A9300B6E426 /* SiteCreationPurchasingWebFlowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationPurchasingWebFlowController.swift; sourceTree = "<group>"; };
F47FE1042BE3BA8D0057D159 /* CommentDetailContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentDetailContentView.swift; sourceTree = "<group>"; };
F484D4E92A32B51C0050BE15 /* RootViewPresenter+AppSettingsNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RootViewPresenter+AppSettingsNavigation.swift"; sourceTree = "<group>"; };
Expand All @@ -9328,6 +9334,8 @@
F48EBF892B2F94DD004CD561 /* BlogDashboardAnalyticPropertiesProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlogDashboardAnalyticPropertiesProviding.swift; sourceTree = "<group>"; };
F48EBF8C2B3262D5004CD561 /* dashboard-200-with-multiple-dynamic-cards.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "dashboard-200-with-multiple-dynamic-cards.json"; sourceTree = "<group>"; };
F48EBF912B333111004CD561 /* dashboard-200-with-only-one-dynamic-card.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "dashboard-200-with-only-one-dynamic-card.json"; sourceTree = "<group>"; };
F48EE3032C072E570068EA92 /* View+ReadSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ReadSize.swift"; sourceTree = "<group>"; };
F48EE3062C0747520068EA92 /* CommentModerationSheetHostingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentModerationSheetHostingView.swift; sourceTree = "<group>"; };
F499CFB22BD978340072FB00 /* DynamicDashboardCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicDashboardCard.swift; sourceTree = "<group>"; };
F49B99FE2937C9B4000CEFCE /* MigrationEmailService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationEmailService.swift; sourceTree = "<group>"; };
F49B9A05293A21BF000CEFCE /* MigrationAnalyticsTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationAnalyticsTracker.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -10294,6 +10302,7 @@
0844BF862BDFBC7200AAFC02 /* CommentModerationView.swift */,
088482192BE139E30017AD8B /* CommentModerationViewModel.swift */,
0884821B2BE13CC00017AD8B /* CommentModerationState.swift */,
F48EE3062C0747520068EA92 /* CommentModerationSheetHostingView.swift */,
);
path = "Comment Moderation";
sourceTree = "<group>";
Expand Down Expand Up @@ -11505,6 +11514,7 @@
325D3B3A23A8372500766DF6 /* Comments */ = {
isa = PBXGroup;
children = (
F47A36D02C08DE7900A2A433 /* Views */,
325D3B3B23A8373E00766DF6 /* Controllers */,
);
path = Comments;
Expand Down Expand Up @@ -15720,6 +15730,7 @@
B56994471B7A82CD00FF26FA /* Controllers */ = {
isa = PBXGroup;
children = (
FE9CC71926D7A2A40026AEF3 /* CommentDetailViewController.swift */,
08A250FA28D9EDF600F50420 /* CommentDetailInfo */,
C533CF330E6D3ADA000C3DE8 /* CommentsViewController.h */,
C533CF340E6D3ADA000C3DE8 /* CommentsViewController.m */,
Expand All @@ -15730,7 +15741,6 @@
2906F810110CDA8900169D56 /* EditCommentViewController.m */,
0A3FCA1C28B71CBC00499A15 /* FullScreenCommentReplyViewModel.swift */,
328CEC5D23A532BA00A6899E /* FullScreenCommentReplyViewController.swift */,
FE9CC71926D7A2A40026AEF3 /* CommentDetailViewController.swift */,
);
name = Controllers;
sourceTree = "<group>";
Expand All @@ -15749,6 +15759,7 @@
B587796C19B799D800E57C5A /* Extensions */ = {
isa = PBXGroup;
children = (
F48EE3022C072E3F0068EA92 /* SwiftUI */,
F4C34C812BDA7AF900B7E472 /* Design System */,
F407AF1529BA835B008BA5B9 /* Font */,
4326191322FCB8BE003C7642 /* Colors and Styles */,
Expand Down Expand Up @@ -18126,6 +18137,14 @@
path = "white-on-pink";
sourceTree = "<group>";
};
F47A36D02C08DE7900A2A433 /* Views */ = {
isa = PBXGroup;
children = (
F47A36D12C08DE8800A2A433 /* CommentModerationSheetHostingViewTests.swift */,
);
path = Views;
sourceTree = "<group>";
};
F48D44B4298992A90051EAA6 /* Blocking */ = {
isa = PBXGroup;
children = (
Expand All @@ -18135,6 +18154,14 @@
path = Blocking;
sourceTree = "<group>";
};
F48EE3022C072E3F0068EA92 /* SwiftUI */ = {
isa = PBXGroup;
children = (
F48EE3032C072E570068EA92 /* View+ReadSize.swift */,
);
path = SwiftUI;
sourceTree = "<group>";
};
F49B9A04293A21A7000CEFCE /* Analytics */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -22580,6 +22607,7 @@
9801E682274EEBC4002FDDB6 /* ReaderDetailCommentsHeader.swift in Sources */,
B5EFB1C21B31B98E007608A3 /* NotificationSettingsService.swift in Sources */,
011896A829D5BBB400D34BA9 /* DomainsDashboardFactory.swift in Sources */,
F48EE3042C072E570068EA92 /* View+ReadSize.swift in Sources */,
011F52BD2A15327700B04114 /* BaseDashboardDomainsCardCell.swift in Sources */,
0CDA090C2BD04B270032D123 /* PostMediaUploadsViewModel.swift in Sources */,
F45EB5012B865AF4004E9053 /* NotificationTableViewCell.swift in Sources */,
Expand Down Expand Up @@ -22939,6 +22967,7 @@
FF0D8146205809C8000EE505 /* PostCoordinator.swift in Sources */,
B0B89DC02A1E882F003D5295 /* DomainResultView.swift in Sources */,
7EA30DB621ADA20F0092F894 /* AztecAttachmentDelegate.swift in Sources */,
F48EE3072C0747520068EA92 /* CommentModerationSheetHostingView.swift in Sources */,
931215F4267FE177008C3B69 /* ReferrerDetailsSpamActionCell.swift in Sources */,
FEDDD46F26A03DE900F8942B /* ListTableViewCell+Notifications.swift in Sources */,
9AA0ADB3235F11DC0027AB5D /* StatsPeriodAsyncOperation.swift in Sources */,
Expand Down Expand Up @@ -24383,6 +24412,7 @@
933D1F471EA64108009FB462 /* TestingAppDelegate.m in Sources */,
0A9687BC28B40771009DCD2F /* FullScreenCommentReplyViewModelMock.swift in Sources */,
C8567498243F41CA001A995E /* MockTenorService.swift in Sources */,
F47A36D22C08DE8800A2A433 /* CommentModerationSheetHostingViewTests.swift in Sources */,
1D19C56629C9DB0A00FB0087 /* GutenbergVideoPressUploadProcessorTests.swift in Sources */,
4A2C73F72A9585B000ACE79E /* PostRepositoryTests.swift in Sources */,
4A9314DC297790C300360232 /* PeopleServiceTests.swift in Sources */,
Expand Down Expand Up @@ -24518,6 +24548,7 @@
012041042AAAFE3A00E7C707 /* WidgetCenter+JetpackWidgets.swift in Sources */,
FABB20EE2602FC2C00C8785C /* StockPhotosResultsPage.swift in Sources */,
FABB20EF2602FC2C00C8785C /* QuickStartTourGuide.swift in Sources */,
F48EE3082C07478C0068EA92 /* CommentModerationSheetHostingView.swift in Sources */,
FABB20F02602FC2C00C8785C /* ReaderDetailToolbar.swift in Sources */,
FAD1263D2A0CF2F50004E24C /* String+NonbreakingSpace.swift in Sources */,
FABB20F12602FC2C00C8785C /* RecentSitesService.swift in Sources */,
Expand Down Expand Up @@ -25156,6 +25187,7 @@
FABB22B12602FC2C00C8785C /* ReaderDetailFeaturedImageView.swift in Sources */,
FEA7948E26DD136700CEC520 /* CommentHeaderTableViewCell.swift in Sources */,
FABB22B22602FC2C00C8785C /* StatsDataHelper.swift in Sources */,
F48EE3052C072F8C0068EA92 /* View+ReadSize.swift in Sources */,
FABB22B32602FC2C00C8785C /* DeprecatedPrepublishingViewController.swift in Sources */,
FABB22B52602FC2C00C8785C /* SearchableItemConvertable.swift in Sources */,
4A9948E5297624EF006282A9 /* Blog+Creation.swift in Sources */,
Expand Down
Loading
Loading