Use new compose UI for share extension
This commit is contained in:
parent
c7c363782b
commit
e9e08bdadd
@ -24,9 +24,10 @@ public struct ComposeUIConfig {
|
|||||||
public var groupedBackgroundColor = Color(uiColor: .systemGroupedBackground)
|
public var groupedBackgroundColor = Color(uiColor: .systemGroupedBackground)
|
||||||
public var groupedCellBackgroundColor = Color(uiColor: .systemBackground)
|
public var groupedCellBackgroundColor = Color(uiColor: .systemBackground)
|
||||||
public var fillColor = Color(uiColor: .systemFill)
|
public var fillColor = Color(uiColor: .systemFill)
|
||||||
public var avatarStyle = AvatarImageView.Style.roundRect
|
|
||||||
|
|
||||||
|
// TODO: remove these in favor of @PreferenceObserving
|
||||||
// Preferences
|
// Preferences
|
||||||
|
public var avatarStyle = AvatarImageView.Style.roundRect
|
||||||
public var useTwitterKeyboard = false
|
public var useTwitterKeyboard = false
|
||||||
public var contentType = StatusContentType.plain
|
public var contentType = StatusContentType.plain
|
||||||
public var requireAttachmentDescriptions = false
|
public var requireAttachmentDescriptions = false
|
||||||
|
@ -36,7 +36,6 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable {
|
|||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@Environment(\.composeUIConfig.fillColor) private var fillColor
|
@Environment(\.composeUIConfig.fillColor) private var fillColor
|
||||||
@Environment(\.composeUIConfig.useTwitterKeyboard) private var useTwitterKeyboard
|
@Environment(\.composeUIConfig.useTwitterKeyboard) private var useTwitterKeyboard
|
||||||
// TODO: test textSelectionStartsAtBeginning
|
|
||||||
@Environment(\.composeUIConfig.textSelectionStartsAtBeginning) private var textSelectionStartsAtBeginning
|
@Environment(\.composeUIConfig.textSelectionStartsAtBeginning) private var textSelectionStartsAtBeginning
|
||||||
|
|
||||||
func makeUIView(context: Context) -> UITextView {
|
func makeUIView(context: Context) -> UITextView {
|
||||||
|
@ -12,6 +12,7 @@ import TuskerComponents
|
|||||||
import WebURLFoundationExtras
|
import WebURLFoundationExtras
|
||||||
import Combine
|
import Combine
|
||||||
import TuskerPreferences
|
import TuskerPreferences
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
class ShareHostingController: UIHostingController<ShareHostingController.View> {
|
class ShareHostingController: UIHostingController<ShareHostingController.View> {
|
||||||
private static func fetchAvatar(_ url: URL) async -> UIImage? {
|
private static func fetchAvatar(_ url: URL) async -> UIImage? {
|
||||||
@ -27,48 +28,21 @@ class ShareHostingController: UIHostingController<ShareHostingController.View> {
|
|||||||
return await image.byPreparingThumbnail(ofSize: CGSize(width: size, height: size)) ?? image
|
return await image.byPreparingThumbnail(ofSize: CGSize(width: size, height: size)) ?? image
|
||||||
}
|
}
|
||||||
|
|
||||||
private let controller: ComposeController
|
@ObservableObjectBox private var config = ComposeUIConfig()
|
||||||
|
private let accountSwitchingState: AccountSwitchingState
|
||||||
private var mastodonContextPublisher: CurrentValueSubject<ShareMastodonContext, Never>
|
private let state: ComposeViewState
|
||||||
private var cancellables = Set<AnyCancellable>()
|
|
||||||
|
|
||||||
init(draft: Draft, mastodonContext: ShareMastodonContext) {
|
init(draft: Draft, mastodonContext: ShareMastodonContext) {
|
||||||
let mastodonContextPublisher = CurrentValueSubject<ShareMastodonContext, Never>(mastodonContext)
|
self.accountSwitchingState = AccountSwitchingState(mastodonContext: mastodonContext)
|
||||||
self.mastodonContextPublisher = mastodonContextPublisher
|
self.state = ComposeViewState(draft: draft)
|
||||||
controller = ComposeController(
|
let rootView = View(
|
||||||
draft: draft,
|
accountSwitchingState: self.accountSwitchingState,
|
||||||
config: ComposeUIConfig(),
|
state: state,
|
||||||
mastodonController: mastodonContext,
|
config: _config
|
||||||
fetchAvatar: Self.fetchAvatar,
|
|
||||||
fetchAttachment: { _ in fatalError("edits aren't allowed in share sheet, can't fetch existing attachment") },
|
|
||||||
fetchStatus: { _ in fatalError("replies aren't allowed in share sheet") },
|
|
||||||
displayNameLabel: { account, style, _ in AnyView(Text(account.displayName).font(.system(style))) },
|
|
||||||
currentAccountContainerView: { AnyView(SwitchAccountContainerView(content: $0, mastodonContextPublisher: mastodonContextPublisher)) },
|
|
||||||
replyContentView: { _, _ in fatalError("replies aren't allowed in share sheet") },
|
|
||||||
emojiImageView: {
|
|
||||||
AnyView(AsyncImage(url: URL($0.url)!) {
|
|
||||||
$0
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
} placeholder: {
|
|
||||||
Image(systemName: "smiley.fill")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
super.init(rootView: View(controller: controller))
|
super.init(rootView: rootView)
|
||||||
|
|
||||||
updateConfig()
|
updateConfig()
|
||||||
|
|
||||||
mastodonContextPublisher
|
|
||||||
.sink { [unowned self] in
|
|
||||||
self.controller.mastodonController = $0
|
|
||||||
self.controller.draft.accountID = $0.accountInfo!.id
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
mastodonContextPublisher
|
|
||||||
.flatMap { $0.$ownAccount }
|
|
||||||
.sink { [unowned self] in self.controller.currentAccount = $0 }
|
|
||||||
.store(in: &cancellables)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
@ -95,8 +69,13 @@ class ShareHostingController: UIHostingController<ShareHostingController.View> {
|
|||||||
config.requireAttachmentDescriptions = Preferences.shared.requireAttachmentDescriptions
|
config.requireAttachmentDescriptions = Preferences.shared.requireAttachmentDescriptions
|
||||||
|
|
||||||
config.dismiss = { [unowned self] in self.dismiss(mode: $0) }
|
config.dismiss = { [unowned self] in self.dismiss(mode: $0) }
|
||||||
|
config.fetchAvatar = Self.fetchAvatar
|
||||||
|
config.displayNameLabel = { account, style, _ in
|
||||||
|
// TODO: move AccountDisplayNameView to TuskerComponents and use that here as well
|
||||||
|
AnyView(Text(account.displayName).font(.system(style)))
|
||||||
|
}
|
||||||
|
|
||||||
controller.config = config
|
self.config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dismiss(mode: DismissMode) {
|
private func dismiss(mode: DismissMode) {
|
||||||
@ -110,10 +89,35 @@ class ShareHostingController: UIHostingController<ShareHostingController.View> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct View: SwiftUI.View {
|
struct View: SwiftUI.View {
|
||||||
let controller: ComposeController
|
@ObservedObject var accountSwitchingState: AccountSwitchingState
|
||||||
|
let state: ComposeViewState
|
||||||
|
@ObservedObject @ObservableObjectBox private var config: ComposeUIConfig
|
||||||
|
@State private var currentAccount: Account?
|
||||||
|
|
||||||
|
fileprivate init(
|
||||||
|
accountSwitchingState: AccountSwitchingState,
|
||||||
|
state: ComposeViewState,
|
||||||
|
config: ObservableObjectBox<ComposeUIConfig>
|
||||||
|
) {
|
||||||
|
self.accountSwitchingState = accountSwitchingState
|
||||||
|
self.state = state
|
||||||
|
self._config = ObservedObject(wrappedValue: config)
|
||||||
|
self._currentAccount = State(wrappedValue: accountSwitchingState.currentAccount)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some SwiftUI.View {
|
var body: some SwiftUI.View {
|
||||||
ControllerView(controller: { controller })
|
ComposeView(
|
||||||
|
state: state,
|
||||||
|
mastodonController: accountSwitchingState.mastodonContext,
|
||||||
|
currentAccount: currentAccount,
|
||||||
|
config: config
|
||||||
|
)
|
||||||
|
.onReceive(accountSwitchingState.$mastodonContext) {
|
||||||
|
state.draft.accountID = $0.accountInfo!.id
|
||||||
|
}
|
||||||
|
.onReceive(accountSwitchingState.currentAccountPublisher) {
|
||||||
|
currentAccount = $0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +126,16 @@ class ShareHostingController: UIHostingController<ShareHostingController.View> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: put this somewhere instead of just copying it from ComposeHostingController
|
||||||
|
@MainActor
|
||||||
|
@propertyWrapper
|
||||||
|
private final class ObservableObjectBox<T>: ObservableObject {
|
||||||
|
@Published var wrappedValue: T
|
||||||
|
init(wrappedValue: T) {
|
||||||
|
self.wrappedValue = wrappedValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo: shouldn't just copy this from the main Colors.swift
|
// todo: shouldn't just copy this from the main Colors.swift
|
||||||
extension UIColor {
|
extension UIColor {
|
||||||
static let appBackground = UIColor { traitCollection in
|
static let appBackground = UIColor { traitCollection in
|
||||||
|
@ -13,9 +13,28 @@ import Pachyderm
|
|||||||
import Combine
|
import Combine
|
||||||
import ComposeUI
|
import ComposeUI
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class AccountSwitchingState: ObservableObject {
|
||||||
|
@Published var mastodonContext: ShareMastodonContext
|
||||||
|
|
||||||
|
var currentAccount: Account? {
|
||||||
|
mastodonContext.ownAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentAccountPublisher: some Publisher<Account, Never> {
|
||||||
|
$mastodonContext
|
||||||
|
.flatMap { $0.$ownAccount }
|
||||||
|
.compactMap { $0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
init(mastodonContext: ShareMastodonContext) {
|
||||||
|
self.mastodonContext = mastodonContext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SwitchAccountContainerView: View {
|
struct SwitchAccountContainerView: View {
|
||||||
let content: AnyView
|
let content: AnyView
|
||||||
let mastodonContextPublisher: CurrentValueSubject<ShareMastodonContext, Never>
|
@ObservedObject var state: AccountSwitchingState
|
||||||
|
|
||||||
var accounts: [UserAccountInfo] {
|
var accounts: [UserAccountInfo] {
|
||||||
UserAccountsManager.shared.accounts
|
UserAccountsManager.shared.accounts
|
||||||
@ -50,7 +69,7 @@ struct SwitchAccountContainerView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func selectAccount(_ account: UserAccountInfo) {
|
private func selectAccount(_ account: UserAccountInfo) {
|
||||||
mastodonContextPublisher.send(ShareMastodonContext(accountInfo: account))
|
state.mastodonContext = ShareMastodonContext(accountInfo: account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,8 +45,7 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
|
|||||||
self.mastodonController = mastodonController
|
self.mastodonController = mastodonController
|
||||||
self.config = ComposeUIConfig()
|
self.config = ComposeUIConfig()
|
||||||
self.currentAccount = mastodonController.account
|
self.currentAccount = mastodonController.account
|
||||||
let state = ComposeViewState(draft: draft)
|
self.state = ComposeViewState(draft: draft)
|
||||||
self.state = state
|
|
||||||
|
|
||||||
let rootView = View(
|
let rootView = View(
|
||||||
state: state,
|
state: state,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user