Skip to content

Commit

Permalink
Adopt concurrency
Browse files Browse the repository at this point in the history
  • Loading branch information
bourvill committed Jan 29, 2024
1 parent fc30903 commit caf32a6
Show file tree
Hide file tree
Showing 25 changed files with 189 additions and 163 deletions.
30 changes: 30 additions & 0 deletions App/Features/Entry/Add/AddEntryModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Factory
import Foundation
import Observation
import SwiftUI

@Observable
final class AddEntryModel {
@ObservationIgnored
@Injected(\.wallabagSession) private var session

var url: String = ""
var submitting: Bool = false
var succeeded: Bool = false

@MainActor
func addEntry() async {
defer {
submitting = false
succeeded = false
url = ""
}

submitting = true
do {
try await session.addEntry(url: url)
succeeded = true
try await Task.sleep(for: .seconds(3))
} catch {}
}
}
34 changes: 34 additions & 0 deletions App/Features/Entry/Add/AddEntryView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import SwiftUI

struct AddEntryView: View {
@State private var model = AddEntryModel()

var body: some View {
Form {
TextField("Url", text: $model.url)
#if os(iOS)
.autocapitalization(.none)
#endif
.disableAutocorrection(true)
HStack {
if model.succeeded {
Text("Great! Entry was added")
} else {
Button(model.submitting ? "Submitting..." : "Submit") {
Task {
await model.addEntry()
}
}.disabled(model.submitting)
}
}
.disabled(model.url.isEmpty)
}
.animation(.easeInOut, value: model.succeeded)
.animation(.easeInOut, value: model.submitting)
.navigationTitle("Add entry")
}
}

#Preview {
AddEntryView()
}
53 changes: 0 additions & 53 deletions App/Features/Entry/AddEntryView.swift

This file was deleted.

2 changes: 1 addition & 1 deletion App/Features/Entry/EntriesListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI

struct EntriesListView: View {
@Environment(\.managedObjectContext) var context: NSManagedObjectContext
@EnvironmentObject var appSync: AppSync
@Environment(AppSync.self) var appSync: AppSync
@FetchRequest var entries: FetchedResults<Entry>

init(predicate: NSPredicate, entriesSortAscending: Bool) {
Expand Down
2 changes: 1 addition & 1 deletion App/Features/Entry/EntriesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import CoreData
import SwiftUI

struct EntriesView: View {
@EnvironmentObject var router: Router
@Environment(Router.self) var router: Router
@EnvironmentObject var appState: AppState
@StateObject var searchViewModel = SearchViewModel()
@State var entriesSortAscending = false
Expand Down
2 changes: 1 addition & 1 deletion App/Features/Entry/EntryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct EntryView: View {
@Environment(\.managedObjectContext) var context: NSManagedObjectContext
@Environment(\.openURL) var openURL
@Environment(\.dismiss) private var dismiss
@EnvironmentObject var appSync: AppSync
@Environment(AppSync.self) var appSync: AppSync
#if os(iOS)
@EnvironmentObject var player: PlayerPublisher
#endif
Expand Down
3 changes: 2 additions & 1 deletion App/Features/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI
struct MainView: View {
@EnvironmentObject var appState: AppState
@EnvironmentObject var player: PlayerPublisher
@EnvironmentObject var router: Router
@Environment(Router.self) var router: Router

var body: some View {
if appState.registred {
Expand All @@ -18,6 +18,7 @@ struct MainView: View {
var mainView: some View {
ZStack {
GeometryReader { geometry in
@Bindable var router = router
NavigationStack(path: $router.path) {
EntriesView()
.appRouting()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SharedLib
import SwiftUI

struct ClientIdClientSecretView: View {
@StateObject var clientIdSecretViewModel = ClientIdSecretViewModel()
@State private var clientIdSecretViewModel = ClientIdSecretViewModel()

var body: some View {
Form {
Expand All @@ -20,7 +20,15 @@ struct ClientIdClientSecretView: View {
.autocapitalization(.none)
#endif
}
NavigationLink("Next", destination: LoginView()).disabled(!clientIdSecretViewModel.isValid)
Button(action: {
clientIdSecretViewModel.goNext()
}, label: {
Text("Next")
})
.disabled(!clientIdSecretViewModel.isValid)
}
.navigationDestination(isPresented: $clientIdSecretViewModel.shouldGoNextStep) {
LoginView()
}
#if os(iOS)
.navigationBarTitle("Client id & secret")
Expand All @@ -32,12 +40,8 @@ struct ClientIdClientSecretView: View {
}
}

#if DEBUG
struct ClientIdClientSecretView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
ClientIdClientSecretView()
}
}
#Preview {
NavigationView {
ClientIdClientSecretView()
}
#endif
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import Combine
import Foundation
import Observation
import SharedLib
import SwiftUI

class ClientIdSecretViewModel: ObservableObject {
private(set) var isValid: Bool = false

@Published var clientId: String = ""
@Published var clientSecret: String = ""
@Observable
final class ClientIdSecretViewModel {
var isValid: Bool {
!clientId.isEmpty && !clientSecret.isEmpty
}

private var cancellable: AnyCancellable?
var clientId: String = ""
var clientSecret: String = ""
var shouldGoNextStep = false

init() {
clientId = WallabagUserDefaults.clientId
clientSecret = WallabagUserDefaults.clientSecret

cancellable = Publishers.CombineLatest($clientId, $clientSecret).sink { [unowned self] clientId, clientSecret in
isValid = !clientId.isEmpty && !clientSecret.isEmpty
if isValid {
WallabagUserDefaults.clientId = clientId.trimmingCharacters(in: .whitespacesAndNewlines)
WallabagUserDefaults.clientSecret = clientSecret.trimmingCharacters(in: .whitespacesAndNewlines)
}
}
}

deinit {
cancellable?.cancel()
func goNext() {
WallabagUserDefaults.clientId = clientId.trimmingCharacters(in: .whitespacesAndNewlines)
WallabagUserDefaults.clientSecret = clientSecret.trimmingCharacters(in: .whitespacesAndNewlines)
shouldGoNextStep = true
}
}
2 changes: 1 addition & 1 deletion App/Features/Registration/Login/LoginView.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SwiftUI

struct LoginView: View {
@StateObject var loginViewModel = LoginViewModel()
@State var loginViewModel = LoginViewModel()

var body: some View {
Form {
Expand Down
27 changes: 13 additions & 14 deletions App/Features/Registration/Login/LoginViewModel.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import Combine
import Factory
import Foundation
import Observation
import SharedLib

class LoginViewModel: ObservableObject {
@Observable
final class LoginViewModel {
@ObservationIgnored
@Injected(\.appState) private var appState
@ObservationIgnored
@Injected(\.wallabagSession) private var session
@ObservationIgnored
@Injected(\.router) private var router

@Published var login: String = ""
@Published var password: String = ""
@Published var error: String?

private(set) var isValid: Bool = false
private var cancellable = Set<AnyCancellable>()

var login: String = ""
var password: String = ""
var error: String?
var isValid: Bool {
!login.isEmpty && !password.isEmpty
}

init() {
login = WallabagUserDefaults.login
Publishers.CombineLatest($login, $password).sink { [unowned self] login, password in
isValid = !login.isEmpty && !password.isEmpty
}.store(in: &cancellable)

session.$state.receive(on: DispatchQueue.main).sink { [unowned self] state in
switch state {
Expand All @@ -45,8 +48,4 @@ class LoginViewModel: ObservableObject {
password: password
)
}

deinit {
cancellable.forEach { $0.cancel() }
}
}
10 changes: 3 additions & 7 deletions App/Features/Registration/RegistrationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ struct RegistrationView: View {
}
}

#if DEBUG
struct RegistrationView_Previews: PreviewProvider {
static var previews: some View {
RegistrationView()
}
}
#endif
#Preview {
RegistrationView()
}
12 changes: 9 additions & 3 deletions App/Features/Registration/Server/ServerView.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SwiftUI

struct ServerView: View {
@StateObject var serverViewModel = ServerViewModel()
@State private var serverViewModel = ServerViewModel()

var body: some View {
Form {
Expand All @@ -12,9 +12,15 @@ struct ServerView: View {
.autocapitalization(.none)
#endif
}
NavigationLink(destination: ClientIdClientSecretView()) {
Button(action: {
serverViewModel.goNext()
}, label: {
Text("Next")
}.disabled(!serverViewModel.isValid)
})
.disabled(!serverViewModel.isValid)
}
.navigationDestination(isPresented: $serverViewModel.shouldGoNextStep) {
ClientIdClientSecretView()
}
#if os(iOS)
.navigationBarTitle("Server")
Expand Down
25 changes: 12 additions & 13 deletions App/Features/Registration/Server/ServerViewModel.swift
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import Combine
import Foundation
import Observation
import SharedLib
import SwiftUI

final class ServerViewModel: ObservableObject {
@Published private(set) var isValid: Bool = false
@Published var url: String = ""
@Observable
final class ServerViewModel {
var isValid: Bool {
validateServer(host: url)
}

var url: String = ""

private var cancellable: AnyCancellable?
var shouldGoNextStep = false

init() {
url = WallabagUserDefaults.host
cancellable = $url.sink { [unowned self] url in
isValid = validateServer(host: url)
if isValid {
WallabagUserDefaults.host = url
}
}
}

deinit {
cancellable?.cancel()
func goNext() {
WallabagUserDefaults.host = url
shouldGoNextStep = true
}

private func validateServer(host: String) -> Bool {
Expand Down
7 changes: 4 additions & 3 deletions App/Features/Router/Router.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Combine
import Foundation
import Observation
import SwiftUI

final class Router: ObservableObject {
@Published var path: [RoutePath] = []
@Observable
final class Router {
var path: [RoutePath] = []
}
Loading

0 comments on commit caf32a6

Please sign in to comment.