157 lines
6.0 KiB
Swift
157 lines
6.0 KiB
Swift
//
|
|
// ComposeToolbar.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 11/12/22.
|
|
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
import Pachyderm
|
|
|
|
struct ComposeToolbar: View {
|
|
static let height: CGFloat = 44
|
|
private static let visibilityOptions: [MenuPicker.Option] = Status.Visibility.allCases.map { vis in
|
|
.init(value: vis, title: vis.displayName, subtitle: vis.subtitle, image: UIImage(systemName: vis.unfilledImageName), accessibilityLabel: "Visibility: \(vis.displayName)")
|
|
}
|
|
|
|
@ObservedObject var draft: Draft
|
|
|
|
@EnvironmentObject private var uiState: ComposeUIState
|
|
@EnvironmentObject private var mastodonController: MastodonController
|
|
@ObservedObject private var preferences = Preferences.shared
|
|
@ScaledMetric(relativeTo: .body) private var imageSize: CGFloat = 22
|
|
@State private var minWidth: CGFloat?
|
|
@State private var realWidth: CGFloat?
|
|
|
|
var body: some View {
|
|
ScrollView(.horizontal, showsIndicators: false) {
|
|
HStack(spacing: 0) {
|
|
Button("CW") {
|
|
draft.contentWarningEnabled.toggle()
|
|
}
|
|
.accessibilityLabel(draft.contentWarningEnabled ? "Remove content warning" : "Add content warning")
|
|
.padding(5)
|
|
.hoverEffect()
|
|
|
|
MenuPicker(selection: $draft.visibility, options: Self.visibilityOptions, buttonStyle: .iconOnly)
|
|
// // the button has a bunch of extra space by default, but combined with what we add it's too much
|
|
.padding(.horizontal, -8)
|
|
|
|
if mastodonController.instanceFeatures.localOnlyPosts {
|
|
MenuPicker(selection: $draft.localOnly, options: [
|
|
.init(value: true, title: "Local-only", subtitle: "Only \(mastodonController.accountInfo!.instanceURL.host!)", image: UIImage(named: "link.broken")),
|
|
.init(value: false, title: "Federated", image: UIImage(systemName: "link"))
|
|
], buttonStyle: .iconOnly)
|
|
.padding(.horizontal, -8)
|
|
}
|
|
|
|
if let currentInput = uiState.currentInput, currentInput.toolbarElements.contains(.emojiPicker) {
|
|
Button(action: self.emojiPickerButtonPressed) {
|
|
Label("Insert custom emoji", systemImage: "face.smiling")
|
|
}
|
|
.labelStyle(.iconOnly)
|
|
.font(.system(size: imageSize))
|
|
.padding(5)
|
|
.hoverEffect()
|
|
}
|
|
|
|
if let currentInput = uiState.currentInput,
|
|
currentInput.toolbarElements.contains(.formattingButtons),
|
|
preferences.statusContentType != .plain {
|
|
Spacer()
|
|
|
|
ForEach(StatusFormat.allCases, id: \.rawValue) { format in
|
|
Button(action: self.formatAction(format)) {
|
|
if let imageName = format.imageName {
|
|
Image(systemName: imageName)
|
|
.font(.system(size: imageSize))
|
|
} else if let (str, attrs) = format.title {
|
|
let container = try! AttributeContainer(attrs, including: \.uiKit)
|
|
Text(AttributedString(str, attributes: container))
|
|
}
|
|
}
|
|
.accessibilityLabel(format.accessibilityLabel)
|
|
.padding(5)
|
|
.hoverEffect()
|
|
}
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Button(action: self.draftsButtonPressed) {
|
|
Text("Drafts")
|
|
}
|
|
.padding(5)
|
|
.hoverEffect()
|
|
}
|
|
.padding(.horizontal, 16)
|
|
.frame(minWidth: minWidth)
|
|
.background(GeometryReader { proxy in
|
|
Color.clear
|
|
.preference(key: ToolbarWidthPrefKey.self, value: proxy.size.width)
|
|
.onPreferenceChange(ToolbarWidthPrefKey.self) { width in
|
|
realWidth = width
|
|
}
|
|
})
|
|
}
|
|
.scrollDisabledIfAvailable(realWidth ?? 0 <= minWidth ?? 0)
|
|
.frame(height: Self.height)
|
|
.frame(maxWidth: .infinity)
|
|
.background(.regularMaterial, ignoresSafeAreaEdges: .bottom)
|
|
.overlay(alignment: .top) {
|
|
Divider()
|
|
}
|
|
.background(GeometryReader { proxy in
|
|
Color.clear
|
|
.preference(key: ToolbarWidthPrefKey.self, value: proxy.size.width)
|
|
.onPreferenceChange(ToolbarWidthPrefKey.self) { width in
|
|
minWidth = width
|
|
}
|
|
})
|
|
}
|
|
|
|
private func emojiPickerButtonPressed() {
|
|
guard uiState.autocompleteState == nil else {
|
|
return
|
|
}
|
|
uiState.shouldEmojiAutocompletionBeginExpanded = true
|
|
uiState.currentInput?.beginAutocompletingEmoji()
|
|
}
|
|
|
|
private func draftsButtonPressed() {
|
|
uiState.isShowingDraftsList = true
|
|
}
|
|
|
|
private func formatAction(_ format: StatusFormat) -> () -> Void {
|
|
{
|
|
uiState.currentInput?.applyFormat(format)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct ToolbarWidthPrefKey: PreferenceKey {
|
|
static var defaultValue: CGFloat? = nil
|
|
static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {
|
|
value = nextValue()
|
|
}
|
|
}
|
|
|
|
private extension View {
|
|
@available(iOS, obsoleted: 16.0)
|
|
@ViewBuilder
|
|
func scrollDisabledIfAvailable(_ disabled: Bool) -> some View {
|
|
if #available(iOS 16.0, *) {
|
|
self.scrollDisabled(disabled)
|
|
} else {
|
|
self
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ComposeToolbar_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
ComposeToolbar(draft: Draft(accountID: ""))
|
|
}
|
|
}
|