Hello,
I am currently developing an app using visionOS, and I am looking for a way to obscure specific content in screenshots. My app includes certain content that is exclusive to premium users, and I need to hide these parts when screenshots are shared on social media.
In iOS, I was able to achieve this by extending SecureField to hide specific Views or Images, but this method does not work in visionOS. I am seeking advice on the best approach to implement this feature in visionOS.
https://github.com/yoxisem544/ScreenshotPreventing-iOS
Specifically, I would appreciate guidance on the following points:
The optimal method for obscuring specific Views or Images in screenshots on visionOS
Any tips or tricks when using existing components similar to SecureField
Techniques or approaches used by other developers to implement similar features
Your assistance would be greatly appreciated. Thank you for your help.
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello everyone!
I have a WKWebView in my swiftui app and would like to enable to "pop root view when selected tab is tapped again" feature, but I have been unable to figure out how to implement this.
Here's the basic code:
class TabIdentifierModel:ObservableObject {
@Published var tabSelection:TabIdentifier {
willSet {
if newValue == tabSelection {
NotificationCenter.default.post(name: .popRootView, object: nil, userInfo: ["tab": newValue.rawValue])
}
}
}
init() {
tabSelection = .home
}
}
struct ContentView: View {
@AppStorage(AppStorageKeys.enableShorts) var enableShorts = true
@StateObject var storeVM = StoreVM()
@StateObject var downloadURLManager = DownloadURLManager.shared
@State var downloadViewIsOpen = false
// ......
@State var tabSelection = TabIdentifierModel()
var body: some View {
TabView(selection: $tabSelection.tabSelection) {
// ......
WebViewWrapper(url: $libraryTabURL)
.tabItem {
Label {
Text("Library")
} icon: {
Image(systemName: "folder.fill")
}
}.tag(TabIdentifier.library)
// ......
}
.environmentObject(tabSelection)
}
}
Tapping on the tab again doesn't seem to set the value again thus the NotificationCenter.default.post is not sent and the web view is not reloaded.
Help would be much appreciated! Thanks in advance!
Hi, would appreciate based on my implementation how can I control the dimmed effect of sheet presentation on iOS 17 later.
Here is my sample implementation:
struct ContentView: View {
@State private var present = true
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
.sheet(isPresented: $present, content: {
ContentView2()
.modifier(
SheetModifier(
dismissDisabled: true,
detents: [.medium, .large],
dragIndicator: .hidden
)
)
})
}
}
#Preview {
ContentView()
}
struct SheetModifier: ViewModifier {
var dismissDisabled: Bool
var detents: Set<PresentationDetent>
var backgroundInteraction: PresentationBackgroundInteraction
var dragIndicator: Visibility
var cornerRadius: CGFloat
init(
dismissDisabled: Bool = false,
detents: Set<PresentationDetent>,
backgroundInteraction: PresentationBackgroundInteraction = .automatic,
dragIndicator: Visibility = .automatic,
cornerRadius: CGFloat = 20
) {
self.dismissDisabled = dismissDisabled
self.detents = detents
self.backgroundInteraction = backgroundInteraction
self.dragIndicator = dragIndicator
self.cornerRadius = cornerRadius
}
func body(content: Content) -> some View {
content
.background(.clear)
.interactiveDismissDisabled(dismissDisabled)
.presentationDetents(detents)
.presentationBackgroundInteraction(backgroundInteraction)
.presentationDragIndicator(dragIndicator)
.presentationCornerRadius(cornerRadius)
}
}
We can add many models in the Reality Composer Pro scene, but when I use RealityView to display and add modifiers in SwiftUI, the modifiers will have Effect, and I don't want to do this. I hope this modifier will be valid for a single model in the Reality Composer Pro scenario.
May I ask how to add modifiers to a single model in the Reality Composer Pro scene?
Hello !
This will be my first blog post. I hope I will find the solution.
So, I try to use the new iOS 17+ API for ScrollView. I have an array of messages that I want to show in scroll view.
And I need to scroll to bottom when I tap to Send button. When I use scrollPosition(id:anchor:), it freeze the UI. The link to the screencast to demonstrate. I think the problem might be the keyboard when it shows and hides. But I can't understand what can I do.
struct ChatView: View {
@ObservedObject var viewModel: CoachViewModel
@State private var scrollTo: Message.ID?
var body: some View {
ScrollView {
LazyVStack {
ForEach(viewModel.messages) { message in
MessageView(viewModel: viewModel, message: message)
}
}
.scrollTargetLayout()
}
.scrollPosition(id: $scrollTo)
.background(.primaryBackground)
.onChange(of: viewModel.scrollToBottom) {
if $1, let lastMessage = viewModel.messages.last {
withAnimation {
scrollTo = lastMessage.id
}
viewModel.scrollToBottom = false
}
}
}
}
struct Message: Identifiable, Hashable {
let id: UUID
let author: MessageAuthor
let text: String
}
final class CoachViewModel: ObservableObject {
@Published var messageTextInput = ""
@Published var scrollToBottom = false
@Published var messages: [Message] = [...]
// ... more code ...
func sendMessage() {
messages.append(
.init(
id: .init(),
author: .user,
text: messageTextInput
)
)
messageTextInput.removeAll()
scrollToBottom = true
}
}
struct CoachView: View {
@StateObject private var viewModel = CoachViewModel()
@State private var isSearching = false
var body: some View {
VStack(spacing: 0) {
Group {
CoachTitleView(viewModel: viewModel, isSearching: $isSearching)
ChatView(viewModel: viewModel)
}
.onTapGesture {
UIApplication.shared.endEditing()
}
if isSearching {
MatchboxView(viewModel: viewModel)
} else {
InputTextFieldView(viewModel: viewModel)
}
}
}
}
For some reason, every time I'm accessing a view populated with posts and fetching posts, my app has like a 5-8 second hang time. I don't know whats causing this issue, and I have been dealing with this for 3 days.
`func fetchPosts(completion: @escaping (Result<[PostWithUser], Error>) -> Void) {
if !cachedPosts.isEmpty {
completion(.success(self.cachedPosts))
return
}
postsRef.order(by: "timestamp", descending: true).getDocuments { [weak self] snapshot, error in
guard let self = self else { return }
if let error = error {
completion(.failure(error))
return
}
guard let documents = snapshot?.documents else {
completion(.success([]))
return
}
let group = DispatchGroup()
var postsWithUsers: [PostWithUser] = []
DispatchQueue.global(qos: .userInitiated).async {
for document in documents {
group.enter()
let data = document.data()
guard let userId = data["userId"] as? String,
let parentId = data["parentId"] as? String,
let groupId = data["groupId"] as? String,
let text = data["text"] as? String,
let isPinned = data["isPinned"] as? Bool,
let imageUrl = data["imageUrl"] as? String,
let videoUrl = data["videoUrl"] as? String,
let timestamp = data["timestamp"] as? Timestamp,
let views = data["views"] as? Int else {
group.leave()
continue
}
let post = Post(id: document.documentID, userId: userId, parentId: parentId, groupId: groupId, text: text, imageUrl: imageUrl, videoUrl: videoUrl, timestamp: timestamp.dateValue(), isPinned: isPinned, likedBy: [], views: views)
self.usersRef.document(userId).getDocument { userDocument, error in
defer { group.leave() }
if let userDocument = userDocument, let userData = userDocument.data() {
let user = User(
id: userId,
username: userData["username"] as? String ?? "",
bio: userData["bio"] as? String ?? "",
profilePictureUrl: userData["profileImageUrl"] as? String ?? "",
privateProfile: userData["privateProfile"] as? Bool ?? false,
privateFollowerList: userData["privateFollowerList"] as? Bool ?? false,
privateFollowingList: userData["privateFollowingList"] as? Bool ?? false,
privateReplies: userData["privateReplies"] as? Bool ?? false,
privateLikes: userData["privateLikes"] as? Bool ?? false
)
let postWithUser = PostWithUser(post: post, user: user)
DispatchQueue.main.async {
postsWithUsers.append(postWithUser)
}
} else {
print("Failed to fetch user data for userId: \(userId), error: \(String(describing: error))")
}
}
}
group.notify(queue: .main) {
self.cachedPosts = postsWithUsers
completion(.success(postsWithUsers))
}
}
}
}`
`
func fetchPosts() {
PostService.shared.fetchPosts { result in
switch result {
case .success(let posts):
DispatchQueue.main.async {
self.posts = posts
}
case .failure(let error):
print("Failed to fetch posts: \(error)")
}
}
}
func refreshPosts() {
PostService.shared.refreshPosts { result in
switch result {
case .success(let posts):
DispatchQueue.main.async {
self.posts = posts
}
case .failure(let error):
print("Failed to fetch posts: \(error)")
}
}
}
I am currently refactoring my app's side menu to be more like Twitter's. I have the UI down in terms of how the side menu looks and appears, but the issue is navigating to a view from the side menu. The views that a user can go to from the side menu are a mix of SwiftUI views & UIKit View Controllers. As of right now, when a user navigates to a view from the side menu, it presents it modally as a sheet. I want it to have regular navigation, where the user goes to the view displayed in full screen and can tap on the back button to go back to the previous view.
Here is the associated code:
SideMenuView.swift
SideMenuViewModel.swift
How can I modify the navigation logic to be like Twitter's? I've been stuck for days trying to find a fix but it has been a struggle.
0
I'm trying to make a list of trips that a person has gone on, and when someone has no trips in their list, it will display a ContentUnavailableView with a NavigationLink to take them to a new view. I am encountering strange issues when using the ContentUnavailableView with the NavigationLink, such as the back button being unaligned and not being able to swipe back to the previous view.
I expected the ContentUnavailableView to link without any of these issues.
Any guidance would be greatly appreciated.
Prerequisite Information
I am trying to use Core Data in my SwiftUI app. I have created 3 entities, a Record, a Header and an Entry. The Record contains the Header entities. The Header contain other Header or Entry entities. The Entry has a title and a value.
My List view looks like this, I fetch the records with a @FetchRequest.
NavigationView {
List {
ForEach(records) { record in
NavigationLink(destination: DetailView(headers: record.headers!.allObjects as? [Header] ?? [], isNewEntry: true)) {
Text(record.id!.uuidString)
}
}
}
}
In my DetailView I have a form that passes the details to other views which create a DisclosureGroup for a Header, a bold Text for a subheader, and a TextField for an Entry
let headers: [Header]
let isNewEntry: Bool
@Environment(\.managedObjectContext) var managedObjectContext
init(headers: [Header], isNewEntry: Bool = false) {
self.headers = headers
self.isNewEntry = isNewEntry
}
Form {
ForEach(Array(headers.enumerated()), id: \.element) { index, header in
HeaderView(header: header, isExpanded: Binding(
get: { self.expandedStates[header.id!, default: false] },
set: { self.expandedStates[header.id!] = $0 }
))
}
}
Problem
When I press the record in the list, it takes me to the DetailView where I can write something in the TextField.
Then if I slide back and do not press the save button and then press the same record again from the list, it retains the data I wrote in the TextField.
Question
How can I make it so that the data is not retained if I slide back except only when I press the save button?
Please let me know if any other information is needed or if something is unclear.
Hello everyone,
I'm working on a SwiftUI app that requires location services, and I've implemented a LocationManager class to handle location updates and permissions. However, I'm facing an issue where the location permission popup does not appear when the app is launched.
Here is my current implementation:
LocationManager.swift:
import CoreLocation
import SwiftUI
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
@Published var userLocation: CLLocation?
@Published var isAuthorized = false
@Published var authorizationStatus: CLAuthorizationStatus = .notDetermined
override init() {
super.init()
locationManager.delegate = self
checkAuthorizationStatus()
}
func startLocationUpdates() {
locationManager.startUpdatingLocation()
}
func stopLocationUpdates() {
locationManager.stopUpdatingLocation()
}
func requestLocationAuthorization() {
print("Requesting location authorization")
DispatchQueue.main.async {
self.locationManager.requestWhenInUseAuthorization()
}
}
private func checkAuthorizationStatus() {
print("Checking authorization status")
authorizationStatus = locationManager.authorizationStatus
print("Initial authorization status: \(authorizationStatus.rawValue)")
handleAuthorizationStatus(authorizationStatus)
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("Authorization status changed")
authorizationStatus = manager.authorizationStatus
print("New authorization status: \(authorizationStatus.rawValue)")
handleAuthorizationStatus(authorizationStatus)
}
private func handleAuthorizationStatus(_ status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways, .authorizedWhenInUse:
DispatchQueue.main.async {
self.isAuthorized = true
self.startLocationUpdates()
}
case .notDetermined:
requestLocationAuthorization()
case .denied, .restricted:
DispatchQueue.main.async {
self.isAuthorized = false
self.stopLocationUpdates()
print("Location access denied or restricted")
}
@unknown default:
DispatchQueue.main.async {
self.isAuthorized = false
self.stopLocationUpdates()
}
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
DispatchQueue.main.async {
self.userLocation = locations.last
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Location manager error: \(error.localizedDescription)")
}
}
MapzinApp.swift:
@main
struct MapzinApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
@StateObject private var locationManager = LocationManager()
var body: some Scene {
WindowGroup {
Group {
if locationManager.authorizationStatus == .notDetermined {
Text("Determining location authorization status...")
} else if locationManager.isAuthorized {
CoordinatorView()
.environmentObject(locationManager)
} else {
Text("Location access is required to use this app. Please enable it in Settings.")
}
}
}
}
}
Log input:
Checking authorization status
Initial authorization status: 0
Requesting location authorization
Authorization status changed
New authorization status: 0
Requesting location authorization
Despite calling requestWhenInUseAuthorization() when the authorization status is .notDetermined, the permission popup never appears. Here are the specific steps I have taken:
Checked the Info.plist to ensure the necessary keys for location usage are present:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
NSLocationAlwaysAndWhenInUseUsageDescription
Verified that the app's target settings include location services capabilities.
Tested on a real device to ensure it's not a simulator issue.
I'm not sure what I might be missing. Any advice or suggestions to resolve this issue would be greatly appreciated. Thank you!
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntax Image(uiImage: UIImage(named: String)). This successfully displays the image, but if I change the image file name in the app, the image doesn't update properly.
I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly.
I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
Hi, thought I'd share some feedback (which was also sent to Apple) publicly in case anyone else is experiencing the same issue or has an idea of how to circumvent the issue while Apple investigates.
TLDR: Views presented with the .fullScreenCover modifier can be incorrectly dismissed when a child view presented with a .sheet modifier inside the .fullScreenCover is dismissed.
The intended behavior is that the child sheet views can be dismissed without dismissing the parent full screen cover views. It appears this bug has been present in versions of iOS 17 as well as iOS 18.
Short of using something other than a .fullScreenCover to present the view, I'm still searching for a solution to this bug.
Filing: FB14007758
Steps to Reproduce (see code below):
Open a View in .fullScreenCover presentation
In the view presented via the .fullScreenCover, add two sheet modifiers with two different views (e.g. SheetOneView, SheetTwoView)
Toggle the presentation of SheetOneView and SheetTwoView randomly until the .fullScreenCover is incorrectly dismissed.
Reproducible Code:
import SwiftUI
struct SheetOneView: View {
var body: some View {
Text("Sheet: 1")
}
}
struct SheetTwoView: View {
var body: some View {
Text("Sheet: 2")
}
}
struct FullScreenCoverView: View {
@State var isSheetOnePresented = false
@State var isSheetTwoPresented = false
var body: some View {
VStack(content: {
Text("Full Screen Cover")
HStack {
Button("Open Sheet 1") {
isSheetOnePresented = true
}
Button("Open Sheet 2") {
isSheetTwoPresented = true
}
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
})
.sheet(isPresented: $isSheetOnePresented) {
SheetOneView()
}
.sheet(isPresented: $isSheetTwoPresented) {
SheetTwoView()
}
}
}
struct ContentView: View {
@State var isFullScreenCoverPresented = false
var body: some View {
VStack {
Button("Open Full Screen Cover") {
isFullScreenCoverPresented = true
}
}
.fullScreenCover(isPresented: $isFullScreenCoverPresented, content: {
FullScreenCoverView()
})
.padding()
}
}
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntaxImage(uiImage: UIImage(named: String))This
successfully displays the image, but if I change the image file name in the app, the image doesn't update properly.
I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly.
I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
When testing my app on an iPhone SE i noticed an issue with the UI when editing some text in a text field. When the keyboard comes up it pushes everything in the view up and part of the text field gets covered by the navigation title and buttons. It gets worse when testing dynamic fonts and changing the text to XXLarge or higher. There are no issues on a larger screen.
Is it possible to prevent the keyboard from push up the content of the view when it is displayed?
This is with the default font of large.
This is with the extra large text
var body: some View {
NavigationStack {
VStack {
HStack {
Text("Name")
Spacer()
TextField("Name", text: $name)
.multilineTextAlignment(.trailing)
.textFieldStyle(.roundedBorder)
.frame(width: 240)
.onChange(of: name) {
if name.count >= 10 {
isShowingLongNameWarning = true
} else {
isShowingLongNameWarning = false
}
}
}
VStack(alignment: .trailing){
HStack {
Text("Short Name")
Spacer()
TextField("Short Name", text: $shortName.max(shortNameCharacterLimit))
.multilineTextAlignment(.trailing)
.textFieldStyle(.roundedBorder)
.frame(width: isShowingLongNameWarning ? 215 : 240)
if isShowingLongNameWarning {
VStack {
Image(systemName: "exclamationmark.circle")
}
.popoverTip(shortNameTip)
}
}
Text("Short Name Length: \(shortName.count) characters")
.font(.caption)
.foregroundStyle(shortName.count >= shortNameCharacterLimit ? .red : .primary)
}
HStack {
Text("Fluid Amount")
Spacer()
TextField("Fluid Amount", value: $amount, format: .number)
.multilineTextAlignment(.trailing)
.textFieldStyle(.roundedBorder)
.keyboardType(.decimalPad)
.focused($numberPadIsFocused)
.frame(width: 140)
.toolbar {
if numberPadIsFocused {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("Done") {
numberPadIsFocused = false
}
}
}
}
}
HStack {
Text("Unit of Measure")
Spacer()
Picker("Unit of measure", selection: $unitOfMeasure) {
ForEach(FluidUnit.allCases) {
Text($0.title)
}
}
.tint(colorScheme == .dark ? .yellow : .pink)
}
.accessibilityElement()
Toggle("Favorite Drink", isOn: $isFavorite)
Text("Drink Image")
ScrollView(.horizontal) {
HStack{
ForEach(DataStore.drinkImages, id: \.self) { image in
Button {
selectDrinkImage(imageName: image)
} label: {
ZStack {
Image(image)
.resizable()
.scaledToFit()
.frame(height: 100)
if imageName == image {
SelectedDrinkImageView()
}
}
}
.padding(.trailing, 30)
}
}
.scrollTargetLayout()
}
.scrollIndicators(.hidden)
.scrollTargetBehavior(.viewAligned)
Spacer()
.navigationTitle("Add a Drink")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Save") {
addDrink()
}
.tint(colorScheme == .dark ? .yellow : .pink)
.disabled(disableSaveButton())
}
ToolbarItem(placement: .topBarLeading) {
Button("Cancel") {
dismiss()
}
.tint(colorScheme == .dark ? .yellow : .pink)
}
}
}
.padding()
}
}
I'm loving the TabView behaviour, but specifically on a landscape iPad, I'd like to have the app default to sidebar mode. There's tons of space, and for my app it just looks better. I'd like the TabView behaviour everywhere else, though.
I know I can set
TabView {
...
}.tabViewStyle(.sidebarAdaptable)
But what I really want is a .sidebarPreferred attribute that uses a sidebar where it would make sense, and a tab bar anywhere else.
Even on a portrait iPad I'd like to have the option to have the sidebar style be the default.
Is there a way to do this now, or should I open a Feedback?
Thanks
I'm creating an application with swiftui which gets images and videos from the Photos picker then store them with swiftData for later use.
I save both images and videos as data with @Attribute(.externalStorage).
But it just seems wrong to me to store the videos that way, they can be several gigabytes in size . What is the correct way to handle something like this ? Is it to store the url and then each time the user wants to see a video save a temporary video ?. If that's the case can anyone show me how this should be done?
Any comments appreciated
Guillermo
With the introduction of the new matchedTransitionSource from iOS 18, we can apply a zoom transition in the navigation view using .navigationTransition(.zoom) This works well for zoom animations.
However, when I try to apply a matched geometry effect to views that are similar in the source and destination views, the zoom transition works, but those views don't transition seamlessly as they do with a matched geometry effect.
Is it possible to still use matched geometry for subviews of the source and destination views along with the new navigationTransition?
Here’s a little demo that reproduces this behaviour:
struct ContentView: View {
let colors: [[Color]] = [
[.red, .blue, .green],
[.yellow, .purple, .brown],
[.cyan, .gray]
]
@Namespace() var namespace
var body: some View {
NavigationStack {
Grid(horizontalSpacing: 50, verticalSpacing: 50) {
ForEach(colors, id: \.hashValue) { rowColors in
GridRow {
ForEach(rowColors, id: \.self) { color in
NavigationLink {
DetailView(color: color, namespace: namespace)
.navigationTransition(
.zoom(
sourceID: color,
in: namespace
)
)
.edgesIgnoringSafeArea(.all)
} label: {
ZStack {
RoundedRectangle(cornerRadius: 5)
.foregroundStyle(color)
.frame(width: 48, height: 48)
Image(systemName: "star.fill")
.foregroundStyle(Material.bar)
.matchedGeometryEffect(id: color,
in: namespace,
properties: .frame, isSource: false)
}
}
.matchedTransitionSource(id: color, in: namespace)
}
}
}
}
}
}
}
struct DetailView: View {
var color: Color
let namespace: Namespace.ID
var body: some View {
ZStack {
color
Image(systemName: "star.fill")
.resizable()
.foregroundStyle(Material.bar)
.matchedGeometryEffect(id: color,
in: namespace,
properties: .frame, isSource: false)
.frame(width: 100, height: 100)
}
.navigationBarHidden(false)
}
}
#Preview {
ContentView()
}
As the title states, I'm trying to apply a .popoverTip to a Menu { } which is inside of a .toolbar { }. The toolbar has default placement and the menu includes a toggle button, and a NavigationLink.
I've ensured that tips can show on the view by using a TipView(tip: ) within my view which displays. Am I missing something? Is this not possible?
Alternatively, can anyone recommend a method to potentially debug why a tip won't show for future debugging?
I'm not quite sure whether this post belongs in a Design forum or here, but with iOS 18 Developer Beta 1 and watchOS 11 Developer Beta 1, when a Live Activity is displayed on an Apple Watch, the system font used is SF Pro rather than SF Compact.
I would expect that the design guidance would be to stick with SF Compact while on watchOS, and I would expect that the system font, when displayed on the Apple Watch using .supplementalActivityFamilies([.small]), would appear as SF Compact.
To ensure that SF Compact appears on my Live Activity when viewed on Apple Watch, I can set a custom font for use with the small supplemental family, but this seems really clunky; is there any other guidance here?
If anyone even uses this, GCVirtualController from import GameController no longer plays nice with SwiftUI NavigationView
Working on changes to get by...
This was working in iOS 17.x but not in iOS 18 and iPadOS 18.
Just a heads up...