RSS Widget For iOS 14 Shows Empty - ios

I use an XMLParser for my app written in Swift, and am trying to get a Widget set up for iOS 14 in which it will show the most recent article on the RSS. I see the placeholder just fine when I add it, but it stays empty with just a line where text should be and never seems to get the information from the timeline.
struct Provider: TimelineProvider {
#State private var rssItems:[RSSItem]?
let feedParser = FeedParser()
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), title:"News", description: "News article here", link: "Http://link", pubDate: "The day it posted")
}
func getSnapshot(in context: Context, completion: #escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), title:"News", description: "News Article Here", link: "Http://link", pubDate: "The day it posted")
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<SimpleEntry>) -> ()) {
var entries: [SimpleEntry] = []
feedParser.parseFeed(url: "http://fritchcoc.wordpress.com/feed") {(rssItems) in
self.rssItems = rssItems
let currentDate = Date()
let entry = SimpleEntry(date: currentDate, title:rssItems[0].title, description: rssItems[0].description, link: rssItems[0].link, pubDate: rssItems[0].pubDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let title: String
let description: String
let link: String
let pubDate: String
}
struct FritchNewsEntryView : View {
var entry: SimpleEntry
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(entry.title)
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading)
.padding()
.background(LinearGradient(gradient: Gradient(colors: [.orange, .yellow]), startPoint: .top, endPoint: .bottom))
}
}
#main
struct FritchNews: Widget {
let kind: String = "FritchNews"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
FritchNewsEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}

UPDATE BY THE OP:
It was indeed a combination of the timeline being set in the wrong spot, along with a couple of typos within the parser that caused this particular issue.
Apple does not allow HTTP connections by default, the easiest solution is to change the URL to https://fritchcoc.wordpress.com/feed
If you want to allow HTTP connections in your app (or widget) you can add exceptions (to one domain or all) in the Info.plist for the target, see NSAppTransportSecurity at Apple Docs
Edit:
After a better look and finding for the implementation of FeedParser online, I noticed that parseFeed() is asynchronous.
Thus the completion is called with an empty array, it should be called after the parsing is done:
struct Provider: TimelineProvider {
...
func getTimeline(in context: Context, completion: #escaping (Timeline<SimpleEntry>) -> ()) {
var entries: [SimpleEntry] = []
feedParser.parseFeed(url: "http://fritchcoc.wordpress.com/feed") {(rssItems) in
self.rssItems = rssItems
let currentDate = Date()
let entry = SimpleEntry(date: currentDate, title:rssItems[0].title, description: rssItems[0].description, link: rssItems[0].link, pubDate: rssItems[0].pubDate)
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
}

Related

IOS Widget is not updating

I have an Quote app made in Flutter and now i create widget for IOS. My Widget loads some data from UserDefaults/ Appgroups and depending on that it shows some quotes and a picture. This works with the first start when i press button to set quote and images.
I want the widget to show new quotes every minute, tried different approaches with the Timeline, but it is not working. Can anyone help me make this works?
Below the code for the widget:
func placeholder(in context: Context) -> ExampleEntry {
ExampleEntry(date: Date(), flutterData: FlutterData( title: "Placeholder Title", message: "Placeholder Message",imageId:"tree", textColor:"Color.black"))
}
func getSnapshot(in context: Context, completion: #escaping (ExampleEntry) -> ()) {
let data = UserDefaults.init(suiteName:"***")
let entry = ExampleEntry(date: Date(),flutterData: FlutterData( title: data?.string(forKey: "title") ?? "Set quote and background in Settings > Widget", message: data?.string(forKey: "message") ?? "No Message Set", imageId: data?.string(forKey: "imageId") ?? "Color.black", textColor: data?.string(forKey: "textColor") ?? "Color.white"))
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<ExampleEntry>) -> ()) {
let data = UserDefaults.init(suiteName:"***")
var entries = [ExampleEntry]()
let currentDate = Date()
let entry = ExampleEntry(date: currentDate,flutterData:FlutterData(title: data?.string(forKey: "title") ?? "Set quote and background in Settings > Widget", message: data?.string(forKey: "message") ?? "No Message Set", imageId: data?.string(forKey: "imageId") ?? "Color.black", textColor: data?.string(forKey: "textColor") ?? "Color.white"))
let entryDate = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate)
print(entryDate)
let timeline = Timeline(entries: [entry], policy: .after(entryDate!))
completion(timeline)
}
}
var body: some View {
VStack.init(alignment: .leading, spacing: nil, content: {
Text(entry.flutterData!.title)
.font(.body)
.foregroundColor(Color.white)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: Alignment.center)
.padding(.vertical)
.padding(.horizontal,6)
.background(
Image(entry.flutterData!.imageId)
.resizable()
.scaledToFill()
.frame( maxWidth: .infinity, maxHeight: .infinity)
)
.onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { _ in
// make sure you don't call this too often
WidgetCenter.shared.reloadAllTimelines()
}
}
)
}
}
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind,provider: Provider()) { entry in
HomeWidgetExampleEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}

Widget with relative date text not updating when device is locked

I have a widget with a SwiftUI Text timer date. It countdowns as expected. However, when the device is locked, the timer is frozen.
To reproduce it, add the SwiftUI Text(_:style:) view to a widget and place the widget on the "Today View". The countdown should work as expected. However, lock the phone then view the Today View in a locked state. The timer is frozen.
Below is the full working sample code:
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: #escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
}
struct TestWidget123EntryView : View {
var entry: Provider.Entry
var body: some View {
Text(entry.date, style: .timer)
.multilineTextAlignment(.center)
.padding()
}
}
#main
struct TestWidget123: Widget {
let kind: String = "TestWidget123"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
TestWidget123EntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
struct TestWidget123_Previews: PreviewProvider {
static var previews: some View {
TestWidget123EntryView(entry: SimpleEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
I don't have any data protected data and I tried using a timer but didn't work at all. How can I allow the Text timer to countdown in a locked state?

Implementing In App Purchases in IOS Widget

I'm currently stuck trying to implement in app purchases within my IOS Widget. My widget works, the in-app purchase works, and the app works for the baseline functions.
I am unable to make the purchases available within the widget. My current strategy is to use if else statements to turn change with parts of code to point to.
Could anyone tell me how to implement in app purchases within my Widget?
Here is my code:
code
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
let userDefaults = UserDefaults(suiteName: "group.QuotePackage")
func placeholder(in context: Context) -> SimpleEntry {
_ = Quote.self
if UserDefaults.standard.bool(forKey: "premiumQuotes") == true {
// remove adds
return SimpleEntry(date: Date(), quoteDetails: QuoteProvider.random())
} else {
return SimpleEntry(date: Date(), quoteDetails: QuoteProvider2.random2())
}
}
//let userDefaults = UserDefaults(suiteName: "group.QuotePackage")
public typealias Entry = SimpleEntry
public func getSnapshot(in context: Context, completion: #escaping (SimpleEntry) -> ()) {
if UserDefaults.standard.bool(forKey: "premiumQuotes") == true {
// remove adds
let entry = SimpleEntry(date: Date(), quoteDetails: QuoteProvider.random())
} else {
let entry = SimpleEntry(date: Date(), quoteDetails: QuoteProvider2.random2())
}
completion(entry)
}
public func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> Void) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
if UserDefaults.standard.bool(forKey: "premiumQuotes") == true {
// remove adds
let entry = SimpleEntry(date: entryDate, quoteDetails: QuoteProvider.random())
} else {
let entry = SimpleEntry(date: entryDate, quoteDetails: QuoteProvider2.random2())
}
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct Quote_WidgetEntryView: View {
var entry: Provider.Entry
var body: some View {
QuoteWidgetEntryView(quoteDetails: entry.quoteDetails)
}
}
struct SimpleEntry: TimelineEntry {
public let date: Date
public let quoteDetails: QuoteDetails
}
struct PlaceholderView : View {
var body: some View {
Text("Inspo")
}
}
struct QuoteWidgetEntryView : View {
let quoteDetails: QuoteDetails
var body: some View {
ZStack {
Image("background")
.resizable()
.aspectRatio(contentMode: .fill)
VStack (alignment: .center, spacing: 15) {
Text("\"\(quoteDetails.texts)\"")
.font(Font.custom("Georgia", size: 20))
.fontWeight(.light)
.foregroundColor(Color.white)
.multilineTextAlignment(.center)
.lineLimit(5)
.padding(.leading, 20)
.padding(.trailing, 20)
Text("\(quoteDetails.authors)")
.font(Font.custom("Georgia", size: 15))
.fontWeight(.light)
.foregroundColor(Color.white)
}
}
}
}
#main
struct Quote2_Widget: Widget {
private let kind: String = "Quote2_Widget"
public var body: some WidgetConfiguration {
if UserDefaults.standard.bool(forKey: "premiumQuotes") == true {
// remove adds
StaticConfiguration(kind: kind, provider: Provider()) { entry in
QuoteWidgetEntryView(quoteDetails: QuoteProvider.random())
} else {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
QuoteWidgetEntryView(quoteDetails: QuoteProvider.random())
}
}
.configurationDisplayName("Inspo")
.description("Add Inspo Quotes to your homescreen.")
.supportedFamilies([.systemMedium])
}
}
}
struct QuoteWidgetView_Previews: PreviewProvider {
static var previews: some View {
QuoteWidgetEntryView(quoteDetails: QuoteProvider.random())
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}

Error while running widgetkit extension target on physical device

Added a WidgetBuilder to my extension so I could include a second type of widget for my app. I keep getting this error in a popup when building it onto my device.
Details
SendProcessControlEvent:toPid: encountered an error: Error Domain=com.apple.dt.deviceprocesscontrolservice Code=8 "Failed to show Widget 'com.identifier' error: Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=2 "Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'" UserInfo={NSLocalizedDescription=Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'}." UserInfo={NSLocalizedDescription=Failed to show Widget 'com.identifiert' error: Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=2 "Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'" UserInfo={NSLocalizedDescription=Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'}., NSUnderlyingError=0x12f915290 {Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=2 "Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'" UserInfo={NSLocalizedDescription=Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'}}}
Domain: DTXMessage
Code: 1
--
Heres the before and after code.
Before adding the second widget:
import WidgetKit
import SwiftUI
import Foundation
let testBook = Book(id: UUID(), name: "Name", author: "Author", genre: "Error", page: "0", total: "77")
public enum AppGroup: String {
case Livre = "group.com.idetifier"
public var containerURL: URL {
switch self {
case .Livre:
return FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: self.rawValue)!
}
}
}
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), book: testBook)
}
func getSnapshot(in context: Context, completion: #escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), book: testBook)
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
let books: [Book] = self.load("list")
let entry = SimpleEntry(date: currentDate, book: books.randomElement() ?? testBook)
let timeline = Timeline(entries: [entry], policy: .after(entryDate))
completion(timeline)
}
func load<T: Decodable>(_ filename: String) -> T {
let groupDirectory = AppGroup.Livre.containerURL
let groupURL = groupDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
return try! JSONDecoder().decode(T.self, from: Data(contentsOf: groupURL))
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let book: Book
}
struct PlaceholderView: View {
var body: some View {
RandomWidgetView(book: testBook)
.redacted(reason: .placeholder)
}
}
struct LivreWidgetEntryView : View {
#Environment(\.widgetFamily) var family
var entry: Provider.Entry
#ViewBuilder
var body: some View {
switch family {
case .systemSmall:
RandomWidgetView(book: entry.book, size: .small)
case .systemMedium:
RandomWidgetView(book: entry.book, size: .medium)
case .systemLarge:
RandomWidgetView(book: entry.book, size: .large)
default:
RandomWidgetView(book: entry.book, size: .small)
}
}
}
#main
struct LivreWidget: Widget {
let kind: String = "LivreWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
LivreWidgetEntryView(entry: entry)
}
.configurationDisplayName("Progress of a random book")
.description("This widget shows the progress from a random book in your Library")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
and after adding the second widget:
import WidgetKit
import SwiftUI
import Foundation
#main
struct LivreWidgetBuilder: WidgetBundle {
init() {}
#WidgetBundleBuilder
var body: some Widget {
RandomWidget()
QuoteWidget()
}
}
let testBook = Book(id: UUID(), name: "Name", author: "Author", genre: "Error", page: "0", total: "77", quotes: ["Quote"])
public enum AppGroup: String {
case Livre = "group.com.identifier"
public var containerURL: URL {
switch self {
case .Livre:
return FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: self.rawValue)!
}
}
}
//MARK: Random book widget
struct RandomProvider: TimelineProvider {
func placeholder(in context: Context) -> RandomSimpleEntry {
RandomSimpleEntry(date: Date(), book: testBook)
}
func getSnapshot(in context: Context, completion: #escaping (RandomSimpleEntry) -> ()) {
let entry = RandomSimpleEntry(date: Date(), book: testBook)
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
let books: [Book] = self.load("list")
let entry = RandomSimpleEntry(date: currentDate, book: books.randomElement() ?? testBook)
let timeline = Timeline(entries: [entry], policy: .after(entryDate))
completion(timeline)
}
func load<T: Decodable>(_ filename: String) -> T {
let groupDirectory = AppGroup.Livre.containerURL
let groupURL = groupDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
return try! JSONDecoder().decode(T.self, from: Data(contentsOf: groupURL))
}
}
struct RandomSimpleEntry: TimelineEntry {
let date: Date
let book: Book
}
struct RandomPlaceholderView: View {
var body: some View {
RandomWidgetView(book: testBook)
.redacted(reason: .placeholder)
}
}
struct RandomWidgetEntryView : View {
#Environment(\.widgetFamily) var family
var entry: RandomProvider.Entry
#ViewBuilder
var body: some View {
switch family {
case .systemSmall:
RandomWidgetView(book: entry.book, size: .small)
case .systemMedium:
RandomWidgetView(book: entry.book, size: .medium)
case .systemLarge:
RandomWidgetView(book: entry.book, size: .large)
default:
RandomWidgetView(book: entry.book, size: .small)
}
}
}
struct RandomWidget: Widget {
let kind: String = "RandomWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: RandomProvider()) { entry in
RandomWidgetEntryView(entry: entry)
}
.configurationDisplayName("Random book progress")
.description("This widget shows the progress from a random book in your Library")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
//MARK: Quote Widget
struct QuoteProvider: TimelineProvider {
func placeholder(in context: Context) -> QuoteSimpleEntry {
QuoteSimpleEntry(date: Date(), book: testBook)
}
func getSnapshot(in context: Context, completion: #escaping (QuoteSimpleEntry) -> ()) {
let entry = QuoteSimpleEntry(date: Date(), book: testBook)
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
let books: [Book] = self.load("list")
let entry = QuoteSimpleEntry(date: currentDate, book: books.randomElement() ?? testBook)
let timeline = Timeline(entries: [entry], policy: .after(entryDate))
completion(timeline)
}
func load<T: Decodable>(_ filename: String) -> T {
let groupDirectory = AppGroup.Livre.containerURL
let groupURL = groupDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
return try! JSONDecoder().decode(T.self, from: Data(contentsOf: groupURL))
}
}
struct QuoteSimpleEntry: TimelineEntry {
let date: Date
let book: Book
}
struct QuotePlaceholderView: View {
var body: some View {
QuoteWidgetView(book: testBook)
.redacted(reason: .placeholder)
}
}
struct QuoteWidgetEntryView : View {
#Environment(\.widgetFamily) var family
var entry: QuoteProvider.Entry
var body: some View {
QuoteWidgetView(book: entry.book, size: .small)
}
}
struct QuoteWidget: Widget {
let kind: String = "QuoteWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: QuoteProvider()) { entry in
QuoteWidgetEntryView(entry: entry)
}
.configurationDisplayName("Quote widget")
.description("This widget shows a random quote from a random book in your Library")
.supportedFamilies([.systemMedium])
}
}
The widgets seem to work, but I'm trying to find out why i'm getting this popup error.

Pass data entered in a UIView to a Widget

I try to implement a simple pattern on Widgets:
get a textField in the app;
have the Widget updated when textField is changed.
App is UIKit (not SwiftUI).
I've read here that I could pass it through UserDefaults,
How to pass uiviewcontroller data to swiftui widget class
and also through a shared singleton. I tried but couldn't make it work.
What I tried:
Create a singleton to hold the data to pass:
class Util {
class var shared : Util {
struct Singleton {
static let instance = Util()
}
return Singleton.instance;
}
var globalToPass = "Hello"
}
shared the file between the 2 targets App and WidgetExtension
In VC, update the singleton when textField is changed and ask for widget to reload timeline
#IBAction func updateMessage(_ sender: UITextField) {
Util.shared.globalToPass = valueToPassLabel.text ?? "--"
WidgetCenter.shared.reloadTimelines(ofKind: "WidgetForTest")
WidgetCenter.shared.reloadAllTimelines()
}
Problem : Widget never updated its message field
Here is the full widget code at this time:
import WidgetKit
import SwiftUI
struct LoadStatusProvider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), loadEntry: 0, message: Util.shared.globalToPass)
}
func getSnapshot(in context: Context, completion: #escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), loadEntry: 0, message: Util.shared.globalToPass)
completion(entry)
}
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for minuteOffset in 0 ..< 2 {
let entryDate = Calendar.current.date(byAdding: .minute, value: 5*minuteOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, loadEntry: minuteOffset, message: Util.shared.globalToPass)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let loadEntry: Int
let message: String
}
struct WidgetForTestNoIntentEntryView : View {
var entry: LoadStatusProvider.Entry
var body: some View {
let formatter = DateFormatter()
formatter.timeStyle = .medium
let dateString = formatter.string(from: entry.date)
return
VStack {
Text(String(entry.message))
HStack {
Text("Started")
Text(entry.date, style: .time)
}
HStack {
Text("Now")
Text(dateString)
}
HStack {
Text("Loaded")
Text(String(entry.loadEntry))
}
}
}
}
#main
struct WidgetForTestNoIntent: Widget {
let kind: String = "WidgetForTestNoIntent"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: LoadStatusProvider()) { entry in
WidgetForTestNoIntentEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
struct WidgetForTestNoIntent_Previews: PreviewProvider {
static var previews: some View {
WidgetForTestNoIntentEntryView(entry: SimpleEntry(date: Date(), loadEntry: 0, message: "-"))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}

Resources