I am growing a health app for the Apple Watch that allows you to select an depth earlier than beginning a exercise. I wish to current the depth picker earlier than the exercise begins, so I attempted presenting it as a sheet earlier than navigating to the precise exercise view. The issue is that when I attempt to dismiss the sheet, it’s dismissed however it comes proper again. I am utilizing Xcode 14.2 and watchOS 9.1.
That is the principle view and in addition the view that presents the mentioned sheet (the primary one, managed by showingZonePickerView
):
import SwiftUI
@major
struct Wise_Watch_AppApp: App {
@StateObject non-public var workoutManager = WorkoutManager()
@SceneBuilder var physique: some Scene {
WindowGroup {
NavigationView {
WorkoutView()
}
.sheet(isPresented: $workoutManager.showingZonePickerView, onDismiss: {
workoutManager.showingZonePickerView = false
}) {
WorkoutLevelPickerView(complete: 5, accomplished: 1)
.toolbar(.hidden)
}
.sheet(isPresented: $workoutManager.showingSummaryView) {
SummaryView()
}
.environmentObject(workoutManager)
}
}
}
That is the view the place the person can decide the popular exercise:
import SwiftUI
import HealthKit
struct WorkoutView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@State var linkActive: Bool = false
var workoutTypes: [HKWorkoutActivityType] = [.cycling, .running, .walking]
var workoutDictionary: Dictionary<String, HKWorkoutActivityType> = [
"figure.outdoor.cycle" : .cycling,
"figure.run" : .running,
"figure.walk" : .walking
]
var physique: some View {
Record(Array(workoutDictionary.keys), id: .self) { workoutType in
NavigationLink(
vacation spot: SessionPagingView(),
tag: workoutDictionary[workoutType]!,
choice: $workoutManager.selectedWorkout
) {
Label("(workoutDictionary[workoutType]!.title)", systemImage: workoutType)
.font(.subheadline)
.fontWeight(.semibold)
.padding()
}
.padding(EdgeInsets(prime: 15, main: 5, backside: 15, trailing: 5))
}
.listStyle(.carousel)
.navigationBarTitle("Exercises")
.onAppear {
workoutManager.requestAuthorization()
}
}
}
That is the view to which the app navigates when a NavigationLink is pressed:
import SwiftUI
import WatchKit
import ConfettiSwiftUI
struct SessionPagingView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@State non-public var choice: Tab = .metrics
@State non-public var counter: Int = 0
@State non-public var isViewHidden: Bool = true
enum Tab {
case metrics, nowPlaying, milestone
}
var physique: some View {
if(isViewHidden) {
sessionView.hidden()
} else {
sessionView
}
}
var sessionView: some View {
TabView(choice: $choice) {
ForEach(workoutManager.tabItems) { merchandise in
VStack {
Textual content("Congrats!")
.font(.title2)
.fontWeight(.daring)
.confettiCannon(counter: $counter, num: 40, radius: 200)
Textual content("You simply reached")
.font(.subheadline)
.foregroundColor(.cyan)
.tag(Tab.milestone)
Textual content("(merchandise.worth) km")
.font(.subheadline)
.foregroundColor(.cyan)
.tag(Tab.milestone)
}
}
MetricsView().tag(Tab.metrics)
NowPlayingView().tag(Tab.nowPlaying)
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
.onAppear {
workoutManager.showingZonePickerView = true
DispatchQueue.major.asyncAfter(deadline: .now() + 1) {
self.isViewHidden = false
}
}
.onChange(of: workoutManager.working) { _ in
displayMetricsView()
}
.onChange(of: workoutManager.tabItems) { _ in
if(workoutManager.tabItems.depend > 0) {
displayMilestoneView()
DispatchQueue.major.asyncAfter(deadline: .now() + .seconds(5), execute: {
displayMetricsView()
})
}
}
.ignoresSafeArea()
.animation(.easeInOut, worth: self.choice)
}
non-public func displayMetricsView() {
withAnimation {
choice = .metrics
}
}
non-public func displayMilestoneView() {
withAnimation {
choice = .milestone
WKInterfaceDevice.present().play(.notification)
DispatchQueue.major.asyncAfter(deadline: .now() + .seconds(1), execute: {
counter += 1
})
}
}
}
That is the precise view that I am presenting contained in the sheet:
import SwiftUI
struct WorkoutLevelPickerView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@Setting(.dismiss) non-public var dismiss
let complete: Int
@State var lineWidth: CGFloat = 16
@State var colour: Shade = .inexperienced
@State var accomplished: Double = 1.0
@State var currentZone: HeartRateZone = zones[0]
@State var isScrolling: Bool = false
var physique: some View {
VStack {
ZStack {
CircleLabelView(
radius: 30,
monitoring: 0,
dimension: .init(width: 120, top: 120),
textual content: currentZone.depth.uppercased()
)
.font(.headline)
.body(width: 50, top: 50)
.rotationEffect(Angle(levels: Double(currentZone.labelRotationAngleModifier * currentZone.depth.depend / 2)))
.opacity(isScrolling ? 0 : 1)
.animation(.easeInOut, worth: isScrolling)
WorkoutLevelPickerBackgroundView(complete: complete, lineWidth: lineWidth)
withAnimation(.spring()) {
WorkoutLevelPickerProgressView(complete: complete, accomplished: Int(accomplished), lineWidth: lineWidth, zone: currentZone)
}
VStack {
Button {
dismiss()
} label: {
Picture(systemName: currentZone.iconName)
.padding()
.font(.title2)
}
.body(width: 70, top: 70)
}
}
.body(width: 150, top: 150)
.focusable()
.digitalCrownRotation(
detent: $accomplished.animation(.spring()),
from: 1.0,
via: 5.0,
by: 1.0,
sensitivity: .low,
isContinuous: false,
isHapticFeedbackEnabled: true,
onChange: { _ in
isScrolling = true
},
onIdle: {
isScrolling = false
}
)
.digitalCrownAccessory(.hidden)
.onChange(of: accomplished) {_ in
if(Int(accomplished) != currentZone.id) {
currentZone = zones[Int(completed) - 1]
print(currentZone.tint.description)
}
}
}
}
}
It is a video of the stream that generates my drawback:
I attempted presenting the sheet from different views. I additionally tried dismissing the sheet via a binding, not via the dismiss motion. On all these modifications, the result was the identical as earlier than.
Edit:
Forgot to say that, when the sheet is introduced, urgent the facet button will dismiss it and the app will work as supposed till the person tries to start out a brand new exercise.