Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Common/Extensions/Double.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
import Foundation


extension Double {
func floored(to increment: Double) -> Double {
extension FloatingPoint {
func floored(to increment: Self) -> Self {
if increment == 0 {
return self
}

return floor(self / increment) * increment
}

func ceiled(to increment: Double) -> Double {
func ceiled(to increment: Self) -> Self {
if increment == 0 {
return self
}
Expand Down
2 changes: 2 additions & 0 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ extension DeviceDataManager: CustomDebugStringConvertible {
"",
pumpManager != nil ? String(reflecting: pumpManager!) : "pumpManager: nil",
"",
String(reflecting: watchManager!),
"",
String(reflecting: statusExtensionManager!),
].joined(separator: "\n")
}
Expand Down
143 changes: 101 additions & 42 deletions Loop/Managers/WatchDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,33 +42,18 @@ final class WatchDataManager: NSObject {
@objc private func updateWatch(_ notification: Notification) {
guard
let rawUpdateContext = notification.userInfo?[LoopDataManager.LoopUpdateContextKey] as? LoopDataManager.LoopUpdateContext.RawValue,
let updateContext = LoopDataManager.LoopUpdateContext(rawValue: rawUpdateContext),
let session = watchSession
let updateContext = LoopDataManager.LoopUpdateContext(rawValue: rawUpdateContext)
else {
return
}

switch updateContext {
case .glucose:
break
case .tempBasal:
break
case .glucose, .tempBasal:
sendWatchContextIfNeeded()
case .preferences:
sendSettingsIfNeeded()
return
default:
return
}

switch session.activationState {
case .notActivated, .inactive:
session.activate()
case .activated:
createWatchContext { (context) in
if let context = context {
self.sendWatchContext(context)
}
}
break
}
}

Expand Down Expand Up @@ -98,6 +83,17 @@ final class WatchDataManager: NSObject {

log.default("Transferring LoopSettingsUserInfo")
session.transferUserInfo(LoopSettingsUserInfo(settings: settings).rawValue)
}

private func sendWatchContextIfNeeded() {
guard let session = watchSession, session.isPaired, session.isWatchAppInstalled else {
return
}

guard case .activated = session.activationState else {
session.activate()
return
}

createWatchContext { (context) in
if let context = context {
Expand All @@ -107,32 +103,39 @@ final class WatchDataManager: NSObject {
}

private func sendWatchContext(_ context: WatchContext) {
if let session = watchSession, session.isPaired && session.isWatchAppInstalled {
let complicationShouldUpdate: Bool
guard let session = watchSession, session.isPaired, session.isWatchAppInstalled else {
return
}

guard case .activated = session.activationState else {
session.activate()
return
}

if let lastContext = lastComplicationContext,
let lastGlucose = lastContext.glucose, let lastGlucoseDate = lastContext.glucoseDate,
let newGlucose = context.glucose, let newGlucoseDate = context.glucoseDate
{
let enoughTimePassed = newGlucoseDate.timeIntervalSince(lastGlucoseDate).minutes >= 30
let enoughTrendDrift = abs(newGlucose.doubleValue(for: minTrendUnit) - lastGlucose.doubleValue(for: minTrendUnit)) >= minTrendDrift
let complicationShouldUpdate: Bool

complicationShouldUpdate = enoughTimePassed || enoughTrendDrift
} else {
complicationShouldUpdate = true
}
if let lastContext = lastComplicationContext,
let lastGlucose = lastContext.glucose, let lastGlucoseDate = lastContext.glucoseDate,
let newGlucose = context.glucose, let newGlucoseDate = context.glucoseDate
{
let enoughTimePassed = newGlucoseDate.timeIntervalSince(lastGlucoseDate) >= session.complicationUserInfoTransferInterval
let enoughTrendDrift = abs(newGlucose.doubleValue(for: minTrendUnit) - lastGlucose.doubleValue(for: minTrendUnit)) >= minTrendDrift

if session.isComplicationEnabled && complicationShouldUpdate {
log.default("transferCurrentComplicationUserInfo")
session.transferCurrentComplicationUserInfo(context.rawValue)
lastComplicationContext = context
} else {
do {
log.default("updateApplicationContext")
try session.updateApplicationContext(context.rawValue)
} catch let error {
log.error(error)
}
complicationShouldUpdate = enoughTimePassed || enoughTrendDrift
} else {
complicationShouldUpdate = true
}

if session.isComplicationEnabled && complicationShouldUpdate {
log.default("transferCurrentComplicationUserInfo")
session.transferCurrentComplicationUserInfo(context.rawValue)
lastComplicationContext = context
} else {
do {
log.default("updateApplicationContext")
try session.updateApplicationContext(context.rawValue)
} catch let error {
log.error(error)
}
}
}
Expand Down Expand Up @@ -266,6 +269,7 @@ extension WatchDataManager: WCSessionDelegate {
log.error(error)
} else {
sendSettingsIfNeeded()
sendWatchContextIfNeeded()
}
case .inactive, .notActivated:
break
Expand All @@ -292,6 +296,7 @@ extension WatchDataManager: WCSessionDelegate {
}

func sessionDidDeactivate(_ session: WCSession) {
lastSentSettings = nil
watchSession = WCSession.default
watchSession?.delegate = self
watchSession?.activate()
Expand All @@ -301,3 +306,57 @@ extension WatchDataManager: WCSessionDelegate {
sendSettingsIfNeeded()
}
}


extension WatchDataManager {
override var debugDescription: String {
var items = [
"## WatchDataManager",
"lastSentSettings: \(String(describing: lastSentSettings))",
"lastComplicationContext: \(String(describing: lastComplicationContext))",
]

if let session = watchSession {
items.append(String(reflecting: session))
} else {
items.append(contentsOf: [
"watchSession: nil"
])
}

return items.joined(separator: "\n")
}
}


extension WCSession {
open override var debugDescription: String {
return [
"\(self)",
"* hasContentPending: \(hasContentPending)",
"* isComplicationEnabled: \(isComplicationEnabled)",
"* isPaired: \(isPaired)",
"* isReachable: \(isReachable)",
"* isWatchAppInstalled: \(isWatchAppInstalled)",
"* outstandingFileTransfers: \(outstandingFileTransfers)",
"* outstandingUserInfoTransfers: \(outstandingUserInfoTransfers)",
"* receivedApplicationContext: \(receivedApplicationContext)",
"* remainingComplicationUserInfoTransfers: \(remainingComplicationUserInfoTransfers)",
"* complicationUserInfoTransferInterval: \(round(complicationUserInfoTransferInterval.minutes)) min",
"* watchDirectoryURL: \(watchDirectoryURL?.absoluteString ?? "nil")",
].joined(separator: "\n")
}

fileprivate var complicationUserInfoTransferInterval: TimeInterval {
let now = Date()
let timeUntilMidnight: TimeInterval

if let midnight = Calendar.current.nextDate(after: now, matching: DateComponents(hour: 0), matchingPolicy: .nextTime) {
timeUntilMidnight = midnight.timeIntervalSince(now)
} else {
timeUntilMidnight = .hours(24)
}

return timeUntilMidnight / Double(remainingComplicationUserInfoTransfers + 1)
}
}
3 changes: 3 additions & 0 deletions WatchApp Extension/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* Title of the user activity for adding carbs */
"Add Carb Entry" = "Add Carb Entry";

/* The title of the alert controller displayed after a bolus attempt fails */
"Bolus Failed" = "Bolus Failed";

Expand Down
12 changes: 6 additions & 6 deletions WatchApp Extension/Controllers/ActionHUDController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class ActionHUDController: HUDInterfaceController {
override func update() {
super.update()

let schedule = loopManager?.settings.glucoseTargetRangeSchedule
let schedule = loopManager.settings.glucoseTargetRangeSchedule
let activeOverrideContext: GlucoseRangeSchedule.Override.Context?
if let glucoseRangeScheduleOverride = schedule?.override, glucoseRangeScheduleOverride.isActive()
{
Expand Down Expand Up @@ -82,7 +82,7 @@ final class ActionHUDController: HUDInterfaceController {
// MARK: - Menu Items

@IBAction func togglePreMealMode() {
guard var glucoseTargetRangeSchedule = loopManager?.settings.glucoseTargetRangeSchedule else {
guard var glucoseTargetRangeSchedule = loopManager.settings.glucoseTargetRangeSchedule else {
return
}
if preMealButtonGroup.state == .on {
Expand All @@ -97,7 +97,7 @@ final class ActionHUDController: HUDInterfaceController {
}

@IBAction func toggleWorkoutMode() {
guard var glucoseTargetRangeSchedule = loopManager?.settings.glucoseTargetRangeSchedule else {
guard var glucoseTargetRangeSchedule = loopManager.settings.glucoseTargetRangeSchedule else {
return
}
if workoutButtonGroup.state == .on {
Expand Down Expand Up @@ -127,19 +127,19 @@ final class ActionHUDController: HUDInterfaceController {
if let error = error {
if self.pendingMessageResponses == 0 {
ExtensionDelegate.shared().present(error)
self.updateForOverrideContext(self.loopManager?.settings.glucoseTargetRangeSchedule?.override?.context)
self.updateForOverrideContext(self.loopManager.settings.glucoseTargetRangeSchedule?.override?.context)
}
} else {
if self.pendingMessageResponses == 0 {
self.loopManager?.settings.glucoseTargetRangeSchedule = schedule
self.loopManager.settings.glucoseTargetRangeSchedule = schedule
}
}
}
})
} catch {
pendingMessageResponses -= 1
if pendingMessageResponses == 0 {
updateForOverrideContext(self.loopManager?.settings.glucoseTargetRangeSchedule?.override?.context)
updateForOverrideContext(self.loopManager.settings.glucoseTargetRangeSchedule?.override?.context)
}
presentAlert(
withTitle: NSLocalizedString("Send Failed", comment: "The title of the alert controller displayed after a glucose range override send attempt fails"),
Expand Down
23 changes: 4 additions & 19 deletions WatchApp Extension/Controllers/AddCarbsInterfaceController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ final class AddCarbsInterfaceController: WKInterfaceController, IdentifiableClas
replyHandler: { (suggestion) in
DispatchQueue.main.async {
WKInterfaceDevice.current().play(.success)

ExtensionDelegate.shared().loopManager.addConfirmedCarbEntry(entry)

WKExtension.shared().rootInterfaceController?.presentController(withName: BolusInterfaceController.className, context: suggestion)
}
},
Expand Down Expand Up @@ -215,31 +218,13 @@ extension AddCarbsInterfaceController: WKCrownDelegate {
func crownDidRotate(_ crownSequencer: WKCrownSequencer?, rotationalDelta: Double) {
accumulatedRotation += rotationalDelta
let remainder = accumulatedRotation.truncatingRemainder(dividingBy: rotationsPerIncrement)
var delta = Int((accumulatedRotation - remainder) / rotationsPerIncrement)
let delta = Int((accumulatedRotation - remainder) / rotationsPerIncrement)

switch inputMode {
case .value:
let oldValue = carbValue
carbValue += delta

// If we didn't change, adjust the delta to prevent the haptic
if oldValue == carbValue {
delta = 0
}
case .date:
let oldValue = date
date += TimeInterval(minutes: Double(delta))

// If we didn't change, adjust the delta to prevent the haptic
if oldValue == date {
delta = 0
}
}

if delta > 0 {
WKInterfaceDevice.current().play(.click)
} else if delta < 0 {
WKInterfaceDevice.current().play(.click)
}

accumulatedRotation = remainder
Expand Down
24 changes: 10 additions & 14 deletions WatchApp Extension/Controllers/BolusInterfaceController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ final class BolusInterfaceController: WKInterfaceController, IdentifiableClass {
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}

override func didAppear() {
super.didAppear()

crownSequencer.focus()
}
Expand Down Expand Up @@ -141,7 +145,11 @@ final class BolusInterfaceController: WKInterfaceController, IdentifiableClass {
do {
try WCSession.default.sendBolusMessage(bolus) { (error) in
DispatchQueue.main.async {
ExtensionDelegate.shared().present(error)
if let error = error {
ExtensionDelegate.shared().present(error)
} else {
ExtensionDelegate.shared().loopManager.addConfirmedBolus(bolus)
}
}
}
} catch {
Expand Down Expand Up @@ -170,22 +178,10 @@ extension BolusInterfaceController: WKCrownDelegate {
accumulatedRotation += rotationalDelta

let remainder = accumulatedRotation.truncatingRemainder(dividingBy: rotationsPerValue)
var delta = Int((accumulatedRotation - remainder) / rotationsPerValue)
let delta = Int((accumulatedRotation - remainder) / rotationsPerValue)

let oldValue = pickerValue
pickerValue += delta

// If we didn't change, adjust the delta to prevent the haptic
if oldValue == pickerValue {
delta = 0
}

if delta > 0 {
WKInterfaceDevice.current().play(.click)
} else if delta < 0 {
WKInterfaceDevice.current().play(.click)
}

accumulatedRotation = remainder
}
}
Loading