Make things compile on iOS 15

This commit is contained in:
Shadowfacts 2024-12-15 21:01:41 -05:00
parent c68902b34b
commit 6730575aed
12 changed files with 105 additions and 49 deletions

View File

@ -30,11 +30,12 @@ enum ToolbarElement {
} }
private struct FocusedComposeInput: FocusedValueKey { private struct FocusedComposeInput: FocusedValueKey {
typealias Value = any ComposeInput typealias Value = (any ComposeInput)?
} }
extension FocusedValues { extension FocusedValues {
var composeInput: (any ComposeInput)? { // double optional is necessary pre-iOS 16
var composeInput: (any ComposeInput)?? {
get { self[FocusedComposeInput.self] } get { self[FocusedComposeInput.self] }
set { self[FocusedComposeInput.self] = newValue } set { self[FocusedComposeInput.self] = newValue }
} }

View File

@ -221,16 +221,3 @@ extension AttachmentRowController {
case allowEntry, recognizingText case allowEntry, recognizingText
} }
} }
private extension View {
@available(iOS, obsoleted: 16.0)
@available(visionOS 1.0, *)
@ViewBuilder
func contextMenu<M: View, P: View>(@ViewBuilder menuItems: () -> M, @ViewBuilder previewIfAvailable preview: () -> P) -> some View {
if #available(iOS 16.0, *) {
self.contextMenu(menuItems: menuItems, preview: preview)
} else {
self.contextMenu(menuItems: menuItems)
}
}
}

View File

@ -509,18 +509,6 @@ public final class ComposeController: ViewController {
} }
} }
private extension View {
@available(iOS, obsoleted: 16.0)
@ViewBuilder
func scrollDismissesKeyboardInteractivelyIfAvailable() -> some View {
if #available(iOS 16.0, *) {
self.scrollDismissesKeyboard(.interactively)
} else {
self
}
}
}
private struct GlobalFrameOutsideListPrefKey: PreferenceKey { private struct GlobalFrameOutsideListPrefKey: PreferenceKey {
static var defaultValue: CGRect = .zero static var defaultValue: CGRect = .zero
static func reduce(value: inout CGRect, nextValue: () -> CGRect) { static func reduce(value: inout CGRect, nextValue: () -> CGRect) {

View File

@ -23,4 +23,33 @@ extension View {
} }
} }
#endif #endif
@available(iOS, obsoleted: 16.0)
@ViewBuilder
func scrollDismissesKeyboardInteractivelyIfAvailable() -> some View {
#if os(visionOS)
self.scrollDismissesKeyboard(.interactively)
#else
if #available(iOS 16.0, *) {
self.scrollDismissesKeyboard(.interactively)
} else {
self
}
#endif
}
@available(iOS, obsoleted: 16.0)
@available(visionOS 1.0, *)
@ViewBuilder
func contextMenu<M: View, P: View>(@ViewBuilder menuItems: () -> M, @ViewBuilder previewIfAvailable preview: () -> P) -> some View {
#if os(visionOS)
self.contextMenu(menuItems: menuItems, preview: preview)
#else
if #available(iOS 16.0, *) {
self.contextMenu(menuItems: menuItems, preview: preview)
} else {
self.contextMenu(menuItems: menuItems)
}
#endif
}
} }

View File

@ -45,7 +45,7 @@ struct AttachmentRowView: View {
EditDrawingButton(attachment: attachment) EditDrawingButton(attachment: attachment)
RecognizeTextButton(attachment: attachment, isRecognizingText: $isRecognizingText, error: $textRecognitionError) RecognizeTextButton(attachment: attachment, isRecognizingText: $isRecognizingText, error: $textRecognitionError)
DeleteButton(attachment: attachment) DeleteButton(attachment: attachment)
} preview: { } previewIfAvailable: {
// TODO: need to fix flash of preview changing size // TODO: need to fix flash of preview changing size
AttachmentThumbnailView(attachment: attachment) AttachmentThumbnailView(attachment: attachment)
} }

View File

@ -114,9 +114,21 @@ private struct AttachmentThumbnailViewContent: View {
let asset = AVURLAsset(url: url) let asset = AVURLAsset(url: url)
let imageGenerator = AVAssetImageGenerator(asset: asset) let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true imageGenerator.appliesPreferredTrackTransform = true
#if os(visionOS)
if let (cgImage, _) = try? await imageGenerator.image(at: .zero) { if let (cgImage, _) = try? await imageGenerator.image(at: .zero) {
self.mode = .image(UIImage(cgImage: cgImage)) self.mode = .image(UIImage(cgImage: cgImage))
} }
#else
if #available(iOS 16.0, *) {
if let (cgImage, _) = try? await imageGenerator.image(at: .zero) {
self.mode = .image(UIImage(cgImage: cgImage))
}
} else {
if let cgImage = try? imageGenerator.copyCGImage(at: .zero, actualTime: nil) {
self.mode = .image(UIImage(cgImage: cgImage))
}
}
#endif
} }
enum Mode { enum Mode {

View File

@ -9,12 +9,14 @@ import UIKit
import SwiftUI import SwiftUI
final class AttachmentCollectionViewCell: UICollectionViewCell { final class AttachmentCollectionViewCell: UICollectionViewCell {
let attachmentView: UIView & UIContentView let attachmentView: UIView// & UIContentView
override init(frame: CGRect) { override init(frame: CGRect) {
attachmentView = UIHostingConfiguration(content: { attachmentView = UIView()
AttachmentCollectionViewCellView(attachment: nil) attachmentView.backgroundColor = .red
}).makeContentView() // attachmentView = UIHostingConfiguration(content: {
// AttachmentCollectionViewCellView(attachment: nil)
// }).makeContentView()
super.init(frame: frame) super.init(frame: frame)
@ -27,9 +29,9 @@ final class AttachmentCollectionViewCell: UICollectionViewCell {
} }
func updateUI(attachment: DraftAttachment) { func updateUI(attachment: DraftAttachment) {
attachmentView.configuration = UIHostingConfiguration(content: { // attachmentView.configuration = UIHostingConfiguration(content: {
AttachmentCollectionViewCellView(attachment: attachment) // AttachmentCollectionViewCellView(attachment: attachment)
}).margins(.all, .zero) // }).margins(.all, .zero)
} }
} }
@ -127,6 +129,7 @@ private struct RoundedSquare: Shape {
} }
} }
@available(iOS 16.0, *)
private struct SquareFrame: Layout { private struct SquareFrame: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
precondition(subviews.count == 1) precondition(subviews.count == 1)
@ -145,10 +148,21 @@ private struct SquareFrame: Layout {
} }
private extension View { private extension View {
@ViewBuilder
func squareFrame() -> some View { func squareFrame() -> some View {
#if os(visionOS)
SquareFrame { SquareFrame {
self self
} }
#else
if #available(iOS 16.0, *) {
SquareFrame {
self
}
} else {
self
}
#endif
} }
} }

View File

@ -70,8 +70,8 @@ private class WrappedCollectionViewController: UIViewController {
let layout = UICollectionViewCompositionalLayout { [unowned self] section, environment in let layout = UICollectionViewCompositionalLayout { [unowned self] section, environment in
let (itemSize, itemsPerRow) = self.itemSize(width: environment.container.contentSize.width) let (itemSize, itemsPerRow) = self.itemSize(width: environment.container.contentSize.width)
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .absolute(itemSize), heightDimension: .absolute(itemSize))) let items = Array(repeating: NSCollectionLayoutItem(layoutSize: .init(widthDimension: .absolute(itemSize), heightDimension: .absolute(itemSize))), count: itemsPerRow)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(itemSize)), repeatingSubitem: item, count: itemsPerRow) let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(itemSize)), subitems: items)
group.interItemSpacing = .fixed(spacing) group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group) let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing section.interGroupSpacing = spacing
@ -81,9 +81,10 @@ private class WrappedCollectionViewController: UIViewController {
cell.updateUI(attachment: attachment) cell.updateUI(attachment: attachment)
} }
let addButtonCell = UICollectionView.CellRegistration<UICollectionViewCell, Bool> { [unowned self] cell, indexPath, item in let addButtonCell = UICollectionView.CellRegistration<UICollectionViewCell, Bool> { [unowned self] cell, indexPath, item in
cell.contentConfiguration = UIHostingConfiguration(content: { cell.contentView.backgroundColor = .blue
AddAttachmentButton(viewController: self, enabled: item) // cell.contentConfiguration = UIHostingConfiguration(content: {
}).margins(.all, .zero) // AddAttachmentButton(viewController: self, enabled: item)
// }).margins(.all, .zero)
} }
let collectionView = IntrinsicContentSizeCollectionView(frame: .zero, collectionViewLayout: layout) let collectionView = IntrinsicContentSizeCollectionView(frame: .zero, collectionViewLayout: layout)
self.view = collectionView self.view = collectionView

View File

@ -72,7 +72,7 @@ private struct ToolbarScrollView<Content: View>: View {
} }
} }
} }
.scrollDisabled(realWidth ?? 0 <= minWidth ?? 0) .scrollDisabledIfAvailable(realWidth ?? 0 <= minWidth ?? 0)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background { .background {
GeometryReader { proxy in GeometryReader { proxy in
@ -182,7 +182,7 @@ private struct InsertEmojiButton: View {
@ScaledMetric(relativeTo: .body) private var imageSize: CGFloat = 22 @ScaledMetric(relativeTo: .body) private var imageSize: CGFloat = 22
var body: some View { var body: some View {
if input?.toolbarElements.contains(.emojiPicker) == true { if input??.toolbarElements.contains(.emojiPicker) == true {
Button(action: beginAutocompletingEmoji) { Button(action: beginAutocompletingEmoji) {
Label("Insert custom emoji", systemImage: "face.smiling") Label("Insert custom emoji", systemImage: "face.smiling")
} }
@ -195,7 +195,7 @@ private struct InsertEmojiButton: View {
} }
private func beginAutocompletingEmoji() { private func beginAutocompletingEmoji() {
input?.beginAutocompletingEmoji() input??.beginAutocompletingEmoji()
} }
} }
@ -204,7 +204,7 @@ private struct FormatButtons: View {
@PreferenceObserving(\.$statusContentType) private var contentType @PreferenceObserving(\.$statusContentType) private var contentType
var body: some View { var body: some View {
if let input, if let input = input.flatMap(\.self),
input.toolbarElements.contains(.formattingButtons), input.toolbarElements.contains(.formattingButtons),
contentType != .plain { contentType != .plain {

View File

@ -15,10 +15,28 @@ struct ComposeView: View {
@EnvironmentObject private var controller: ComposeController @EnvironmentObject private var controller: ComposeController
var body: some View { var body: some View {
navigation
.environmentObject(mastodonController.instanceFeatures)
}
@ViewBuilder
private var navigation: some View {
#if os(visionOS)
NavigationStack { NavigationStack {
navigationRoot navigationRoot
} }
.environmentObject(mastodonController.instanceFeatures) #else
if #available(iOS 16.0, *) {
NavigationStack {
navigationRoot
}
} else {
NavigationView {
navigationRoot
}
.navigationViewStyle(.stack)
}
#endif
} }
private var navigationRoot: some View { private var navigationRoot: some View {
@ -26,7 +44,7 @@ struct ComposeView: View {
ScrollView { ScrollView {
scrollContent scrollContent
} }
.scrollDismissesKeyboard(.interactively) .scrollDismissesKeyboardInteractivelyIfAvailable()
#if !os(visionOS) && !targetEnvironment(macCatalyst) #if !os(visionOS) && !targetEnvironment(macCatalyst)
.modifier(ToolbarSafeAreaInsetModifier()) .modifier(ToolbarSafeAreaInsetModifier())
#endif #endif

View File

@ -62,7 +62,8 @@ private struct LanguageButton: View {
@State private var hasChanged = false @State private var hasChanged = false
var body: some View { var body: some View {
if instanceFeatures.createStatusWithLanguage { if #available(iOS 16.0, *),
instanceFeatures.createStatusWithLanguage {
LanguagePicker(draftLanguage: $draft.language, hasChangedSelection: $hasChanged) LanguagePicker(draftLanguage: $draft.language, hasChangedSelection: $hasChanged)
.buttonStyle(LanguageButtonStyle()) .buttonStyle(LanguageButtonStyle())
.onReceive(NotificationCenter.default.publisher(for: UITextInputMode.currentInputModeDidChangeNotification), perform: currentInputModeChanged) .onReceive(NotificationCenter.default.publisher(for: UITextInputMode.currentInputModeDidChangeNotification), perform: currentInputModeChanged)
@ -72,10 +73,11 @@ private struct LanguageButton: View {
} }
} }
@available(iOS 16.0, *)
private func currentInputModeChanged(_ notification: Foundation.Notification) { private func currentInputModeChanged(_ notification: Foundation.Notification) {
guard !hasChanged, guard !hasChanged,
!draft.hasContent, !draft.hasContent,
let mode = input?.textInputMode, let mode = input??.textInputMode,
let code = LanguagePicker.codeFromInputMode(mode) else { let code = LanguagePicker.codeFromInputMode(mode) else {
return return
} }

View File

@ -41,7 +41,11 @@ private struct NewMainTextViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> UITextView { func makeUIView(context: Context) -> UITextView {
// TODO: if we're not doing the pill background, reevaluate whether this version fork is necessary // TODO: if we're not doing the pill background, reevaluate whether this version fork is necessary
let view = WrappedTextView(usingTextLayoutManager: true) let view = if #available(iOS 16.0, *) {
WrappedTextView(usingTextLayoutManager: true)
} else {
WrappedTextView()
}
view.addInteraction(UIDropInteraction(delegate: context.coordinator)) view.addInteraction(UIDropInteraction(delegate: context.coordinator))
view.delegate = context.coordinator view.delegate = context.coordinator
view.adjustsFontForContentSizeCategory = true view.adjustsFontForContentSizeCategory = true