Merge pull request #100 from writeas/show-progressview-during-network-requests

Show ProgressView during network requests
This commit is contained in:
Angelo Stavrow 2020-10-21 14:01:56 -04:00 committed by GitHub
commit a2efef2f72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 18 deletions

View File

@ -11,7 +11,8 @@ class WriteFreelyModel: ObservableObject {
@Published var posts = PostListModel()
@Published var editor = PostEditorModel()
@Published var isLoggingIn: Bool = false
@Published var hasNetworkConnection: Bool = false
@Published var isProcessingRequest: Bool = false
@Published var hasNetworkConnection: Bool = true
@Published var selectedPost: WFAPost? {
didSet {
if let post = selectedPost {
@ -27,6 +28,7 @@ class WriteFreelyModel: ObservableObject {
}
@Published var isPresentingDeleteAlert: Bool = false
@Published var isPresentingLoginErrorAlert: Bool = false
@Published var isPresentingNetworkErrorAlert: Bool = false
@Published var postToDelete: WFAPost?
#if os(iOS)
@Published var isPresentingSettingsView: Bool = false
@ -82,6 +84,10 @@ class WriteFreelyModel: ObservableObject {
extension WriteFreelyModel {
func login(to server: URL, as username: String, password: String) {
if !hasNetworkConnection {
isPresentingNetworkErrorAlert = true
return
}
let secureProtocolPrefix = "https://"
let insecureProtocolPrefix = "http://"
var serverString = server.absoluteString
@ -104,6 +110,10 @@ extension WriteFreelyModel {
}
func logout() {
if !hasNetworkConnection {
DispatchQueue.main.async { self.isPresentingNetworkErrorAlert = true }
return
}
guard let loggedInClient = client else {
do {
try purgeTokenFromKeychain(username: account.username, server: account.server)
@ -117,17 +127,41 @@ extension WriteFreelyModel {
}
func fetchUserCollections() {
if !hasNetworkConnection {
DispatchQueue.main.async { self.isPresentingNetworkErrorAlert = true }
return
}
guard let loggedInClient = client else { return }
// We're starting the network request.
DispatchQueue.main.async {
self.isProcessingRequest = true
}
loggedInClient.getUserCollections(completion: fetchUserCollectionsHandler)
}
func fetchUserPosts() {
if !hasNetworkConnection {
DispatchQueue.main.async { self.isPresentingNetworkErrorAlert = true }
return
}
guard let loggedInClient = client else { return }
// We're starting the network request.
DispatchQueue.main.async {
self.isProcessingRequest = true
}
loggedInClient.getPosts(completion: fetchUserPostsHandler)
}
func publish(post: WFAPost) {
if !hasNetworkConnection {
DispatchQueue.main.async { self.isPresentingNetworkErrorAlert = true }
return
}
guard let loggedInClient = client else { return }
// We're starting the network request.
DispatchQueue.main.async {
self.isProcessingRequest = true
}
if post.language == nil {
if let languageCode = Locale.current.languageCode {
@ -166,10 +200,16 @@ extension WriteFreelyModel {
}
func updateFromServer(post: WFAPost) {
if !hasNetworkConnection {
DispatchQueue.main.async { self.isPresentingNetworkErrorAlert = true }
return
}
guard let loggedInClient = client else { return }
guard let postId = post.postId else { return }
// We're starting the network request.
DispatchQueue.main.async {
self.selectedPost = post
self.isProcessingRequest = true
}
if let postCollectionAlias = post.collectionAlias,
let postSlug = post.slug {
@ -180,8 +220,16 @@ extension WriteFreelyModel {
}
func move(post: WFAPost, from oldCollection: WFACollection?, to newCollection: WFACollection?) {
if !hasNetworkConnection {
DispatchQueue.main.async { self.isPresentingNetworkErrorAlert = true }
return
}
guard let loggedInClient = client,
let postId = post.postId else { return }
// We're starting the network request.
DispatchQueue.main.async {
self.isProcessingRequest = true
}
post.collectionAlias = newCollection?.alias
loggedInClient.movePost(postId: postId, to: newCollection?.alias, completion: movePostHandler)
@ -271,6 +319,10 @@ private extension WriteFreelyModel {
}
func fetchUserCollectionsHandler(result: Result<[WFCollection], Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
do {
let fetchedCollections = try result.get()
for fetchedCollection in fetchedCollections {
@ -294,6 +346,10 @@ private extension WriteFreelyModel {
}
func fetchUserPostsHandler(result: Result<[WFPost], Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
do {
var postsToDelete = posts.userPosts.filter { $0.status != PostStatus.local.rawValue }
let fetchedPosts = try result.get()
@ -336,6 +392,10 @@ private extension WriteFreelyModel {
}
func publishHandler(result: Result<WFPost, Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
// NOTE:
// The API does not return a collection alias, so we take care not to overwrite the
// cached post's collection alias with the 'nil' value from the fetched post.
@ -366,6 +426,10 @@ private extension WriteFreelyModel {
}
func updateFromServerHandler(result: Result<WFPost, Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
// NOTE:
// The API does not return a collection alias, so we take care not to overwrite the
// cached post's collection alias with the 'nil' value from the fetched post.
@ -393,6 +457,10 @@ private extension WriteFreelyModel {
}
func movePostHandler(result: Result<Bool, Error>) {
// We're done with the network request.
DispatchQueue.main.async {
self.isProcessingRequest = false
}
do {
let succeeded = try result.get()
if succeeded {

View File

@ -55,6 +55,15 @@ struct ContentView: View {
}
)
}
.alert(isPresented: $model.isPresentingNetworkErrorAlert, content: {
Alert(
title: Text("Connection Error"),
message: Text("There is no internet connection at the moment. Please reconnect or try again later"),
dismissButton: .default(Text("OK"), action: {
model.isPresentingNetworkErrorAlert = false
})
)
})
#if os(iOS)
EmptyView()

View File

@ -35,12 +35,16 @@ struct PostListView: View {
Text(pluralizedPostCount(for: showPosts(for: selectedCollection)))
.foregroundColor(.secondary)
Spacer()
Button(action: {
reloadFromServer()
}, label: {
Image(systemName: "arrow.clockwise")
})
.disabled(!model.account.isLoggedIn || !model.hasNetworkConnection)
if model.isProcessingRequest {
ProgressView()
} else {
Button(action: {
reloadFromServer()
}, label: {
Image(systemName: "arrow.clockwise")
})
.disabled(!model.account.isLoggedIn)
}
}
.padding()
.frame(width: geometry.size.width)
@ -66,7 +70,7 @@ struct PostListView: View {
}, label: {
Image(systemName: "arrow.clockwise")
})
.disabled(!model.account.isLoggedIn || !model.hasNetworkConnection)
.disabled(!model.account.isLoggedIn)
}
#endif
}

View File

@ -153,7 +153,10 @@ struct PostEditorView: View {
PostEditorStatusToolbarView(post: post)
}
ToolbarItem(placement: .primaryAction) {
Menu(content: {
if model.isProcessingRequest {
ProgressView()
} else {
Menu(content: {
if post.status == PostStatus.local.rawValue {
Menu(content: {
Label("Publish to…", systemImage: "paperplane")
@ -192,12 +195,7 @@ struct PostEditorView: View {
}, label: {
Label("Publish", systemImage: "paperplane")
})
.disabled(
post.status ==
PostStatus.published.rawValue ||
!model.hasNetworkConnection ||
post.body.count == 0
)
.disabled(post.status == PostStatus.published.rawValue || post.body.count == 0)
}
Button(action: {
sharePost()
@ -226,6 +224,7 @@ struct PostEditorView: View {
}, label: {
Image(systemName: "ellipsis.circle")
})
}
}
}
.onChange(of: post.hasNewerRemoteCopy, perform: { _ in

View File

@ -143,9 +143,7 @@ struct PostEditorView: View {
}, label: {
Image(systemName: "paperplane")
})
.disabled(
post.status == PostStatus.published.rawValue || !model.hasNetworkConnection || post.body.count == 0
)
.disabled(post.status == PostStatus.published.rawValue || || post.body.count == 0)
}
}
.onChange(of: post.hasNewerRemoteCopy, perform: { _ in