release
Laurent 3 years ago
parent 9f0438a6b6
commit 92e980114e
  1. 18
      LaunchIntents/IntentHandler.swift
  2. 52
      LaunchWidget/CountdownView.swift
  3. 59
      LaunchWidget/LaunchWidget.intentdefinition
  4. 82
      LaunchWidget/LaunchWidget.swift
  5. 2
      LeCountdown.xcodeproj/project.pbxproj
  6. 14
      LeCountdown/Model/Model+Extensions.swift

@ -9,23 +9,15 @@ import Intents
class IntentHandler: INExtension, SelectCountdownIntentHandling {
// func resolveCountdown(for intent: SelectCountdownIntent, with completion: @escaping (CountdownPropertiesResolutionResult) -> Void) {
// }
func resolveCountdown(for intent: SelectCountdownIntent) async -> CountdownPropertiesResolutionResult {
func resolveCountdown(for intent: SelectCountdownIntent) async -> [CountdownPropertiesResolutionResult] {
print("***resolveCountdown")
if let countdown = intent.countdown {
return CountdownPropertiesResolutionResult.success(with: countdown)
} else {
return CountdownPropertiesResolutionResult.needsValue()
if let properties = intent.countdown?.first {
return [CountdownPropertiesResolutionResult.success(with: properties)]
}
return [CountdownPropertiesResolutionResult.needsValue()]
}
// func provideCountdownOptionsCollection(for intent: SelectCountdownIntent, with completion: @escaping (INObjectCollection<CountdownProperties>?, Error?) -> Void) {
//
//
// }
func provideCountdownOptionsCollection(for intent: SelectCountdownIntent) async throws -> INObjectCollection<CountdownProperties> {
print("*** provideCountdownOptionsCollection")

@ -7,18 +7,18 @@
import SwiftUI
import WidgetKit
import CoreData
struct CountdownView: View {
@Environment(\.widgetFamily) var family: WidgetFamily
var name: String?
var duration: Double
var countdown: Countdown
var body: some View {
VStack {
Text(name ?? "")
Text(duration.minuteSecond)
Text(countdown.name ?? "")
Text(countdown.duration.minuteSecond)
}
.font(self.font)
}
@ -34,8 +34,50 @@ struct CountdownView: View {
}
struct CountdownMultiView: View {
@Environment(\.widgetFamily) var family: WidgetFamily
var countdowns: [Countdown]
var body: some View {
HStack {
ForEach(countdowns) { countdown in
VStack {
Text(countdown.name ?? "")
Text(countdown.duration.minuteSecond)
}
.font(self.font)
.widgetURL(countdown.url)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}.frame(maxWidth: .infinity)
}
private var font: Font {
switch family {
case .systemSmall, .systemMedium, .systemLarge, .systemExtraLarge:
return .title2
default:
return .body
}
}
}
struct CountdownView_Previews: PreviewProvider {
static var previews: some View {
CountdownView(name: "Tea", duration: 3 * 60.0).previewContext(WidgetPreviewContext(family: .accessoryRectangular))
CountdownView(countdown: Countdown.fake(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .accessoryRectangular))
CountdownMultiView(countdowns: self.countdowns(context: PersistenceController.preview.container.viewContext)).previewContext(WidgetPreviewContext(family: .systemMedium))
}
static func countdowns(context: NSManagedObjectContext) -> [Countdown] {
return (0..<4).map { _ in
Countdown.fake(context: context)
}
}
}

@ -26,12 +26,63 @@
<key>INIntentIneligibleForSuggestions</key>
<true/>
<key>INIntentLastParameterTag</key>
<integer>2</integer>
<integer>3</integer>
<key>INIntentName</key>
<string>SelectCountdown</string>
<key>INIntentParameters</key>
<array>
<dict>
<key>INIntentParameterArraySizes</key>
<array>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>1</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>Small</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>4</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>Medium</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>8</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>Large</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>12</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>ExtraLarge</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>1</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>AccessoryInline</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>1</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>AccessoryCorner</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>1</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>AccessoryCircular</string>
</dict>
<dict>
<key>INIntentParameterArraySizeSize</key>
<integer>2</integer>
<key>INIntentParameterArraySizeSizeClass</key>
<string>AccessoryRectangular</string>
</dict>
</array>
<key>INIntentParameterConfigurable</key>
<true/>
<key>INIntentParameterCustomDisambiguation</key>
@ -42,6 +93,8 @@
<string>lE8mOk</string>
<key>INIntentParameterDisplayPriority</key>
<integer>1</integer>
<key>INIntentParameterFixedSizeArray</key>
<integer>1</integer>
<key>INIntentParameterName</key>
<string>countdown</string>
<key>INIntentParameterObjectType</key>
@ -85,10 +138,12 @@
</array>
<key>INIntentParameterSupportsDynamicEnumeration</key>
<true/>
<key>INIntentParameterSupportsMultipleValues</key>
<true/>
<key>INIntentParameterSupportsResolution</key>
<true/>
<key>INIntentParameterTag</key>
<integer>2</integer>
<integer>3</integer>
<key>INIntentParameterType</key>
<string>Object</string>
</dict>

@ -11,29 +11,26 @@ import Intents
struct Provider: IntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(id: "", name: "Tea", duration: 4 * 60.0, date: Date(), configuration: SelectCountdownIntent())
SimpleEntry(countdowns: [], date: Date(), configuration: SelectCountdownIntent())
}
func getSnapshot(for configuration: SelectCountdownIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
guard let cp = configuration.countdown,
let identifier = cp.identifier,
let countdown = IntentDataProvider.main.countdown(id: identifier) else {
print("WARNING PLACEHOLDER!")
let entry = SimpleEntry(id: "",
name: "Not found",
duration: 0.0,
date: Date(),
configuration: configuration)
completion(entry)
guard let cp = configuration.countdown
else {
completion(placeholder(in: context))
return
}
let entry = SimpleEntry(id: identifier,
name: countdown.name,
duration: countdown.duration,
let countdowns: [Countdown] = cp.compactMap {
if let id = $0.identifier {
return IntentDataProvider.main.countdown(id: id)
} else {
return nil
}
}
let entry = SimpleEntry(countdowns: countdowns,
date: Date(),
configuration: configuration)
completion(entry)
@ -51,26 +48,44 @@ struct Provider: IntentTimelineProvider {
}
struct SimpleEntry: TimelineEntry {
let id: String
let name: String?
let duration: Double
let countdowns: [Countdown]
// let id: String
// let name: String?
// let duration: Double
let date: Date
let configuration: SelectCountdownIntent
}
struct CountdownWidgetView: View {
struct CountdownSimpleWidgetView: View {
let id: String
let name: String?
let duration: Double
let countdown: Countdown
var body: some View {
CountdownView(name: name, duration: duration).widgetURL(URL(string: id))
CountdownView(countdown: countdown)
.widgetURL(countdown.url)
}
}
struct CountdownMultiWidgetView: View {
let countdowns: [Countdown]
var body: some View {
CountdownMultiView(countdowns: countdowns)
}
}
struct VoidView : View {
var body: some View {
Text("Nothing here")
}
}
struct LaunchWidgetEntryView : View {
@Environment(\.widgetFamily) var family: WidgetFamily
@ -80,7 +95,14 @@ struct LaunchWidgetEntryView : View {
@ViewBuilder
var body: some View {
switch family {
case .systemSmall: CountdownWidgetView(id: entry.id, name: entry.name, duration: entry.duration)
case .systemSmall, .accessoryInline, .accessoryRectangular, .accessoryCircular:
if let countdown = entry.countdowns.first {
CountdownSimpleWidgetView(countdown: countdown)
} else {
VoidView()
}
default:
CountdownMultiView(countdowns: entry.countdowns)
// case .systemMedium: GameStatusWithLastTurnResult(gameStatus)
// case .systemLarge: GameStatusWithStatistics(gameStatus)
@ -88,7 +110,6 @@ struct LaunchWidgetEntryView : View {
// case .accessoryCircular: HealthLevelCircular(selectedCharacter)
// case .accessoryRectangular: HealthLevelRectangular(selectedCharacter)
// case .accessoryInline: HealthLevelInline(selectedCharacter)
default: CountdownWidgetView(id: entry.id, name: entry.name, duration: entry.duration)
}
}
@ -112,10 +133,13 @@ struct LaunchWidget: Widget {
struct LaunchWidget_Previews: PreviewProvider {
static var previews: some View {
LaunchWidgetEntryView(entry: SimpleEntry(id: "", name: "Tea", duration: 3 * 60.0, date: Date(), configuration: SelectCountdownIntent()))
let fake = Countdown.fake(context: PersistenceController.preview.container.viewContext)
LaunchWidgetEntryView(entry: SimpleEntry(countdowns: [fake], date: Date(), configuration: SelectCountdownIntent()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
LaunchWidgetEntryView(entry: SimpleEntry(id: "", name: "Tea", duration: 3 * 60.0, date: Date(), configuration: SelectCountdownIntent()))
.previewContext(WidgetPreviewContext(family: .accessoryRectangular))
LaunchWidgetEntryView(entry: SimpleEntry(countdowns: [fake, fake, fake, fake], date: Date(), configuration: SelectCountdownIntent()))
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}

@ -139,7 +139,6 @@
C438C80C2982847300BF3EF9 /* CoreDataRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataRequests.swift; sourceTree = "<group>"; };
C438C80E29828B8600BF3EF9 /* RecordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsView.swift; sourceTree = "<group>"; };
C438C81029829EAF00BF3EF9 /* PropertyWrappers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyWrappers.swift; sourceTree = "<group>"; };
C438C8122982BAA100BF3EF9 /* LaunchWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LaunchWidgetExtension.entitlements; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -187,7 +186,6 @@
C4060DB3297AE73B003FAB80 = {
isa = PBXGroup;
children = (
C438C8122982BAA100BF3EF9 /* LaunchWidgetExtension.entitlements */,
C4060DBE297AE73B003FAB80 /* LeCountdown */,
C4060DD5297AE73D003FAB80 /* LeCountdownTests */,
C4060DDF297AE73D003FAB80 /* LeCountdownUITests */,

@ -7,6 +7,7 @@
import Foundation
import SwiftUI
import CoreData
extension Countdown {
@ -14,6 +15,19 @@ extension Countdown {
return self.activity?.name
}
var url: URL? {
return URL(string: self.stringId)
}
static func fake(context: NSManagedObjectContext) -> Countdown {
let cd = Countdown(context: context)
cd.duration = 4 * 60.0
let activity = Activity(context: context)
activity.name = "Tea"
cd.activity = activity
return cd
}
}
extension Record {

Loading…
Cancel
Save