Skip to content

Commit

Permalink
Display a progress when url has changed and content is being updated
Browse files Browse the repository at this point in the history
  • Loading branch information
Ceylo committed Dec 29, 2024
1 parent 53a7196 commit 8b324b5
Showing 1 changed file with 49 additions and 7 deletions.
56 changes: 49 additions & 7 deletions FurAffinity/Helper Views/RemoteView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protocol UpdateHandler<Data> {
struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: View>: View, UpdateHandler {
init(
url: URL,
dataSource: @escaping (_ sourceUrl: URL) async -> Data?,
dataSource: @escaping (_ sourceUrl: URL) async throws -> Data?,
@ViewBuilder preview: @escaping () -> PreviewView? = { nil },
view: @escaping (Data, any UpdateHandler<Data>) -> ContentsView
) {
Expand All @@ -33,7 +33,7 @@ struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: Vi
}

var url: URL
var dataSource: (_ sourceUrl: URL) async -> Data?
var dataSource: (_ sourceUrl: URL) async throws -> Data?
@ViewBuilder var preview: () -> PreviewView?
var view: (
_ data: Data,
Expand All @@ -42,16 +42,33 @@ struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: Vi

private enum DataState {
case loaded(Data)
case updating(oldData: Data)
case failed
}
@State private var dataState: DataState?

var loadingView: some View {
VStack(spacing: 20) {
ProgressView()
Link("Waiting for \(url.host(percentEncoded: false) ?? "?")", destination: url)
.fixedSize()
}
}

var body: some View {
Group {
if let dataState {
switch dataState {
case .loaded(let data):
view(data, self)
case .updating(let oldData):
view(oldData, self)
.overlay {
loadingView
.padding(20)
.background(.thinMaterial)
.clipShape(RoundedRectangle(cornerRadius: 10))
}
case .failed:
ScrollView {
LoadingFailedView(url: url)
Expand All @@ -61,10 +78,7 @@ struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: Vi
if let preview = preview() {
preview
} else {
VStack(spacing: 20) {
ProgressView()
Link("Waiting for \(url.host(percentEncoded: false) ?? "?")", destination: url)
}
loadingView
}
}
}
Expand All @@ -77,6 +91,16 @@ struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: Vi
await update()
}
.onChange(of: url) {
let newState: DataState? = switch dataState {
case .loaded(let data):
.updating(oldData: data)
case .updating(let oldData):
.updating(oldData: oldData)
case .failed, nil:
nil
}

dataState = newState
Task {
await update()
}
Expand All @@ -91,7 +115,7 @@ struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: Vi
}

func update() async {
let data = await dataSource(url)
let data = try? await dataSource(url)
update(with: data)
}

Expand All @@ -105,3 +129,21 @@ struct PreviewableRemoteView<Data: Sendable, ContentsView: View, PreviewView: Vi
}

typealias RemoteView<Data: Sendable, ContentsView: View> = PreviewableRemoteView<Data, ContentsView, EmptyView>

#Preview {
@Previewable
@State var url = URL(string: "https://www.furaffinity.net/")!

RemoteView(url: url) { sourceUrl in
try await Task.sleep(for: .seconds(1))
return sourceUrl
} view: { data, updateHandler in
VStack {
Text(data.absoluteString)
Button("Update") {
url = url.appending(component: "hi")
}
}
.border(.red)
}
}

0 comments on commit 8b324b5

Please sign in to comment.