diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index e8a8cfd3..009026a8 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -271,7 +271,6 @@ D6CA6A92249FAD8900AD45C1 /* AudioSessionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6CA6A91249FAD8900AD45C1 /* AudioSessionHelper.swift */; }; D6CA6A94249FADE700AD45C1 /* GalleryPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6CA6A93249FADE700AD45C1 /* GalleryPlayerViewController.swift */; }; D6D3F4C424FDB6B700EC4A6A /* View+ConditionalModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D3F4C324FDB6B700EC4A6A /* View+ConditionalModifier.swift */; }; - D6D3FDE024F41B8400FF50A5 /* ComposeContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D3FDDF24F41B8400FF50A5 /* ComposeContainerView.swift */; }; D6D3FDE224F46A8D00FF50A5 /* ComposeUIState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D3FDE124F46A8D00FF50A5 /* ComposeUIState.swift */; }; D6D4CC94250DB86A00FCCF8D /* ComposeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4CC93250DB86A00FCCF8D /* ComposeTests.swift */; }; D6D4DDD0212518A000E1C4BB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */; }; @@ -634,7 +633,6 @@ D6CA6A91249FAD8900AD45C1 /* AudioSessionHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionHelper.swift; sourceTree = ""; }; D6CA6A93249FADE700AD45C1 /* GalleryPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryPlayerViewController.swift; sourceTree = ""; }; D6D3F4C324FDB6B700EC4A6A /* View+ConditionalModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ConditionalModifier.swift"; sourceTree = ""; }; - D6D3FDDF24F41B8400FF50A5 /* ComposeContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeContainerView.swift; sourceTree = ""; }; D6D3FDE124F46A8D00FF50A5 /* ComposeUIState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeUIState.swift; sourceTree = ""; }; D6D4CC93250DB86A00FCCF8D /* ComposeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTests.swift; sourceTree = ""; }; D6D4DDCC212518A000E1C4BB /* Tusker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tusker.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -989,7 +987,6 @@ D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */, D6D3FDE124F46A8D00FF50A5 /* ComposeUIState.swift */, D622759F24F1677200B82A16 /* ComposeHostingController.swift */, - D6D3FDDF24F41B8400FF50A5 /* ComposeContainerView.swift */, D677284724ECBCB100C732D3 /* ComposeView.swift */, D677284924ECBDF400C732D3 /* ComposeCurrentAccount.swift */, D677284B24ECBE9100C732D3 /* ComposeAvatarImageView.swift */, @@ -1891,7 +1888,6 @@ D6AEBB4A23216F0400E5038B /* UnfollowAccountActivity.swift in Sources */, D61DC84D28F500D200B82C6E /* ProfileViewController.swift in Sources */, D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */, - D6D3FDE024F41B8400FF50A5 /* ComposeContainerView.swift in Sources */, D693A72A25CF8C1E003A14E2 /* ProfileDirectoryViewController.swift in Sources */, D693A72F25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift in Sources */, D627943223A5466600D38C68 /* SelectableTableViewCell.swift in Sources */, diff --git a/Tusker/Screens/Compose/ComposeContainerView.swift b/Tusker/Screens/Compose/ComposeContainerView.swift deleted file mode 100644 index 0809a29e..00000000 --- a/Tusker/Screens/Compose/ComposeContainerView.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// ComposeContainerView.swift -// Tusker -// -// Created by Shadowfacts on 8/24/20. -// Copyright © 2020 Shadowfacts. All rights reserved. -// - -import SwiftUI -import Combine - -struct ComposeContainerView: View { - let mastodonController: MastodonController - @ObservedObject var uiState: ComposeUIState - - init( - mastodonController: MastodonController, - uiState: ComposeUIState - ) { - self.mastodonController = mastodonController - self.uiState = uiState - } - - var body: some View { - ComposeView(draft: uiState.draft) - .environmentObject(mastodonController) - .environmentObject(uiState) - } -} - -//struct ComposeContainerView_Previews: PreviewProvider { -// static var previews: some View { -// ComposeContainerView() -// } -//} diff --git a/Tusker/Screens/Compose/ComposeHostingController.swift b/Tusker/Screens/Compose/ComposeHostingController.swift index 7531fee3..895b4bda 100644 --- a/Tusker/Screens/Compose/ComposeHostingController.swift +++ b/Tusker/Screens/Compose/ComposeHostingController.swift @@ -16,7 +16,7 @@ protocol ComposeHostingControllerDelegate: AnyObject { func dismissCompose(mode: ComposeUIState.DismissMode) -> Bool } -class ComposeHostingController: UIHostingController, DuckableViewController { +class ComposeHostingController: UIHostingController, DuckableViewController { weak var delegate: ComposeHostingControllerDelegate? weak var duckableDelegate: DuckableViewControllerDelegate? @@ -36,14 +36,11 @@ class ComposeHostingController: UIHostingController, Ducka self.uiState = ComposeUIState(draft: realDraft) - // we need our own environment object wrapper so that we can set the mastodon controller as an - // environment object and setup the draft change listener while still having a concrete type - // to use as the UIHostingController type parameter - let container = ComposeContainerView( + let compose = ComposeView( mastodonController: mastodonController, uiState: uiState ) - super.init(rootView: container) + super.init(rootView: compose) self.uiState.delegate = self diff --git a/Tusker/Screens/Compose/ComposeView.swift b/Tusker/Screens/Compose/ComposeView.swift index 977951ff..5d740d19 100644 --- a/Tusker/Screens/Compose/ComposeView.swift +++ b/Tusker/Screens/Compose/ComposeView.swift @@ -43,8 +43,8 @@ import Combine struct ComposeView: View { @ObservedObject var draft: Draft - @EnvironmentObject var mastodonController: MastodonController - @EnvironmentObject var uiState: ComposeUIState + @ObservedObject var mastodonController: MastodonController + @ObservedObject var uiState: ComposeUIState @State private var globalFrameOutsideList: CGRect = .zero @State private var contentWarningBecomeFirstResponder = false @@ -60,27 +60,35 @@ struct ComposeView: View { private let stackPadding: CGFloat = 8 - init(draft: Draft) { - self.draft = draft + init(mastodonController: MastodonController, uiState: ComposeUIState) { + self.draft = uiState.draft + self.mastodonController = mastodonController + self.uiState = uiState } - var charactersRemaining: Int { + private var charactersRemaining: Int { let limit = mastodonController.instanceFeatures.maxStatusChars let cwCount = draft.contentWarningEnabled ? draft.contentWarning.count : 0 return limit - (cwCount + CharacterCounter.count(text: draft.text, for: mastodonController.instance)) } - var requiresAttachmentDescriptions: Bool { + private var requiresAttachmentDescriptions: Bool { guard Preferences.shared.requireAttachmentDescriptions else { return false } let attachmentIds = draft.attachments.map(\.id) return attachmentIds.contains { uiState.attachmentsMissingDescriptions.contains($0) } } - var postButtonEnabled: Bool { + private var postButtonEnabled: Bool { draft.hasContent && charactersRemaining >= 0 && !isPosting && !requiresAttachmentDescriptions && (draft.poll == nil || draft.poll!.options.allSatisfy { !$0.text.isEmpty }) } var body: some View { + bodyWithoutEnvironment + .environmentObject(uiState) + .environmentObject(mastodonController) + } + + private var bodyWithoutEnvironment: some View { ZStack(alignment: .top) { mainList .scrollDismissesKeyboardInteractivelyIfAvailable() @@ -128,13 +136,13 @@ struct ComposeView: View { } @ViewBuilder - var autocompleteSuggestions: some View { + private var autocompleteSuggestions: some View { if let state = uiState.autocompleteState { ComposeAutocompleteView(autocompleteState: state) } } - var mainList: some View { + private var mainList: some View { List { if let id = draft.inReplyToID, let status = mastodonController.persistentContainer.status(for: id) {