Files
iOS/Sources/Extensions/Watch/Complication/ComplicationController.swift
Bruno Pantaleão Gonçalves 4daad9416b Fix watch crash (Realm migration not called) (#2886)
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->
For some reason Realm database migration was not being called event
though scheme version was already bumped to 28, apparently this was
caused by watch complication that was accessing realm passing specific
object types

Test process:

- Checkout commit c257fa21f6
- Run App in iPhone and watch (with some Actions created)
- Checkout commit 2c8470e5fe
- Run App in iPhone and watch
> - this was crashing in watch and now it is running the migration
block.

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->
2024-07-31 16:00:58 +02:00

139 lines
4.8 KiB
Swift

import ClockKit
import RealmSwift
import Shared
class ComplicationController: NSObject, CLKComplicationDataSource {
// Helpful resources
// https://github.com/LoopKit/Loop/issues/816
// https://crunchybagel.com/detecting-which-complication-was-tapped/
private func complicationModel(for complication: CLKComplication) -> WatchComplication? {
// Helper function to get a complication using the correct ID depending on watchOS version
let model: WatchComplication?
if complication.identifier != CLKDefaultComplicationIdentifier {
// existing complications that were configured pre-7 have no identifier set
// so we can only access the value if it's a valid one. otherwise, fall back to old matching behavior.
model = Current.realm().object(
ofType: WatchComplication.self,
forPrimaryKey: complication.identifier
)
} else {
// we migrate pre-existing complications, and when still using watchOS 6 create new ones,
// with the family as the identifier, so we can rely on this code path for older OS and older complications
let matchedFamily = ComplicationGroupMember(family: complication.family)
model = Current.realm().object(
ofType: WatchComplication.self,
forPrimaryKey: matchedFamily.rawValue
)
}
return model
}
private func template(for complication: CLKComplication) -> CLKComplicationTemplate {
MaterialDesignIcons.register()
let template: CLKComplicationTemplate
if let generated = complicationModel(for: complication)?.CLKComplicationTemplate(family: complication.family) {
template = generated
} else if complication.identifier == AssistDefaultComplication.defaultComplicationId {
template = AssistDefaultComplication.createAssistTemplate(for: complication.family)
} else {
Current.Log.info {
"no configured template for \(complication.identifier), providing placeholder"
}
template = ComplicationGroupMember(family: complication.family)
.fallbackTemplate(for: complication.identifier)
}
return template
}
// MARK: - Timeline Configuration
func getPrivacyBehavior(
for complication: CLKComplication,
withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void
) {
let model = complicationModel(for: complication)
if model?.IsPublic == false {
handler(.hideOnLockScreen)
} else {
handler(.showOnLockScreen)
}
}
// MARK: - Timeline Population
func getCurrentTimelineEntry(
for complication: CLKComplication,
withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void
) {
Current.Log.verbose {
"Providing template for \(complication.identifier) family \(complication.family.description)"
}
let date = Date().encodedForComplication(family: complication.family) ?? Date()
handler(.init(date: date, complicationTemplate: template(for: complication)))
}
// MARK: - Placeholder Templates
func getLocalizableSampleTemplate(
for complication: CLKComplication,
withHandler handler: @escaping (CLKComplicationTemplate?) -> Void
) {
handler(template(for: complication))
}
// MARK: - Complication Descriptors
func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
let configured = Current.realm().objects(WatchComplication.self)
.map(\.complicationDescriptor)
let placeholders = ComplicationGroupMember.allCases
.map(\.placeholderComplicationDescriptor)
let assistDefaultComplicationDescriptor = [AssistDefaultComplication.descriptor]
handler(configured + placeholders + assistDefaultComplicationDescriptor)
}
}
extension CLKComplicationFamily {
var description: String {
switch self {
case .circularSmall:
return "Circular Small"
case .extraLarge:
return "Extra Large"
case .graphicBezel:
return "Graphic Bezel"
case .graphicCircular:
return "Graphic Circular"
case .graphicCorner:
return "Graphic Corner"
case .graphicRectangular:
return "Graphic Rectangular"
case .modularLarge:
return "Modular Large"
case .modularSmall:
return "Modular Small"
case .utilitarianLarge:
return "Utilitarian Large"
case .utilitarianSmall:
return "Utilitarian Small"
case .utilitarianSmallFlat:
return "Utilitarian Small Flat"
default:
return "unknown"
}
}
}