drop iOS 17 and removed all #available and #unavaible checks for 17 and 18

This commit is contained in:
Mauro Romito
2025-11-28 14:37:37 +01:00
committed by Mauro
parent 7496f30966
commit 656648fc7c
12 changed files with 79 additions and 160 deletions
+2 -2
View File
@@ -9075,7 +9075,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5; IPHONEOS_DEPLOYMENT_TARGET = 18.5;
KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)"; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)";
MACOSX_DEPLOYMENT_TARGET = 14.5; MACOSX_DEPLOYMENT_TARGET = 14.5;
MARKETING_VERSION = 25.12.0; MARKETING_VERSION = 25.12.0;
@@ -9151,7 +9151,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5; IPHONEOS_DEPLOYMENT_TARGET = 18.5;
KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)"; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(DEVELOPMENT_TEAM).$(BASE_BUNDLE_IDENTIFIER)";
MACOSX_DEPLOYMENT_TARGET = 14.5; MACOSX_DEPLOYMENT_TARGET = 14.5;
MARKETING_VERSION = 25.12.0; MARKETING_VERSION = 25.12.0;
@@ -39,10 +39,7 @@ import SwiftUI
} }
func barVisibility(in horizontalSizeClass: UserInterfaceSizeClass?) -> Visibility { func barVisibility(in horizontalSizeClass: UserInterfaceSizeClass?) -> Visibility {
if #unavailable(iOS 18.0) { if let barVisibilityOverride {
// There are glitches with the tab bar on iPadOS 17, so disable the tab bar until we have fixed it.
.hidden
} else if let barVisibilityOverride {
barVisibilityOverride barVisibilityOverride
} else if horizontalSizeClass == .compact, navigationSplitCoordinator?.detailCoordinator != nil { } else if horizontalSizeClass == .compact, navigationSplitCoordinator?.detailCoordinator != nil {
// Whilst we support pushing screens on the stack in the sidebarCoordinator, in practice // Whilst we support pushing screens on the stack in the sidebarCoordinator, in practice
@@ -10,43 +10,6 @@ import Compound
import SwiftUI import SwiftUI
extension View { extension View {
// MARK: iOS 18
/// Uses the old page style modal so that on iPadOS 18 the presentation detents have no effect.
@ViewBuilder func backportPresentationSizingPage() -> some View {
if #available(iOS 18.0, *) {
presentationSizing(.page)
} else {
self
}
}
/// A convenience modifier to conditionally apply `.navigationTransition(.zoom(…))` when available.
@ViewBuilder func backportNavigationTransitionZoom(sourceID: some Hashable, in namespace: Namespace.ID) -> some View {
if #available(iOS 18.0, *) {
navigationTransition(.zoom(sourceID: sourceID, in: namespace))
} else {
self
}
}
/// A convenience modifier to conditionally apply `.matchedTransitionSource(…)` when available.
@ViewBuilder func backportMatchedTransitionSource(id: some Hashable, in namespace: Namespace.ID) -> some View {
if #available(iOS 18.0, *) {
matchedTransitionSource(id: id, in: namespace)
} else {
self
}
}
@ViewBuilder func backportAccessibilityHint(_ hint: String, isEnabled: Bool) -> some View {
if #available(iOS 18, *) {
accessibilityHint(hint, isEnabled: isEnabled)
} else {
self
}
}
// MARK: iOS 26 // MARK: iOS 26
@ViewBuilder func backportTabBarMinimizeBehaviorOnScrollDown() -> some View { @ViewBuilder func backportTabBarMinimizeBehaviorOnScrollDown() -> some View {
+3 -7
View File
@@ -228,13 +228,9 @@ private struct FocusSearchIfHardwareKeyboardAvailableModifier: ViewModifier {
@FocusState private var isFocused @FocusState private var isFocused
func body(content: Content) -> some View { func body(content: Content) -> some View {
if #available(iOS 18.0, *) { content
content .searchFocused($isFocused)
.searchFocused($isFocused) .onAppear(perform: focusIfHardwareKeyboardAvailable)
.onAppear(perform: focusIfHardwareKeyboardAvailable)
} else {
content
}
} }
func focusIfHardwareKeyboardAvailable() { func focusIfHardwareKeyboardAvailable() {
@@ -51,59 +51,52 @@ struct SwipeRightAction<Label: View>: ViewModifier {
@ViewBuilder @ViewBuilder
private func mainContent(content: Content) -> some View { private func mainContent(content: Content) -> some View {
if #available(iOS 18, *) { content
content .offset(x: xOffset, y: 0.0)
.offset(x: xOffset, y: 0.0) .animation(.interactiveSpring().speed(0.5), value: xOffset)
.animation(.interactiveSpring().speed(0.5), value: xOffset) .gesture(PanGestureRepresentable { gesture in
.gesture(PanGestureRepresentable { gesture in switch gesture.state {
switch gesture.state { case .ended, .cancelled, .failed:
case .ended, .cancelled, .failed: if xOffset > actionThreshold {
if xOffset > actionThreshold { action()
action()
}
xOffset = 0.0
default:
guard shouldStartAction() else {
return
}
let translation = gesture.translation(in: nil)
// Due to https://forums.developer.apple.com/forums/thread/760035 we had to make
// the drag a simultaneous gesture otherwise it was impossible to scroll the timeline.
// Therefore we need to prevent the animation to run if the user is to scrolling vertically.
// It would be nice if we could somehow abort the gesture in this case.
let width: CGFloat = if translation.x > abs(translation.y) {
translation.x
} else {
0.0
}
// We want to add a spring like behaviour to the drag in which the view
// moves slower the more it's dragged. We use a circular easing function
// to generate those values up to the `swipeThreshold`
// The final translation will be between 0 and `swipeThreshold` with the action being enabled from
// `actionThreshold` onwards
let screenWidthNormalisedTranslation = max(0.0, min(width, swipeThreshold)) / swipeThreshold
let easedTranslation = circularEaseOut(screenWidthNormalisedTranslation)
xOffset = easedTranslation * xOffsetThreshold
if xOffset > actionThreshold {
if !hasReachedActionThreshold {
feedbackGenerator.impactOccurred()
hasReachedActionThreshold = true
}
} else {
hasReachedActionThreshold = false
}
} }
})
} else { xOffset = 0.0
content default:
.offset(x: xOffset, y: 0.0) guard shouldStartAction() else {
.animation(.interactiveSpring().speed(0.5), value: xOffset) return
.gesture(oldGesture) }
} let translation = gesture.translation(in: nil)
// Due to https://forums.developer.apple.com/forums/thread/760035 we had to make
// the drag a simultaneous gesture otherwise it was impossible to scroll the timeline.
// Therefore we need to prevent the animation to run if the user is to scrolling vertically.
// It would be nice if we could somehow abort the gesture in this case.
let width: CGFloat = if translation.x > abs(translation.y) {
translation.x
} else {
0.0
}
// We want to add a spring like behaviour to the drag in which the view
// moves slower the more it's dragged. We use a circular easing function
// to generate those values up to the `swipeThreshold`
// The final translation will be between 0 and `swipeThreshold` with the action being enabled from
// `actionThreshold` onwards
let screenWidthNormalisedTranslation = max(0.0, min(width, swipeThreshold)) / swipeThreshold
let easedTranslation = circularEaseOut(screenWidthNormalisedTranslation)
xOffset = easedTranslation * xOffsetThreshold
if xOffset > actionThreshold {
if !hasReachedActionThreshold {
feedbackGenerator.impactOccurred()
hasReachedActionThreshold = true
}
} else {
hasReachedActionThreshold = false
}
}
})
} }
private var oldGesture: some Gesture { private var oldGesture: some Gesture {
@@ -21,25 +21,19 @@ struct TimelineItemMacContextMenu: View {
if let menuActions = actionProvider.makeActions() { if let menuActions = actionProvider.makeActions() {
Section { Section {
if !menuActions.reactions.isEmpty { if !menuActions.reactions.isEmpty {
if #available(iOS 17.0, *) { let reactions = (item as? EventBasedTimelineItemProtocol)?.properties.reactions ?? []
let reactions = (item as? EventBasedTimelineItemProtocol)?.properties.reactions ?? [] ControlGroup {
ControlGroup { ForEach(menuActions.reactions, id: \.key) {
ForEach(menuActions.reactions, id: \.key) { ReactionToggle(reaction: $0, reactions: reactions) {
ReactionToggle(reaction: $0, reactions: reactions) { send(.toggleReaction(key: $0))
send(.toggleReaction(key: $0))
}
}
Button { send(.react) } label: {
CompoundIcon(\.reactionAdd)
} }
} }
.controlGroupStyle(.palette)
} else {
Button { send(.react) } label: { Button { send(.react) } label: {
TimelineItemMenuAction.react.label CompoundIcon(\.reactionAdd)
} }
} }
.controlGroupStyle(.palette)
} }
ForEach(menuActions.actions) { action in ForEach(menuActions.actions) { action in
@@ -53,7 +53,7 @@ struct TimelineItemMenu: View {
} }
} }
.accessibilityIdentifier(A11yIdentifiers.roomScreen.timelineItemActionMenu) .accessibilityIdentifier(A11yIdentifiers.roomScreen.timelineItemActionMenu)
.backportPresentationSizingPage() .presentationSizing(.page)
.presentationDetents([.medium, .large]) .presentationDetents([.medium, .large])
.presentationBackground(Color.compound.bgCanvasDefault) .presentationBackground(Color.compound.bgCanvasDefault)
.presentationDragIndicator(.visible) .presentationDragIndicator(.visible)
@@ -94,8 +94,7 @@ struct PollView: View {
private var optionsView: some View { private var optionsView: some View {
ForEach(poll.options, id: \.id) { option in ForEach(poll.options, id: \.id) { option in
pollOption(option: option) pollOption(option: option)
.backportAccessibilityHint(L10n.a11yPollsWillRemoveSelection, .accessibilityHint(L10n.a11yPollsWillRemoveSelection, isEnabled: isRemovePreviousSelectionHintEnabled(option: option))
isEnabled: isRemovePreviousSelectionHintEnabled(option: option))
} }
} }
@@ -16,26 +16,19 @@ struct LongPressWithFeedback: ViewModifier {
private let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy) private let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
func body(content: Content) -> some View { func body(content: Content) -> some View {
if #available(iOS 18, *) { mainContent(content: content)
mainContent(content: content) .gesture(LongPressGestureRepresentable { gesture in
.gesture(LongPressGestureRepresentable { gesture in switch gesture.state {
switch gesture.state { case .began:
case .began: handleLongPress(isPressing: true)
handleLongPress(isPressing: true) case .ended, .cancelled, .failed:
case .ended, .cancelled, .failed: handleLongPress(isPressing: false)
handleLongPress(isPressing: false) case .possible, .changed:
case .possible, .changed: break
break @unknown default:
@unknown default: break
break
}
})
} else {
mainContent(content: content)
.onLongPressGesture(minimumDuration: 0.25) { } onPressingChanged: { isPressing in
handleLongPress(isPressing: isPressing)
} }
} })
} }
// The gesture's minimum duration doesn't actually invoke the perform block when elapsed (thus // The gesture's minimum duration doesn't actually invoke the perform block when elapsed (thus
@@ -119,14 +119,9 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
} }
func setFilter(_ filter: RoomSummaryProviderFilter) { func setFilter(_ filter: RoomSummaryProviderFilter) {
let baseFilter: [RoomListEntriesDynamicFilterKind] = if #available(iOS 18.0, *) { let baseFilter: [RoomListEntriesDynamicFilterKind] = [.any(filters: [.all(filters: [.nonSpace, .nonLeft]),
[.any(filters: [.all(filters: [.nonSpace, .nonLeft]), .all(filters: [.space, .invite])]),
.all(filters: [.space, .invite])]), .deduplicateVersions]
.deduplicateVersions]
} else {
// Don't show space invites on iOS 17 given that the tab bar is disabled due to glitches on iPad.
[.nonLeft, .nonSpace, .deduplicateVersions]
}
switch filter { switch filter {
case .excludeAll: case .excludeAll:
@@ -123,12 +123,12 @@ public struct ListRow<Icon: View, DetailsIcon: View, CustomContent: View, Select
Button(action: action) { Button(action: action) {
RowContent(details: details, accessory: .selection(isSelected)) { label } RowContent(details: details, accessory: .selection(isSelected)) { label }
} }
.isToggle() .accessibilityAddTraits(.isToggle)
case .multiSelection(let isSelected, let action): case .multiSelection(let isSelected, let action):
Button(action: action) { Button(action: action) {
RowContent(details: details, accessory: .multiSelection(isSelected)) { label } RowContent(details: details, accessory: .multiSelection(isSelected)) { label }
} }
.isToggle() .accessibilityAddTraits(.isToggle)
case .textField(let text, let axis): case .textField(let text, let axis):
TextField(text: text, axis: axis) { TextField(text: text, axis: axis) {
Text(label.title ?? "") Text(label.title ?? "")
@@ -259,17 +259,6 @@ private extension TextField {
} }
} }
private extension Button {
/// Adds the `isToggle` accessibility trait on iOS 17+
@ViewBuilder func isToggle() -> some View {
if #available(iOS 17.0, *) {
accessibilityAddTraits(.isToggle)
} else {
self
}
}
}
// MARK: - Previews // MARK: - Previews
// swiftlint:disable print_deprecation // swiftlint:disable print_deprecation
+1 -1
View File
@@ -11,7 +11,7 @@ options:
groupSortPosition: bottom groupSortPosition: bottom
createIntermediateGroups: true createIntermediateGroups: true
deploymentTarget: deploymentTarget:
iOS: '17.5' iOS: '18.5'
macOS: '14.5' macOS: '14.5'
groupOrdering: groupOrdering:
- order: - order: