0

I have a WKCrownSequencer that triggers an action in my pushed interface controller and the first time through everything works fine. When I go back to root interface controller regardless of the method (pop or reloadRootcontrollers) the digital crown no longer works in first interface controller nor the second one. The StartInterfaceController is the rootInterfaceController and the MidWorkoutInterfaceController is the pushed one.

import WatchKit
import Foundation


class StartInterfaceController: 
WKInterfaceController,CLLocationManagerDelegate {

override func awake(withContext context: Any?) {
    super.awake(withContext: context)

    // Configure interface objects here.
}

override func willActivate() {
    // This method is called when watch view controller is about to be visible to user
    super.willActivate()
}

@IBAction func start() {

    WKInterfaceController.reloadRootControllers(
        withNames: ["midWorkout"], contexts: []
    )
}

The second interface controller is below.

import WatchKit
import Foundation
class MidWorkoutInterfaceController: WKInterfaceController, WKCrownDelegate {

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
        print("viewdidAwake")
        print("ViewWillActivate")
        crownSequencer.delegate = self

        crownSequencer.focus()
        WKInterfaceDevice.current().play(.success)


        currentPhase = 0

        let workoutType = UserDefaults.standard.object(forKey: "CurrentType") as? [String] ?? [ "Swimming", "T1"]
        orderOfEventsSetter = workoutType
        updateCurrentPhase()
    }
    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
        crownSequencer.focus()
    }

    var clockTimer: Timer!
    func workoutStarted(){
        clockTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer  in
            self?.totalTimeOutlet.setText( String(describing: -1 * Int(self!.startDate!.timeIntervalSinceNow)))
            self?.splitTimeOutlet.setText( String(describing: -1 * Int(self!.currentStartDate!.timeIntervalSinceNow)))
        }   
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }


    var startDate: Date?
    var currentStartDate: Date?
    //Outlets

    @IBOutlet var currentPhaseOutlet: WKInterfaceLabel!
    @IBOutlet var totalTimeOutlet: WKInterfaceLabel!
    @IBOutlet var splitTimeOutlet: WKInterfaceLabel!
    @IBOutlet var currentPaceOutlet: WKInterfaceLabel!
    @IBOutlet var totalDistanceOutlet: WKInterfaceLabel!

    var orderOfEventsSetter: Array<String>{
        get{
            return orderOfEvents
        }
        set{
            var tempArray = ["GPS Locking In"]
            for phase in newValue {
                tempArray.append(phase)
            }
            orderOfEvents = tempArray
        }
    }

    private var orderOfEvents: [String] = []
    var currentPhase = 0 {
        didSet{
            if !orderOfEvents.isEmpty {
                updateCurrentPhase()
            }
        }
    }
    func updateCurrentPhase(){
        currentPhaseOutlet.setText(orderOfEvents[currentPhase])
    }

    //timing for location requests

    //Corelocation Section

    //CoreMotion Section

    ///crown control
    var currentDialRotation = 0.0
    let dialRotationRange =  Range(uncheckedBounds: (lower: -Double.pi / 4, upper: Double.pi / 4))
    let constantForTimer: TimeInterval = 0.1
    var justTransitioned = false

    func crownDidRotate(_ crownSequencer: WKCrownSequencer?, rotationalDelta: Double) {
        currentDialRotation += rotationalDelta
        if !dialRotationRange.contains(currentDialRotation){

            currentDialRotation = 0.0
            justTransitioned = true
            makeTransition()

            //make so two transitions cannot happen right after each other

        }
        print(currentDialRotation)
    }
    func crownDidBecomeIdle(_ crownSequencer: WKCrownSequencer?) {
        print(String(describing: orderOfEvents[currentPhase]))
        print("crown stopped")
    }

    func makeTransition(){

        print(currentPhase)
        print(orderOfEvents.count)
        if (currentPhase) == orderOfEvents.count - 1 {
            endWorkout()
        }
        else if (currentPhase == 0){
            WKInterfaceDevice.current().play(.start)
            let dateFormat = DateFormatter()
            dateFormat.dateFormat = "mm/dd/yyyy"
            startDate = Date()
            currentStartDate = Date()
            workoutStarted()
            currentPhase += 1
        }
        else{
            WKInterfaceDevice.current().play(.start)
            print("transitioning to " + String(describing: orderOfEvents[currentPhase + 1]))

            currentStartDate = Date()

            stopTimers()
            currentPhase += 1
        }
    }

    @IBAction func endWorkoutButton() {
        endWorkout()
    }
    func endWorkout(){
        stopTimers()
        clockTimer.invalidate()
        alerts()
    }

    func alerts(){
        let saveAction = WKAlertAction(title: "Save",
                                       style: WKAlertActionStyle.default) {

                                        self.goToStartScreen()
        }

        let discardAction = WKAlertAction(title: "Discard Workout",
                                          style: WKAlertActionStyle.cancel) {

                                            self.goToStartScreen()
        }
        presentAlert(withTitle: "Workout Complete",
                     message: "Would you like to save the workout?",
                     preferredStyle: WKAlertControllerStyle.alert,
                     actions: [saveAction, discardAction])
    }

    func goToStartScreen(){
        crownSequencer.resignFocus()

        self.popToRootController()
    }

    func stopTimers(){
        if orderOfEvents[currentPhase] == "Running"{
        }
        if orderOfEvents[currentPhase] == "Biking"{
        }
        if currentPhase == orderOfEvents.count {
            clockTimer.invalidate()
        }
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • What happens if you remove the `crownSequencer.focus()` lines from both `awake(withContext:)` and `willActivate()`? You shouldn't have to call it, the interface controller should be scrollable automatically using the crown. – Dávid Pásztor Aug 24 '17 at 08:57
  • I just tried and deleting the crownSequencer.focus() results in no longer being able to collect rotational data from the digital crown which is the main purpose of the code because it triggers an action. – Kodie Artner Aug 24 '17 at 15:10

1 Answers1

0

According to Apple's document here:

"...Only one object in your interface can have focus at any given time, so if your interface also contains picker objects or has scrollable scenes, you must coordinate changes in focus accordingly. For example, calling the sequencer's focus method causes any picker objects or interface controllers to resign focus. When the user taps on a picker object, the currently active sequencer resigns focus, and the selected picker object gains the focus... "

And you are to lose the focus at any time unpredictable...

"...If the user taps a picker object or a scrollable scene in your interface, the system automatically removes the focus from any active crown sequencer..."

Jiulong Zhao
  • 1,313
  • 1
  • 15
  • 25