Joseph
Joseph

Reputation: 333

How do I make ClockKit generate more than just 100 timeline entries?

I am trying to create a ClockKit complication that provides data for when a person's next shift starts, but not enough timeline entries are being generated or generated often enough, so sometimes, the data is inaccurate after a certain amount of time.

I have tried debugging and concluded that only 100 timeline entries are being created, good for 1:40 hours of date in each direction, not sufficent for my app. I have read the documentation and for the method that extends the timeline, but have found that it only can be used a certain number of times per day.

I included print(String(limit) + " After") in my getTimelineEntries(complication:date:limit:handler) to find how many it is generating. Output of print(String(limit) + " After") or before where applicable

What can I do to make my complication extend from 00:00 to 23:59 for its timeline? Also, why doesn't the timeline extend automatically upon it surpassing the future-most entry? It seems counterintuitive to Apple's intent for the complications.

I included my ComplicationController.swift` below.

//
//  ComplicationController.swift
//  Watch Bell Schedule Extension
//
//  Created by Joseph on 8/23/18.
//  Copyright © 2018 juniorRubyist. All rights reserved.
//

import ClockKit


class ComplicationController: NSObject, CLKComplicationDataSource {

    // MARK: - Timeline Configuration

    func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void) {
        handler([.forward, .backward])
    }

    func getTimelineStartDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
        handler(Date().addingTimeInterval(-256200))
    }

    func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
        handler(Date().addingTimeInterval(256200))
    }

    func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
        handler(.showOnLockScreen)
    }

    // MARK: - Timeline Population

    func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        let date = Date()
        let outputFormat = DateFormatter()
        outputFormat.locale = Locale(identifier:"en_US")
        outputFormat.dateFormat = "e"
        let override = 0
        let currentSchedule = currentSch((outputFormat.string(from: date)), unless: override)
        let nextPeriodObj = nextPeriod(on: currentSchedule, at: date)
        outputFormat.dateFormat = "hh:mm"

        switch complication.family {
        case .utilitarianLarge:
            let complicationTemplate = CLKComplicationTemplateUtilitarianLargeFlat()
            let compText: String
            if nextPeriodObj != Period(" ", 0, 0) {
                compText = "🔔 \(outputFormat.string(from: nextPeriodObj.time)) 🏫 \(nextPeriodObj.name)"
            } else {
                compText = "🔕 None Today"
            }
            complicationTemplate.textProvider = CLKSimpleTextProvider(text: compText)

            let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
            handler(timelineEntry)

        case .utilitarianSmall, .utilitarianSmallFlat:
            let complicationTemplate = CLKComplicationTemplateUtilitarianSmallFlat()
            let compText: String
            if nextPeriodObj != Period(" ", 0, 0) {
                compText = "🔔 \(outputFormat.string(from: nextPeriodObj.time))"
            } else {
                compText = "🔕"
            }
            complicationTemplate.textProvider = CLKSimpleTextProvider(text: compText)

            let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
            handler(timelineEntry)

        case .modularLarge:
            let complicationTemplate = CLKComplicationTemplateModularLargeStandardBody()
            let headerText, body1Text, body2Text: String

            if nextPeriodObj != Period(" ", 0, 0) {
                headerText = "Bell Schedule"
                body1Text = "\(nextPeriodObj.name)"
                body2Text = "\(outputFormat.string(from: nextPeriodObj.time))"
            } else {
                headerText = "No more bells."
                body1Text = ""
                body2Text = ""
            }

            complicationTemplate.headerTextProvider = CLKSimpleTextProvider(text: headerText)
            complicationTemplate.headerTextProvider.tintColor = TitanColors.red
            complicationTemplate.body1TextProvider = CLKSimpleTextProvider(text: body1Text)
            complicationTemplate.body2TextProvider = CLKSimpleTextProvider(text: body2Text)

            let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
            handler(timelineEntry)

        case .modularSmall, .circularSmall, .extraLarge:

            let body1Text, body2Text: String

            if nextPeriodObj != Period(" ", 0, 0) {
                body1Text = "\(nextPeriodObj.name)"
                body2Text = "\(outputFormat.string(from: nextPeriodObj.time))"
            } else {
                body1Text = "NO"
                body2Text = "BELL"
            }

            if complication.family == .modularSmall {
                let complicationTemplate = CLKComplicationTemplateModularSmallStackText()
                complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                complicationTemplate.line1TextProvider.tintColor = TitanColors.red
                complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                handler(timelineEntry)
            } else if complication.family == .circularSmall {
                let complicationTemplate = CLKComplicationTemplateCircularSmallStackText()
                complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                handler(timelineEntry)
            } else if complication.family == .extraLarge {
                let complicationTemplate = CLKComplicationTemplateExtraLargeStackText()
                complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                complicationTemplate.line1TextProvider.tintColor = TitanColors.red
                complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                handler(timelineEntry)
            }
        }
    }

    func getTimelineEntries(for complication: CLKComplication, before originalDate: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
        print(String(limit) + " Before")
        var entries = [CLKComplicationTimelineEntry]()
        for i in (1...(limit + 1)).reversed() {
            var date = originalDate
            date.addTimeInterval(TimeInterval(-1 * (60 * i)))
            let outputFormat = DateFormatter()
            outputFormat.locale = Locale(identifier:"en_US")
            outputFormat.dateFormat = "e"
            let override = 0
            let currentSchedule = currentSch((outputFormat.string(from: date)), unless: override)
            let nextPeriodObj = nextPeriod(on: currentSchedule, at: date)
            outputFormat.dateFormat = "hh:mm"

            switch complication.family {
            case .utilitarianLarge:
                let complicationTemplate = CLKComplicationTemplateUtilitarianLargeFlat()
                let compText: String
                if nextPeriodObj != Period(" ", 0, 0) {
                    compText = "🔔 \(outputFormat.string(from: nextPeriodObj.time)) 🏫 \(nextPeriodObj.name)"
                } else {
                    compText = "🔕 None Today"
                }
                complicationTemplate.textProvider = CLKSimpleTextProvider(text: compText)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                entries.append(timelineEntry)

            case .utilitarianSmall, .utilitarianSmallFlat:
                let complicationTemplate = CLKComplicationTemplateUtilitarianSmallFlat()
                let compText: String
                if nextPeriodObj != Period(" ", 0, 0) {
                    compText = "🔔 \(outputFormat.string(from: nextPeriodObj.time))"
                } else {
                    compText = "🔕"
                }
                complicationTemplate.textProvider = CLKSimpleTextProvider(text: compText)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                entries.append(timelineEntry)

            case .modularLarge:
                let complicationTemplate = CLKComplicationTemplateModularLargeStandardBody()
                let headerText, body1Text, body2Text: String

                if nextPeriodObj != Period(" ", 0, 0) {
                    headerText = "Bell Schedule"
                    body1Text = "\(nextPeriodObj.name)"
                    body2Text = "\(outputFormat.string(from: nextPeriodObj.time))"
                } else {
                    headerText = "No more bells."
                    body1Text = ""
                    body2Text = ""
                }

                complicationTemplate.headerTextProvider = CLKSimpleTextProvider(text: headerText)
                complicationTemplate.headerTextProvider.tintColor = TitanColors.red
                complicationTemplate.body1TextProvider = CLKSimpleTextProvider(text: body1Text)
                complicationTemplate.body2TextProvider = CLKSimpleTextProvider(text: body2Text)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                entries.append(timelineEntry)

            case .modularSmall, .circularSmall, .extraLarge:

                let body1Text, body2Text: String

                if nextPeriodObj != Period(" ", 0, 0) {
                    body1Text = "\(nextPeriodObj.name)"
                    body2Text = "\(outputFormat.string(from: nextPeriodObj.time))"
                } else {
                    body1Text = "NO"
                    body2Text = "BELL"
                }

                if complication.family == .modularSmall {
                    let complicationTemplate = CLKComplicationTemplateModularSmallStackText()
                    complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                    complicationTemplate.line1TextProvider.tintColor = TitanColors.red
                    complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                    let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                    entries.append(timelineEntry)
                } else if complication.family == .circularSmall {
                    let complicationTemplate = CLKComplicationTemplateCircularSmallStackText()
                    complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                    complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                    let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                    entries.append(timelineEntry)
                } else if complication.family == .extraLarge {
                    let complicationTemplate = CLKComplicationTemplateExtraLargeStackText()
                    complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                    complicationTemplate.line1TextProvider.tintColor = TitanColors.red
                    complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                    let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                    entries.append(timelineEntry)
                }
            }
        }
        handler(entries)
    }

    func getTimelineEntries(for complication: CLKComplication, after originalDate: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
        var entries = [CLKComplicationTimelineEntry]()
        print(String(limit) + " After")
        for i in 1...(limit + 1) {
            var date = originalDate
            date.addTimeInterval(TimeInterval(60 * i))
            let outputFormat = DateFormatter()
            outputFormat.locale = Locale(identifier:"en_US")
            outputFormat.dateFormat = "e"
            let override = 0
            let currentSchedule = currentSch((outputFormat.string(from: date)), unless: override)
            let nextPeriodObj = nextPeriod(on: currentSchedule, at: date)
            outputFormat.dateFormat = "hh:mm"

            switch complication.family {
            case .utilitarianLarge:
                let complicationTemplate = CLKComplicationTemplateUtilitarianLargeFlat()
                let compText: String
                if nextPeriodObj != Period(" ", 0, 0) {
                    compText = "🔔 \(outputFormat.string(from: nextPeriodObj.time)) 🏫 \(nextPeriodObj.name)"
                } else {
                    compText = "🔕 None Today"
                }
                complicationTemplate.textProvider = CLKSimpleTextProvider(text: compText)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                entries.append(timelineEntry)

            case .utilitarianSmall, .utilitarianSmallFlat:
                let complicationTemplate = CLKComplicationTemplateUtilitarianSmallFlat()
                let compText: String
                if nextPeriodObj != Period(" ", 0, 0) {
                    compText = "🔔 \(outputFormat.string(from: nextPeriodObj.time))"
                } else {
                    compText = "🔕"
                }
                complicationTemplate.textProvider = CLKSimpleTextProvider(text: compText)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                entries.append(timelineEntry)

            case .modularLarge:
                let complicationTemplate = CLKComplicationTemplateModularLargeStandardBody()
                let headerText, body1Text, body2Text: String

                if nextPeriodObj != Period(" ", 0, 0) {
                    headerText = "Bell Schedule"
                    body1Text = "\(nextPeriodObj.name)"
                    body2Text = "\(outputFormat.string(from: nextPeriodObj.time))"
                } else {
                    headerText = "No more bells."
                    body1Text = ""
                    body2Text = ""
                }

                complicationTemplate.headerTextProvider = CLKSimpleTextProvider(text: headerText)
                complicationTemplate.headerTextProvider.tintColor = TitanColors.red
                complicationTemplate.body1TextProvider = CLKSimpleTextProvider(text: body1Text)
                complicationTemplate.body2TextProvider = CLKSimpleTextProvider(text: body2Text)

                let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                entries.append(timelineEntry)

            case .modularSmall, .circularSmall, .extraLarge:

                let body1Text, body2Text: String

                if nextPeriodObj != Period(" ", 0, 0) {
                    body1Text = "\(nextPeriodObj.name)"
                    body2Text = "\(outputFormat.string(from: nextPeriodObj.time))"
                } else {
                    body1Text = "NO"
                    body2Text = "BELL"
                }

                if complication.family == .modularSmall {
                    let complicationTemplate = CLKComplicationTemplateModularSmallStackText()
                    complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                    complicationTemplate.line1TextProvider.tintColor = TitanColors.red
                    complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                    let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                    entries.append(timelineEntry)
                } else if complication.family == .circularSmall {
                    let complicationTemplate = CLKComplicationTemplateCircularSmallStackText()
                    complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                    complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                    let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                    entries.append(timelineEntry)
                } else if complication.family == .extraLarge {
                    let complicationTemplate = CLKComplicationTemplateExtraLargeStackText()
                    complicationTemplate.line1TextProvider = CLKSimpleTextProvider(text: body1Text)
                    complicationTemplate.line1TextProvider.tintColor = TitanColors.red
                    complicationTemplate.line2TextProvider = CLKSimpleTextProvider(text: body2Text)

                    let timelineEntry = CLKComplicationTimelineEntry(date: date, complicationTemplate: complicationTemplate)
                    entries.append(timelineEntry)
                }
            }
        }
        handler(entries)
    }

    // MARK: - Placeholder Templates

    func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        // This method will be called once per supported complication, and the results will be cached
        handler(nil)
    }

}

Upvotes: 4

Views: 401

Answers (1)

Patrick 2N
Patrick 2N

Reputation: 74

Schedule a backgroundRefresh e.g. one hour into the future to do an extendTimeline.

To schedule the background refresh, run this in your applicationDidFinishLaunching in your ExtensionDelegate, and don't forget to reschedule it during each refresh.

let minutesToRefresh = 60 WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: Date().addingTimeInterval(minutesToRefresh * 60), userInfo: nil, scheduledCompletion: scheduledCompletion)

Upvotes: 2

Related Questions