FIX: Save the latest successful timeline entry in case of network error

This commit is contained in:
Marcos Rodriguez Velez 2023-12-26 23:00:30 -04:00 committed by Overtorment
parent 80c1b66604
commit cd54601fc8
4 changed files with 123 additions and 85 deletions

View file

@ -11,8 +11,10 @@ import SwiftUI
struct WalletInformationWidgetProvider: TimelineProvider {
typealias Entry = WalletInformationWidgetEntry
static var lastSuccessfulEntry: WalletInformationWidgetEntry?
func placeholder(in context: Context) -> WalletInformationWidgetEntry {
return WalletInformationWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10,000", rate: 10000), allWalletsBalance: WalletData(balance: 1000000, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: 1568804029000)))
return WalletInformationWidgetEntry.placeholder
}
func getSnapshot(in context: Context, completion: @escaping (WalletInformationWidgetEntry) -> ()) {
@ -27,22 +29,28 @@ struct WalletInformationWidgetProvider: TimelineProvider {
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [WalletInformationWidgetEntry] = []
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency();
let marketDataEntry = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime())
WidgetAPI.fetchPrice(currency: userPreferredCurrency, completion: { (result, error) in
WidgetAPI.fetchPrice(currency: userPreferredCurrency) { (result, error) in
let entry: WalletInformationWidgetEntry
if let result = result {
entry = WalletInformationWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "", sats: "", price: result.formattedRate ?? "!", rate: result.rateDouble), allWalletsBalance: allwalletsBalance)
WalletInformationWidgetProvider.lastSuccessfulEntry = entry
} else {
entry = WalletInformationWidgetEntry(date: Date(), marketData: marketDataEntry, allWalletsBalance: allwalletsBalance)
// Use the last successful entry if available
if let lastEntry = WalletInformationWidgetProvider.lastSuccessfulEntry {
entry = lastEntry
} else {
// Fallback to a default entry if no successful entry is available
entry = WalletInformationWidgetEntry.placeholder
}
}
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
})
}
}
}
@ -52,6 +60,12 @@ struct WalletInformationWidgetEntry: TimelineEntry {
var allWalletsBalance: WalletData = WalletData(balance: 0)
}
extension WalletInformationWidgetEntry {
static var placeholder: WalletInformationWidgetEntry {
WalletInformationWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10,000", rate: 10000), allWalletsBalance: WalletData(balance: 1000000, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: 1568804029000)))
}
}
struct WalletInformationWidgetEntryView : View {
let entry: WalletInformationWidgetEntry

View file

@ -10,6 +10,8 @@ import WidgetKit
import SwiftUI
struct MarketWidgetProvider: TimelineProvider {
static var lastSuccessfulEntry: MarketWidgetEntry?
func placeholder(in context: Context) -> MarketWidgetEntry {
return MarketWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10 000", rate: 10000))
}
@ -25,28 +27,34 @@ struct MarketWidgetProvider: TimelineProvider {
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [MarketWidgetEntry] = []
if context.isPreview {
let entry = MarketWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10 000", rate: 10000))
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}else {
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency();
let marketDataEntry = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
WidgetAPI.fetchMarketData(currency: userPreferredCurrency, completion: { (result, error) in
let entry: MarketWidgetEntry
if let result = result {
entry = MarketWidgetEntry(date: Date(), marketData: result)
} else {
entry = MarketWidgetEntry(date: Date(), marketData: marketDataEntry)
}
var entries: [MarketWidgetEntry] = []
if context.isPreview {
let entry = MarketWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10 000", rate: 10000))
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
})
}
} else {
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
WidgetAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in
let entry: MarketWidgetEntry
if let result = result {
entry = MarketWidgetEntry(date: Date(), marketData: result)
MarketWidgetProvider.lastSuccessfulEntry = entry
} else {
// Use the last successful entry if available
if let lastEntry = MarketWidgetProvider.lastSuccessfulEntry {
entry = lastEntry
} else {
// Fallback to a default entry if no successful entry is available
entry = MarketWidgetEntry(date: Date(), marketData: emptyMarketData)
}
}
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
}
}

View file

@ -12,6 +12,7 @@ import SwiftUI
var marketData: [MarketDataTimeline: MarketData?] = [ .Current: nil, .Previous: nil]
struct PriceWidgetProvider: TimelineProvider {
typealias Entry = PriceWidgetEntry
static var lastSuccessfulEntry: PriceWidgetEntry?
func placeholder(in context: Context) -> PriceWidgetEntry {
return PriceWidgetEntry(date: Date(), currentMarketData: MarketData(nextBlock: "", sats: "", price: "$10,000", rate: 10000, dateString: "2019-09-18T17:27:00+00:00"))
@ -35,73 +36,78 @@ struct PriceWidgetProvider: TimelineProvider {
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
} else {
if WidgetAPI.getUserPreferredCurrency() != WidgetAPI.getLastSelectedCurrency() {
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
if userPreferredCurrency != WidgetAPI.getLastSelectedCurrency() {
marketData[.Current] = nil
marketData[.Previous] = nil
WidgetAPI.saveNewSelectedCurrency()
}
var entryMarketData = marketData[.Current] ?? emptyMarketData
WidgetAPI.fetchPrice(currency: WidgetAPI.getUserPreferredCurrency()) { (data, error) in
WidgetAPI.fetchPrice(currency: userPreferredCurrency) { (data, error) in
let entry: PriceWidgetEntry
if let data = data, let formattedRate = data.formattedRate {
let currentMarketData = MarketData(nextBlock: "", sats: "", price: formattedRate, rate: data.rateDouble, dateString: data.lastUpdate)
if let cachedMarketData = marketData[.Current], currentMarketData.dateString != cachedMarketData?.dateString {
marketData[.Previous] = marketData[.Current]
marketData[.Current] = currentMarketData
entryMarketData = currentMarketData
entries.append(PriceWidgetEntry(date:Date(), currentMarketData: entryMarketData))
marketData[.Previous] = marketData[.Current]
marketData[.Current] = currentMarketData
entry = PriceWidgetEntry(date: Date(), currentMarketData: currentMarketData)
PriceWidgetProvider.lastSuccessfulEntry = entry
} else {
// Use the last successful entry if available
if let lastEntry = PriceWidgetProvider.lastSuccessfulEntry {
entry = lastEntry
} else {
entries.append(PriceWidgetEntry(date:Date(), currentMarketData: currentMarketData))
// Fallback to a default entry if no successful entry is available
entry = PriceWidgetEntry(date: Date(), currentMarketData: emptyMarketData)
}
}
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}}
}
struct PriceWidgetEntry: TimelineEntry {
let date: Date
let currentMarketData: MarketData?
var previousMarketData: MarketData? {
return marketData[.Previous] as? MarketData
}
}
}
struct PriceWidgetEntry: TimelineEntry {
let date: Date
let currentMarketData: MarketData?
var previousMarketData: MarketData? {
return marketData[.Previous] as? MarketData
}
}
struct PriceWidgetEntryView : View {
let entry: PriceWidgetEntry
var priceView: some View {
PriceView(currentMarketData: entry.currentMarketData, previousMarketData: marketData[.Previous] ?? emptyMarketData).padding()
}
struct PriceWidgetEntryView : View {
let entry: PriceWidgetEntry
var priceView: some View {
PriceView(currentMarketData: entry.currentMarketData, previousMarketData: marketData[.Previous] ?? emptyMarketData).padding()
}
var body: some View {
VStack(content: {
priceView
}).background(Color.widgetBackground)
}
}
struct PriceWidget: Widget {
let kind: String = "PriceWidget"
var body: some WidgetConfiguration {
if #available(iOSApplicationExtension 16.0, *) {
return StaticConfiguration(kind: kind, provider: PriceWidgetProvider()) { entry in
PriceWidgetEntryView(entry: entry)
}
.configurationDisplayName("Price")
.description("View the current price of Bitcoin.").supportedFamilies([.systemSmall])
} else {
return StaticConfiguration(kind: kind, provider: PriceWidgetProvider()) { entry in
PriceWidgetEntryView(entry: entry)
}
.configurationDisplayName("Price")
.description("View the current price of Bitcoin.").supportedFamilies([.systemSmall])
var body: some View {
VStack(content: {
priceView
}).background(Color.widgetBackground)
}
}
struct PriceWidget: Widget {
let kind: String = "PriceWidget"
var body: some WidgetConfiguration {
if #available(iOSApplicationExtension 16.0, *) {
return StaticConfiguration(kind: kind, provider: PriceWidgetProvider()) { entry in
PriceWidgetEntryView(entry: entry)
}
.configurationDisplayName("Price")
.description("View the current price of Bitcoin.").supportedFamilies([.systemSmall])
} else {
return StaticConfiguration(kind: kind, provider: PriceWidgetProvider()) { entry in
PriceWidgetEntryView(entry: entry)
}
.configurationDisplayName("Price")
.description("View the current price of Bitcoin.").supportedFamilies([.systemSmall])
}
}
}
}
struct PriceWidget_Previews: PreviewProvider {
static var previews: some View {

View file

@ -11,8 +11,10 @@ import SwiftUI
struct WalletInformationAndMarketWidgetProvider: TimelineProvider {
typealias Entry = WalletInformationAndMarketWidgetEntry
static var lastSuccessfulEntry: WalletInformationAndMarketWidgetEntry?
func placeholder(in context: Context) -> WalletInformationAndMarketWidgetEntry {
return WalletInformationAndMarketWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10,000", rate: 10000), allWalletsBalance: WalletData(balance: 1000000, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: 1568804029000)))
return WalletInformationAndMarketWidgetEntry.placeholder
}
func getSnapshot(in context: Context, completion: @escaping (WalletInformationAndMarketWidgetEntry) -> ()) {
@ -33,21 +35,28 @@ struct WalletInformationAndMarketWidgetProvider: TimelineProvider {
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
} else {
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency();
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime())
let marketDataEntry = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
WidgetAPI.fetchMarketData(currency: userPreferredCurrency, completion: { (result, error) in
WidgetAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in
let entry: WalletInformationAndMarketWidgetEntry
if let result = result {
entry = WalletInformationAndMarketWidgetEntry(date: Date(), marketData: result, allWalletsBalance: allwalletsBalance)
WalletInformationAndMarketWidgetProvider.lastSuccessfulEntry = entry
} else {
entry = WalletInformationAndMarketWidgetEntry(date: Date(), marketData: marketDataEntry, allWalletsBalance: allwalletsBalance)
// Use the last successful entry if available
if let lastEntry = WalletInformationAndMarketWidgetProvider.lastSuccessfulEntry {
entry = lastEntry
} else {
// Fallback to a default entry if no successful entry is available
entry = WalletInformationAndMarketWidgetEntry.placeholder
}
}
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
})
}
}
}
}
@ -56,6 +65,7 @@ struct WalletInformationAndMarketWidgetEntry: TimelineEntry {
let date: Date
let marketData: MarketData
var allWalletsBalance: WalletData = WalletData(balance: 0)
static var placeholder = WalletInformationAndMarketWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0), allWalletsBalance: WalletData(balance: 0, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: 1568804029000)))
}
struct WalletInformationAndMarketWidgetEntryView : View {