From d43a12e57bf60d78f90abc80aa8caf71e03f92f2 Mon Sep 17 00:00:00 2001 From: PhongND Date: Thu, 5 Oct 2023 14:45:34 +0700 Subject: [PATCH] fix server Signed-off-by: PhongND --- .DS_Store | Bin 6148 -> 6148 bytes BasicApp/.DS_Store | Bin 6148 -> 6148 bytes BasicApp/SwiftUI/.DS_Store | Bin 8196 -> 8196 bytes .../SwiftUI/Todo+Combine+SwiftUI/.DS_Store | Bin 6148 -> 6148 bytes .../Shared/CoreApp/Exports.swift | 2 + .../Shared/CoreApp/TodoApp.swift | 2 +- .../CoreApp/TodoApp/Models/TodoModel.swift | 2 +- .../CoreApp/TodoApp/Views/AuthView.swift | 1 - .../CoreApp/TodoApp/Views/MainView.swift | 143 +++--- .../CoreApp/TodoApp/Views/RootView.swift | 6 - .../CoreApp/TodoApp/Views/SplashView.swift | 11 - .../project.pbxproj | 193 ++----- .../xcshareddata/swiftpm/Package.resolved | 46 +- .../Todo+Combine+SwiftUI (iOS).xcscheme | 77 +++ .../Shared/CoreApp/Exports.swift | 2 + .../Shared/CoreApp/TodoApp.swift | 2 +- .../Shared/CoreApp/TodoApp/AuthView.swift | 1 - .../Shared/CoreApp/TodoApp/MainView.swift | 156 +++--- .../CoreApp/TodoApp/Models/TodoModel.swift | 2 +- .../project.pbxproj | 191 ++----- .../xcshareddata/swiftpm/Package.resolved | 30 +- .../Shared/CoreApp/Exports.swift | 2 + .../Shared/CoreApp/TodoApp.swift | 3 +- .../CoreApp/TodoApp/Models/TodoModel.swift | 2 +- .../{AppScreens => Views}/AuthView.swift | 0 .../{AppScreens => Views}/CounterView.swift | 0 .../{AppScreens => Views}/MainView.swift | 143 +++--- .../{AppScreens => Views}/RootView.swift | 6 - .../project.pbxproj | 193 ++----- .../xcshareddata/swiftpm/Package.resolved | 42 +- TodoListServer/.dockerignore | 2 + TodoListServer/Dockerfile | 31 +- TodoListServer/Package.resolved | 476 +++++++++--------- TodoListServer/Package.swift | 59 +-- TodoListServer/Public/.gitkeep | 0 .../App/Controllers/TodoController.swift | 41 +- .../Sources/App/Migrations/CreateTodo.swift | 12 +- .../Sources/App/Migrations/CreateUser.swift | 21 - TodoListServer/Sources/App/Models/Todo.swift | 8 +- TodoListServer/Sources/App/Models/User.swift | 27 - .../Sources/App/Socket/Websocket.swift | 43 -- .../Sources/App/UserAuthenticator.swift | 15 - TodoListServer/Sources/App/configure.swift | 31 +- TodoListServer/Sources/App/entrypoint.swift | 40 ++ TodoListServer/Sources/App/routes.swift | 18 +- TodoListServer/Sources/Run/main.swift | 9 - TodoListServer/Tests/AppTests/AppTests.swift | 4 +- TodoListServer/db.sqlite | Bin 0 -> 24576 bytes 48 files changed, 869 insertions(+), 1226 deletions(-) delete mode 100644 BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/SplashView.swift create mode 100644 BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/xcshareddata/xcschemes/Todo+Combine+SwiftUI (iOS).xcscheme rename BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/{AppScreens => Views}/AuthView.swift (100%) rename BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/{AppScreens => Views}/CounterView.swift (100%) rename BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/{AppScreens => Views}/MainView.swift (76%) rename BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/{AppScreens => Views}/RootView.swift (92%) create mode 100644 TodoListServer/.dockerignore create mode 100644 TodoListServer/Public/.gitkeep delete mode 100644 TodoListServer/Sources/App/Migrations/CreateUser.swift delete mode 100644 TodoListServer/Sources/App/Models/User.swift delete mode 100644 TodoListServer/Sources/App/Socket/Websocket.swift delete mode 100644 TodoListServer/Sources/App/UserAuthenticator.swift create mode 100644 TodoListServer/Sources/App/entrypoint.swift delete mode 100644 TodoListServer/Sources/Run/main.swift create mode 100644 TodoListServer/db.sqlite diff --git a/.DS_Store b/.DS_Store index dcd627375091c8c237fd30cae40149ec8b9d1fae..ad283086e39787de586ecb508e5e0a7f80dbbaf1 100644 GIT binary patch delta 83 zcmZoMXfc=|#>B)qu~2NHo+2a5#(>?7j4YdZSf(B!ku~2NHo+2aL#(>?7ixpUy7}+-SFimA-H@DDHFgGxryoSks@^fYd zSw4mkhJ1z;AogL%WGH4RVF+eOWhi1O1Cf&zm>VZAWpX2+>Id`x&Fmcf96)O~3vzsC Wp3E=e$ic|Kz{CIqnez;yB)X8X-gndC(QUbF{S diff --git a/BasicApp/SwiftUI/.DS_Store b/BasicApp/SwiftUI/.DS_Store index 996f5c072c37c70b316d6315b4ae121a97783eb4..e9e6401ac861699062e35ab1e17c1b5350d68007 100644 GIT binary patch delta 20 bcmZp1XmQxEQ-IybKu5vc)NJzs0T+G%MzaPl delta 20 bcmZp1XmQxEQ-IyvLPx>ez;yEg0T+G%M;-$e3^_xF+OP{=s$q&JF;xEWB3{K9^EnolvMup9Z Q%*$9NHt=m`=lIJH0BAWEBme*a delta 70 zcmZoMXffCj$;8YU9Wi+WlhfpROk8Yb>)3;@L`+`C = [] var isLoading: Bool = false } @@ -62,13 +62,13 @@ struct Main: Reducer { case .logout: return .send(.changeRootScreen(.auth)) case .viewCreateTodo: - if state.title.isEmpty { + if state.text.isEmpty { return .none } - let title = state.title - state.title = "" + let text = state.text + state.text = "" let id = uuid() - let todo = TodoModel(id: id, title: title, isCompleted: false) + let todo = TodoModel(id: id, text: text, isCompleted: false) return .send(.createOrUpdateTodo(todo)) // MARK: - Networking /// GET TODO @@ -79,7 +79,7 @@ struct Main: Reducer { state.isLoading = true state.todos.removeAll() let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) RMethod(.get) } if isUsingPublisher { @@ -95,23 +95,28 @@ struct Main: Reducer { await send(.responseTodo(data)) } } - case .responseTodo(let json): - if let items = json.toModel([TodoModel].self) { + case .responseTodo(let data): + log.info(Json(data)) + state.isLoading = false + if let items = data.toModel([TodoModel].self) { for item in items { state.todos.updateOrAppend(item) } } /// CREATE OR UPDATE TODO case .createOrUpdateTodo(let todo): + log.info(todo.toJson()) let request = MRequest { - RUrl(urlString: urlString) - REncoding(JSONEncoding.default) + RUrl(urlString) RMethod(.post) Rbody(todo.toData()) + REncoding(JSONEncoding.default) + } if isUsingPublisher { return .publisher { request + .printCURLRequest() .compactMap{$0.data} .map(Main.Action.responseCreateOrUpdateTodo) .eraseToAnyPublisher() @@ -122,21 +127,24 @@ struct Main: Reducer { await send(.responseCreateOrUpdateTodo(data)) } } - case .responseCreateOrUpdateTodo(let json): - if let item = json.toModel(TodoModel.self) { + case .responseCreateOrUpdateTodo(let data): + log.info(Json(data)) + if let item = data.toModel(TodoModel.self) { state.todos.updateOrAppend(item) } /// UPDATE TODO case .updateTodo(let todo): let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) .withPath(todo.id.toString()) - RMethod(.post) Rbody(todo.toData()) + RMethod(.post) + REncoding(JSONEncoding.default) } if isUsingPublisher { return .publisher { request + .printCURLRequest() .compactMap{$0.data} .map(Main.Action.responseUpdateTodo) .eraseToAnyPublisher() @@ -147,14 +155,15 @@ struct Main: Reducer { await send(.responseUpdateTodo(data)) } } - case .responseUpdateTodo(let json): - if let item = json.toModel(TodoModel.self) { + case .responseUpdateTodo(let data): + log.info(data.toJson()) + if let item = data.toModel(TodoModel.self) { state.todos.updateOrAppend(item) } /// DELETE TODO case .deleteTodo(let todo): let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) .withPath(todo.id.toString()) RMethod(.delete) } @@ -201,38 +210,12 @@ struct MainView: View { var body: some View { ZStack { -#if os(macOS) - content - .toolbar { - ToolbarItem(placement: .status) { - HStack { - CounterView( - store: store - .scope( - state: \.counterState, - action: Main.Action.counterAction - ) - ) - Spacer() - Button(action: { - viewStore.send(.logout) - }, label: { - Text("Logout") - .foregroundColor(Color.blue) - }) - } - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity) -#endif -#if os(iOS) NavigationView { content .navigationTitle("Todos") .navigationBarItems(leading: leadingBarItems, trailing: trailingBarItems) } .navigationViewStyle(.stack) -#endif } .onAppear { viewStore.send(.viewOnAppear) @@ -243,47 +226,18 @@ struct MainView: View { } } - extension MainView { /// create content view in screen private var content: some View { List { - Section { - ZStack { - HStack { - Spacer() - if viewStore.isLoading { - ProgressView() - } else { - Text("Reload") - .bold() - .onTapGesture { - viewStore.send(.getTodo) - } - } - Spacer() - } - .frame(height: 60) - } - } - HStack { - TextField("title", text: viewStore.$title) - Button(action: { - viewStore.send(.viewCreateTodo) - }, label: { - Text("Create") - .bold() - .foregroundColor(viewStore.title.isEmpty ? Color.gray : Color.green) - }) - .disabled(viewStore.title.isEmpty) - } - + topview + inputview ForEach(viewStore.todos) { todo in HStack { HStack { Image(systemName: todo.isCompleted ? "checkmark.square" : "square") .frame(width: 40, height: 40, alignment: .center) - Text(todo.title) + Text(todo.text) .underline(todo.isCompleted, color: Color.black) Spacer() } @@ -291,19 +245,50 @@ extension MainView { .onTapGesture { viewStore.send(.toggleTodo(todo)) } - Button(action: { + Button { viewStore.send(.deleteTodo(todo)) - }, label: { + } label: { Text("Delete") .foregroundColor(Color.gray) - }) + } } } - .padding(.all, 0) } .padding(.all, 0) } + private var topview: some View { + Section { + ZStack(alignment: .center) { + if viewStore.isLoading { + ProgressView() + } else { + Text("Reload") + .bold() + .onTapGesture { + viewStore.send(.getTodo) + } + } + } + .frame(height: 60) + .frame(maxWidth: .infinity) + } + } + + private var inputview: some View { + HStack { + TextField("text", text: viewStore.$text) + Button(action: { + viewStore.send(.viewCreateTodo) + }, label: { + Text("Create") + .bold() + .foregroundColor(viewStore.text.isEmpty ? Color.gray : Color.green) + }) + .disabled(viewStore.text.isEmpty) + } + } + private var leadingBarItems: some View { CounterView( store: store diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift index 7ded735..4eb9c39 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift +++ b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift @@ -1,4 +1,3 @@ -import ComposableArchitecture import SwiftUI struct Root: Reducer { @@ -55,8 +54,6 @@ struct Root: Reducer { } } - - struct RootView: View { private let store: StoreOf @@ -99,9 +96,6 @@ struct RootView: View { .onDisappear { viewStore.send(.viewOnDisappear) } -#if os(macOS) - .frame(minWidth: 700, idealWidth: 700, maxWidth: .infinity, minHeight: 500, idealHeight: 500, maxHeight: .infinity, alignment: .center) -#endif } } diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/SplashView.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/SplashView.swift deleted file mode 100644 index 3362e03..0000000 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/SplashView.swift +++ /dev/null @@ -1,11 +0,0 @@ -import SwiftUI - -struct SplashView: View { - var body: some View { - Text("Hello, World!") - } -} - -#Preview { - SplashView() -} diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.pbxproj b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.pbxproj index 48be0cb..296be71 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.pbxproj +++ b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.pbxproj @@ -7,37 +7,24 @@ objects = { /* Begin PBXBuildFile section */ - 8714CD30299CEA3A00F5B26C /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8714CD2F299CEA3A00F5B26C /* SplashView.swift */; }; - 8714CD31299CEA3A00F5B26C /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8714CD2F299CEA3A00F5B26C /* SplashView.swift */; }; 879A266127079EC900CCD1DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 879A264F27079EC900CCD1DD /* Assets.xcassets */; }; - 879A266227079EC900CCD1DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 879A264F27079EC900CCD1DD /* Assets.xcassets */; }; 87BB878727A57FB4000B269B /* CombineRequest in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB878627A57FB4000B269B /* CombineRequest */; }; - 87BB878C27A5803A000B269B /* CombineRequest in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB878B27A5803A000B269B /* CombineRequest */; }; 87BB87CE27A581A8000B269B /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB879227A581A8000B269B /* TodoApp.swift */; }; - 87BB87CF27A581A8000B269B /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB879227A581A8000B269B /* TodoApp.swift */; }; 87BB87D627A581A8000B269B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB879927A581A8000B269B /* MainView.swift */; }; - 87BB87D727A581A8000B269B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB879927A581A8000B269B /* MainView.swift */; }; 87BB87DE27A581A8000B269B /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB879E27A581A8000B269B /* CounterView.swift */; }; - 87BB87DF27A581A8000B269B /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB879E27A581A8000B269B /* CounterView.swift */; }; 87BB87E627A581A8000B269B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB87A327A581A8000B269B /* AuthView.swift */; }; - 87BB87E727A581A8000B269B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB87A327A581A8000B269B /* AuthView.swift */; }; 87BB880627A581A8000B269B /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB87B627A581A8000B269B /* RootView.swift */; }; - 87BB880727A581A8000B269B /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB87B627A581A8000B269B /* RootView.swift */; }; 87BB880E27A581A8000B269B /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB87BD27A581A8000B269B /* TodoModel.swift */; }; - 87BB880F27A581A8000B269B /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB87BD27A581A8000B269B /* TodoModel.swift */; }; EB5C21572AB1A229004F53C7 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21562AB1A229004F53C7 /* ComposableArchitecture */; }; - EB5C21592AB1A23E004F53C7 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21582AB1A23E004F53C7 /* ComposableArchitecture */; }; - EB5C215B2AB1A245004F53C7 /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C215A2AB1A245004F53C7 /* Transform */; }; EB5C215D2AB1A250004F53C7 /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C215C2AB1A250004F53C7 /* Transform */; }; EB5C215F2AB1A2A9004F53C7 /* Exports.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C215E2AB1A2A9004F53C7 /* Exports.swift */; }; - EB5C21602AB1A2A9004F53C7 /* Exports.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C215E2AB1A2A9004F53C7 /* Exports.swift */; }; + EBA4697B2ACE91440060376F /* Json in Frameworks */ = {isa = PBXBuildFile; productRef = EBA4697A2ACE91440060376F /* Json */; }; + EBA4697E2ACE91E10060376F /* SwiftLogger in Frameworks */ = {isa = PBXBuildFile; productRef = EBA4697D2ACE91E10060376F /* SwiftLogger */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 8714CD2F299CEA3A00F5B26C /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 879A264F27079EC900CCD1DD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 879A265427079EC900CCD1DD /* Todo+Combine+SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+Combine+SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 879A265A27079EC900CCD1DD /* Todo+Combine+SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+Combine+SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 879A265C27079EC900CCD1DD /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 87BB879227A581A8000B269B /* TodoApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoApp.swift; sourceTree = ""; }; 87BB879927A581A8000B269B /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -55,20 +42,12 @@ files = ( EB5C215D2AB1A250004F53C7 /* Transform in Frameworks */, 87BB878727A57FB4000B269B /* CombineRequest in Frameworks */, + EBA4697E2ACE91E10060376F /* SwiftLogger in Frameworks */, + EBA4697B2ACE91440060376F /* Json in Frameworks */, EB5C21572AB1A229004F53C7 /* ComposableArchitecture in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 879A265727079EC900CCD1DD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EB5C215B2AB1A245004F53C7 /* Transform in Frameworks */, - 87BB878C27A5803A000B269B /* CombineRequest in Frameworks */, - EB5C21592AB1A23E004F53C7 /* ComposableArchitecture in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -95,7 +74,6 @@ isa = PBXGroup; children = ( 879A265427079EC900CCD1DD /* Todo+Combine+SwiftUI.app */, - 879A265A27079EC900CCD1DD /* Todo+Combine+SwiftUI.app */, ); name = Products; sourceTree = ""; @@ -141,7 +119,6 @@ 87BB879927A581A8000B269B /* MainView.swift */, 87BB87A327A581A8000B269B /* AuthView.swift */, 87BB879E27A581A8000B269B /* CounterView.swift */, - 8714CD2F299CEA3A00F5B26C /* SplashView.swift */, ); path = Views; sourceTree = ""; @@ -174,33 +151,13 @@ 87BB878627A57FB4000B269B /* CombineRequest */, EB5C21562AB1A229004F53C7 /* ComposableArchitecture */, EB5C215C2AB1A250004F53C7 /* Transform */, + EBA4697A2ACE91440060376F /* Json */, + EBA4697D2ACE91E10060376F /* SwiftLogger */, ); productName = "Todo+Combine+SwiftUI (iOS)"; productReference = 879A265427079EC900CCD1DD /* Todo+Combine+SwiftUI.app */; productType = "com.apple.product-type.application"; }; - 879A265927079EC900CCD1DD /* Todo+Combine+SwiftUI (macOS) */ = { - isa = PBXNativeTarget; - buildConfigurationList = 879A266827079EC900CCD1DD /* Build configuration list for PBXNativeTarget "Todo+Combine+SwiftUI (macOS)" */; - buildPhases = ( - 879A265627079EC900CCD1DD /* Sources */, - 879A265727079EC900CCD1DD /* Frameworks */, - 879A265827079EC900CCD1DD /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Todo+Combine+SwiftUI (macOS)"; - packageProductDependencies = ( - 87BB878B27A5803A000B269B /* CombineRequest */, - EB5C21582AB1A23E004F53C7 /* ComposableArchitecture */, - EB5C215A2AB1A245004F53C7 /* Transform */, - ); - productName = "Todo+Combine+SwiftUI (macOS)"; - productReference = 879A265A27079EC900CCD1DD /* Todo+Combine+SwiftUI.app */; - productType = "com.apple.product-type.application"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -214,9 +171,6 @@ 879A265327079EC900CCD1DD = { CreatedOnToolsVersion = 13.0; }; - 879A265927079EC900CCD1DD = { - CreatedOnToolsVersion = 13.0; - }; }; }; buildConfigurationList = 879A264B27079EC800CCD1DD /* Build configuration list for PBXProject "Todo+Combine+SwiftUI" */; @@ -232,13 +186,14 @@ 87BB878527A57FB4000B269B /* XCRemoteSwiftPackageReference "Networking" */, 87BB878827A58015000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */, EB5C21552AB1A229004F53C7 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, + EBA469792ACE91440060376F /* XCRemoteSwiftPackageReference "swift-json" */, + EBA4697C2ACE915D0060376F /* XCRemoteSwiftPackageReference "swift-logger" */, ); productRefGroup = 879A265527079EC900CCD1DD /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 879A265327079EC900CCD1DD /* Todo+Combine+SwiftUI (iOS) */, - 879A265927079EC900CCD1DD /* Todo+Combine+SwiftUI (macOS) */, ); }; /* End PBXProject section */ @@ -252,14 +207,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 879A265827079EC900CCD1DD /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 879A266227079EC900CCD1DD /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -268,7 +215,6 @@ buildActionMask = 2147483647; files = ( 87BB87E627A581A8000B269B /* AuthView.swift in Sources */, - 8714CD30299CEA3A00F5B26C /* SplashView.swift in Sources */, 87BB880E27A581A8000B269B /* TodoModel.swift in Sources */, 87BB87D627A581A8000B269B /* MainView.swift in Sources */, 87BB880627A581A8000B269B /* RootView.swift in Sources */, @@ -278,21 +224,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 879A265627079EC900CCD1DD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 87BB87E727A581A8000B269B /* AuthView.swift in Sources */, - 8714CD31299CEA3A00F5B26C /* SplashView.swift in Sources */, - 87BB880F27A581A8000B269B /* TodoModel.swift in Sources */, - 87BB87D727A581A8000B269B /* MainView.swift in Sources */, - 87BB880727A581A8000B269B /* RootView.swift in Sources */, - 87BB87CF27A581A8000B269B /* TodoApp.swift in Sources */, - 87BB87DF27A581A8000B269B /* CounterView.swift in Sources */, - EB5C21602AB1A2A9004F53C7 /* Exports.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ @@ -480,66 +411,6 @@ }; name = Release; }; - 879A266927079EC900CCD1DD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = 2H5PN3F9B6; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "mike.fullstackswift.Todo-Combine-SwiftUI"; - PRODUCT_NAME = "Todo+Combine+SwiftUI"; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 879A266A27079EC900CCD1DD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = 2H5PN3F9B6; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "mike.fullstackswift.Todo-Combine-SwiftUI"; - PRODUCT_NAME = "Todo+Combine+SwiftUI"; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -561,15 +432,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 879A266827079EC900CCD1DD /* Build configuration list for PBXNativeTarget "Todo+Combine+SwiftUI (macOS)" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 879A266927079EC900CCD1DD /* Debug */, - 879A266A27079EC900CCD1DD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -597,6 +459,22 @@ kind = branch; }; }; + EBA469792ACE91440060376F /* XCRemoteSwiftPackageReference "swift-json" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-json"; + requirement = { + branch = main; + kind = branch; + }; + }; + EBA4697C2ACE915D0060376F /* XCRemoteSwiftPackageReference "swift-logger" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-logger"; + requirement = { + branch = main; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -605,30 +483,25 @@ package = 87BB878527A57FB4000B269B /* XCRemoteSwiftPackageReference "Networking" */; productName = CombineRequest; }; - 87BB878B27A5803A000B269B /* CombineRequest */ = { - isa = XCSwiftPackageProductDependency; - package = 87BB878527A57FB4000B269B /* XCRemoteSwiftPackageReference "Networking" */; - productName = CombineRequest; - }; EB5C21562AB1A229004F53C7 /* ComposableArchitecture */ = { isa = XCSwiftPackageProductDependency; package = EB5C21552AB1A229004F53C7 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; productName = ComposableArchitecture; }; - EB5C21582AB1A23E004F53C7 /* ComposableArchitecture */ = { - isa = XCSwiftPackageProductDependency; - package = EB5C21552AB1A229004F53C7 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; - productName = ComposableArchitecture; - }; - EB5C215A2AB1A245004F53C7 /* Transform */ = { + EB5C215C2AB1A250004F53C7 /* Transform */ = { isa = XCSwiftPackageProductDependency; package = 87BB878827A58015000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; productName = Transform; }; - EB5C215C2AB1A250004F53C7 /* Transform */ = { + EBA4697A2ACE91440060376F /* Json */ = { isa = XCSwiftPackageProductDependency; - package = 87BB878827A58015000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; - productName = Transform; + package = EBA469792ACE91440060376F /* XCRemoteSwiftPackageReference "swift-json" */; + productName = Json; + }; + EBA4697D2ACE91E10060376F /* SwiftLogger */ = { + isa = XCSwiftPackageProductDependency; + package = EBA4697C2ACE915D0060376F /* XCRemoteSwiftPackageReference "swift-logger" */; + productName = SwiftLogger; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 82e3fb9..e49fefd 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,7 +24,7 @@ "location" : "https://github.com/FullStack-Swift/Networking", "state" : { "branch" : "main", - "revision" : "481eac1d78c7c8d8111788b4fdccc27ceabe5138" + "revision" : "23e446cfffd8a5f554fd564fc7568eeaa85843e4" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ReactiveCocoa/ReactiveSwift.git", "state" : { - "revision" : "efb2f0a6f6c8739cce8fb14148a5bd3c83f2f91d", - "version" : "7.0.0" + "revision" : "40c465af19b993344e84355c00669ba2022ca3cd", + "version" : "7.1.1" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ReactiveX/RxSwift.git", "state" : { - "revision" : "b4307ba0b6425c0ba4178e138799946c3da594f8", - "version" : "6.5.0" + "revision" : "9dcaa4b333db437b0fbfaf453fad29069044a8b4", + "version" : "6.6.0" } }, { @@ -50,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/socketio/socket.io-client-swift", "state" : { - "revision" : "af5ce97b755d964235348d96f6db5cbdcbe334a5", - "version" : "16.0.1" + "revision" : "175da8b5156f6b132436f0676cc84c2f6a766b6e", + "version" : "16.1.0" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/daltoniam/Starscream.git", "state" : { - "revision" : "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version" : "4.0.4" + "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", + "version" : "4.0.6" } }, { @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections", "state" : { - "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version" : "1.0.4" + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" } }, { @@ -96,7 +96,7 @@ "location" : "https://github.com/pointfreeco/swift-composable-architecture", "state" : { "branch" : "main", - "revision" : "667d92fad15e60b32a4c3e1289c9a15814798665" + "revision" : "2e0f5142c7bb4a6b053ab45f89c0db77d065da47" } }, { @@ -113,8 +113,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-custom-dump", "state" : { - "revision" : "edd66cace818e1b1c6f1b3349bb1d8e00d6f8b01", - "version" : "1.0.0" + "revision" : "3efbfba0e4e56c7187cc19137ee16b7c95346b79", + "version" : "1.1.0" } }, { @@ -135,6 +135,24 @@ "version" : "1.0.0" } }, + { + "identity" : "swift-json", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/swift-json", + "state" : { + "branch" : "main", + "revision" : "ac54806fd7e10587755ac5cfd802ae15ef6907d4" + } + }, + { + "identity" : "swift-logger", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/swift-logger", + "state" : { + "branch" : "main", + "revision" : "12fda88a83ce0c373381e6eaa5db1c27b4dc2eaa" + } + }, { "identity" : "swiftextension", "kind" : "remoteSourceControl", diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/xcshareddata/xcschemes/Todo+Combine+SwiftUI (iOS).xcscheme b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/xcshareddata/xcschemes/Todo+Combine+SwiftUI (iOS).xcscheme new file mode 100644 index 0000000..7753d81 --- /dev/null +++ b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Todo+Combine+SwiftUI.xcodeproj/xcshareddata/xcschemes/Todo+Combine+SwiftUI (iOS).xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/Exports.swift b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/Exports.swift index 755ef22..fc9a0d7 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/Exports.swift +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/Exports.swift @@ -1,3 +1,5 @@ @_exported import Transform @_exported import MReactiveSwiftRequest @_exported import ComposableArchitecture +@_exported import Json +@_exported import SwiftLogger diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp.swift b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp.swift index 1dfc65f..39c0012 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp.swift +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp.swift @@ -11,7 +11,7 @@ struct TodoApp: App { public extension DependencyValues { var urlString: String { - "http://127.0.0.1:8080" + "http://127.0.0.1:8080/todos" } } diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/AuthView.swift b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/AuthView.swift index 8fc2019..7690ff3 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/AuthView.swift +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/AuthView.swift @@ -1,4 +1,3 @@ -import ComposableArchitecture import SwiftUI struct Auth: Reducer { diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/MainView.swift b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/MainView.swift index 3ac56c3..0dd5d08 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/MainView.swift +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/MainView.swift @@ -5,7 +5,7 @@ struct Main: Reducer { // MARK: State struct State: Equatable { var counterState = Counter.State() - @BindingState var title: String = "" + @BindingState var text: String = "" var todos: IdentifiedArrayOf = [] var isLoading: Bool = false } @@ -62,13 +62,13 @@ struct Main: Reducer { case .logout: return .send(.changeRootScreen(.auth)) case .viewCreateTodo: - if state.title.isEmpty { + if state.text.isEmpty { return .none } - let title = state.title - state.title = "" + let text = state.text + state.text = "" let id = uuid() - let todo = TodoModel(id: id, title: title, isCompleted: false) + let todo = TodoModel(id: id, text: text, isCompleted: false) return .send(.createOrUpdateTodo(todo)) // MARK: - Networking /// GET TODO @@ -79,12 +79,13 @@ struct Main: Reducer { state.isLoading = true state.todos.removeAll() let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) RMethod(.get) } if isUsingPublisher { return .publisher { - request.producer + request + .producer .compactMap{$0.data} .map(Main.Action.responseTodo) .eraseToAnyPublisher() @@ -95,23 +96,29 @@ struct Main: Reducer { await send(.responseTodo(data)) } } - case .responseTodo(let json): - if let items = json.toModel([TodoModel].self) { + case .responseTodo(let data): + log.info(Json(data)) + state.isLoading = false + if let items = data.toModel([TodoModel].self) { for item in items { state.todos.updateOrAppend(item) } } /// CREATE OR UPDATE TODO case .createOrUpdateTodo(let todo): + log.info(todo.toJson()) let request = MRequest { - RUrl(urlString: urlString) - REncoding(JSONEncoding.default) + RUrl(urlString) RMethod(.post) Rbody(todo.toData()) + REncoding(JSONEncoding.default) + } if isUsingPublisher { return .publisher { - request.producer + request + .printCURLRequest() + .producer .compactMap{$0.data} .map(Main.Action.responseCreateOrUpdateTodo) .eraseToAnyPublisher() @@ -122,21 +129,25 @@ struct Main: Reducer { await send(.responseCreateOrUpdateTodo(data)) } } - case .responseCreateOrUpdateTodo(let json): - if let item = json.toModel(TodoModel.self) { + case .responseCreateOrUpdateTodo(let data): + log.info(Json(data)) + if let item = data.toModel(TodoModel.self) { state.todos.updateOrAppend(item) } /// UPDATE TODO case .updateTodo(let todo): let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) .withPath(todo.id.toString()) - RMethod(.post) Rbody(todo.toData()) + RMethod(.post) + REncoding(JSONEncoding.default) } if isUsingPublisher { return .publisher { - request.producer + request + .printCURLRequest() + .producer .compactMap{$0.data} .map(Main.Action.responseUpdateTodo) .eraseToAnyPublisher() @@ -147,20 +158,23 @@ struct Main: Reducer { await send(.responseUpdateTodo(data)) } } - case .responseUpdateTodo(let json): - if let item = json.toModel(TodoModel.self) { + case .responseUpdateTodo(let data): + log.info(data.toJson()) + if let item = data.toModel(TodoModel.self) { state.todos.updateOrAppend(item) } /// DELETE TODO case .deleteTodo(let todo): let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) .withPath(todo.id.toString()) RMethod(.delete) } if isUsingPublisher { return .publisher { - request.producer + request + .printCURLRequest() + .producer .compactMap{$0.data} .map(Main.Action.responseDeleteTodo) .eraseToAnyPublisher() @@ -201,38 +215,12 @@ struct MainView: View { var body: some View { ZStack { -#if os(macOS) - content - .toolbar { - ToolbarItem(placement: .status) { - HStack { - CounterView( - store: store - .scope( - state: \.counterState, - action: Main.Action.counterAction - ) - ) - Spacer() - Button(action: { - viewStore.send(.logout) - }, label: { - Text("Logout") - .foregroundColor(Color.blue) - }) - } - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity) -#endif -#if os(iOS) NavigationView { content .navigationTitle("Todos") .navigationBarItems(leading: leadingBarItems, trailing: trailingBarItems) } .navigationViewStyle(.stack) -#endif } .onAppear { viewStore.send(.viewOnAppear) @@ -243,47 +231,18 @@ struct MainView: View { } } - extension MainView { /// create content view in screen private var content: some View { List { - Section { - ZStack { - HStack { - Spacer() - if viewStore.isLoading { - ProgressView() - } else { - Text("Reload") - .bold() - .onTapGesture { - viewStore.send(.getTodo) - } - } - Spacer() - } - .frame(height: 60) - } - } - HStack { - TextField("title", text: viewStore.$title) - Button(action: { - viewStore.send(.viewCreateTodo) - }, label: { - Text("Create") - .bold() - .foregroundColor(viewStore.title.isEmpty ? Color.gray : Color.green) - }) - .disabled(viewStore.title.isEmpty) - } - + topview + inputview ForEach(viewStore.todos) { todo in HStack { HStack { Image(systemName: todo.isCompleted ? "checkmark.square" : "square") .frame(width: 40, height: 40, alignment: .center) - Text(todo.title) + Text(todo.text) .underline(todo.isCompleted, color: Color.black) Spacer() } @@ -291,19 +250,50 @@ extension MainView { .onTapGesture { viewStore.send(.toggleTodo(todo)) } - Button(action: { + Button { viewStore.send(.deleteTodo(todo)) - }, label: { + } label: { Text("Delete") .foregroundColor(Color.gray) - }) + } } } - .padding(.all, 0) } .padding(.all, 0) } + private var topview: some View { + Section { + ZStack(alignment: .center) { + if viewStore.isLoading { + ProgressView() + } else { + Text("Reload") + .bold() + .onTapGesture { + viewStore.send(.getTodo) + } + } + } + .frame(height: 60) + .frame(maxWidth: .infinity) + } + } + + private var inputview: some View { + HStack { + TextField("text", text: viewStore.$text) + Button(action: { + viewStore.send(.viewCreateTodo) + }, label: { + Text("Create") + .bold() + .foregroundColor(viewStore.text.isEmpty ? Color.gray : Color.green) + }) + .disabled(viewStore.text.isEmpty) + } + } + private var leadingBarItems: some View { CounterView( store: store diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift index f113757..1240ba8 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift @@ -2,6 +2,6 @@ import Foundation struct TodoModel: Codable, Identifiable, Equatable { var id: UUID - var title: String + var text: String var isCompleted: Bool } diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.pbxproj b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.pbxproj index 676becb..f0b3a5d 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.pbxproj +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.pbxproj @@ -8,33 +8,23 @@ /* Begin PBXBuildFile section */ 879A26CF2707A01A00CCD1DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 879A26BD2707A01A00CCD1DD /* Assets.xcassets */; }; - 879A26D02707A01A00CCD1DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 879A26BD2707A01A00CCD1DD /* Assets.xcassets */; }; 87BB883E27A588AE000B269B /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB882127A588AE000B269B /* TodoApp.swift */; }; - 87BB883F27A588AE000B269B /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB882127A588AE000B269B /* TodoApp.swift */; }; 87BB884627A588AE000B269B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB882827A588AE000B269B /* MainView.swift */; }; - 87BB884727A588AE000B269B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB882827A588AE000B269B /* MainView.swift */; }; 87BB884E27A588AE000B269B /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB882D27A588AE000B269B /* CounterView.swift */; }; - 87BB884F27A588AE000B269B /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB882D27A588AE000B269B /* CounterView.swift */; }; 87BB885627A588AE000B269B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB883227A588AE000B269B /* AuthView.swift */; }; - 87BB885727A588AE000B269B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB883227A588AE000B269B /* AuthView.swift */; }; 87BB886227A588AE000B269B /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB883927A588AE000B269B /* RootView.swift */; }; - 87BB886327A588AE000B269B /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB883927A588AE000B269B /* RootView.swift */; }; 87BB886827A588AE000B269B /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB883D27A588AE000B269B /* TodoModel.swift */; }; - 87BB886927A588AE000B269B /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB883D27A588AE000B269B /* TodoModel.swift */; }; 87BB886C27A58910000B269B /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB886B27A58910000B269B /* ComposableArchitecture */; }; - 87BB887427A58A30000B269B /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB887327A58A30000B269B /* ComposableArchitecture */; }; EB5C216D2AB1AFDB004F53C7 /* ReactiveSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C216C2AB1AFDB004F53C7 /* ReactiveSwiftRequest */; }; EB5C216F2AB1AFDB004F53C7 /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C216E2AB1AFDB004F53C7 /* Transform */; }; - EB5C21712AB1AFE5004F53C7 /* ReactiveSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21702AB1AFE5004F53C7 /* ReactiveSwiftRequest */; }; - EB5C21732AB1AFE5004F53C7 /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21722AB1AFE5004F53C7 /* Transform */; }; EB5C21752AB1B05A004F53C7 /* Exports.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C21742AB1B05A004F53C7 /* Exports.swift */; }; - EB5C21762AB1B05A004F53C7 /* Exports.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C21742AB1B05A004F53C7 /* Exports.swift */; }; + EBA469882ACEC1420060376F /* Json in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469872ACEC1420060376F /* Json */; }; + EBA4698A2ACEC1420060376F /* SwiftLogger in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469892ACEC1420060376F /* SwiftLogger */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 879A26BD2707A01A00CCD1DD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 879A26C22707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+ReactiveSwift+SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 879A26C82707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+ReactiveSwift+SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 879A26CA2707A01A00CCD1DD /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 87BB882127A588AE000B269B /* TodoApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoApp.swift; sourceTree = ""; }; 87BB882827A588AE000B269B /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -52,20 +42,12 @@ files = ( EB5C216F2AB1AFDB004F53C7 /* Transform in Frameworks */, 87BB886C27A58910000B269B /* ComposableArchitecture in Frameworks */, + EBA4698A2ACEC1420060376F /* SwiftLogger in Frameworks */, + EBA469882ACEC1420060376F /* Json in Frameworks */, EB5C216D2AB1AFDB004F53C7 /* ReactiveSwiftRequest in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 879A26C52707A01A00CCD1DD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EB5C21732AB1AFE5004F53C7 /* Transform in Frameworks */, - 87BB887427A58A30000B269B /* ComposableArchitecture in Frameworks */, - EB5C21712AB1AFE5004F53C7 /* ReactiveSwiftRequest in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -92,7 +74,6 @@ isa = PBXGroup; children = ( 879A26C22707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI.app */, - 879A26C82707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI.app */, ); name = Products; sourceTree = ""; @@ -125,10 +106,10 @@ 87BB882227A588AE000B269B /* TodoApp */ = { isa = PBXGroup; children = ( + 87BB883927A588AE000B269B /* RootView.swift */, 87BB882827A588AE000B269B /* MainView.swift */, - 87BB882D27A588AE000B269B /* CounterView.swift */, 87BB883227A588AE000B269B /* AuthView.swift */, - 87BB883927A588AE000B269B /* RootView.swift */, + 87BB882D27A588AE000B269B /* CounterView.swift */, 87BB883C27A588AE000B269B /* Models */, ); path = TodoApp; @@ -162,33 +143,13 @@ 87BB886B27A58910000B269B /* ComposableArchitecture */, EB5C216C2AB1AFDB004F53C7 /* ReactiveSwiftRequest */, EB5C216E2AB1AFDB004F53C7 /* Transform */, + EBA469872ACEC1420060376F /* Json */, + EBA469892ACEC1420060376F /* SwiftLogger */, ); productName = "Todo+ReactiveSwift+SwiftUI (iOS)"; productReference = 879A26C22707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI.app */; productType = "com.apple.product-type.application"; }; - 879A26C72707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI (macOS) */ = { - isa = PBXNativeTarget; - buildConfigurationList = 879A26D62707A01A00CCD1DD /* Build configuration list for PBXNativeTarget "Todo+ReactiveSwift+SwiftUI (macOS)" */; - buildPhases = ( - 879A26C42707A01A00CCD1DD /* Sources */, - 879A26C52707A01A00CCD1DD /* Frameworks */, - 879A26C62707A01A00CCD1DD /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Todo+ReactiveSwift+SwiftUI (macOS)"; - packageProductDependencies = ( - 87BB887327A58A30000B269B /* ComposableArchitecture */, - EB5C21702AB1AFE5004F53C7 /* ReactiveSwiftRequest */, - EB5C21722AB1AFE5004F53C7 /* Transform */, - ); - productName = "Todo+ReactiveSwift+SwiftUI (macOS)"; - productReference = 879A26C82707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI.app */; - productType = "com.apple.product-type.application"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -197,14 +158,11 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1300; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1500; TargetAttributes = { 879A26C12707A01A00CCD1DD = { CreatedOnToolsVersion = 13.0; }; - 879A26C72707A01A00CCD1DD = { - CreatedOnToolsVersion = 13.0; - }; }; }; buildConfigurationList = 879A26B92707A01700CCD1DD /* Build configuration list for PBXProject "Todo+ReactiveSwift+SwiftUI" */; @@ -220,13 +178,14 @@ 87BB886A27A58910000B269B /* XCRemoteSwiftPackageReference "reactiveswift-composable-architecture" */, 87BB886D27A5892E000B269B /* XCRemoteSwiftPackageReference "Networking" */, 87BB887027A5894B000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */, + EBA469852ACEC0D80060376F /* XCRemoteSwiftPackageReference "swift-json" */, + EBA469862ACEC0EE0060376F /* XCRemoteSwiftPackageReference "swift-logger" */, ); productRefGroup = 879A26C32707A01A00CCD1DD /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 879A26C12707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI (iOS) */, - 879A26C72707A01A00CCD1DD /* Todo+ReactiveSwift+SwiftUI (macOS) */, ); }; /* End PBXProject section */ @@ -240,14 +199,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 879A26C62707A01A00CCD1DD /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 879A26D02707A01A00CCD1DD /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -265,20 +216,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 879A26C42707A01A00CCD1DD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EB5C21762AB1B05A004F53C7 /* Exports.swift in Sources */, - 87BB886927A588AE000B269B /* TodoModel.swift in Sources */, - 87BB886327A588AE000B269B /* RootView.swift in Sources */, - 87BB885727A588AE000B269B /* AuthView.swift in Sources */, - 87BB883F27A588AE000B269B /* TodoApp.swift in Sources */, - 87BB884727A588AE000B269B /* MainView.swift in Sources */, - 87BB884F27A588AE000B269B /* CounterView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ @@ -286,6 +223,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -316,9 +254,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -345,6 +285,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -375,9 +316,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -454,64 +397,6 @@ }; name = Release; }; - 879A26D72707A01A00CCD1DD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 2H5PN3F9B6; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "mike.fullstackswift.Todo-ReactiveSwift-SwiftUI"; - PRODUCT_NAME = "Todo+ReactiveSwift+SwiftUI"; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 879A26D82707A01A00CCD1DD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 2H5PN3F9B6; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "mike.fullstackswift.Todo-ReactiveSwift-SwiftUI"; - PRODUCT_NAME = "Todo+ReactiveSwift+SwiftUI"; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -533,15 +418,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 879A26D62707A01A00CCD1DD /* Build configuration list for PBXNativeTarget "Todo+ReactiveSwift+SwiftUI (macOS)" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 879A26D72707A01A00CCD1DD /* Debug */, - 879A26D82707A01A00CCD1DD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -569,6 +445,22 @@ kind = branch; }; }; + EBA469852ACEC0D80060376F /* XCRemoteSwiftPackageReference "swift-json" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-json"; + requirement = { + branch = main; + kind = branch; + }; + }; + EBA469862ACEC0EE0060376F /* XCRemoteSwiftPackageReference "swift-logger" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-logger"; + requirement = { + branch = main; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -577,11 +469,6 @@ package = 87BB886A27A58910000B269B /* XCRemoteSwiftPackageReference "reactiveswift-composable-architecture" */; productName = ComposableArchitecture; }; - 87BB887327A58A30000B269B /* ComposableArchitecture */ = { - isa = XCSwiftPackageProductDependency; - package = 87BB886A27A58910000B269B /* XCRemoteSwiftPackageReference "reactiveswift-composable-architecture" */; - productName = ComposableArchitecture; - }; EB5C216C2AB1AFDB004F53C7 /* ReactiveSwiftRequest */ = { isa = XCSwiftPackageProductDependency; package = 87BB886D27A5892E000B269B /* XCRemoteSwiftPackageReference "Networking" */; @@ -592,15 +479,15 @@ package = 87BB887027A5894B000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; productName = Transform; }; - EB5C21702AB1AFE5004F53C7 /* ReactiveSwiftRequest */ = { + EBA469872ACEC1420060376F /* Json */ = { isa = XCSwiftPackageProductDependency; - package = 87BB886D27A5892E000B269B /* XCRemoteSwiftPackageReference "Networking" */; - productName = ReactiveSwiftRequest; + package = EBA469852ACEC0D80060376F /* XCRemoteSwiftPackageReference "swift-json" */; + productName = Json; }; - EB5C21722AB1AFE5004F53C7 /* Transform */ = { + EBA469892ACEC1420060376F /* SwiftLogger */ = { isa = XCSwiftPackageProductDependency; - package = 87BB887027A5894B000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; - productName = Transform; + package = EBA469862ACEC0EE0060376F /* XCRemoteSwiftPackageReference "swift-logger" */; + productName = SwiftLogger; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e24f967..a75eedd 100644 --- a/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/SwiftUI/Todo+ReactiveSwift+SwiftUI/Todo+ReactiveSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,7 +24,7 @@ "location" : "https://github.com/FullStack-Swift/Networking", "state" : { "branch" : "main", - "revision" : "481eac1d78c7c8d8111788b4fdccc27ceabe5138" + "revision" : "23e446cfffd8a5f554fd564fc7568eeaa85843e4" } }, { @@ -42,7 +42,7 @@ "location" : "https://github.com/FullStack-Swift/reactiveswift-composable-architecture", "state" : { "branch" : "main", - "revision" : "7eca2b9c5a361550cde14a00ac2e5ff3a41f4316" + "revision" : "f0463f0b8cde504d625f755ce61dd70cbb76d61c" } }, { @@ -104,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections", "state" : { - "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version" : "1.0.4" + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" } }, { @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-custom-dump", "state" : { - "revision" : "edd66cace818e1b1c6f1b3349bb1d8e00d6f8b01", - "version" : "1.0.0" + "revision" : "3efbfba0e4e56c7187cc19137ee16b7c95346b79", + "version" : "1.1.0" } }, { @@ -144,6 +144,24 @@ "version" : "1.0.0" } }, + { + "identity" : "swift-json", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/swift-json", + "state" : { + "branch" : "main", + "revision" : "ac54806fd7e10587755ac5cfd802ae15ef6907d4" + } + }, + { + "identity" : "swift-logger", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/swift-logger", + "state" : { + "branch" : "main", + "revision" : "12fda88a83ce0c373381e6eaa5db1c27b4dc2eaa" + } + }, { "identity" : "swiftextension", "kind" : "remoteSourceControl", diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/Exports.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/Exports.swift index a392464..74aefe4 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/Exports.swift +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/Exports.swift @@ -1,3 +1,5 @@ @_exported import Transform @_exported import MRxSwiftRequest @_exported import ComposableArchitecture +@_exported import Json +@_exported import SwiftLogger diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp.swift index 1dfc65f..96dde50 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp.swift +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp.swift @@ -1,5 +1,6 @@ import SwiftUI + @main struct TodoApp: App { var body: some Scene { @@ -11,7 +12,7 @@ struct TodoApp: App { public extension DependencyValues { var urlString: String { - "http://127.0.0.1:8080" + "http://127.0.0.1:8080/todos" } } diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift index f113757..1240ba8 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift @@ -2,6 +2,6 @@ import Foundation struct TodoModel: Codable, Identifiable, Equatable { var id: UUID - var title: String + var text: String var isCompleted: Bool } diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/AuthView.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/AuthView.swift similarity index 100% rename from BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/AuthView.swift rename to BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/AuthView.swift diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/CounterView.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/CounterView.swift similarity index 100% rename from BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/CounterView.swift rename to BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/CounterView.swift diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/MainView.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/MainView.swift similarity index 76% rename from BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/MainView.swift rename to BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/MainView.swift index b4e99d4..88cf7df 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/MainView.swift +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/MainView.swift @@ -5,7 +5,7 @@ struct Main: Reducer { // MARK: State struct State: Equatable { var counterState = Counter.State() - @BindingState var title: String = "" + @BindingState var text: String = "" var todos: IdentifiedArrayOf = [] var isLoading: Bool = false } @@ -62,13 +62,13 @@ struct Main: Reducer { case .logout: return .send(.changeRootScreen(.auth)) case .viewCreateTodo: - if state.title.isEmpty { + if state.text.isEmpty { return .none } - let title = state.title - state.title = "" + let text = state.text + state.text = "" let id = uuid() - let todo = TodoModel(id: id, title: title, isCompleted: false) + let todo = TodoModel(id: id, text: text, isCompleted: false) return .send(.createOrUpdateTodo(todo)) // MARK: - Networking /// GET TODO @@ -79,7 +79,7 @@ struct Main: Reducer { state.isLoading = true state.todos.removeAll() let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) RMethod(.get) } if isUsingPublisher { @@ -95,23 +95,28 @@ struct Main: Reducer { await send(.responseTodo(data)) } } - case .responseTodo(let json): - if let items = json.toModel([TodoModel].self) { + case .responseTodo(let data): + log.info(Json(data)) + state.isLoading = false + if let items = data.toModel([TodoModel].self) { for item in items { state.todos.updateOrAppend(item) } } /// CREATE OR UPDATE TODO case .createOrUpdateTodo(let todo): + log.info(todo.toJson()) let request = MRequest { - RUrl(urlString: urlString) - REncoding(JSONEncoding.default) + RUrl(urlString) RMethod(.post) Rbody(todo.toData()) + REncoding(JSONEncoding.default) + } if isUsingPublisher { return .publisher { request + .printCURLRequest() .compactMap{$0.data} .map(Main.Action.responseCreateOrUpdateTodo) .eraseToAnyPublisher() @@ -122,21 +127,24 @@ struct Main: Reducer { await send(.responseCreateOrUpdateTodo(data)) } } - case .responseCreateOrUpdateTodo(let json): - if let item = json.toModel(TodoModel.self) { + case .responseCreateOrUpdateTodo(let data): + log.info(Json(data)) + if let item = data.toModel(TodoModel.self) { state.todos.updateOrAppend(item) } /// UPDATE TODO case .updateTodo(let todo): let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) .withPath(todo.id.toString()) - RMethod(.post) Rbody(todo.toData()) + RMethod(.post) + REncoding(JSONEncoding.default) } if isUsingPublisher { return .publisher { request + .printCURLRequest() .compactMap{$0.data} .map(Main.Action.responseUpdateTodo) .eraseToAnyPublisher() @@ -147,14 +155,15 @@ struct Main: Reducer { await send(.responseUpdateTodo(data)) } } - case .responseUpdateTodo(let json): - if let item = json.toModel(TodoModel.self) { + case .responseUpdateTodo(let data): + log.info(data.toJson()) + if let item = data.toModel(TodoModel.self) { state.todos.updateOrAppend(item) } /// DELETE TODO case .deleteTodo(let todo): let request = MRequest { - RUrl(urlString: urlString) + RUrl(urlString) .withPath(todo.id.toString()) RMethod(.delete) } @@ -201,38 +210,12 @@ struct MainView: View { var body: some View { ZStack { -#if os(macOS) - content - .toolbar { - ToolbarItem(placement: .status) { - HStack { - CounterView( - store: store - .scope( - state: \.counterState, - action: Main.Action.counterAction - ) - ) - Spacer() - Button(action: { - viewStore.send(.logout) - }, label: { - Text("Logout") - .foregroundColor(Color.blue) - }) - } - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity) -#endif -#if os(iOS) NavigationView { content .navigationTitle("Todos") .navigationBarItems(leading: leadingBarItems, trailing: trailingBarItems) } .navigationViewStyle(.stack) -#endif } .onAppear { viewStore.send(.viewOnAppear) @@ -243,47 +226,18 @@ struct MainView: View { } } - extension MainView { /// create content view in screen private var content: some View { List { - Section { - ZStack { - HStack { - Spacer() - if viewStore.isLoading { - ProgressView() - } else { - Text("Reload") - .bold() - .onTapGesture { - viewStore.send(.getTodo) - } - } - Spacer() - } - .frame(height: 60) - } - } - HStack { - TextField("title", text: viewStore.$title) - Button(action: { - viewStore.send(.viewCreateTodo) - }, label: { - Text("Create") - .bold() - .foregroundColor(viewStore.title.isEmpty ? Color.gray : Color.green) - }) - .disabled(viewStore.title.isEmpty) - } - + topview + inputview ForEach(viewStore.todos) { todo in HStack { HStack { Image(systemName: todo.isCompleted ? "checkmark.square" : "square") .frame(width: 40, height: 40, alignment: .center) - Text(todo.title) + Text(todo.text) .underline(todo.isCompleted, color: Color.black) Spacer() } @@ -291,19 +245,50 @@ extension MainView { .onTapGesture { viewStore.send(.toggleTodo(todo)) } - Button(action: { + Button { viewStore.send(.deleteTodo(todo)) - }, label: { + } label: { Text("Delete") .foregroundColor(Color.gray) - }) + } } } - .padding(.all, 0) } .padding(.all, 0) } + private var topview: some View { + Section { + ZStack(alignment: .center) { + if viewStore.isLoading { + ProgressView() + } else { + Text("Reload") + .bold() + .onTapGesture { + viewStore.send(.getTodo) + } + } + } + .frame(height: 60) + .frame(maxWidth: .infinity) + } + } + + private var inputview: some View { + HStack { + TextField("text", text: viewStore.$text) + Button(action: { + viewStore.send(.viewCreateTodo) + }, label: { + Text("Create") + .bold() + .foregroundColor(viewStore.text.isEmpty ? Color.gray : Color.green) + }) + .disabled(viewStore.text.isEmpty) + } + } + private var leadingBarItems: some View { CounterView( store: store diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/RootView.swift b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift similarity index 92% rename from BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/RootView.swift rename to BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift index 6ef777f..9f8067a 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/AppScreens/RootView.swift +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Shared/CoreApp/TodoApp/Views/RootView.swift @@ -1,4 +1,3 @@ -import ComposableArchitecture import SwiftUI struct Root: Reducer { @@ -55,8 +54,6 @@ struct Root: Reducer { } } - - struct RootView: View { private let store: StoreOf @@ -99,9 +96,6 @@ struct RootView: View { .onDisappear { viewStore.send(.viewOnDisappear) } -#if os(macOS) - .frame(minWidth: 700, idealWidth: 700, maxWidth: .infinity, minHeight: 500, idealHeight: 500, maxHeight: .infinity, alignment: .center) -#endif } } diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.pbxproj b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.pbxproj index a14bf1c..9f8c768 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.pbxproj +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.pbxproj @@ -8,33 +8,23 @@ /* Begin PBXBuildFile section */ 879A25F127079C3600CCD1DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 879A25DF27079C3600CCD1DD /* Assets.xcassets */; }; - 879A25F227079C3600CCD1DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 879A25DF27079C3600CCD1DD /* Assets.xcassets */; }; 87BB887B27A58AB1000B269B /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB887A27A58AB1000B269B /* ComposableArchitecture */; }; 87BB889D27A58B0B000B269B /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB888027A58B0B000B269B /* TodoApp.swift */; }; - 87BB889E27A58B0B000B269B /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB888027A58B0B000B269B /* TodoApp.swift */; }; 87BB88A527A58B0B000B269B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB888727A58B0B000B269B /* MainView.swift */; }; - 87BB88A627A58B0B000B269B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB888727A58B0B000B269B /* MainView.swift */; }; 87BB88AD27A58B0B000B269B /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB888C27A58B0B000B269B /* CounterView.swift */; }; - 87BB88AE27A58B0B000B269B /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB888C27A58B0B000B269B /* CounterView.swift */; }; 87BB88B527A58B0B000B269B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB889127A58B0B000B269B /* AuthView.swift */; }; - 87BB88B627A58B0B000B269B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB889127A58B0B000B269B /* AuthView.swift */; }; 87BB88C127A58B0B000B269B /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB889827A58B0B000B269B /* RootView.swift */; }; - 87BB88C227A58B0B000B269B /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB889827A58B0B000B269B /* RootView.swift */; }; 87BB88C727A58B0B000B269B /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB889C27A58B0B000B269B /* TodoModel.swift */; }; - 87BB88C827A58B0B000B269B /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BB889C27A58B0B000B269B /* TodoModel.swift */; }; - 87BB88CD27A58B40000B269B /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB88CC27A58B40000B269B /* ComposableArchitecture */; }; - EB5C21622AB1AE74004F53C7 /* RxSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21612AB1AE74004F53C7 /* RxSwiftRequest */; }; - EB5C21642AB1AE74004F53C7 /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21632AB1AE74004F53C7 /* Transform */; }; EB5C21662AB1AE82004F53C7 /* RxSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21652AB1AE82004F53C7 /* RxSwiftRequest */; }; EB5C21682AB1AE82004F53C7 /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EB5C21672AB1AE82004F53C7 /* Transform */; }; EB5C216A2AB1AEA7004F53C7 /* Exports.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C21692AB1AEA7004F53C7 /* Exports.swift */; }; - EB5C216B2AB1AEA7004F53C7 /* Exports.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C21692AB1AEA7004F53C7 /* Exports.swift */; }; + EBA469812ACEA45F0060376F /* SwiftLogger in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469802ACEA45F0060376F /* SwiftLogger */; }; + EBA469842ACEA8800060376F /* Json in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469832ACEA8800060376F /* Json */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 879A25DF27079C3600CCD1DD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 879A25E427079C3600CCD1DD /* Todo+RxSwift+SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+RxSwift+SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 879A25EA27079C3600CCD1DD /* Todo+RxSwift+SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+RxSwift+SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 879A25EC27079C3600CCD1DD /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 87BB888027A58B0B000B269B /* TodoApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoApp.swift; sourceTree = ""; }; 87BB888727A58B0B000B269B /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -50,22 +40,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EBA469812ACEA45F0060376F /* SwiftLogger in Frameworks */, EB5C21682AB1AE82004F53C7 /* Transform in Frameworks */, EB5C21662AB1AE82004F53C7 /* RxSwiftRequest in Frameworks */, + EBA469842ACEA8800060376F /* Json in Frameworks */, 87BB887B27A58AB1000B269B /* ComposableArchitecture in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 879A25E727079C3600CCD1DD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EB5C21642AB1AE74004F53C7 /* Transform in Frameworks */, - EB5C21622AB1AE74004F53C7 /* RxSwiftRequest in Frameworks */, - 87BB88CD27A58B40000B269B /* ComposableArchitecture in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -92,7 +74,6 @@ isa = PBXGroup; children = ( 879A25E427079C3600CCD1DD /* Todo+RxSwift+SwiftUI.app */, - 879A25EA27079C3600CCD1DD /* Todo+RxSwift+SwiftUI.app */, ); name = Products; sourceTree = ""; @@ -125,21 +106,21 @@ 87BB888127A58B0B000B269B /* TodoApp */ = { isa = PBXGroup; children = ( - 87BB888227A58B0B000B269B /* AppScreens */, + 87BB888227A58B0B000B269B /* Views */, 87BB889B27A58B0B000B269B /* Models */, ); path = TodoApp; sourceTree = ""; }; - 87BB888227A58B0B000B269B /* AppScreens */ = { + 87BB888227A58B0B000B269B /* Views */ = { isa = PBXGroup; children = ( + 87BB889827A58B0B000B269B /* RootView.swift */, 87BB888727A58B0B000B269B /* MainView.swift */, - 87BB888C27A58B0B000B269B /* CounterView.swift */, 87BB889127A58B0B000B269B /* AuthView.swift */, - 87BB889827A58B0B000B269B /* RootView.swift */, + 87BB888C27A58B0B000B269B /* CounterView.swift */, ); - path = AppScreens; + path = Views; sourceTree = ""; }; 87BB889B27A58B0B000B269B /* Models */ = { @@ -170,33 +151,13 @@ 87BB887A27A58AB1000B269B /* ComposableArchitecture */, EB5C21652AB1AE82004F53C7 /* RxSwiftRequest */, EB5C21672AB1AE82004F53C7 /* Transform */, + EBA469802ACEA45F0060376F /* SwiftLogger */, + EBA469832ACEA8800060376F /* Json */, ); productName = "Todo+RxSwift+SwiftUI (iOS)"; productReference = 879A25E427079C3600CCD1DD /* Todo+RxSwift+SwiftUI.app */; productType = "com.apple.product-type.application"; }; - 879A25E927079C3600CCD1DD /* Todo+RxSwift+SwiftUI (macOS) */ = { - isa = PBXNativeTarget; - buildConfigurationList = 879A25F827079C3600CCD1DD /* Build configuration list for PBXNativeTarget "Todo+RxSwift+SwiftUI (macOS)" */; - buildPhases = ( - 879A25E627079C3600CCD1DD /* Sources */, - 879A25E727079C3600CCD1DD /* Frameworks */, - 879A25E827079C3600CCD1DD /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Todo+RxSwift+SwiftUI (macOS)"; - packageProductDependencies = ( - 87BB88CC27A58B40000B269B /* ComposableArchitecture */, - EB5C21612AB1AE74004F53C7 /* RxSwiftRequest */, - EB5C21632AB1AE74004F53C7 /* Transform */, - ); - productName = "Todo+RxSwift+SwiftUI (macOS)"; - productReference = 879A25EA27079C3600CCD1DD /* Todo+RxSwift+SwiftUI.app */; - productType = "com.apple.product-type.application"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -210,9 +171,6 @@ 879A25E327079C3600CCD1DD = { CreatedOnToolsVersion = 13.0; }; - 879A25E927079C3600CCD1DD = { - CreatedOnToolsVersion = 13.0; - }; }; }; buildConfigurationList = 879A25DB27079C3500CCD1DD /* Build configuration list for PBXProject "Todo+RxSwift+SwiftUI" */; @@ -228,13 +186,14 @@ 87BB887927A58AB1000B269B /* XCRemoteSwiftPackageReference "rxswift-composable-architecture" */, 87BB887C27A58AE7000B269B /* XCRemoteSwiftPackageReference "Networking" */, 87BB88C927A58B31000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */, + EBA4697F2ACEA45F0060376F /* XCRemoteSwiftPackageReference "swift-logger" */, + EBA469822ACEA8800060376F /* XCRemoteSwiftPackageReference "swift-json" */, ); productRefGroup = 879A25E527079C3600CCD1DD /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 879A25E327079C3600CCD1DD /* Todo+RxSwift+SwiftUI (iOS) */, - 879A25E927079C3600CCD1DD /* Todo+RxSwift+SwiftUI (macOS) */, ); }; /* End PBXProject section */ @@ -248,14 +207,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 879A25E827079C3600CCD1DD /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 879A25F227079C3600CCD1DD /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -273,20 +224,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 879A25E627079C3600CCD1DD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 87BB88C827A58B0B000B269B /* TodoModel.swift in Sources */, - 87BB88C227A58B0B000B269B /* RootView.swift in Sources */, - 87BB88B627A58B0B000B269B /* AuthView.swift in Sources */, - 87BB889E27A58B0B000B269B /* TodoApp.swift in Sources */, - 87BB88A627A58B0B000B269B /* MainView.swift in Sources */, - EB5C216B2AB1AEA7004F53C7 /* Exports.swift in Sources */, - 87BB88AE27A58B0B000B269B /* CounterView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ @@ -462,64 +399,6 @@ }; name = Release; }; - 879A25F927079C3600CCD1DD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 2H5PN3F9B6; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "mike.fullstackswift.Todo-RxSwift-SwiftUI"; - PRODUCT_NAME = "Todo+RxSwift+SwiftUI"; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 879A25FA27079C3600CCD1DD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 2H5PN3F9B6; - ENABLE_HARDENED_RUNTIME = YES; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "mike.fullstackswift.Todo-RxSwift-SwiftUI"; - PRODUCT_NAME = "Todo+RxSwift+SwiftUI"; - SDKROOT = macosx; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -541,15 +420,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 879A25F827079C3600CCD1DD /* Build configuration list for PBXNativeTarget "Todo+RxSwift+SwiftUI (macOS)" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 879A25F927079C3600CCD1DD /* Debug */, - 879A25FA27079C3600CCD1DD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -577,6 +447,22 @@ kind = branch; }; }; + EBA4697F2ACEA45F0060376F /* XCRemoteSwiftPackageReference "swift-logger" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-logger"; + requirement = { + branch = main; + kind = branch; + }; + }; + EBA469822ACEA8800060376F /* XCRemoteSwiftPackageReference "swift-json" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-json"; + requirement = { + branch = main; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -585,30 +471,25 @@ package = 87BB887927A58AB1000B269B /* XCRemoteSwiftPackageReference "rxswift-composable-architecture" */; productName = ComposableArchitecture; }; - 87BB88CC27A58B40000B269B /* ComposableArchitecture */ = { - isa = XCSwiftPackageProductDependency; - package = 87BB887927A58AB1000B269B /* XCRemoteSwiftPackageReference "rxswift-composable-architecture" */; - productName = ComposableArchitecture; - }; - EB5C21612AB1AE74004F53C7 /* RxSwiftRequest */ = { + EB5C21652AB1AE82004F53C7 /* RxSwiftRequest */ = { isa = XCSwiftPackageProductDependency; package = 87BB887C27A58AE7000B269B /* XCRemoteSwiftPackageReference "Networking" */; productName = RxSwiftRequest; }; - EB5C21632AB1AE74004F53C7 /* Transform */ = { + EB5C21672AB1AE82004F53C7 /* Transform */ = { isa = XCSwiftPackageProductDependency; package = 87BB88C927A58B31000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; productName = Transform; }; - EB5C21652AB1AE82004F53C7 /* RxSwiftRequest */ = { + EBA469802ACEA45F0060376F /* SwiftLogger */ = { isa = XCSwiftPackageProductDependency; - package = 87BB887C27A58AE7000B269B /* XCRemoteSwiftPackageReference "Networking" */; - productName = RxSwiftRequest; + package = EBA4697F2ACEA45F0060376F /* XCRemoteSwiftPackageReference "swift-logger" */; + productName = SwiftLogger; }; - EB5C21672AB1AE82004F53C7 /* Transform */ = { + EBA469832ACEA8800060376F /* Json */ = { isa = XCSwiftPackageProductDependency; - package = 87BB88C927A58B31000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; - productName = Transform; + package = EBA469822ACEA8800060376F /* XCRemoteSwiftPackageReference "swift-json" */; + productName = Json; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ed7b985..adf59ee 100644 --- a/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/SwiftUI/Todo+RxSwift+SwiftUI/Todo+RxSwift+SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,7 +24,7 @@ "location" : "https://github.com/FullStack-Swift/Networking", "state" : { "branch" : "main", - "revision" : "481eac1d78c7c8d8111788b4fdccc27ceabe5138" + "revision" : "23e446cfffd8a5f554fd564fc7568eeaa85843e4" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ReactiveCocoa/ReactiveSwift.git", "state" : { - "revision" : "efb2f0a6f6c8739cce8fb14148a5bd3c83f2f91d", - "version" : "7.0.0" + "revision" : "40c465af19b993344e84355c00669ba2022ca3cd", + "version" : "7.1.1" } }, { @@ -51,7 +51,7 @@ "location" : "https://github.com/FullStack-Swift/rxswift-composable-architecture", "state" : { "branch" : "main", - "revision" : "66960c573c70ae1ebf52772db8e2d7c85231d326" + "revision" : "61fe1aba2012b6a35c9cce6fc7924767873a231b" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/socketio/socket.io-client-swift", "state" : { - "revision" : "af5ce97b755d964235348d96f6db5cbdcbe334a5", - "version" : "16.0.1" + "revision" : "175da8b5156f6b132436f0676cc84c2f6a766b6e", + "version" : "16.1.0" } }, { @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/daltoniam/Starscream.git", "state" : { - "revision" : "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version" : "4.0.4" + "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", + "version" : "4.0.6" } }, { @@ -104,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections", "state" : { - "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version" : "1.0.4" + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" } }, { @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-custom-dump", "state" : { - "revision" : "edd66cace818e1b1c6f1b3349bb1d8e00d6f8b01", - "version" : "1.0.0" + "revision" : "3efbfba0e4e56c7187cc19137ee16b7c95346b79", + "version" : "1.1.0" } }, { @@ -144,6 +144,24 @@ "version" : "1.0.0" } }, + { + "identity" : "swift-json", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/swift-json", + "state" : { + "branch" : "main", + "revision" : "ac54806fd7e10587755ac5cfd802ae15ef6907d4" + } + }, + { + "identity" : "swift-logger", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/swift-logger", + "state" : { + "branch" : "main", + "revision" : "12fda88a83ce0c373381e6eaa5db1c27b4dc2eaa" + } + }, { "identity" : "swiftextension", "kind" : "remoteSourceControl", diff --git a/TodoListServer/.dockerignore b/TodoListServer/.dockerignore new file mode 100644 index 0000000..2d9f16e --- /dev/null +++ b/TodoListServer/.dockerignore @@ -0,0 +1,2 @@ +.build/ +.swiftpm/ diff --git a/TodoListServer/Dockerfile b/TodoListServer/Dockerfile index 08d155e..e3bde89 100644 --- a/TodoListServer/Dockerfile +++ b/TodoListServer/Dockerfile @@ -1,13 +1,12 @@ # ================================ # Build image # ================================ -FROM swift:5.5-focal as build +FROM swift:5.8-jammy as build # Install OS updates and, if needed, sqlite3 RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ && apt-get -q update \ - && apt-get -q dist-upgrade -y \ - && apt-get install -y libsqlite3-dev \ + && apt-get -q dist-upgrade -y\ && rm -rf /var/lib/apt/lists/* # Set up a build area @@ -24,13 +23,16 @@ RUN swift package resolve COPY . . # Build everything, with optimizations -RUN swift build -c release +RUN swift build -c release --static-swift-stdlib # Switch to the staging area WORKDIR /staging # Copy main executable to staging area -RUN cp "$(swift build --package-path /build -c release --show-bin-path)/Run" ./ +RUN cp "$(swift build --package-path /build -c release --show-bin-path)/App" ./ + +# Copy resources bundled by SPM to staging area +RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \; # Copy any resources from the public directory and views directory if the directories exist # Ensure that by default, neither the directory nor any of its contents are writable. @@ -40,11 +42,20 @@ RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w # ================================ # Run image # ================================ -FROM swift:5.5-focal-slim +FROM ubuntu:jammy -# Make sure all system packages are up to date. -RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true && \ - apt-get -q update && apt-get -q dist-upgrade -y && rm -r /var/lib/apt/lists/* +# Make sure all system packages are up to date, and install only essential packages. +RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ + && apt-get -q update \ + && apt-get -q dist-upgrade -y \ + && apt-get -q install -y \ + ca-certificates \ + tzdata \ +# If your app or its dependencies import FoundationNetworking, also install `libcurl4`. + # libcurl4 \ +# If your app or its dependencies import FoundationXML, also install `libxml2`. + # libxml2 \ + && rm -r /var/lib/apt/lists/* # Create a vapor user and group with /app as its home directory RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor @@ -62,5 +73,5 @@ USER vapor:vapor EXPOSE 8080 # Start the Vapor service when the image is run, default to listening on 8080 in production environment -ENTRYPOINT ["./Run"] +ENTRYPOINT ["./App"] CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] diff --git a/TodoListServer/Package.resolved b/TodoListServer/Package.resolved index 09654a3..16047cf 100644 --- a/TodoListServer/Package.resolved +++ b/TodoListServer/Package.resolved @@ -1,241 +1,239 @@ { - "object": { - "pins": [ - { - "package": "async-http-client", - "repositoryURL": "https://github.com/swift-server/async-http-client.git", - "state": { - "branch": null, - "revision": "1d24271feee99403c80e5387a1775299c84f902f", - "version": "1.14.0" - } - }, - { - "package": "async-kit", - "repositoryURL": "https://github.com/vapor/async-kit.git", - "state": { - "branch": null, - "revision": "9acea4c92f51a5885c149904f0d11db4712dda80", - "version": "1.16.0" - } - }, - { - "package": "console-kit", - "repositoryURL": "https://github.com/vapor/console-kit.git", - "state": { - "branch": null, - "revision": "447f1046fb4e9df40973fe426ecb24a6f0e8d3b4", - "version": "4.6.0" - } - }, - { - "package": "fluent", - "repositoryURL": "https://github.com/vapor/fluent.git", - "state": { - "branch": null, - "revision": "4db22cc7797b3a687de65e32e11108cf92fb32da", - "version": "4.7.0" - } - }, - { - "package": "fluent-kit", - "repositoryURL": "https://github.com/vapor/fluent-kit.git", - "state": { - "branch": null, - "revision": "10f32130a0f7e29de8def48edf69564c36cf3b74", - "version": "1.38.0" - } - }, - { - "package": "fluent-sqlite-driver", - "repositoryURL": "https://github.com/vapor/fluent-sqlite-driver.git", - "state": { - "branch": null, - "revision": "7f2a0b105e9cd22141dee220848d8739da6b7232", - "version": "4.3.0" - } - }, - { - "package": "multipart-kit", - "repositoryURL": "https://github.com/vapor/multipart-kit.git", - "state": { - "branch": null, - "revision": "0d55c35e788451ee27222783c7d363cb88092fab", - "version": "4.5.2" - } - }, - { - "package": "routing-kit", - "repositoryURL": "https://github.com/vapor/routing-kit.git", - "state": { - "branch": null, - "revision": "ffac7b3a127ce1e85fb232f1a6271164628809ad", - "version": "4.6.0" - } - }, - { - "package": "sql-kit", - "repositoryURL": "https://github.com/vapor/sql-kit.git", - "state": { - "branch": null, - "revision": "fcc29f543b3de7b661cbe7540805974234cb9740", - "version": "3.24.0" - } - }, - { - "package": "sqlite-kit", - "repositoryURL": "https://github.com/vapor/sqlite-kit.git", - "state": { - "branch": null, - "revision": "c07d53044727db7edf8550c2e8ccfe1fa40177d2", - "version": "4.2.0" - } - }, - { - "package": "sqlite-nio", - "repositoryURL": "https://github.com/vapor/sqlite-nio.git", - "state": { - "branch": null, - "revision": "88a7a57f4376bddec3b976efd6d3cc3a13de97a0", - "version": "1.3.3" - } - }, - { - "package": "swift-algorithms", - "repositoryURL": "https://github.com/apple/swift-algorithms.git", - "state": { - "branch": null, - "revision": "b14b7f4c528c942f121c8b860b9410b2bf57825e", - "version": "1.0.0" - } - }, - { - "package": "swift-atomics", - "repositoryURL": "https://github.com/apple/swift-atomics.git", - "state": { - "branch": null, - "revision": "ff3d2212b6b093db7f177d0855adbc4ef9c5f036", - "version": "1.0.3" - } - }, - { - "package": "swift-backtrace", - "repositoryURL": "https://github.com/swift-server/swift-backtrace.git", - "state": { - "branch": null, - "revision": "f25620d5d05e2f1ba27154b40cafea2b67566956", - "version": "1.3.3" - } - }, - { - "package": "swift-collections", - "repositoryURL": "https://github.com/apple/swift-collections.git", - "state": { - "branch": null, - "revision": "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version": "1.0.4" - } - }, - { - "package": "swift-crypto", - "repositoryURL": "https://github.com/apple/swift-crypto.git", - "state": { - "branch": null, - "revision": "75ec60b8b4cc0f085c3ac414f3dca5625fa3588e", - "version": "2.2.4" - } - }, - { - "package": "swift-log", - "repositoryURL": "https://github.com/apple/swift-log.git", - "state": { - "branch": null, - "revision": "32e8d724467f8fe623624570367e3d50c5638e46", - "version": "1.5.2" - } - }, - { - "package": "swift-metrics", - "repositoryURL": "https://github.com/apple/swift-metrics.git", - "state": { - "branch": null, - "revision": "e8bced74bc6d747745935e469f45d03f048d6cbd", - "version": "2.3.4" - } - }, - { - "package": "swift-nio", - "repositoryURL": "https://github.com/apple/swift-nio.git", - "state": { - "branch": null, - "revision": "45167b8006448c79dda4b7bd604e07a034c15c49", - "version": "2.48.0" - } - }, - { - "package": "swift-nio-extras", - "repositoryURL": "https://github.com/apple/swift-nio-extras.git", - "state": { - "branch": null, - "revision": "98378d1fe56527761c180f70b2d66a7b2307fc39", - "version": "1.16.0" - } - }, - { - "package": "swift-nio-http2", - "repositoryURL": "https://github.com/apple/swift-nio-http2.git", - "state": { - "branch": null, - "revision": "22757ac305f3d44d2b99ba541193ff1d64e77d00", - "version": "1.24.1" - } - }, - { - "package": "swift-nio-ssl", - "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", - "state": { - "branch": null, - "revision": "4fb7ead803e38949eb1d6fabb849206a72c580f3", - "version": "2.23.0" - } - }, - { - "package": "swift-nio-transport-services", - "repositoryURL": "https://github.com/apple/swift-nio-transport-services.git", - "state": { - "branch": null, - "revision": "c0d9a144cfaec8d3d596aadde3039286a266c15c", - "version": "1.15.0" - } - }, - { - "package": "swift-numerics", - "repositoryURL": "https://github.com/apple/swift-numerics", - "state": { - "branch": null, - "revision": "0a5bc04095a675662cf24757cc0640aa2204253b", - "version": "1.0.2" - } - }, - { - "package": "vapor", - "repositoryURL": "https://github.com/vapor/vapor.git", - "state": { - "branch": null, - "revision": "7b76fe01a8eb02aa7f61d9ca10624f98b25a5735", - "version": "4.69.2" - } - }, - { - "package": "websocket-kit", - "repositoryURL": "https://github.com/vapor/websocket-kit.git", - "state": { - "branch": null, - "revision": "2d9d2188a08eef4a869d368daab21b3c08510991", - "version": "2.6.1" - } - } - ] - }, - "version": 1 + "pins" : [ + { + "identity" : "async-http-client", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/async-http-client.git", + "state" : { + "revision" : "78db67e5bf4a8543075787f228e8920097319281", + "version" : "1.18.0" + } + }, + { + "identity" : "async-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/async-kit.git", + "state" : { + "revision" : "a61da00d404ec91d12766f1b9aac7d90777b484d", + "version" : "1.17.0" + } + }, + { + "identity" : "console-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/console-kit.git", + "state" : { + "revision" : "447f1046fb4e9df40973fe426ecb24a6f0e8d3b4", + "version" : "4.6.0" + } + }, + { + "identity" : "fluent", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/fluent.git", + "state" : { + "revision" : "4b4d8bf15a06fd60137e9c543e5503c4b842654e", + "version" : "4.8.0" + } + }, + { + "identity" : "fluent-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/fluent-kit.git", + "state" : { + "revision" : "e562a1015a814d42582cbccd3e58f03187d6718c", + "version" : "1.44.0" + } + }, + { + "identity" : "fluent-sqlite-driver", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/fluent-sqlite-driver.git", + "state" : { + "revision" : "138a546e3b7e33efa5362e05da2a0dec3a30534f", + "version" : "4.5.0" + } + }, + { + "identity" : "multipart-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/multipart-kit.git", + "state" : { + "revision" : "1adfd69df2da08f7931d4281b257475e32c96734", + "version" : "4.5.4" + } + }, + { + "identity" : "routing-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/routing-kit.git", + "state" : { + "revision" : "611bc45c5dfb1f54b84d99b89d1f72191fb6b71b", + "version" : "4.7.2" + } + }, + { + "identity" : "sql-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/sql-kit.git", + "state" : { + "revision" : "b2f128cb62a3abfbb1e3b2893ff3ee69e70f4f0f", + "version" : "3.28.0" + } + }, + { + "identity" : "sqlite-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/sqlite-kit.git", + "state" : { + "revision" : "2b20fc0f4f6574f59dae402ccf0ed050c6790b43", + "version" : "4.3.1" + } + }, + { + "identity" : "sqlite-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/sqlite-nio.git", + "state" : { + "revision" : "2b7bcf3d2e4d2f68d52a66d12d2057867cee383a", + "version" : "1.5.2" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-backtrace", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/swift-backtrace.git", + "state" : { + "revision" : "f25620d5d05e2f1ba27154b40cafea2b67566956", + "version" : "1.3.3" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", + "version" : "1.0.4" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "33a20e650c33f6d72d822d558333f2085effa3dc", + "version" : "2.5.0" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "32e8d724467f8fe623624570367e3d50c5638e46", + "version" : "1.5.2" + } + }, + { + "identity" : "swift-metrics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-metrics.git", + "state" : { + "revision" : "971ba26378ab69c43737ee7ba967a896cb74c0d1", + "version" : "2.4.1" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "a2e487b77f17edbce9a65f2b7415f2f479dc8e48", + "version" : "2.57.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", + "version" : "1.19.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "a8ccf13fa62775277a5d56844878c828bbb3be1a", + "version" : "1.27.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "e866a626e105042a6a72a870c88b4c531ba05f83", + "version" : "2.24.0" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "41f4098903878418537020075a4d8a6e20a0b182", + "version" : "1.17.0" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics", + "state" : { + "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", + "version" : "1.0.2" + } + }, + { + "identity" : "vapor", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/vapor.git", + "state" : { + "revision" : "e98077ddd1e3535bea6c9514f99d57463816c3bd", + "version" : "4.77.2" + } + }, + { + "identity" : "websocket-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/websocket-kit.git", + "state" : { + "revision" : "53fe0639a98903858d0196b699720decb42aee7b", + "version" : "2.14.0" + } + } + ], + "version" : 2 } diff --git a/TodoListServer/Package.swift b/TodoListServer/Package.swift index ddb5c6a..9f54d0f 100644 --- a/TodoListServer/Package.swift +++ b/TodoListServer/Package.swift @@ -1,36 +1,31 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.9 import PackageDescription let package = Package( - name: "TodoListServer", - platforms: [ - .macOS(.v10_15) - ], - dependencies: [ - // πŸ’§ A server-side Swift web framework. - .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"), - .package(url: "https://github.com/vapor/fluent.git", from: "4.0.0"), - .package(url: "https://github.com/vapor/fluent-sqlite-driver.git", from: "4.0.0"), - ], - targets: [ - .target( - name: "App", - dependencies: [ - .product(name: "Fluent", package: "fluent"), - .product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"), - .product(name: "Vapor", package: "vapor") - ], - swiftSettings: [ - // Enable better optimizations when building in Release configuration. Despite the use of - // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release - // builds. See for details. - .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) - ] - ), - .executableTarget(name: "Run", dependencies: [.target(name: "App")]), - .testTarget(name: "AppTests", dependencies: [ - .target(name: "App"), - .product(name: "XCTVapor", package: "vapor"), - ]) - ] + name: "TodoListServer", + platforms: [ + .macOS(.v13) + ], + dependencies: [ + // πŸ’§ A server-side Swift web framework. + .package(url: "https://github.com/vapor/vapor.git", from: "4.77.1"), + // πŸ—„ An ORM for SQL and NoSQL databases. + .package(url: "https://github.com/vapor/fluent.git", from: "4.8.0"), + // αΎ«6 Fluent driver for SQLite. + .package(url: "https://github.com/vapor/fluent-sqlite-driver.git", from: "4.0.0"), + ], + targets: [ + .executableTarget( + name: "App", + dependencies: [ + .product(name: "Fluent", package: "fluent"), + .product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"), + .product(name: "Vapor", package: "vapor") + ] + ), + .testTarget(name: "AppTests", dependencies: [ + .target(name: "App"), + .product(name: "XCTVapor", package: "vapor"), + ]) + ] ) diff --git a/TodoListServer/Public/.gitkeep b/TodoListServer/Public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/TodoListServer/Sources/App/Controllers/TodoController.swift b/TodoListServer/Sources/App/Controllers/TodoController.swift index 5f13789..10b8be2 100644 --- a/TodoListServer/Sources/App/Controllers/TodoController.swift +++ b/TodoListServer/Sources/App/Controllers/TodoController.swift @@ -8,30 +8,35 @@ struct TodoController: RouteCollection { todos.post(use: create) todos.delete(":todoID", use: delete(req:)) todos.post(":todoID", use: update(req:)) + todos.patch(":todoID", use: update(req:)) } - - func index(req: Request) throws -> EventLoopFuture<[Todo]> { - return Todo.query(on: req.db).all() + /// read all todos + func index(req: Request) async throws -> [Todo] { + try await Todo.query(on: req.db).all() } - - func create(req: Request) throws -> EventLoopFuture { + /// create or update the todo + func create(req: Request) async throws -> Todo { let todo = try req.content.decode(Todo.self) - return todo.save(on: req.db).map { todo } + try await todo.save(on: req.db) + return todo } - - func update(req: Request) throws -> EventLoopFuture { + /// update the todo + func update(req: Request) async throws -> Todo { let update = try req.content.decode(Todo.self) - return Todo.find(req.parameters.get("todoID"), on: req.db).unwrap(or: Abort(.notFound)).flatMap { todo in - todo.isCompleted = update.isCompleted - todo.title = update.title - return todo.save(on: req.db).map({update}) + guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else { + throw Abort(.notFound) } + todo.isCompleted = update.isCompleted + todo.text = update.text + try await todo.save(on: req.db) + return todo } - - func delete(req: Request) throws -> EventLoopFuture { - return Todo.find(req.parameters.get("todoID"), on: req.db) - .unwrap(or: Abort(.notFound)) - .flatMap { todo in - todo.delete(on: req.db).map {todo} } + /// delete the todo + func delete(req: Request) async throws -> Todo { + guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else { + throw Abort(.notFound) + } + try await todo.delete(on: req.db) + return todo } } diff --git a/TodoListServer/Sources/App/Migrations/CreateTodo.swift b/TodoListServer/Sources/App/Migrations/CreateTodo.swift index 0b49d6a..467c7c7 100644 --- a/TodoListServer/Sources/App/Migrations/CreateTodo.swift +++ b/TodoListServer/Sources/App/Migrations/CreateTodo.swift @@ -1,15 +1,15 @@ import Fluent -struct CreateTodo: Migration { - func prepare(on database: Database) -> EventLoopFuture { - return database.schema("todos") +struct CreateTodo: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("todos") .id() - .field("title", .string, .required) + .field("text", .string, .required) .field("isCompleted", .bool, .required) .create() } - func revert(on database: Database) -> EventLoopFuture { - return database.schema("todos").delete() + func revert(on database: Database) async throws { + try await database.schema("todos").delete() } } diff --git a/TodoListServer/Sources/App/Migrations/CreateUser.swift b/TodoListServer/Sources/App/Migrations/CreateUser.swift deleted file mode 100644 index ee1c99e..0000000 --- a/TodoListServer/Sources/App/Migrations/CreateUser.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Fluent -import Vapor -import AsyncKit - -struct CreateUser: AsyncMigration { - var name: String { "CreateUser" } - - func prepare(on database: Database) async throws { - try await database.schema("users") - .id() - .field("name", .string, .required) - .field("email", .string, .required) - .field("password_hash", .string, .required) - .unique(on: "email") - .create() - } - - func revert(on database: Database) async throws { - try await database.schema("users").delete() - } - } diff --git a/TodoListServer/Sources/App/Models/Todo.swift b/TodoListServer/Sources/App/Models/Todo.swift index 78210b8..0b537d6 100644 --- a/TodoListServer/Sources/App/Models/Todo.swift +++ b/TodoListServer/Sources/App/Models/Todo.swift @@ -7,17 +7,17 @@ final class Todo: Model, Content { @ID(key: .id) var id: UUID? - @Field(key: "title") - var title: String + @Field(key: "text") + var text: String @Field(key: "isCompleted") var isCompleted: Bool init() { } - init(id: UUID? = nil, title: String, isCompleted: Bool) { + init(id: UUID? = nil, text: String, isCompleted: Bool) { self.id = id - self.title = title + self.text = text self.isCompleted = isCompleted } } diff --git a/TodoListServer/Sources/App/Models/User.swift b/TodoListServer/Sources/App/Models/User.swift deleted file mode 100644 index f58c2ef..0000000 --- a/TodoListServer/Sources/App/Models/User.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Fluent -import Vapor - -final class User: Model, Content { - static let schema = "users" - - @ID(key: .id) - var id: UUID? - - @Field(key: "name") - var name: String - - @Field(key: "email") - var email: String - - @Field(key: "password_hash") - var passwordHash: String - - init() { } - - init(id: UUID? = nil, name: String, email: String, passwordHash: String) { - self.id = id - self.name = name - self.email = email - self.passwordHash = passwordHash - } -} diff --git a/TodoListServer/Sources/App/Socket/Websocket.swift b/TodoListServer/Sources/App/Socket/Websocket.swift deleted file mode 100644 index 931096a..0000000 --- a/TodoListServer/Sources/App/Socket/Websocket.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Foundation -import WebSocketKit - -open class WebSocketClient { - open var id: UUID - open var socket: WebSocket - - public init(id: UUID, socket: WebSocket) { - self.id = id - self.socket = socket - } -} - -open class WebsocketClients { - var eventLoop: EventLoop - var storage: [UUID: WebSocketClient] - - var active: [WebSocketClient] { - self.storage.values.filter { !$0.socket.isClosed } - } - - init(eventLoop: EventLoop, clients: [UUID: WebSocketClient] = [:]) { - self.eventLoop = eventLoop - self.storage = clients - } - - func add(_ client: WebSocketClient) { - self.storage[client.id] = client - } - - func remove(_ client: WebSocketClient) { - self.storage[client.id] = nil - } - - func find(_ uuid: UUID) -> WebSocketClient? { - self.storage[uuid] - } - - deinit { - let futures = self.storage.values.map { $0.socket.close() } - try! self.eventLoop.flatten(futures).wait() - } -} diff --git a/TodoListServer/Sources/App/UserAuthenticator.swift b/TodoListServer/Sources/App/UserAuthenticator.swift deleted file mode 100644 index 309370b..0000000 --- a/TodoListServer/Sources/App/UserAuthenticator.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Fluent -import Vapor - -struct UserAuthenticator: AsyncBearerAuthenticator { - typealias User = App.User - - func authenticate( - bearer: BearerAuthorization, - for request: Request - ) async throws { - if bearer.token == "foo" { - request.auth.login(User(name: "Vapor")) - } - } -} diff --git a/TodoListServer/Sources/App/configure.swift b/TodoListServer/Sources/App/configure.swift index 8cf5897..ed01d1a 100644 --- a/TodoListServer/Sources/App/configure.swift +++ b/TodoListServer/Sources/App/configure.swift @@ -1,25 +1,18 @@ +import NIOSSL import Fluent import FluentSQLiteDriver import Vapor -var websocketClients: WebsocketClients! - // configures your application -public func configure(_ app: Application) throws { - // uncomment to serve files from /Public folder - // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) - app.databases.use(.sqlite(.memory), as: .sqlite) + +// configures your application +public func configure(_ app: Application) async throws { + // uncomment to serve files from /Public folder + // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) + + app.databases.use(.sqlite(.file("db.sqlite")), as: .sqlite) + app.migrations.add(CreateTodo()) - try app.autoMigrate().wait() - // websocket - websocketClients = WebsocketClients(eventLoop: app.eventLoopGroup.next()) - app.webSocket("todo-list") { request, webSocket in - webSocket.send("Connected Socket", promise: request.eventLoop.makePromise()) - websocketClients.add(WebSocketClient(id: UUID(), socket: webSocket)) - webSocket.onText { ws, text in - websocketClients.active.forEach { client in - client.socket.send(text, promise: request.eventLoop.makePromise()) - } - } - } - // register routes + try await app.autoMigrate() + + // register routes try routes(app) } diff --git a/TodoListServer/Sources/App/entrypoint.swift b/TodoListServer/Sources/App/entrypoint.swift new file mode 100644 index 0000000..419d29c --- /dev/null +++ b/TodoListServer/Sources/App/entrypoint.swift @@ -0,0 +1,40 @@ +import Vapor +import Dispatch +import Logging + +/// This extension is temporary and can be removed once Vapor gets this support. +private extension Vapor.Application { + static let baseExecutionQueue = DispatchQueue(label: "vapor.codes.entrypoint") + + func runFromAsyncMainEntrypoint() async throws { + try await withCheckedThrowingContinuation { continuation in + Vapor.Application.baseExecutionQueue.async { [self] in + do { + try self.run() + continuation.resume() + } catch { + continuation.resume(throwing: error) + } + } + } + } +} + +@main +enum Entrypoint { + static func main() async throws { + var env = try Environment.detect() + try LoggingSystem.bootstrap(from: &env) + + let app = Application(env) + defer { app.shutdown() } + + do { + try await configure(app) + } catch { + app.logger.report(error: error) + throw error + } + try await app.runFromAsyncMainEntrypoint() + } +} diff --git a/TodoListServer/Sources/App/routes.swift b/TodoListServer/Sources/App/routes.swift index c85dbfe..f958df1 100644 --- a/TodoListServer/Sources/App/routes.swift +++ b/TodoListServer/Sources/App/routes.swift @@ -2,13 +2,13 @@ import Fluent import Vapor func routes(_ app: Application) throws { - app.get { req in - return "It works!" - } - - app.get("hello") { req -> String in - return "Hello, world!" - } - - try app.register(collection: TodoController()) + app.get { req async in + "It works!" + } + + app.get("hello") { req async -> String in + "Hello, world!" + } + + try app.register(collection: TodoController()) } diff --git a/TodoListServer/Sources/Run/main.swift b/TodoListServer/Sources/Run/main.swift deleted file mode 100644 index 373be5f..0000000 --- a/TodoListServer/Sources/Run/main.swift +++ /dev/null @@ -1,9 +0,0 @@ -import App -import Vapor - -var env = try Environment.detect() -try LoggingSystem.bootstrap(from: &env) -let app = Application(env) -defer { app.shutdown() } -try configure(app) -try app.run() diff --git a/TodoListServer/Tests/AppTests/AppTests.swift b/TodoListServer/Tests/AppTests/AppTests.swift index 9817630..8cfd310 100644 --- a/TodoListServer/Tests/AppTests/AppTests.swift +++ b/TodoListServer/Tests/AppTests/AppTests.swift @@ -2,10 +2,10 @@ import XCTVapor final class AppTests: XCTestCase { - func testHelloWorld() throws { + func testHelloWorld() async throws { let app = Application(.testing) defer { app.shutdown() } - try configure(app) + try await configure(app) try app.test(.GET, "hello", afterResponse: { res in XCTAssertEqual(res.status, .ok) diff --git a/TodoListServer/db.sqlite b/TodoListServer/db.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..a92456bf140a35a2642b3ed7fcdf3d90e6be2d7b GIT binary patch literal 24576 zcmeI)O=}ZD7zgm#=FPMuYZ1x8%aV(Uc1w1%ZxIA%Ut)u?v1t}+75hStGCv?$!vJR=F9OkSel!=zQb?4srd=}4c>n>MTTt~=d!_$1;io`QdrAbQT!!+gbSk#*N%R!{^K_cvV zx;A>IQmk?ON5VD~2tWV=5P$##AOHafKmY;|fB*#kD}g00?&gz;1eFX~mrX;oRmT(+ z)h>x<$<#!xObtu6X~|Gk+V3w~;i5)^tq0Ms(zkcL)%WN7S(X>ae<5r`fdB*`009U< z00Izz00bZa0SG|giV56~xXEc&2hQIAPY8c<#S+AHApijgKmY;|fB*y_009U<00I!0 zATS@vColdUAjQ8Xk@P9yYkW3+`m^fkuud2RVF*9~0uX=z1Rwwb2tWV=5P-my5Lk#u z-J3~jN{&r+Rg{W)QB