From 054178c95ea7c92d6b83a14519dcea6264864ce9 Mon Sep 17 00:00:00 2001 From: kernelkind Date: Thu, 18 Apr 2024 14:32:43 -0400 Subject: [PATCH] Reduce minimum IOS version to 15 Signed-off-by: kernelkind Signed-off-by: William Casarin --- damus.xcodeproj/project.pbxproj | 29 ++++++++++-- .../xcshareddata/swiftpm/Package.resolved | 9 ++++ damus/Components/Status/UserStatusSheet.swift | 18 ++++++-- damus/Components/Status/UserStatusView.swift | 24 ++++++---- damus/ContentView.swift | 23 +++++++--- damus/Models/Purple/DamusPurple.swift | 46 ++++++++++++++++--- damus/TestData.swift | 6 ++- damus/Util/ConditionalModifier.swift | 23 ++++++++++ damus/Util/Relays/RelayBootstrap.swift | 17 +++++-- damus/Views/ActionBar/EventDetailBar.swift | 7 +-- damus/Views/ConfigView.swift | 17 +++---- damus/Views/DMChatView.swift | 3 +- .../Views/Notifications/EventGroupView.swift | 3 +- .../Notifications/NotificationItemView.swift | 3 +- damus/Views/PostView.swift | 8 +++- damus/Views/Profile/ProfileEditButton.swift | 3 +- damus/Views/Profile/ProfileView.swift | 23 ++++++---- damus/Views/ProfileActionSheetView.swift | 8 +++- damus/Views/Purple/DamusPurpleView.swift | 8 +++- damus/Views/Relays/RecommendedRelayView.swift | 3 +- damus/Views/Relays/RelayConfigView.swift | 8 +++- damus/Views/Relays/RelayPicView.swift | 12 +++-- damus/Views/Relays/RelayView.swift | 3 +- damus/Views/Relays/SignalView.swift | 3 +- damus/Views/ReportView.swift | 6 ++- damus/Views/Reposts/RepostedEvent.swift | 3 +- damus/Views/Search/SearchingEventView.swift | 5 +- damus/Views/SearchResultsView.swift | 3 +- damus/Views/SetupView.swift | 5 +- damus/Views/SideMenuView.swift | 15 +++--- damus/Views/Zaps/CustomizeZapView.swift | 27 +++++++---- 31 files changed, 279 insertions(+), 92 deletions(-) create mode 100644 damus/Util/ConditionalModifier.swift diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index f5660a9c4..b2450c923 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -621,6 +621,8 @@ D7FF94002AC7AC5300FD969D /* RelayURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7FF93FF2AC7AC5200FD969D /* RelayURL.swift */; }; E02B54182B4DFADA0077FF42 /* Bech32ObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E02B54172B4DFADA0077FF42 /* Bech32ObjectTests.swift */; }; E04A37C62B544F090029650D /* URIParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E04A37C52B544F090029650D /* URIParsing.swift */; }; + E06336A22B6D7B5800A88E6B /* NavigationBackport in Frameworks */ = {isa = PBXBuildFile; productRef = E06336A12B6D7B5800A88E6B /* NavigationBackport */; }; + E06336A42B6D839A00A88E6B /* ConditionalModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E06336A32B6D839A00A88E6B /* ConditionalModifier.swift */; }; E4FA1C032A24BB7F00482697 /* SearchSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */; }; E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; }; E9E4ED0B295867B900DD7078 /* ThreadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E4ED0A295867B900DD7078 /* ThreadView.swift */; }; @@ -1390,6 +1392,7 @@ D7FF93FF2AC7AC5200FD969D /* RelayURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayURL.swift; sourceTree = ""; }; E02B54172B4DFADA0077FF42 /* Bech32ObjectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bech32ObjectTests.swift; sourceTree = ""; }; E04A37C52B544F090029650D /* URIParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIParsing.swift; sourceTree = ""; }; + E06336A32B6D839A00A88E6B /* ConditionalModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalModifier.swift; sourceTree = ""; }; E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsView.swift; sourceTree = ""; }; E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = ""; }; E9E4ED0A295867B900DD7078 /* ThreadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadView.swift; sourceTree = ""; }; @@ -1415,6 +1418,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E06336A22B6D7B5800A88E6B /* NavigationBackport in Frameworks */, 4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */, 4C649881286E0EE300EAE2B3 /* secp256k1 in Frameworks */, 4C27C9322A64766F007DBC75 /* MarkdownUI in Frameworks */, @@ -2121,6 +2125,7 @@ D74AAFCE2B155D8C006CF0F4 /* ZapDataModel.swift */, D74AAFD32B155ECB006CF0F4 /* Zaps+.swift */, D74AAFD52B155F0C006CF0F4 /* WalletConnect+.swift */, + E06336A32B6D839A00A88E6B /* ConditionalModifier.swift */, ); path = Util; sourceTree = ""; @@ -2717,6 +2722,7 @@ 4C649880286E0EE300EAE2B3 /* secp256k1 */, 4C06670328FC7EC500038D2A /* Kingfisher */, 4C27C9312A64766F007DBC75 /* MarkdownUI */, + E06336A12B6D7B5800A88E6B /* NavigationBackport */, ); productName = damus; productReference = 4CE6DEE327F7A08100C66700 /* damus.app */; @@ -2854,6 +2860,7 @@ 4CCF9AB02A1FE80B00E03CFB /* XCRemoteSwiftPackageReference "GSPlayer" */, 4C27C9302A64766F007DBC75 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */, D7A343EC2AD0D77C00CED48B /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, + E06336A02B6D7B5800A88E6B /* XCRemoteSwiftPackageReference "NavigationBackport" */, ); productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */; projectDirPath = ""; @@ -3327,6 +3334,7 @@ 4C2B10282A7B0F5C008AA43E /* Log.swift in Sources */, 4C90BD1A283AA67F008EE7EF /* Bech32.swift in Sources */, E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */, + E06336A42B6D839A00A88E6B /* ConditionalModifier.swift in Sources */, 4CB8FC232A41ABA800763C51 /* AboutView.swift in Sources */, D74AAFCC2B155D07006CF0F4 /* MakeZapRequest.swift in Sources */, 5C513FBA297F72980072348F /* CustomPicker.swift in Sources */, @@ -3761,7 +3769,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 12.3; MARKETING_VERSION = 1.7; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -3823,7 +3831,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 12.3; MARKETING_VERSION = 1.7; MTL_ENABLE_DEBUG_INFO = NO; @@ -3862,7 +3870,7 @@ INFOPLIST_KEY_UILaunchStoryboardName = Launch.storyboard; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -3911,7 +3919,7 @@ INFOPLIST_KEY_UILaunchStoryboardName = Launch.storyboard; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -4164,6 +4172,14 @@ minimumVersion = 1.14.1; }; }; + E06336A02B6D7B5800A88E6B /* XCRemoteSwiftPackageReference "NavigationBackport" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/johnpatrickmorgan/NavigationBackport.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.9.1; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -4207,6 +4223,11 @@ package = 4C27C9302A64766F007DBC75 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; productName = MarkdownUI; }; + E06336A12B6D7B5800A88E6B /* NavigationBackport */ = { + isa = XCSwiftPackageProductDependency; + package = E06336A02B6D7B5800A88E6B /* XCRemoteSwiftPackageReference "NavigationBackport" */; + productName = NavigationBackport; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 4CE6DEDB27F7A08100C66700 /* Project object */; diff --git a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1990dd350..cb8576c7c 100644 --- a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,6 +18,15 @@ "version" : "7.6.1" } }, + { + "identity" : "navigationbackport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/johnpatrickmorgan/NavigationBackport.git", + "state" : { + "revision" : "b002991691b54fd7b952e1e780de252620f8ac77", + "version" : "0.9.1" + } + }, { "identity" : "secp256k1.swift", "kind" : "remoteSourceControl", diff --git a/damus/Components/Status/UserStatusSheet.swift b/damus/Components/Status/UserStatusSheet.swift index 8acbfa77b..04d67ec86 100644 --- a/damus/Components/Status/UserStatusSheet.swift +++ b/damus/Components/Status/UserStatusSheet.swift @@ -134,11 +134,19 @@ struct UserStatusSheet: View { VStack(spacing: 0) { HStack { - TextField(NSLocalizedString("Staying humble...", comment: "Placeholder as an example of what the user could set as their profile status."), text: status_binding, axis: .vertical) - .autocorrectionDisabled(true) - .textInputAutocapitalization(.never) - .lineLimit(3) - .frame(width: 175) + if #available(iOS 16.0, *){ + TextField(NSLocalizedString("Staying humble...", comment: "Placeholder as an example of what the user could set as their profile status."), text: status_binding, axis: .vertical) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .lineLimit(3) + .frame(width: 175) + } else { + TextField(NSLocalizedString("Staying humble...", comment: "Placeholder as an example of what the user could set as their profile status."), text: status_binding) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .lineLimit(3) + .frame(width: 175) + } } .padding(10) diff --git a/damus/Components/Status/UserStatusView.swift b/damus/Components/Status/UserStatusView.swift index 8bea043a3..b6a642acd 100644 --- a/damus/Components/Status/UserStatusView.swift +++ b/damus/Components/Status/UserStatusView.swift @@ -35,15 +35,21 @@ struct UserStatusView: View { openURL(url) } } - .contextMenu( - menuItems: { - if let url = st.url { - Button(url.absoluteString, action: { openURL(url) }) } - }, preview: { - if let url = st.url { - URLPreview(url: url) - } - }) + .conditionalModifier { view in + if #available(iOS 16.0, *){ + return AnyView(view.contextMenu( + menuItems: { + if let url = st.url { + Button(url.absoluteString, action: { openURL(url) }) } + }, preview: { + if let url = st.url { + URLPreview(url: url) + } + })) + } else { + return view + } + } } var body: some View { diff --git a/damus/ContentView.swift b/damus/ContentView.swift index 0488587e6..d8fb51165 100644 --- a/damus/ContentView.swift +++ b/damus/ContentView.swift @@ -8,6 +8,7 @@ import SwiftUI import AVKit import MediaPlayer +import NavigationBackport struct ZapSheet { let target: ZapTarget @@ -241,7 +242,7 @@ struct ContentView: View { var body: some View { VStack(alignment: .leading, spacing: 0) { if let damus = self.damus_state { - NavigationStack(path: $navigationCoordinator.path) { + NBNavigationStack(path: $navigationCoordinator.path) { TabView { // Prevents navbar appearance change on scroll MainContent(damus: damus) .toolbar() { @@ -278,7 +279,7 @@ struct ContentView: View { .overlay( SideMenuView(damus_state: damus_state!, isSidebarVisible: $isSideBarOpened.animation()) ) - .navigationDestination(for: Route.self) { route in + .nbNavigationDestination(for: Route.self) { route in route.view(navigationCoordinator: navigationCoordinator, damusState: damus_state!) } .onReceive(handle_notify(.switched_timeline)) { _ in @@ -316,7 +317,13 @@ struct ContentView: View { PostView(action: action, damus_state: damus_state!) case .user_status: UserStatusSheet(damus_state: damus_state!, postbox: damus_state!.postbox, keypair: damus_state!.keypair, status: damus_state!.profiles.profile_data(damus_state!.pubkey).status) - .presentationDragIndicator(.visible) + .conditionalModifier { view in + if #available(iOS 16.0, *) { + return AnyView(view.presentationDragIndicator(.visible)) + } else { + return view + } + } case .event: EventDetailView() case .profile_action(let pubkey): @@ -327,9 +334,13 @@ struct ContentView: View { SelectWalletView(default_wallet: damus_state!.settings.default_wallet, active_sheet: $active_sheet, our_pubkey: damus_state!.pubkey, invoice: select.invoice) case .filter: let timeline = selected_timeline - RelayFilterView(state: damus_state!, timeline: timeline) - .presentationDetents([.height(550)]) - .presentationDragIndicator(.visible) + if #available(iOS 16.0, *) { + RelayFilterView(state: damus_state!, timeline: timeline) + .presentationDetents([.height(550)]) + .presentationDragIndicator(.visible) + } else { + RelayFilterView(state: damus_state!, timeline: timeline) + } case .onboardingSuggestions: OnboardingSuggestionsView(model: SuggestedUsersViewModel(damus_state: damus_state!)) case .purple(let purple_url): diff --git a/damus/Models/Purple/DamusPurple.swift b/damus/Models/Purple/DamusPurple.swift index 09008a0a0..f942170c8 100644 --- a/damus/Models/Purple/DamusPurple.swift +++ b/damus/Models/Purple/DamusPurple.swift @@ -162,12 +162,39 @@ class DamusPurple: StoreObserverDelegate { func translate(text: String, source source_language: String, target target_language: String) async throws -> String { var url = environment.api_base_url() - url.append(path: "/translate") - url.append(queryItems: [ - .init(name: "source", value: source_language), - .init(name: "target", value: target_language), - .init(name: "q", value: text) - ]) + if #available(iOS 16.0, *) { + url.append(path: "/translate") + url.append(queryItems: [ + .init(name: "source", value: source_language), + .init(name: "target", value: target_language), + .init(name: "q", value: text) + ]) + } else { + // Prior to iOS 16 + var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) + let queryItems = [ + URLQueryItem(name: "source", value: source_language), + URLQueryItem(name: "target", value: target_language), + URLQueryItem(name: "q", value: text) + ] + + if urlComponents?.path.last != "/" { + urlComponents?.path.append("/translate") + } else { + urlComponents?.path += "translate" + } + + if urlComponents?.queryItems != nil { + urlComponents?.queryItems?.append(contentsOf: queryItems) + } else { + urlComponents?.queryItems = queryItems + } + + if let finalURL = urlComponents?.url { + url = finalURL + } + } + let (data, response) = try await make_nip98_authenticated_request( method: .get, url: url, @@ -192,7 +219,12 @@ class DamusPurple: StoreObserverDelegate { func verify_npub_for_checkout(checkout_id: String) async throws { var url = environment.api_base_url() - url.append(path: "/ln-checkout/\(checkout_id)/verify") + let path = "/ln-checkout/\(checkout_id)/verify" + if #available(iOS 16.0, *) { + url.append(path: path) + } else { + url = URL(string: path, relativeTo: url)! + } let (data, response) = try await make_nip98_authenticated_request( method: .put, diff --git a/damus/TestData.swift b/damus/TestData.swift index 5b0a3b484..80b37b98f 100644 --- a/damus/TestData.swift +++ b/damus/TestData.swift @@ -58,7 +58,11 @@ var test_damus_state: DamusState = ({ let fileManager = FileManager.default let temp = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString) try fileManager.createDirectory(at: temp, withIntermediateDirectories: true, attributes: nil) - tempDir = temp.path(percentEncoded: false) + if #available(iOS 16.0, *) { + tempDir = temp.path(percentEncoded: false) + } else { + tempDir = temp.path + } } catch { tempDir = "." } diff --git a/damus/Util/ConditionalModifier.swift b/damus/Util/ConditionalModifier.swift new file mode 100644 index 000000000..3ba497b7d --- /dev/null +++ b/damus/Util/ConditionalModifier.swift @@ -0,0 +1,23 @@ +// +// ConditionalModifier.swift +// damus +// +// Created by KernelKind on 2/2/24. +// + +import SwiftUI + +struct ConditionalModifier: ViewModifier { + let modification: (AnyView) -> AnyView + + func body(content: Content) -> some View { + modification(AnyView(content)) + } +} + +extension View { + func conditionalModifier(modification: @escaping (AnyView) -> AnyView) -> some View { + self.modifier(ConditionalModifier(modification: modification)) + } +} + diff --git a/damus/Util/Relays/RelayBootstrap.swift b/damus/Util/Relays/RelayBootstrap.swift index cdddbbfd5..b0de1e5f0 100644 --- a/damus/Util/Relays/RelayBootstrap.swift +++ b/damus/Util/Relays/RelayBootstrap.swift @@ -15,18 +15,25 @@ fileprivate let BOOTSTRAP_RELAYS = [ "wss://nos.lol", ] -fileprivate let REGION_SPECIFIC_BOOTSTRAP_RELAYS: [Locale.Region: [String]] = [ - Locale.Region.japan: [ + +fileprivate enum TmpRegion: String, Hashable { + case japan = "JP" + case thailand = "TH" + case germany = "DE" +} + +fileprivate let REGION_SPECIFIC_BOOTSTRAP_RELAYS: [TmpRegion: [String]] = [ + TmpRegion.japan: [ "wss://relay-jp.nostr.wirednet.jp", "wss://yabu.me", "wss://r.kojira.io", ], - Locale.Region.thailand: [ + TmpRegion.thailand: [ "wss://relay.siamstr.com", "wss://relay.zerosatoshi.xyz", "wss://th2.nostr.earnkrub.xyz", ], - Locale.Region.germany: [ + TmpRegion.germany: [ "wss://nostr.einundzwanzig.space", "wss://nostr.cercatrova.me", "wss://nostr.bitcoinplebs.de", @@ -64,7 +71,7 @@ func load_bootstrap_relays(pubkey: Pubkey) -> [String] { func get_default_bootstrap_relays() -> [String] { var default_bootstrap_relays = BOOTSTRAP_RELAYS - if let user_region = Locale.current.region, let regional_bootstrap_relays = REGION_SPECIFIC_BOOTSTRAP_RELAYS[user_region] { + if let user_region = TmpRegion(rawValue: Locale.current.identifier), let regional_bootstrap_relays = REGION_SPECIFIC_BOOTSTRAP_RELAYS[user_region] { default_bootstrap_relays.append(contentsOf: regional_bootstrap_relays) } diff --git a/damus/Views/ActionBar/EventDetailBar.swift b/damus/Views/ActionBar/EventDetailBar.swift index aca05e650..873fd28f5 100644 --- a/damus/Views/ActionBar/EventDetailBar.swift +++ b/damus/Views/ActionBar/EventDetailBar.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct EventDetailBar: View { let state: DamusState @@ -25,7 +26,7 @@ struct EventDetailBar: View { var body: some View { HStack { if bar.boosts > 0 { - NavigationLink(value: Route.Reposts(reposts: RepostsModel(state: state, target: target))) { + NBNavigationLink(value: Route.Reposts(reposts: RepostsModel(state: state, target: target))) { let nounString = pluralizedString(key: "reposts_count", count: bar.boosts) let noun = Text(nounString).foregroundColor(.gray) Text("\(Text(verbatim: bar.boosts.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.") @@ -34,7 +35,7 @@ struct EventDetailBar: View { } if bar.likes > 0 && !state.settings.onlyzaps_mode { - NavigationLink(value: Route.Reactions(reactions: ReactionsModel(state: state, target: target))) { + NBNavigationLink(value: Route.Reactions(reactions: ReactionsModel(state: state, target: target))) { let nounString = pluralizedString(key: "reactions_count", count: bar.likes) let noun = Text(nounString).foregroundColor(.gray) Text("\(Text(verbatim: bar.likes.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many reactions there are on a post. In source English, the first variable is the number of reactions, and the second variable is 'Reaction' or 'Reactions'.") @@ -43,7 +44,7 @@ struct EventDetailBar: View { } if bar.zaps > 0 { - NavigationLink(value: Route.Zaps(target: .note(id: target, author: target_pk))) { + NBNavigationLink(value: Route.Zaps(target: .note(id: target, author: target_pk))) { let nounString = pluralizedString(key: "zaps_count", count: bar.zaps) let noun = Text(nounString).foregroundColor(.gray) Text("\(Text(verbatim: bar.zaps.formatted()).font(.body.bold())) \(noun)", comment: "Sentence composed of 2 variables to describe how many zap payments there are on a post. In source English, the first variable is the number of zap payments, and the second variable is 'Zap' or 'Zaps'.") diff --git a/damus/Views/ConfigView.swift b/damus/Views/ConfigView.swift index 6ffaf066a..d6d204438 100644 --- a/damus/Views/ConfigView.swift +++ b/damus/Views/ConfigView.swift @@ -9,6 +9,7 @@ import Kingfisher import SwiftUI import LocalAuthentication import Combine +import NavigationBackport struct ConfigView: View { let state: DamusState @@ -36,35 +37,35 @@ struct ConfigView: View { ZStack(alignment: .leading) { Form { Section { - NavigationLink(value: Route.KeySettings(keypair: state.keypair)) { + NBNavigationLink(value: Route.KeySettings(keypair: state.keypair)) { IconLabel(NSLocalizedString("Keys", comment: "Settings section for managing keys"), img_name: "Key", color: .purple) } - NavigationLink(value: Route.AppearanceSettings(settings: settings)) { + NBNavigationLink(value: Route.AppearanceSettings(settings: settings)) { IconLabel(NSLocalizedString("Appearance and filters", comment: "Section header for text, appearance, and content filter settings"), img_name: "eye", color: .red) } - NavigationLink(value: Route.SearchSettings(settings: settings)) { + NBNavigationLink(value: Route.SearchSettings(settings: settings)) { IconLabel(NSLocalizedString("Search/Universe", comment: "Section header for search/universe settings"), img_name: "search", color: .red) } - NavigationLink(value: Route.NotificationSettings(settings: settings)) { + NBNavigationLink(value: Route.NotificationSettings(settings: settings)) { IconLabel(NSLocalizedString("Notifications", comment: "Section header for Damus notifications"), img_name: "notification-bell-on", color: .blue) } - NavigationLink(value: Route.ZapSettings(settings: settings)) { + NBNavigationLink(value: Route.ZapSettings(settings: settings)) { IconLabel(NSLocalizedString("Zaps", comment: "Section header for zap settings"), img_name: "zap.fill", color: .orange) } - NavigationLink(value: Route.TranslationSettings(settings: settings)) { + NBNavigationLink(value: Route.TranslationSettings(settings: settings)) { IconLabel(NSLocalizedString("Translation", comment: "Section header for text and appearance settings"), img_name: "globe", color: .green) } - NavigationLink(value: Route.ReactionsSettings(settings: settings)) { + NBNavigationLink(value: Route.ReactionsSettings(settings: settings)) { IconLabel(NSLocalizedString("Reactions", comment: "Section header for reactions settings"), img_name: "shaka.fill", color: .purple) } - NavigationLink(value: Route.DeveloperSettings(settings: settings)) { + NBNavigationLink(value: Route.DeveloperSettings(settings: settings)) { IconLabel(NSLocalizedString("Developer", comment: "Section header for developer settings"), img_name: "magic-stick2.fill", color: DamusColors.adaptableBlack) } } diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift index 9666ffd92..4bc759ad5 100644 --- a/damus/Views/DMChatView.swift +++ b/damus/Views/DMChatView.swift @@ -7,6 +7,7 @@ import SwiftUI import Combine +import NavigationBackport struct DMChatView: View, KeyboardReadable { let damus_state: DamusState @@ -59,7 +60,7 @@ struct DMChatView: View, KeyboardReadable { } var Header: some View { - return NavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) { + return NBNavigationLink(value: Route.ProfileByKey(pubkey: pubkey)) { HStack { ProfilePicView(pubkey: pubkey, size: 24, highlight: .none, profiles: damus_state.profiles, disable_animation: damus_state.settings.disable_animation) diff --git a/damus/Views/Notifications/EventGroupView.swift b/damus/Views/Notifications/EventGroupView.swift index 37fb9c7fc..908edb14e 100644 --- a/damus/Views/Notifications/EventGroupView.swift +++ b/damus/Views/Notifications/EventGroupView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport enum EventGroupType { @@ -234,7 +235,7 @@ struct EventGroupView: View { if let event { let thread = ThreadModel(event: event, damus_state: state) - NavigationLink(value: Route.Thread(thread: thread)) { + NBNavigationLink(value: Route.Thread(thread: thread)) { VStack(alignment: .leading) { GroupDescription(unique_pubkeys) EventBody(damus_state: state, event: event, size: .normal, options: [.truncate_content]) diff --git a/damus/Views/Notifications/NotificationItemView.swift b/damus/Views/Notifications/NotificationItemView.swift index 7a52578ab..9a29e81e9 100644 --- a/damus/Views/Notifications/NotificationItemView.swift +++ b/damus/Views/Notifications/NotificationItemView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport enum ShowItem { case show(NostrEvent?) @@ -59,7 +60,7 @@ struct NotificationItemView: View { EventGroupView(state: state, event: ev, group: .reaction(evgrp)) case .reply(let ev): - NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) { + NBNavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) { EventView(damus: state, event: ev, options: options) } .buttonStyle(.plain) diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift index 8f6fd6893..d5fbeb6ce 100644 --- a/damus/Views/PostView.swift +++ b/damus/Views/PostView.swift @@ -162,8 +162,14 @@ struct PostView: View { } .disabled(posting_disabled) .opacity(posting_disabled ? 0.5 : 1.0) - .bold() .buttonStyle(GradientButtonStyle(padding: 10)) + .conditionalModifier { view in + if #available(iOS 16.0, *) { + AnyView(view.bold()) + } else { + AnyView(view.font(.headline)) + } + } } diff --git a/damus/Views/Profile/ProfileEditButton.swift b/damus/Views/Profile/ProfileEditButton.swift index 6fdd29cfe..9b2515ca2 100644 --- a/damus/Views/Profile/ProfileEditButton.swift +++ b/damus/Views/Profile/ProfileEditButton.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct ProfileEditButton: View { let damus_state: DamusState @@ -13,7 +14,7 @@ struct ProfileEditButton: View { @Environment(\.colorScheme) var colorScheme var body: some View { - NavigationLink(value: Route.EditMetadata) { + NBNavigationLink(value: Route.EditMetadata) { Text("Edit", comment: "Button to edit user's profile.") .frame(height: 30) .padding(.horizontal,25) diff --git a/damus/Views/Profile/ProfileView.swift b/damus/Views/Profile/ProfileView.swift index 47dc0fe83..70d3bf593 100644 --- a/damus/Views/Profile/ProfileView.swift +++ b/damus/Views/Profile/ProfileView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport func follow_btn_txt(_ fs: FollowState, follows_you: Bool) -> String { switch fs { @@ -225,7 +226,7 @@ struct ProfileView: View { var dmButton: some View { let dm_model = damus_state.dms.lookup_or_create(profile.pubkey) - return NavigationLink(value: Route.DMChat(dms: dm_model)) { + return NBNavigationLink(value: Route.DMChat(dms: dm_model)) { Image("messages") .profile_button_style(scheme: colorScheme) } @@ -262,7 +263,7 @@ struct ProfileView: View { follow_state: damus_state.contacts.follow_state(profile.pubkey) ) } else if damus_state.keypair.privkey != nil { - NavigationLink(value: Route.EditMetadata) { + NBNavigationLink(value: Route.EditMetadata) { ProfileEditButton(damus_state: damus_state) } } @@ -348,7 +349,7 @@ struct ProfileView: View { let contacts = Array(contact.referenced_pubkeys) let hashtags = Array(contact.referenced_hashtags) let following_model = FollowingModel(damus_state: damus_state, contacts: contacts, hashtags: hashtags) - NavigationLink(value: Route.Following(following: following_model)) { + NBNavigationLink(value: Route.Following(following: following_model)) { HStack { let noun_text = Text(verbatim: "\(pluralizedString(key: "following_count", count: profile.following))").font(.subheadline).foregroundColor(.gray) Text("\(Text(verbatim: profile.following.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.") @@ -358,7 +359,7 @@ struct ProfileView: View { } if followers.contacts != nil { - NavigationLink(value: Route.Followers(followers: followers)) { + NBNavigationLink(value: Route.Followers(followers: followers)) { followersCount } .buttonStyle(PlainButtonStyle()) @@ -377,12 +378,12 @@ struct ProfileView: View { let noun_text = Text(noun_string).font(.subheadline).foregroundColor(.gray) let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.") if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user { - NavigationLink(value: Route.RelayConfig) { + NBNavigationLink(value: Route.RelayConfig) { relay_text } .buttonStyle(PlainButtonStyle()) } else { - NavigationLink(value: Route.UserRelays(relays: Array(relays.keys).sorted())) { + NBNavigationLink(value: Route.UserRelays(relays: Array(relays.keys).sorted())) { relay_text } .buttonStyle(PlainButtonStyle()) @@ -395,7 +396,7 @@ struct ProfileView: View { if !friended_followers.isEmpty { Spacer() - NavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers, followers: followers)) { + NBNavigationLink(value: Route.FollowersYouKnow(friendedFollowers: friended_followers, followers: followers)) { HStack { CondensedProfilePicturesView(state: damus_state, pubkeys: friended_followers, maxPictures: 3) let followedByString = followedByString(friended_followers, ndb: damus_state.ndb) @@ -449,7 +450,13 @@ struct ProfileView: View { customNavbar } } - .toolbarBackground(.hidden) + .conditionalModifier { view in + if #available(iOS 16.0, *) { + return AnyView(view.toolbarBackground(.hidden)) + } else { + return AnyView(view.navigationBarHidden(true)) + } + } .onReceive(handle_notify(.switched_timeline)) { _ in dismiss() } diff --git a/damus/Views/ProfileActionSheetView.swift b/damus/Views/ProfileActionSheetView.swift index bcec39291..1559ee31f 100644 --- a/damus/Views/ProfileActionSheetView.swift +++ b/damus/Views/ProfileActionSheetView.swift @@ -133,7 +133,13 @@ struct ProfileActionSheetView: View { .onPreferenceChange(InnerHeightPreferenceKey.self) { newHeight in sheetHeight = newHeight } - .presentationDetents([.height(sheetHeight)]) + .conditionalModifier { view in + if #available(iOS 16.0, *){ + return AnyView(view.presentationDetents([.height(sheetHeight)])) + } else { + return view + } + } } } diff --git a/damus/Views/Purple/DamusPurpleView.swift b/damus/Views/Purple/DamusPurpleView.swift index 9d02c7fcb..55940bfcc 100644 --- a/damus/Views/Purple/DamusPurpleView.swift +++ b/damus/Views/Purple/DamusPurpleView.swift @@ -477,7 +477,13 @@ struct DamusPurpleLogoView: View { ) ) .foregroundColor(.white) - .tracking(-2) + .conditionalModifier { view in + if #available(iOS 16.0, *){ + return AnyView(view.tracking(-2)) + } else { + return view + } + } } } .padding(.bottom, 30) diff --git a/damus/Views/Relays/RecommendedRelayView.swift b/damus/Views/Relays/RecommendedRelayView.swift index 8ad0af149..10bd8a075 100644 --- a/damus/Views/Relays/RecommendedRelayView.swift +++ b/damus/Views/Relays/RecommendedRelayView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct RecommendedRelayView: View { let damus: DamusState @@ -66,7 +67,7 @@ struct RecommendedRelayView: View { VStack { RelayPicView(relay: relay, icon: meta?.icon, size: 70, highlight: .none, disable_animation: false) if let meta = damus.relay_model_cache.model(with_relay_id: relay)?.metadata { - NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta)){ + NBNavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta)){ EmptyView() } .opacity(0.0) diff --git a/damus/Views/Relays/RelayConfigView.swift b/damus/Views/Relays/RelayConfigView.swift index 5ddb63fc4..9e84b90b3 100644 --- a/damus/Views/Relays/RelayConfigView.swift +++ b/damus/Views/Relays/RelayConfigView.swift @@ -97,7 +97,13 @@ struct RelayConfigView: View { .padding(.horizontal, 30) .padding(.vertical, 5) } - .scrollIndicators(.hidden) + .conditionalModifier { view in + if #available(iOS 16.0, *) { + return AnyView(view.scrollIndicators(.hidden)) + } else { + return view + } + } .mask( HStack(spacing: 0) { LinearGradient(gradient: Gradient(colors: [Color.clear, Color.white]), startPoint: .leading, endPoint: .trailing) diff --git a/damus/Views/Relays/RelayPicView.swift b/damus/Views/Relays/RelayPicView.swift index a2875c46c..360ab6986 100644 --- a/damus/Views/Relays/RelayPicView.swift +++ b/damus/Views/Relays/RelayPicView.swift @@ -12,9 +12,15 @@ struct FailedRelayImage: View { let url: URL? var body: some View { - let abbrv = String(url?.host()?.first?.uppercased() ?? "R") - Text(abbrv) - .font(.system(size: 40, weight: .bold)) + if #available(iOS 16.0, *){ + let abbrv = String(url?.host()?.first?.uppercased() ?? "R") + Text(abbrv) + .font(.system(size: 40, weight: .bold)) + } else { + let abbrv: String = url?.host?.first?.uppercased() ?? "R" + Text(abbrv) + .font(.system(size: 40, weight: .bold)) + } } } diff --git a/damus/Views/Relays/RelayView.swift b/damus/Views/Relays/RelayView.swift index e6784adca..c96a48ed3 100644 --- a/damus/Views/Relays/RelayView.swift +++ b/damus/Views/Relays/RelayView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct RelayView: View { let state: DamusState @@ -51,7 +52,7 @@ struct RelayView: View { if let relay_connection { RelayStatusView(connection: relay_connection) .background( - NavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta), label: { + NBNavigationLink(value: Route.RelayDetail(relay: relay, metadata: meta), label: { EmptyView() }) .buttonStyle(.plain) diff --git a/damus/Views/Relays/SignalView.swift b/damus/Views/Relays/SignalView.swift index 43a92784c..ccaf04cfc 100644 --- a/damus/Views/Relays/SignalView.swift +++ b/damus/Views/Relays/SignalView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct SignalView: View { let state: DamusState @@ -14,7 +15,7 @@ struct SignalView: View { var body: some View { Group { if signal.signal != signal.max_signal { - NavigationLink(value: Route.RelayConfig) { + NBNavigationLink(value: Route.RelayConfig) { Text("\(signal.signal)/\(signal.max_signal)", comment: "Fraction of how many of the user's relay servers that are operational.") .font(.callout) .foregroundColor(.gray) diff --git a/damus/Views/ReportView.swift b/damus/Views/ReportView.swift index 49a970ac5..785693f19 100644 --- a/damus/Views/ReportView.swift +++ b/damus/Views/ReportView.swift @@ -109,7 +109,11 @@ struct ReportView: View { }) Section(content: { - TextField(NSLocalizedString("Optional", comment: "Prompt to enter optional additional information when reporting an account or content."), text: $report_message, axis: .vertical) + if #available(iOS 16.0, *) { + TextField(NSLocalizedString("Optional", comment: "Prompt to enter optional additional information when reporting an account or content."), text: $report_message, axis: .vertical) + } else { + TextField(NSLocalizedString("Optional", comment: "Prompt to enter optional additional information when reporting an account or content."), text: $report_message) + } }, header: { Text("Additional information", comment: "Header text to prompt user to optionally provide additional information when reporting a user or note.") }) diff --git a/damus/Views/Reposts/RepostedEvent.swift b/damus/Views/Reposts/RepostedEvent.swift index 207ee295a..2f8084320 100644 --- a/damus/Views/Reposts/RepostedEvent.swift +++ b/damus/Views/Reposts/RepostedEvent.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct RepostedEvent: View { let damus: DamusState @@ -15,7 +16,7 @@ struct RepostedEvent: View { var body: some View { VStack(alignment: .leading) { - NavigationLink(value: Route.ProfileByKey(pubkey: event.pubkey)) { + NBNavigationLink(value: Route.ProfileByKey(pubkey: event.pubkey)) { Reposted(damus: damus, pubkey: event.pubkey) .padding(.horizontal) } diff --git a/damus/Views/Search/SearchingEventView.swift b/damus/Views/Search/SearchingEventView.swift index c3aed87f5..99a07fcb3 100644 --- a/damus/Views/Search/SearchingEventView.swift +++ b/damus/Views/Search/SearchingEventView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport enum SearchState { case searching @@ -113,12 +114,12 @@ struct SearchingEventView: View { .progressViewStyle(.circular) } case .found(let ev): - NavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) { + NBNavigationLink(value: Route.Thread(thread: ThreadModel(event: ev, damus_state: state))) { EventView(damus: state, event: ev) } .buttonStyle(PlainButtonStyle()) case .found_profile(let pk): - NavigationLink(value: Route.ProfileByKey(pubkey: pk)) { + NBNavigationLink(value: Route.ProfileByKey(pubkey: pk)) { FollowUserView(target: .pubkey(pk), damus_state: state) } .buttonStyle(PlainButtonStyle()) diff --git a/damus/Views/SearchResultsView.swift b/damus/Views/SearchResultsView.swift index 469a185f5..bd98f0598 100644 --- a/damus/Views/SearchResultsView.swift +++ b/damus/Views/SearchResultsView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NavigationBackport struct MultiSearch { let hashtag: String @@ -50,7 +51,7 @@ struct InnerSearchResults: View { func HashtagSearch(_ ht: String) -> some View { let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht])) - return NavigationLink(value: Route.Search(search: search_model)) { + return NBNavigationLink(value: Route.Search(search: search_model)) { Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.") } } diff --git a/damus/Views/SetupView.swift b/damus/Views/SetupView.swift index 7ae4091d1..954cac13e 100644 --- a/damus/Views/SetupView.swift +++ b/damus/Views/SetupView.swift @@ -6,13 +6,14 @@ // import SwiftUI +import NavigationBackport struct SetupView: View { @StateObject var navigationCoordinator: NavigationCoordinator = NavigationCoordinator() var body: some View { - NavigationStack(path: $navigationCoordinator.path) { + NBNavigationStack(path: $navigationCoordinator.path) { ZStack { VStack(alignment: .center) { Spacer() @@ -54,7 +55,7 @@ struct SetupView: View { } } .background(DamusBackground(maxHeight: 300), alignment: .top) - .navigationDestination(for: Route.self) { route in + .nbNavigationDestination(for: Route.self) { route in route.view(navigationCoordinator: navigationCoordinator, damusState: DamusState.empty) } } diff --git a/damus/Views/SideMenuView.swift b/damus/Views/SideMenuView.swift index 63e545915..4364835a3 100644 --- a/damus/Views/SideMenuView.swift +++ b/damus/Views/SideMenuView.swift @@ -6,6 +6,7 @@ // Ref: https://blog.logrocket.com/create-custom-collapsible-sidebar-swiftui/ import SwiftUI +import NavigationBackport @MainActor struct SideMenuView: View { @@ -46,11 +47,11 @@ struct SideMenuView: View { func SidemenuItems(profile_model: ProfileModel, followers: FollowersModel) -> some View { return VStack(spacing: verticalSpacing) { - NavigationLink(value: Route.Profile(profile: profile_model, followers: followers)) { + NBNavigationLink(value: Route.Profile(profile: profile_model, followers: followers)) { navLabel(title: NSLocalizedString("Profile", comment: "Sidebar menu label for Profile view."), img: "user") } - NavigationLink(value: Route.Wallet(wallet: damus_state.wallet)) { + NBNavigationLink(value: Route.Wallet(wallet: damus_state.wallet)) { navLabel(title: NSLocalizedString("Wallet", comment: "Sidebar menu label for Wallet view."), img: "wallet") } @@ -66,15 +67,15 @@ struct SideMenuView: View { } } - NavigationLink(value: Route.MuteList(users: get_mutelist_users(damus_state.contacts.mutelist))) { + NBNavigationLink(value: Route.MuteList(users: get_mutelist_users(damus_state.contacts.mutelist))) { navLabel(title: NSLocalizedString("Muted", comment: "Sidebar menu label for muted users view."), img: "mute") } - NavigationLink(value: Route.RelayConfig) { + NBNavigationLink(value: Route.RelayConfig) { navLabel(title: NSLocalizedString("Relays", comment: "Sidebar menu label for Relays view."), img: "world-relays") } - NavigationLink(value: Route.Bookmarks) { + NBNavigationLink(value: Route.Bookmarks) { navLabel(title: NSLocalizedString("Bookmarks", comment: "Sidebar menu label for Bookmarks view."), img: "bookmark") } @@ -82,7 +83,7 @@ struct SideMenuView: View { navLabel(title: NSLocalizedString("Merch", comment: "Sidebar menu label for merch store link."), img: "basket") } - NavigationLink(value: Route.Config) { + NBNavigationLink(value: Route.Config) { navLabel(title: NSLocalizedString("Settings", comment: "Sidebar menu label for accessing the app settings"), img: "settings") } } @@ -139,7 +140,7 @@ struct SideMenuView: View { let followers = FollowersModel(damus_state: damus_state, target: damus_state.pubkey) let profile_model = ProfileModel(pubkey: damus_state.pubkey, damus: damus_state) - NavigationLink(value: Route.Profile(profile: profile_model, followers: followers), label: { + NBNavigationLink(value: Route.Profile(profile: profile_model, followers: followers), label: { TopProfile .padding(.bottom, verticalSpacing) diff --git a/damus/Views/Zaps/CustomizeZapView.swift b/damus/Views/Zaps/CustomizeZapView.swift index 224a8bee5..825869bee 100644 --- a/damus/Views/Zaps/CustomizeZapView.swift +++ b/damus/Views/Zaps/CustomizeZapView.swift @@ -146,14 +146,25 @@ struct CustomizeZapView: View { var ZapReply: some View { HStack { - TextField(NSLocalizedString("Send a message with your zap...", comment: "Placeholder text for a comment to send as part of a zap to the user."), text: $model.comment, axis: .vertical) - .focused($focusedTextField, equals: ZapFields.comment) - .task { - self.focusedTextField = .comment - } - .autocorrectionDisabled(true) - .textInputAutocapitalization(.never) - .lineLimit(5) + if #available(iOS 16.0, *) { + TextField(NSLocalizedString("Send a message with your zap...", comment: "Placeholder text for a comment to send as part of a zap to the user."), text: $model.comment, axis: .vertical) + .focused($focusedTextField, equals: ZapFields.comment) + .task { + self.focusedTextField = .comment + } + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .lineLimit(5) + } else { + TextField(NSLocalizedString("Send a message with your zap...", comment: "Placeholder text for a comment to send as part of a zap to the user."), text: $model.comment) + .focused($focusedTextField, equals: ZapFields.comment) + .task { + self.focusedTextField = .comment + } + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .lineLimit(5) + } } .frame(minHeight: 30) .padding(10)