diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index dcd6273..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 2acc2fa..0b84b59 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -2,21 +2,3 @@ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift name: Swift - -on: - push: - branches: [ "develop" ] - pull_request: - branches: [ "develop" ] - -jobs: - build: - - runs-on: macos-latest - - steps: - - uses: actions/checkout@v3 - - name: Build - run: swift build -v - - name: Run tests - run: swift test -v diff --git a/AdvanceApp/.DS_Store b/AdvanceApp/.DS_Store deleted file mode 100644 index 443984b..0000000 Binary files a/AdvanceApp/.DS_Store and /dev/null differ diff --git a/AdvanceApp/SwiftUI/Todo+Combine+SwiftUI/.DS_Store b/AdvanceApp/SwiftUI/Todo+Combine+SwiftUI/.DS_Store deleted file mode 100644 index 9d14778..0000000 Binary files a/AdvanceApp/SwiftUI/Todo+Combine+SwiftUI/.DS_Store and /dev/null differ diff --git a/AdvanceApp/UIKit13+/.DS_Store b/AdvanceApp/UIKit13+/.DS_Store deleted file mode 100644 index 2697fd1..0000000 Binary files a/AdvanceApp/UIKit13+/.DS_Store and /dev/null differ diff --git a/AdvanceApp/UIKit13+/TodoCombineUIKit13/.DS_Store b/AdvanceApp/UIKit13+/TodoCombineUIKit13/.DS_Store deleted file mode 100644 index a94b3dd..0000000 Binary files a/AdvanceApp/UIKit13+/TodoCombineUIKit13/.DS_Store and /dev/null differ diff --git a/AdvanceApp/UIKit13+/TodoRxSwiftUIKit13/.DS_Store b/AdvanceApp/UIKit13+/TodoRxSwiftUIKit13/.DS_Store deleted file mode 100644 index 688d89e..0000000 Binary files a/AdvanceApp/UIKit13+/TodoRxSwiftUIKit13/.DS_Store and /dev/null differ diff --git a/BasicApp/.DS_Store b/BasicApp/.DS_Store deleted file mode 100644 index 1fee65d..0000000 Binary files a/BasicApp/.DS_Store and /dev/null differ diff --git a/BasicApp/SwiftUI/.DS_Store b/BasicApp/SwiftUI/.DS_Store deleted file mode 100644 index 996f5c0..0000000 Binary files a/BasicApp/SwiftUI/.DS_Store and /dev/null differ diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/.DS_Store b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/.DS_Store deleted file mode 100644 index 50898f3..0000000 Binary files a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/.DS_Store and /dev/null differ diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/Exports.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/Exports.swift index 9cc822a..119927c 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/Exports.swift +++ b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/Exports.swift @@ -1,3 +1,5 @@ @_exported import Transform @_exported import MCombineRequest @_exported import ComposableArchitecture +@_exported import Json +@_exported import SwiftLogger diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp.swift index 1dfc65f..39c0012 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp.swift +++ b/BasicApp/SwiftUI/Todo+Combine+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+Combine+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift index f113757..1240ba8 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Models/TodoModel.swift +++ b/BasicApp/SwiftUI/Todo+Combine+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+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/AuthView.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/AuthView.swift index b5e3f4b..6f1c485 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/AuthView.swift +++ b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/AuthView.swift @@ -1,4 +1,3 @@ -import ComposableArchitecture import SwiftUI struct Auth: Reducer { diff --git a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/MainView.swift b/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/MainView.swift index b4e99d4..186476a 100644 --- a/BasicApp/SwiftUI/Todo+Combine+SwiftUI/Shared/CoreApp/TodoApp/Views/MainView.swift +++ b/BasicApp/SwiftUI/Todo+Combine+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+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/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 53becd9..e1f3ef7 100644 --- a/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,97 +1,59 @@ { - "object": { - "pins": [ - { - "package": "Alamofire", - "repositoryURL": "https://github.com/Alamofire/Alamofire", - "state": { - "branch": null, - "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", - "version": "5.5.0" - } - }, - { - "package": "combine-core-architecture", - "repositoryURL": "https://github.com/FullStack-Swift/combine-core-architecture", - "state": { - "branch": "main", - "revision": "243d27364416b7f94dc3fcb884867a26c45a81be", - "version": null - } - }, - { - "package": "Networking", - "repositoryURL": "https://github.com/FullStack-Swift/Networking", - "state": { - "branch": null, - "revision": "fdbb1c94caf8ead0a26c622e8c08cbd6f6ebb8ac", - "version": "1.0.0" - } - }, - { - "package": "OpenCombine", - "repositoryURL": "https://github.com/FullStack-Swift/OpenCombine", - "state": { - "branch": "develop", - "revision": "5edf32f5b502bd0aea8ea14a0bea87735251cade", - "version": null - } - }, - { - "package": "ReactiveSwift", - "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift.git", - "state": { - "branch": null, - "revision": "efb2f0a6f6c8739cce8fb14148a5bd3c83f2f91d", - "version": "7.0.0" - } - }, - { - "package": "RxSwift", - "repositoryURL": "https://github.com/ReactiveX/RxSwift.git", - "state": { - "branch": null, - "revision": "b4307ba0b6425c0ba4178e138799946c3da594f8", - "version": "6.5.0" - } - }, - { - "package": "Starscream", - "repositoryURL": "https://github.com/daltoniam/Starscream.git", - "state": { - "branch": null, - "revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version": "4.0.4" - } - }, - { - "package": "swift-case-paths", - "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", - "state": { - "branch": null, - "revision": "241301b67d8551c26d8f09bd2c0e52cc49f18007", - "version": "0.8.0" - } - }, - { - "package": "SwiftExtension", - "repositoryURL": "https://github.com/FullStack-Swift/SwiftExtension", - "state": { - "branch": null, - "revision": "cdbd56e6cf32fa0eb97a1fba445736cbe8b8e622", - "version": "1.0.0" - } - }, - { - "package": "xctest-dynamic-overlay", - "repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state": { - "branch": null, - "revision": "50a70a9d3583fe228ce672e8923010c8df2deddd", - "version": "0.2.1" - } + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire", + "state" : { + "revision" : "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", + "version" : "5.5.0" } - ] - }, - "version": 1 + }, + { + "identity" : "combine-core-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/combine-core-architecture", + "state" : { + "branch" : "main", + "revision" : "6367fe0a97e7fa0b2a275680b1d583fbcad53568" + } + }, + { + "identity" : "opencombine", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/OpenCombine", + "state" : { + "branch" : "develop", + "revision" : "5edf32f5b502bd0aea8ea14a0bea87735251cade" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "fc45e7b2cfece9dd80b5a45e6469ffe67fe67984", + "version" : "0.14.1" + } + }, + { + "identity" : "swiftextension", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/SwiftExtension", + "state" : { + "revision" : "cdbd56e6cf32fa0eb97a1fba445736cbe8b8e622", + "version" : "1.0.0" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "50843cbb8551db836adec2290bb4bc6bac5c1865", + "version" : "0.9.0" + } + } + ], + "version" : 2 } diff --git a/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/xcshareddata/xcschemes/Todo+Combine+UIKit(iOS11).xcscheme b/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/xcshareddata/xcschemes/Todo+Combine+UIKit(iOS11).xcscheme new file mode 100644 index 0000000..c493cc9 --- /dev/null +++ b/BasicApp/UIKit11+/Todo+Combine+UIKit(iOS11)/Todo+Combine+UIKit(iOS11).xcodeproj/xcshareddata/xcschemes/Todo+Combine+UIKit(iOS11).xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BasicApp/UIKit13+/.DS_Store b/BasicApp/UIKit13+/.DS_Store deleted file mode 100644 index 6eca8cb..0000000 Binary files a/BasicApp/UIKit13+/.DS_Store and /dev/null differ diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/.DS_Store b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/.DS_Store deleted file mode 100644 index 6428d8e..0000000 Binary files a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/.DS_Store and /dev/null differ diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.pbxproj b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.pbxproj index b28df25..b0833d5 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.pbxproj +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.pbxproj @@ -9,59 +9,37 @@ /* Begin PBXBuildFile section */ 87320B8D27A59D9700360667 /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B5327A59D9700360667 /* TodoApp.swift */; }; 87320B8E27A59D9700360667 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B5727A59D9700360667 /* MainViewController.swift */; }; - 87320B8F27A59D9700360667 /* MainReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B5827A59D9700360667 /* MainReducer.swift */; }; - 87320B9027A59D9700360667 /* MainEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B5927A59D9700360667 /* MainEnvironment.swift */; }; - 87320B9127A59D9700360667 /* MainState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B5A27A59D9700360667 /* MainState.swift */; }; - 87320B9227A59D9700360667 /* MainAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B5B27A59D9700360667 /* MainAction.swift */; }; 87320B9827A59D9700360667 /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B6327A59D9700360667 /* AuthViewController.swift */; }; - 87320B9927A59D9700360667 /* AuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B6427A59D9700360667 /* AuthState.swift */; }; - 87320B9F27A59D9700360667 /* AuthReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B6B27A59D9700360667 /* AuthReducer.swift */; }; - 87320BA027A59D9700360667 /* AuthAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B6C27A59D9700360667 /* AuthAction.swift */; }; - 87320BA627A59D9700360667 /* AuthEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7327A59D9700360667 /* AuthEnvironment.swift */; }; - 87320BA727A59D9700360667 /* RootAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7527A59D9700360667 /* RootAction.swift */; }; - 87320BA827A59D9700360667 /* RootEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7627A59D9700360667 /* RootEnvironment.swift */; }; 87320BA927A59D9700360667 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7727A59D9700360667 /* RootViewController.swift */; }; - 87320BAA27A59D9700360667 /* RootState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7827A59D9700360667 /* RootState.swift */; }; - 87320BAB27A59D9700360667 /* RootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7927A59D9700360667 /* RootReducer.swift */; }; 87320BAD27A59D9700360667 /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B7E27A59D9700360667 /* TodoModel.swift */; }; 87320BB027A59D9700360667 /* ButtonReloadMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B8427A59D9700360667 /* ButtonReloadMainTableViewCell.swift */; }; 87320BB127A59D9700360667 /* CreateTitleMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B8527A59D9700360667 /* CreateTitleMainTableViewCell.swift */; }; 87320BB327A59D9700360667 /* MainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B8727A59D9700360667 /* MainTableViewCell.swift */; }; 87320BB627A59D9700360667 /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320B8C27A59D9700360667 /* View+.swift */; }; 87320BB927A59EAC00360667 /* CombineCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 87320BB827A59EAC00360667 /* CombineCocoa */; }; - 876AF6CA27A5D18B009A0148 /* BaseMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6C927A5D18B009A0148 /* BaseMainTableViewCell.swift */; }; + 876AF6CA27A5D18B009A0148 /* BaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6C927A5D18B009A0148 /* BaseTableViewCell.swift */; }; 876AF6CC27A5D7ED009A0148 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6CB27A5D7ED009A0148 /* BaseViewController.swift */; }; 87BB891727A59489000B269B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87BB891627A59489000B269B /* Assets.xcassets */; }; 87BB891A27A59489000B269B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87BB891927A59489000B269B /* Preview Assets.xcassets */; }; - 87BB893C27A59514000B269B /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB893B27A59514000B269B /* ComposableArchitecture */; }; 87BB893F27A5953B000B269B /* CombineRequest in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB893E27A5953B000B269B /* CombineRequest */; }; 87BB894127A5953B000B269B /* CombineWebSocket in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB894027A5953B000B269B /* CombineWebSocket */; }; - 87BB894427A59557000B269B /* ConvertSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 87BB894327A59557000B269B /* ConvertSwift */; }; + EBA4698D2ACEC4D70060376F /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EBA4698C2ACEC4D70060376F /* Transform */; }; + EBA469902ACEC4F00060376F /* SwiftLogger in Frameworks */ = {isa = PBXBuildFile; productRef = EBA4698F2ACEC4F00060376F /* SwiftLogger */; }; + EBA469932ACEC5070060376F /* Json in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469922ACEC5070060376F /* Json */; }; + EBA469962ACEC55D0060376F /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469952ACEC55D0060376F /* ComposableArchitecture */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 87320B5327A59D9700360667 /* TodoApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoApp.swift; sourceTree = ""; }; 87320B5727A59D9700360667 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - 87320B5827A59D9700360667 /* MainReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainReducer.swift; sourceTree = ""; }; - 87320B5927A59D9700360667 /* MainEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainEnvironment.swift; sourceTree = ""; }; - 87320B5A27A59D9700360667 /* MainState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainState.swift; sourceTree = ""; }; - 87320B5B27A59D9700360667 /* MainAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainAction.swift; sourceTree = ""; }; 87320B6327A59D9700360667 /* AuthViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthViewController.swift; sourceTree = ""; }; - 87320B6427A59D9700360667 /* AuthState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = ""; }; - 87320B6B27A59D9700360667 /* AuthReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthReducer.swift; sourceTree = ""; }; - 87320B6C27A59D9700360667 /* AuthAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthAction.swift; sourceTree = ""; }; - 87320B7327A59D9700360667 /* AuthEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthEnvironment.swift; sourceTree = ""; }; - 87320B7527A59D9700360667 /* RootAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootAction.swift; sourceTree = ""; }; - 87320B7627A59D9700360667 /* RootEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootEnvironment.swift; sourceTree = ""; }; 87320B7727A59D9700360667 /* RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; - 87320B7827A59D9700360667 /* RootState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootState.swift; sourceTree = ""; }; - 87320B7927A59D9700360667 /* RootReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootReducer.swift; sourceTree = ""; }; 87320B7E27A59D9700360667 /* TodoModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoModel.swift; sourceTree = ""; }; 87320B8427A59D9700360667 /* ButtonReloadMainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonReloadMainTableViewCell.swift; sourceTree = ""; }; 87320B8527A59D9700360667 /* CreateTitleMainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateTitleMainTableViewCell.swift; sourceTree = ""; }; 87320B8727A59D9700360667 /* MainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTableViewCell.swift; sourceTree = ""; }; 87320B8C27A59D9700360667 /* View+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+.swift"; sourceTree = ""; }; - 876AF6C927A5D18B009A0148 /* BaseMainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseMainTableViewCell.swift; sourceTree = ""; }; + 876AF6C927A5D18B009A0148 /* BaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewCell.swift; sourceTree = ""; }; 876AF6CB27A5D7ED009A0148 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 87BB890F27A59488000B269B /* Todo+Combine+UIKit(iOS13).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+Combine+UIKit(iOS13).app"; sourceTree = BUILT_PRODUCTS_DIR; }; 87BB891627A59489000B269B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -73,11 +51,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EBA469932ACEC5070060376F /* Json in Frameworks */, 87BB893F27A5953B000B269B /* CombineRequest in Frameworks */, + EBA469962ACEC55D0060376F /* ComposableArchitecture in Frameworks */, 87BB894127A5953B000B269B /* CombineWebSocket in Frameworks */, - 87BB894427A59557000B269B /* ConvertSwift in Frameworks */, + EBA4698D2ACEC4D70060376F /* Transform in Frameworks */, 87320BB927A59EAC00360667 /* CombineCocoa in Frameworks */, - 87BB893C27A59514000B269B /* ComposableArchitecture in Frameworks */, + EBA469902ACEC4F00060376F /* SwiftLogger in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -96,58 +76,23 @@ 87320B5427A59D9700360667 /* TodoApp */ = { isa = PBXGroup; children = ( - 87320B5527A59D9700360667 /* AppScreens */, - 87320B7C27A59D9700360667 /* Models */, + 87320B8B27A59D9700360667 /* ViewExt */, 87320B8327A59D9700360667 /* Views */, - 87320B8B27A59D9700360667 /* View+ */, + 87320B5527A59D9700360667 /* ViewControllers */, + EBA469972ACFA4FC0060376F /* Bases */, + 87320B7C27A59D9700360667 /* Models */, ); path = TodoApp; sourceTree = ""; }; - 87320B5527A59D9700360667 /* AppScreens */ = { - isa = PBXGroup; - children = ( - 87320B5627A59D9700360667 /* MainScreen */, - 87320B6227A59D9700360667 /* AuthScreen */, - 87320B7427A59D9700360667 /* RootScreen */, - ); - path = AppScreens; - sourceTree = ""; - }; - 87320B5627A59D9700360667 /* MainScreen */ = { + 87320B5527A59D9700360667 /* ViewControllers */ = { isa = PBXGroup; children = ( 87320B5727A59D9700360667 /* MainViewController.swift */, - 87320B5A27A59D9700360667 /* MainState.swift */, - 87320B5B27A59D9700360667 /* MainAction.swift */, - 87320B5927A59D9700360667 /* MainEnvironment.swift */, - 87320B5827A59D9700360667 /* MainReducer.swift */, - ); - path = MainScreen; - sourceTree = ""; - }; - 87320B6227A59D9700360667 /* AuthScreen */ = { - isa = PBXGroup; - children = ( 87320B6327A59D9700360667 /* AuthViewController.swift */, - 87320B6427A59D9700360667 /* AuthState.swift */, - 87320B6C27A59D9700360667 /* AuthAction.swift */, - 87320B7327A59D9700360667 /* AuthEnvironment.swift */, - 87320B6B27A59D9700360667 /* AuthReducer.swift */, - ); - path = AuthScreen; - sourceTree = ""; - }; - 87320B7427A59D9700360667 /* RootScreen */ = { - isa = PBXGroup; - children = ( 87320B7727A59D9700360667 /* RootViewController.swift */, - 87320B7827A59D9700360667 /* RootState.swift */, - 87320B7527A59D9700360667 /* RootAction.swift */, - 87320B7627A59D9700360667 /* RootEnvironment.swift */, - 87320B7927A59D9700360667 /* RootReducer.swift */, ); - path = RootScreen; + path = ViewControllers; sourceTree = ""; }; 87320B7C27A59D9700360667 /* Models */ = { @@ -164,18 +109,16 @@ 87320B8427A59D9700360667 /* ButtonReloadMainTableViewCell.swift */, 87320B8527A59D9700360667 /* CreateTitleMainTableViewCell.swift */, 87320B8727A59D9700360667 /* MainTableViewCell.swift */, - 876AF6C927A5D18B009A0148 /* BaseMainTableViewCell.swift */, - 876AF6CB27A5D7ED009A0148 /* BaseViewController.swift */, ); path = Views; sourceTree = ""; }; - 87320B8B27A59D9700360667 /* View+ */ = { + 87320B8B27A59D9700360667 /* ViewExt */ = { isa = PBXGroup; children = ( 87320B8C27A59D9700360667 /* View+.swift */, ); - path = "View+"; + path = ViewExt; sourceTree = ""; }; 87BB890627A59488000B269B = { @@ -183,6 +126,7 @@ children = ( 87BB891127A59488000B269B /* Todo+Combine+UIKit(iOS13) */, 87BB891027A59488000B269B /* Products */, + EBA4698B2ACEC4D70060376F /* Frameworks */, ); sourceTree = ""; }; @@ -212,6 +156,22 @@ path = "Preview Content"; sourceTree = ""; }; + EBA4698B2ACEC4D70060376F /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + EBA469972ACFA4FC0060376F /* Bases */ = { + isa = PBXGroup; + children = ( + 876AF6CB27A5D7ED009A0148 /* BaseViewController.swift */, + 876AF6C927A5D18B009A0148 /* BaseTableViewCell.swift */, + ); + path = Bases; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -229,11 +189,13 @@ ); name = "Todo+Combine+UIKit(iOS13)"; packageProductDependencies = ( - 87BB893B27A59514000B269B /* ComposableArchitecture */, 87BB893E27A5953B000B269B /* CombineRequest */, 87BB894027A5953B000B269B /* CombineWebSocket */, - 87BB894327A59557000B269B /* ConvertSwift */, 87320BB827A59EAC00360667 /* CombineCocoa */, + EBA4698C2ACEC4D70060376F /* Transform */, + EBA4698F2ACEC4F00060376F /* SwiftLogger */, + EBA469922ACEC5070060376F /* Json */, + EBA469952ACEC55D0060376F /* ComposableArchitecture */, ); productName = "Todo+Combine+UIKit(iOS13)"; productReference = 87BB890F27A59488000B269B /* Todo+Combine+UIKit(iOS13).app */; @@ -264,10 +226,12 @@ ); mainGroup = 87BB890627A59488000B269B; packageReferences = ( - 87BB893A27A59514000B269B /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, 87BB893D27A5953B000B269B /* XCRemoteSwiftPackageReference "Networking" */, 87BB894227A59557000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */, 87320BB727A59EAC00360667 /* XCRemoteSwiftPackageReference "CombineCocoa" */, + EBA4698E2ACEC4F00060376F /* XCRemoteSwiftPackageReference "swift-logger" */, + EBA469912ACEC5070060376F /* XCRemoteSwiftPackageReference "swift-json" */, + EBA469942ACEC55C0060376F /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, ); productRefGroup = 87BB891027A59488000B269B /* Products */; projectDirPath = ""; @@ -295,29 +259,17 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 87320BA827A59D9700360667 /* RootEnvironment.swift in Sources */, 87320BB627A59D9700360667 /* View+.swift in Sources */, 87320B8D27A59D9700360667 /* TodoApp.swift in Sources */, 876AF6CC27A5D7ED009A0148 /* BaseViewController.swift in Sources */, - 87320B9127A59D9700360667 /* MainState.swift in Sources */, 87320BA927A59D9700360667 /* RootViewController.swift in Sources */, - 87320B9F27A59D9700360667 /* AuthReducer.swift in Sources */, - 87320B9227A59D9700360667 /* MainAction.swift in Sources */, - 87320BA727A59D9700360667 /* RootAction.swift in Sources */, 87320BB327A59D9700360667 /* MainTableViewCell.swift in Sources */, - 87320BA627A59D9700360667 /* AuthEnvironment.swift in Sources */, 87320B9827A59D9700360667 /* AuthViewController.swift in Sources */, 87320BB127A59D9700360667 /* CreateTitleMainTableViewCell.swift in Sources */, - 87320B8F27A59D9700360667 /* MainReducer.swift in Sources */, 87320BAD27A59D9700360667 /* TodoModel.swift in Sources */, - 876AF6CA27A5D18B009A0148 /* BaseMainTableViewCell.swift in Sources */, + 876AF6CA27A5D18B009A0148 /* BaseTableViewCell.swift in Sources */, 87320BB027A59D9700360667 /* ButtonReloadMainTableViewCell.swift in Sources */, - 87320B9027A59D9700360667 /* MainEnvironment.swift in Sources */, - 87320B9927A59D9700360667 /* AuthState.swift in Sources */, - 87320BAA27A59D9700360667 /* RootState.swift in Sources */, 87320B8E27A59D9700360667 /* MainViewController.swift in Sources */, - 87320BAB27A59D9700360667 /* RootReducer.swift in Sources */, - 87320BA027A59D9700360667 /* AuthAction.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -532,28 +484,44 @@ version = 0.4.0; }; }; - 87BB893A27A59514000B269B /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { + 87BB893D27A5953B000B269B /* XCRemoteSwiftPackageReference "Networking" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/FullStack-Swift/swift-composable-architecture"; + repositoryURL = "https://github.com/FullStack-Swift/Networking"; requirement = { - branch = develop; + branch = main; kind = branch; }; }; - 87BB893D27A5953B000B269B /* XCRemoteSwiftPackageReference "Networking" */ = { + 87BB894227A59557000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/FullStack-Swift/Networking"; + repositoryURL = "https://github.com/FullStack-Swift/SwiftExtension"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; - 87BB894227A59557000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */ = { + EBA4698E2ACEC4F00060376F /* XCRemoteSwiftPackageReference "swift-logger" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/FullStack-Swift/SwiftExtension"; + repositoryURL = "https://github.com/FullStack-Swift/swift-logger"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; + }; + }; + EBA469912ACEC5070060376F /* XCRemoteSwiftPackageReference "swift-json" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-json"; + requirement = { + branch = main; + kind = branch; + }; + }; + EBA469942ACEC55C0060376F /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture"; + requirement = { + branch = main; + kind = branch; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -564,11 +532,6 @@ package = 87320BB727A59EAC00360667 /* XCRemoteSwiftPackageReference "CombineCocoa" */; productName = CombineCocoa; }; - 87BB893B27A59514000B269B /* ComposableArchitecture */ = { - isa = XCSwiftPackageProductDependency; - package = 87BB893A27A59514000B269B /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; - productName = ComposableArchitecture; - }; 87BB893E27A5953B000B269B /* CombineRequest */ = { isa = XCSwiftPackageProductDependency; package = 87BB893D27A5953B000B269B /* XCRemoteSwiftPackageReference "Networking" */; @@ -579,10 +542,25 @@ package = 87BB893D27A5953B000B269B /* XCRemoteSwiftPackageReference "Networking" */; productName = CombineWebSocket; }; - 87BB894327A59557000B269B /* ConvertSwift */ = { + EBA4698C2ACEC4D70060376F /* Transform */ = { isa = XCSwiftPackageProductDependency; package = 87BB894227A59557000B269B /* XCRemoteSwiftPackageReference "SwiftExtension" */; - productName = ConvertSwift; + productName = Transform; + }; + EBA4698F2ACEC4F00060376F /* SwiftLogger */ = { + isa = XCSwiftPackageProductDependency; + package = EBA4698E2ACEC4F00060376F /* XCRemoteSwiftPackageReference "swift-logger" */; + productName = SwiftLogger; + }; + EBA469922ACEC5070060376F /* Json */ = { + isa = XCSwiftPackageProductDependency; + package = EBA469912ACEC5070060376F /* XCRemoteSwiftPackageReference "swift-json" */; + productName = Json; + }; + EBA469952ACEC55D0060376F /* ComposableArchitecture */ = { + isa = XCSwiftPackageProductDependency; + package = EBA469942ACEC55C0060376F /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; + productName = ComposableArchitecture; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 64ea925..7ad47d2 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,133 +1,194 @@ { - "object": { - "pins": [ - { - "package": "Alamofire", - "repositoryURL": "https://github.com/Alamofire/Alamofire.git", - "state": { - "branch": null, - "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", - "version": "5.5.0" - } - }, - { - "package": "combine-schedulers", - "repositoryURL": "https://github.com/pointfreeco/combine-schedulers", - "state": { - "branch": null, - "revision": "4cf088c29a20f52be0f2ca54992b492c54e0076b", - "version": "0.5.3" - } - }, - { - "package": "CombineCocoa", - "repositoryURL": "https://github.com/CombineCommunity/CombineCocoa", - "state": { - "branch": null, - "revision": "4e262c2f9fb1cee1cb3be5717f7e6b55eb823971", - "version": "0.4.0" - } - }, - { - "package": "Networking", - "repositoryURL": "https://github.com/FullStack-Swift/Networking", - "state": { - "branch": null, - "revision": "fdbb1c94caf8ead0a26c622e8c08cbd6f6ebb8ac", - "version": "1.0.0" - } - }, - { - "package": "ReactiveSwift", - "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift.git", - "state": { - "branch": null, - "revision": "efb2f0a6f6c8739cce8fb14148a5bd3c83f2f91d", - "version": "7.0.0" - } - }, - { - "package": "RxSwift", - "repositoryURL": "https://github.com/ReactiveX/RxSwift.git", - "state": { - "branch": null, - "revision": "b4307ba0b6425c0ba4178e138799946c3da594f8", - "version": "6.5.0" - } - }, - { - "package": "Starscream", - "repositoryURL": "https://github.com/daltoniam/Starscream.git", - "state": { - "branch": null, - "revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version": "4.0.4" - } - }, - { - "package": "swift-case-paths", - "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", - "state": { - "branch": null, - "revision": "241301b67d8551c26d8f09bd2c0e52cc49f18007", - "version": "0.8.0" - } - }, - { - "package": "swift-collections", - "repositoryURL": "https://github.com/apple/swift-collections", - "state": { - "branch": null, - "revision": "48254824bb4248676bf7ce56014ff57b142b77eb", - "version": "1.0.2" - } - }, - { - "package": "swift-composable-architecture", - "repositoryURL": "https://github.com/FullStack-Swift/swift-composable-architecture", - "state": { - "branch": "develop", - "revision": "b83ef9d86feb48b0f0f05d968f214d69186b5397", - "version": null - } - }, - { - "package": "swift-custom-dump", - "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump", - "state": { - "branch": null, - "revision": "51698ece74ecf31959d3fa81733f0a5363ef1b4e", - "version": "0.3.0" - } - }, - { - "package": "swift-identified-collections", - "repositoryURL": "https://github.com/pointfreeco/swift-identified-collections", - "state": { - "branch": null, - "revision": "680bf440178a78a627b1c2c64c0855f6523ad5b9", - "version": "0.3.2" - } - }, - { - "package": "SwiftExtension", - "repositoryURL": "https://github.com/FullStack-Swift/SwiftExtension", - "state": { - "branch": null, - "revision": "cdbd56e6cf32fa0eb97a1fba445736cbe8b8e622", - "version": "1.0.0" - } - }, - { - "package": "xctest-dynamic-overlay", - "repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state": { - "branch": null, - "revision": "50a70a9d3583fe228ce672e8923010c8df2deddd", - "version": "0.2.1" - } - } - ] - }, - "version": 1 + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "b2fa556e4e48cbf06cf8c63def138c98f4b811fa", + "version" : "5.8.0" + } + }, + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb", + "version" : "1.0.0" + } + }, + { + "identity" : "combinecocoa", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CombineCommunity/CombineCocoa", + "state" : { + "revision" : "4e262c2f9fb1cee1cb3be5717f7e6b55eb823971", + "version" : "0.4.0" + } + }, + { + "identity" : "networking", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/Networking", + "state" : { + "branch" : "main", + "revision" : "23e446cfffd8a5f554fd564fc7568eeaa85843e4" + } + }, + { + "identity" : "reactiveswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveCocoa/ReactiveSwift.git", + "state" : { + "revision" : "40c465af19b993344e84355c00669ba2022ca3cd", + "version" : "7.1.1" + } + }, + { + "identity" : "rxswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveX/RxSwift.git", + "state" : { + "revision" : "9dcaa4b333db437b0fbfaf453fad29069044a8b4", + "version" : "6.6.0" + } + }, + { + "identity" : "socket.io-client-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/socketio/socket.io-client-swift", + "state" : { + "revision" : "175da8b5156f6b132436f0676cc84c2f6a766b6e", + "version" : "16.1.0" + } + }, + { + "identity" : "starscream", + "kind" : "remoteSourceControl", + "location" : "https://github.com/daltoniam/Starscream.git", + "state" : { + "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", + "version" : "4.0.6" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "5da6989aae464f324eef5c5b52bdb7974725ab81", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "d1fd837326aa719bee979bdde1f53cd5797443eb", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" + } + }, + { + "identity" : "swift-composable-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-composable-architecture", + "state" : { + "branch" : "main", + "revision" : "eef1c905f5515655581b5793b5630aba65c075cf" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "ea631ce892687f5432a833312292b80db238186a", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "3efbfba0e4e56c7187cc19137ee16b7c95346b79", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "4e1eb6e28afe723286d8cc60611237ffbddba7c5", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8", + "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", + "location" : "https://github.com/FullStack-Swift/SwiftExtension", + "state" : { + "branch" : "main", + "revision" : "ccbf2fddb982267be28705b3dd8b29ee3c4d149e" + } + }, + { + "identity" : "swiftui-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swiftui-navigation", + "state" : { + "revision" : "6eb293c49505d86e9e24232cb6af6be7fff93bd5", + "version" : "1.0.2" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631", + "version" : "1.0.2" + } + } + ], + "version" : 2 } diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp.swift index e1b7b94..bf36b14 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp.swift @@ -1,12 +1,23 @@ import SwiftUI -import ComposableArchitecture +@_exported import ComposableArchitecture +@_exported import MCombineRequest +@_exported import Combine +@_exported import CombineCocoa +@_exported import Transform @main struct TodoApp: App { var body: some Scene { WindowGroup { - let vc = RootViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) + RootViewController().toSwiftUI() } } } + +public extension DependencyValues { + var urlString: String { + "http://127.0.0.1:8080/todos" + } +} + +public var isUsingPublisher: Bool = true diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift deleted file mode 100644 index effce91..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift +++ /dev/null @@ -1,11 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum AuthAction: Equatable { - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case none - case login - case changeRootScreen(RootScreen) -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift deleted file mode 100644 index a96bc7e..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct AuthEnvironment { - -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift deleted file mode 100644 index 01fca41..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift +++ /dev/null @@ -1,21 +0,0 @@ -import ComposableArchitecture -import Foundation - -let AuthReducer = Reducer.combine( - Reducer { state, action, environment in - switch action { - case .viewDidLoad: - break - case .viewWillAppear: - break - case .viewWillDisappear: - break - case .login: - return Effect(value: .changeRootScreen(.main)) - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift deleted file mode 100644 index 0f0ea3d..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct AuthState: Equatable { - -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift deleted file mode 100644 index a0198cf..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift +++ /dev/null @@ -1,54 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import UIKit -import Combine -import CombineCocoa - -final class AuthViewController: BaseViewController { - - private let store: Store - - private let viewStore: ViewStore - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: AuthState(), reducer: AuthReducer, environment: AuthEnvironment()) - self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - viewStore.send(.viewDidLoad) - // buttonLogin - let buttonLogin = UIButton(type: .system) - buttonLogin.setTitle("Login", for: .normal) - buttonLogin.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(buttonLogin) - // contraint - NSLayoutConstraint.activate([ - buttonLogin.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor), - buttonLogin.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor), - ]) - - //bind view to viewstore - buttonLogin.tapPublisher - .map { AuthAction.login } - .subscribe(viewStore.action) - .store(in: &self.cancellables) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - viewStore.send(.viewWillAppear) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - viewStore.send(.viewWillDisappear) - } -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift deleted file mode 100644 index e676a5b..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift +++ /dev/null @@ -1,35 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum MainAction: Equatable { - // MARK: - View Action - /// lifecycle action - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case viewDeinit - /// navigation view - case logout - case changeRootScreen(RootScreen) - - /// binding - case changeText(String) - /// event network - case viewCreateTodo - case viewReloadTodo - case viewToggleTodo(TodoModel) - case viewDeleteTodo(TodoModel) - // MARK: - Store Action - case resetText - /// network Action - case getTodo - case responseGetTodo(Data) - case createOrUpdateTodo(TodoModel) - case responseCreateOrUpdateTodo(Data) - case updateTodo(TodoModel) - case responseUpdateTodo(Data) - case deleteTodo(TodoModel) - case reponseDeleteTodo(Data) - // MARK: - none - case none -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift deleted file mode 100644 index 179c54c..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift +++ /dev/null @@ -1,8 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct MainEnvironment { - let urlString: String = "https://todolistappproj.herokuapp.com/todos" - init() { - } -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift deleted file mode 100644 index 8a1ac74..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift +++ /dev/null @@ -1,127 +0,0 @@ -import ComposableArchitecture -import CombineRequest -import ConvertSwift - -let MainReducer = Reducer.combine( - Reducer { state, action, environment in - switch action { - /// view action - case .viewDidLoad: - return Effect(value: MainAction.viewReloadTodo) - case .viewWillAppear: - break - case .viewWillDisappear: - break - case .viewDeinit: - break - /// navigation view - case .logout: - return Effect(value: MainAction.changeRootScreen(.auth)) - case .changeText(let text): - state.title = text - case .resetText: - state.title = "" - /// event network - case .viewCreateTodo: - if state.title.isEmpty { - return .none - } - var title = state.title - let id = UUID() - let todo = TodoModel(id: id, title: title, isCompleted: false) - let resetTitleEffect = Effect(value: MainAction.resetText) - .delay(for: 0.3, scheduler: UIScheduler.shared) - .eraseToEffect() - return Effect.merge( - resetTitleEffect, - Effect(value: MainAction.createOrUpdateTodo(todo)) - ) - case .viewReloadTodo: - if state.isLoading { - return .none - } - state.todos.removeAll() - state.isLoading = true - return Effect(value: MainAction.getTodo) - .delay(for: 0.3, scheduler: UIScheduler.shared) - .eraseToEffect() - case .viewToggleTodo(let todo): - var todo = todo - todo.isCompleted.toggle() - return Effect(value: MainAction.updateTodo(todo)) - case .viewDeleteTodo(let todo): - return Effect(value: MainAction.deleteTodo(todo)) - /// network action - case .getTodo: - let request = MRequest { - RMethod(.get) - RUrl(urlString: environment.urlString) - } - return request - .compactMap {$0.data} - .map(MainAction.responseGetTodo) - .eraseToEffect() - case .responseGetTodo(let data): - state.isLoading = false - guard let todos = data.toModel([TodoModel].self) else { - return .none - } - for todo in todos { - state.todos.updateOrAppend(todo) - } - case .createOrUpdateTodo(let todo): - let request = MRequest { - RUrl(urlString: environment.urlString) - REncoding(.json) - RMethod(.post) - Rbody(todo.toData()) - } - return request - .compactMap {$0.data} - .map(MainAction.responseCreateOrUpdateTodo) - .eraseToEffect() - case .responseCreateOrUpdateTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.append(todo) - case .updateTodo(let todo): - let request = MRequest { - REncoding(.json) - RUrl(urlString: environment.urlString) - .withPath(todo.id.toString()) - RMethod(.post) - Rbody(todo.toData()) - } - return request - .compactMap {$0.data} - .map(MainAction.responseUpdateTodo) - .eraseToEffect() - case .responseUpdateTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.updateOrAppend(todo) - case .deleteTodo(let todo): - let request = MRequest { - RUrl(urlString: environment.urlString) - .withPath(todo.id.toString()) - RMethod(.delete) - } - return request - .compactMap {$0.data} - .map(MainAction.reponseDeleteTodo) - .eraseToEffect() - case .reponseDeleteTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.remove(todo) - break - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift deleted file mode 100644 index 28ade31..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift +++ /dev/null @@ -1,8 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct MainState: Equatable { - var title: String = "" - var todos: IdentifiedArrayOf = [] - var isLoading: Bool = false -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift deleted file mode 100644 index f62f176..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift +++ /dev/null @@ -1,196 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import UIKit -import ConvertSwift -import Combine -import CombineCocoa - -final class MainViewController: BaseViewController { - - private let store: Store - - private let viewStore: ViewStore - - private let tableView: UITableView = UITableView() - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: MainState(), reducer: MainReducer, environment: MainEnvironment()) - self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - viewStore.send(.viewDidLoad) - // navigationView - let buttonLogout = UIButton(type: .system) - buttonLogout.setTitle("Logout", for: .normal) - buttonLogout.titleLabel?.font = UIFont.boldSystemFont(ofSize: 15) - buttonLogout.setTitleColor(UIColor(Color.blue), for: .normal) - let rightBarButtonItem = UIBarButtonItem(customView: buttonLogout) - navigationController?.navigationBar.prefersLargeTitles = true - navigationItem.largeTitleDisplayMode = .always - navigationItem.rightBarButtonItem = rightBarButtonItem - // tableView - view.addSubview(tableView) - tableView.register(MainTableViewCell.self) - tableView.register(ButtonReloadMainTableViewCell.self) - tableView.register(CreateTitleMainTableViewCell.self) - tableView.showsVerticalScrollIndicator = false - tableView.showsHorizontalScrollIndicator = false - tableView.delegate = self - tableView.dataSource = self - tableView.translatesAutoresizingMaskIntoConstraints = false - tableView.isUserInteractionEnabled = true - // contraint - NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), - tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10), - tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10), - tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10) - ]) - - //bind view to viewstore - buttonLogout.tapPublisher - .map{MainAction.logout} - .subscribe(viewStore.action) - .store(in: &cancellables) - - //bind viewstore to view - viewStore.publisher.todos - .sink { [weak self] _ in - guard let self = self else { - return - } - self.tableView.reloadData() - } - .store(in: &cancellables) - - viewStore.publisher.todos - .map {$0.count.toString() + " Todos"} - .assign(to: \.navigationItem.title, on: self) - .store(in: &cancellables) - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - viewStore.send(.viewWillAppear) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - viewStore.send(.viewWillDisappear) - } - - deinit { - viewStore.send(.viewDeinit) - } -} - -// MARK: - UITableViewDataSource -extension MainViewController: UITableViewDataSource { - func numberOfSections(in tableView: UITableView) -> Int { - return 3 - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 0: - return 1 - case 1: - return 1 - case 2: - return viewStore.todos.count - default: - return 0 - } - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.section { - case 0: - let cell = tableView.dequeueReusableCell(ButtonReloadMainTableViewCell.self, for: indexPath) - cell.selectionStyle = .none - viewStore.publisher.isLoading - .sink(receiveValue: { value in - cell.buttonReload.isHidden = value - if value { - cell.activityIndicator.startAnimating() - } else { - cell.activityIndicator.stopAnimating() - } - }) - .store(in: &cell.cancellables) - cell.buttonReload - .tapPublisher - .map{MainAction.viewReloadTodo} - .subscribe(viewStore.action) - .store(in: &cell.cancellables) - return cell - case 1: - let cell = tableView.dequeueReusableCell(CreateTitleMainTableViewCell.self, for: indexPath) - viewStore.publisher.title - .map {$0} - .assign(to: \.text, on: cell.titleTextField) - .store(in: &cell.cancellables) - viewStore.publisher.title.isEmpty - .sink(receiveValue: { value in - cell.createButton.setTitleColor(value ? UIColor(Color.gray) : UIColor(Color.green), for: .normal) - }) - .store(in: &cell.cancellables) - cell.createButton - .tapPublisher - .map {MainAction.viewCreateTodo} - .subscribe(viewStore.action) - .store(in: &cell.cancellables) - cell.titleTextField - .textPublisher - .compactMap{$0} - .map{MainAction.changeText($0)} - .subscribe(viewStore.action) - .store(in: &cell.cancellables) - return cell - case 2: - let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) - let todo = viewStore.todos[indexPath.row] - cell.bind(todo) - cell.deleteButton - .tapPublisher - .map{MainAction.viewDeleteTodo(todo)} - .subscribe(viewStore.action) - .store(in: &cell.cancellables) - cell.tapGesture - .tapPublisher - .map {_ in MainAction.viewToggleTodo(todo)} - .subscribe(viewStore.action) - .store(in: &cell.cancellables) - return cell - default: - let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) - return cell - } - } -} - - // MARK: - UITableViewDelegate -extension MainViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 60 - } -} - // MARK: - PreviewProvider -struct MainViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = MainViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift deleted file mode 100644 index 675506b..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift +++ /dev/null @@ -1,11 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum RootAction: Equatable { - case authAction(AuthAction) - case mainAction(MainAction) - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case none -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift deleted file mode 100644 index b7caae1..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct RootEnvironment { - -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift deleted file mode 100644 index 06e5b96..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift +++ /dev/null @@ -1,30 +0,0 @@ -import ComposableArchitecture -import Foundation - -let RootReducer = Reducer.combine( - AuthReducer.pullback(state: \.authState, action: /RootAction.authAction, environment: { _ in - .init() - }), - MainReducer.pullback(state: \.mainState, action: /RootAction.mainAction, environment: { _ in - .init() - }), - Reducer { state, action, environment in - switch action { - case .authAction(.changeRootScreen(let screen)): - state.rootScreen = screen - case .mainAction(.changeRootScreen(let screen)): - state = RootState() - state.rootScreen = screen - case .viewDidLoad: - break - case .viewWillAppear: - break - case .viewWillDisappear: - break - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift deleted file mode 100644 index b0b3276..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift +++ /dev/null @@ -1,13 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct RootState: Equatable { - var authState = AuthState() - var mainState = MainState() - var rootScreen: RootScreen = .main -} - -enum RootScreen: Equatable { - case main - case auth -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift deleted file mode 100644 index 6649939..0000000 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift +++ /dev/null @@ -1,71 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import UIKit -import Combine - -final class RootViewController: BaseViewController { - - private let store: Store - - private let viewStore: ViewStore - - private var viewController = UIViewController() { - willSet { - viewController.willMove(toParent: nil) - viewController.view.removeFromSuperview() - viewController.removeFromParent() - addChild(newValue) - newValue.view.frame = self.view.frame - view.addSubview(newValue.view) - newValue.didMove(toParent: self) - } - } - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: RootState(), reducer: RootReducer, environment: RootEnvironment()) - self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - viewStore.send(.viewDidLoad) - //bind view to viewstore - viewStore.publisher.rootScreen.sink { [weak self] screen in - guard let self = self else {return} - switch screen { - case .main: - let vc = MainViewController(store: self.store.scope(state: \.mainState, action: RootAction.mainAction)) - let nav = UINavigationController(rootViewController: vc) - self.viewController = nav - case .auth: - let vc = AuthViewController(store: self.store.scope(state: \.authState, action: RootAction.authAction)) - let nav = UINavigationController(rootViewController: vc) - self.viewController = nav - } - } - .store(in: &cancellables) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - viewStore.send(.viewWillAppear) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - viewStore.send(.viewWillDisappear) - } -} - -struct RootViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = RootViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } -} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift similarity index 78% rename from BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift rename to BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift index 30bece7..3590953 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift @@ -1,7 +1,7 @@ import UIKit import Combine -class BaseMainTableViewCell: UITableViewCell { +class BaseTableViewCell: UITableViewCell { var cancellables: Set = [] diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift similarity index 61% rename from BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift rename to BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift index 633c254..fdebe51 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift @@ -1,7 +1,7 @@ import UIKit import Combine -class BaseViewController: UIViewController { +open class BaseViewController: UIViewController { var cancellables: Set = [] diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift index f113757..1240ba8 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/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/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift new file mode 100644 index 0000000..5ac9b58 --- /dev/null +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift @@ -0,0 +1,100 @@ +import SwiftUI +import UIKit + +struct AuthReducer: Reducer { + + struct State: Equatable { + + } + + enum Action { + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case none + case login + case changeRootScreen(RootReducer.RootScreen) + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .viewDidLoad: + break + case .viewWillAppear: + break + case .viewWillDisappear: + break + case .login: + return .send(.changeRootScreen(.main)) + default: + break + } + return .none + } + } +} + +final class AuthViewController: BaseViewController { + + private let store: StoreOf + + private var viewStore: ViewStoreOf + + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: AuthReducer.State()) { + AuthReducer() + } + self.store = unwrapStore + self.viewStore = ViewStore(unwrapStore, observe: {$0}) + super.init(nibName: nil, bundle: nil) + } + + private let action = PassthroughSubject() + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + viewStore.send(.viewDidLoad) + + action.sink { [weak self] sendAction in + self?.viewStore.send(sendAction) + } + .store(in: &cancellables) + + // buttonLogin + let buttonLogin = UIButton(type: .system) + buttonLogin.setTitle("Login", for: .normal) + buttonLogin.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(buttonLogin) + // contraint + NSLayoutConstraint.activate([ + buttonLogin.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor), + buttonLogin.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor), + ]) + + //bind view to viewstore + buttonLogin.tapPublisher + .map { AuthReducer.Action.login } +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &self.cancellables) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewStore.send(.viewWillAppear) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + viewStore.send(.viewWillDisappear) + } +} + +#Preview { + AuthViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift new file mode 100644 index 0000000..279db41 --- /dev/null +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift @@ -0,0 +1,380 @@ +import SwiftUI +import UIKit +import Combine + +struct MainReducer: Reducer { + struct State: Equatable { + var text: String = "" + var todos: IdentifiedArrayOf = [] + var isLoading: Bool = false + } + + enum Action: Equatable { + // MARK: - View Action + /// lifecycle action + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case viewDeinit + /// navigation view + case logout + case changeRootScreen(RootReducer.RootScreen) + + /// binding + case changeText(String) + /// event network + case viewCreateTodo + case viewReloadTodo + case viewToggleTodo(TodoModel) + case viewDeleteTodo(TodoModel) + // MARK: - Store Action + case resetText + /// network Action + case getTodo + case responseGetTodo(Data) + case createOrUpdateTodo(TodoModel) + case responseCreateOrUpdateTodo(Data) + case updateTodo(TodoModel) + case responseUpdateTodo(Data) + case deleteTodo(TodoModel) + case reponseDeleteTodo(Data) + // MARK: - none + case none + } + + // MARK: Dependency + @Dependency(\.uuid) var uuid + @Dependency(\.urlString) var urlString + + var body: some ReducerOf { + Reduce { state, action in + switch action { + // MARK: - View Action + case .viewDidLoad: + return .send(.viewReloadTodo) + case .viewWillAppear: + break + case .viewWillDisappear: + break + case .viewDeinit: + break + /// navigation view + case .logout: + return .send(.changeRootScreen(.auth)) + case .changeText(let text): + state.text = text + case .resetText: + state.text = "" + /// event network + case .viewCreateTodo: + if state.text.isEmpty { + return .none + } + let text = state.text + let id = UUID() + let todo = TodoModel(id: id, text: text, isCompleted: false) + return Effect.merge( + .publisher { + Just(.resetText) + .delay(for: 0.3, scheduler: UIScheduler.shared) + }, + .send(.createOrUpdateTodo(todo)) + ) + case .viewReloadTodo: + if state.isLoading { + return .none + } + state.todos.removeAll() + state.isLoading = true + return .publisher { + Just(.getTodo) + .delay(for: 0.3, scheduler: UIScheduler.shared) + } + case .viewToggleTodo(let todo): + var todo = todo + todo.isCompleted.toggle() + return .send(.updateTodo(todo)) + case .viewDeleteTodo(let todo): + return .send(.deleteTodo(todo)) + /// network action + case .getTodo: + let request = MRequest { + RMethod(.get) + RUrl(urlString) + } + return .publisher { + request + .compactMap {$0.data} + .map(Action.responseGetTodo) + } + case .responseGetTodo(let data): + state.isLoading = false + guard let todos = data.toModel([TodoModel].self) else { + return .none + } + for todo in todos { + state.todos.updateOrAppend(todo) + } + case .createOrUpdateTodo(let todo): + return .publisher { + let request = MRequest { + RUrl(urlString) + REncoding(JSONEncoding.default) + RMethod(.post) + Rbody(todo.toData()) + } + return request + .compactMap {$0.data} + .map(Action.responseCreateOrUpdateTodo) + } + case .responseCreateOrUpdateTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.append(todo) + case .updateTodo(let todo): + let request = MRequest { + REncoding(JSONEncoding.default) + RUrl(urlString) + .withPath(todo.id.toString()) + RMethod(.post) + Rbody(todo.toData()) + } + return .publisher { + request + .compactMap {$0.data} + .map(Action.responseUpdateTodo) + } + case .responseUpdateTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.updateOrAppend(todo) + case .deleteTodo(let todo): + let request = MRequest { + RUrl(urlString) + .withPath(todo.id.toString()) + RMethod(.delete) + } + return .publisher { + request + .compactMap {$0.data} + .map(Action.reponseDeleteTodo) + } + case .reponseDeleteTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.remove(todo) + break + default: + break + } + return .none + } + } + +} + +final class MainViewController: BaseViewController { + + private let store: StoreOf + + private var viewStore: ViewStoreOf + + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: MainReducer.State()) { + MainReducer() + } + self.store = unwrapStore + self.viewStore = ViewStore(unwrapStore, observe: {$0}) + super.init(nibName: nil, bundle: nil) + } + + private let tableView: UITableView = UITableView() + + private let action = PassthroughSubject() + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + viewStore.send(.viewDidLoad) + + action.sink { [weak self] sendAction in + self?.viewStore.send(sendAction) + } + .store(in: &cancellables) + + // navigationView + let buttonLogout = UIButton(type: .system) + buttonLogout.setTitle("Logout", for: .normal) + buttonLogout.titleLabel?.font = UIFont.boldSystemFont(ofSize: 15) + buttonLogout.setTitleColor(UIColor(Color.blue), for: .normal) + let rightBarButtonItem = UIBarButtonItem(customView: buttonLogout) + navigationController?.navigationBar.prefersLargeTitles = true + navigationItem.largeTitleDisplayMode = .always + navigationItem.rightBarButtonItem = rightBarButtonItem + // tableView + view.addSubview(tableView) + tableView.register(MainTableViewCell.self) + tableView.register(ButtonReloadMainTableViewCell.self) + tableView.register(CreateTitleMainTableViewCell.self) + tableView.showsVerticalScrollIndicator = false + tableView.showsHorizontalScrollIndicator = false + tableView.delegate = self + tableView.dataSource = self + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.isUserInteractionEnabled = true + // contraint + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), + tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10), + tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10), + tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10) + ]) + + //bind view to viewstore + buttonLogout.tapPublisher + .map{MainReducer.Action.logout} +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &cancellables) + + //bind viewstore to view + viewStore.publisher.todos + .sink { [weak self] _ in + guard let self = self else { + return + } + self.tableView.reloadData() + } + .store(in: &cancellables) + + viewStore.publisher.todos + .map {$0.count.toString() + " Todos"} + .assign(to: \.navigationItem.title, on: self) + .store(in: &cancellables) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewStore.send(.viewWillAppear) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + viewStore.send(.viewWillDisappear) + } + + deinit { + viewStore.send(.viewDeinit) + } +} + +// MARK: - UITableViewDataSource +extension MainViewController: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return 3 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch section { + case 0: + return 1 + case 1: + return 1 + case 2: + return viewStore.todos.count + default: + return 0 + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch indexPath.section { + case 0: + let cell = tableView.dequeueReusableCell(ButtonReloadMainTableViewCell.self, for: indexPath) + cell.selectionStyle = .none + viewStore.publisher.isLoading + .sink(receiveValue: { value in + cell.buttonReload.isHidden = value + if value { + cell.activityIndicator.startAnimating() + } else { + cell.activityIndicator.stopAnimating() + } + }) + .store(in: &cell.cancellables) + cell.buttonReload + .tapPublisher + .map{MainReducer.Action.viewReloadTodo} +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &cell.cancellables) + return cell + case 1: + let cell = tableView.dequeueReusableCell(CreateTitleMainTableViewCell.self, for: indexPath) + viewStore.publisher.text + .map {$0} + .assign(to: \.text, on: cell.titleTextField) + .store(in: &cell.cancellables) + viewStore.publisher.text.isEmpty + .sink(receiveValue: { value in + cell.createButton.setTitleColor(value ? UIColor(Color.gray) : UIColor(Color.green), for: .normal) + }) + .store(in: &cell.cancellables) + cell.createButton + .tapPublisher + .map {MainReducer.Action.viewCreateTodo} +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &cell.cancellables) + cell.titleTextField + .textPublisher + .compactMap{$0} + .map{MainReducer.Action.changeText($0)} +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &cell.cancellables) + return cell + case 2: + let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) + let todo = viewStore.todos[indexPath.row] + cell.bind(todo) + cell.deleteButton + .tapPublisher + .map{MainReducer.Action.viewDeleteTodo(todo)} +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &cell.cancellables) + cell.tapGesture + .tapPublisher + .map {_ in MainReducer.Action.viewToggleTodo(todo)} +// .subscribe(viewStore.action) + .subscribe(action) + .store(in: &cell.cancellables) + return cell + default: + let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) + return cell + } + } +} + + // MARK: - UITableViewDelegate +extension MainViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 60 + } +} + +#Preview { + MainViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift new file mode 100644 index 0000000..d735824 --- /dev/null +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift @@ -0,0 +1,120 @@ +import SwiftUI +import UIKit + +struct RootReducer: Reducer { + + struct State: Equatable { + var authState = AuthReducer.State() + var mainState = MainReducer.State() + var rootScreen: RootScreen = .main + } + + enum Action { + case authAction(AuthReducer.Action) + case mainAction(MainReducer.Action) + case viewDidLoad + case viewWillAppear + case viewWillDisappear + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .authAction(.changeRootScreen(let screen)): + state.rootScreen = screen + case .mainAction(.changeRootScreen(let screen)): + state = .init() + state.rootScreen = screen + case .viewDidLoad: + break + case .viewWillAppear: + break + case .viewWillDisappear: + break + default: + break + } + return .none + } + ._printChanges() + Scope(state: \.authState, action: /Action.authAction) { + AuthReducer() + } + Scope(state: \.mainState, action: /Action.mainAction) { + MainReducer() + } + } + + enum RootScreen: Equatable { + case main + case auth + } + +} + +final class RootViewController: BaseViewController { + + private let store: StoreOf + + private var viewStore: ViewStoreOf + + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: RootReducer.State()) { + RootReducer() + } + self.store = unwrapStore + self.viewStore = ViewStore(unwrapStore, observe: {$0}) + super.init(nibName: nil, bundle: nil) + } + + private var viewController = UIViewController() { + willSet { + viewController.willMove(toParent: nil) + viewController.view.removeFromSuperview() + viewController.removeFromParent() + addChild(newValue) + newValue.view.frame = self.view.frame + view.addSubview(newValue.view) + newValue.didMove(toParent: self) + } + } + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + viewStore.send(.viewDidLoad) + //bind view to viewstore + viewStore.publisher.rootScreen.sink { [weak self] screen in + guard let self = self else {return} + switch screen { + case .main: + let vc = MainViewController(store: self.store.scope(state: \.mainState, action: RootReducer.Action.mainAction)) + let nav = UINavigationController(rootViewController: vc) + self.viewController = nav + case .auth: + let vc = AuthViewController(store: self.store.scope(state: \.authState, action: RootReducer.Action.authAction)) + let nav = UINavigationController(rootViewController: vc) + self.viewController = nav + } + } + .store(in: &cancellables) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewStore.send(.viewWillAppear) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + viewStore.send(.viewWillDisappear) + } +} + +#Preview { + RootViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift similarity index 88% rename from BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift rename to BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift index ed1b0cd..428a0a7 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift @@ -33,3 +33,11 @@ public struct UIViewRepresented: UIViewRepresentable where UIViewTyp self.updateUIView(uiView, context) } } + +extension UIViewController { + public func toSwiftUI() -> some View { + UIViewRepresented { context in + self.view + } + } +} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift index daf11b7..f716124 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class ButtonReloadMainTableViewCell: BaseMainTableViewCell { +class ButtonReloadMainTableViewCell: BaseTableViewCell { let buttonReload = UIButton(type: .system) let activityIndicator = UIActivityIndicatorView() diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift index 4557555..83556e2 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift @@ -1,7 +1,7 @@ import UIKit import SwiftUI -class CreateTitleMainTableViewCell: BaseMainTableViewCell { +class CreateTitleMainTableViewCell: BaseTableViewCell { let createButton = UIButton(type: .system) let titleTextField = UITextField() diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift index d41bef1..7ade2f9 100644 --- a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class MainTableViewCell: BaseMainTableViewCell { +class MainTableViewCell: BaseTableViewCell { let image = UIImageView(image: UIImage(systemName: "square")) let titleView = UILabel() @@ -46,6 +46,6 @@ class MainTableViewCell: BaseMainTableViewCell { return } image.image = data.isCompleted ? UIImage(systemName: "checkmark.square") : UIImage(systemName: "square") - titleView.text = data.title + titleView.text = data.text } } diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/.DS_Store b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/.DS_Store deleted file mode 100644 index d58f2ab..0000000 Binary files a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/.DS_Store and /dev/null differ diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.pbxproj b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.pbxproj index 5aa8971..fb93cb4 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.pbxproj +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.pbxproj @@ -9,20 +9,8 @@ /* Begin PBXBuildFile section */ 87320BDA27A5AD2100360667 /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BBB27A5AD2100360667 /* TodoApp.swift */; }; 87320BDB27A5AD2100360667 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BBF27A5AD2100360667 /* MainViewController.swift */; }; - 87320BDC27A5AD2100360667 /* MainReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC027A5AD2100360667 /* MainReducer.swift */; }; - 87320BDD27A5AD2100360667 /* MainEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC127A5AD2100360667 /* MainEnvironment.swift */; }; - 87320BDE27A5AD2100360667 /* MainState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC227A5AD2100360667 /* MainState.swift */; }; - 87320BDF27A5AD2100360667 /* MainAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC327A5AD2100360667 /* MainAction.swift */; }; 87320BE027A5AD2100360667 /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC527A5AD2100360667 /* AuthViewController.swift */; }; - 87320BE127A5AD2100360667 /* AuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC627A5AD2100360667 /* AuthState.swift */; }; - 87320BE227A5AD2100360667 /* AuthReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC727A5AD2100360667 /* AuthReducer.swift */; }; - 87320BE327A5AD2100360667 /* AuthAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC827A5AD2100360667 /* AuthAction.swift */; }; - 87320BE427A5AD2100360667 /* AuthEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BC927A5AD2100360667 /* AuthEnvironment.swift */; }; - 87320BE527A5AD2100360667 /* RootAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BCB27A5AD2100360667 /* RootAction.swift */; }; - 87320BE627A5AD2100360667 /* RootEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BCC27A5AD2100360667 /* RootEnvironment.swift */; }; 87320BE727A5AD2100360667 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BCD27A5AD2100360667 /* RootViewController.swift */; }; - 87320BE827A5AD2100360667 /* RootState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BCE27A5AD2100360667 /* RootState.swift */; }; - 87320BE927A5AD2100360667 /* RootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BCF27A5AD2100360667 /* RootReducer.swift */; }; 87320BEA27A5AD2100360667 /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BD227A5AD2100360667 /* TodoModel.swift */; }; 87320BEB27A5AD2100360667 /* ButtonReloadMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BD427A5AD2100360667 /* ButtonReloadMainTableViewCell.swift */; }; 87320BEC27A5AD2100360667 /* CreateTitleMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BD527A5AD2100360667 /* CreateTitleMainTableViewCell.swift */; }; @@ -30,38 +18,28 @@ 87320BEF27A5AD2100360667 /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87320BD927A5AD2100360667 /* View+.swift */; }; 87320BF227A5AD6800360667 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87320BF127A5AD6800360667 /* ComposableArchitecture */; }; 87320BF527A5AD8500360667 /* ReactiveSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = 87320BF427A5AD8500360667 /* ReactiveSwiftRequest */; }; - 87320BF827A5ADA200360667 /* ConvertSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 87320BF727A5ADA200360667 /* ConvertSwift */; }; 87320BFB27A5ADE100360667 /* ReactiveCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 87320BFA27A5ADE100360667 /* ReactiveCocoa */; }; 876AF6CE27A5DCE6009A0148 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6CD27A5DCE6009A0148 /* BaseViewController.swift */; }; - 876AF6D027A5DD1B009A0148 /* BaseMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6CF27A5DD1B009A0148 /* BaseMainTableViewCell.swift */; }; + 876AF6D027A5DD1B009A0148 /* BaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6CF27A5DD1B009A0148 /* BaseTableViewCell.swift */; }; 87BB88FD27A59475000B269B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87BB88FC27A59475000B269B /* Assets.xcassets */; }; 87BB890027A59475000B269B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87BB88FF27A59475000B269B /* Preview Assets.xcassets */; }; + EBA4699F2ACFAE7B0060376F /* SwiftLogger in Frameworks */ = {isa = PBXBuildFile; productRef = EBA4699E2ACFAE7B0060376F /* SwiftLogger */; }; + EBA469A22ACFAE950060376F /* Json in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469A12ACFAE950060376F /* Json */; }; + EBA469A62ACFAF980060376F /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469A52ACFAF980060376F /* Transform */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 87320BBB27A5AD2100360667 /* TodoApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoApp.swift; sourceTree = ""; }; 87320BBF27A5AD2100360667 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - 87320BC027A5AD2100360667 /* MainReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainReducer.swift; sourceTree = ""; }; - 87320BC127A5AD2100360667 /* MainEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainEnvironment.swift; sourceTree = ""; }; - 87320BC227A5AD2100360667 /* MainState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainState.swift; sourceTree = ""; }; - 87320BC327A5AD2100360667 /* MainAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainAction.swift; sourceTree = ""; }; 87320BC527A5AD2100360667 /* AuthViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthViewController.swift; sourceTree = ""; }; - 87320BC627A5AD2100360667 /* AuthState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = ""; }; - 87320BC727A5AD2100360667 /* AuthReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthReducer.swift; sourceTree = ""; }; - 87320BC827A5AD2100360667 /* AuthAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthAction.swift; sourceTree = ""; }; - 87320BC927A5AD2100360667 /* AuthEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthEnvironment.swift; sourceTree = ""; }; - 87320BCB27A5AD2100360667 /* RootAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootAction.swift; sourceTree = ""; }; - 87320BCC27A5AD2100360667 /* RootEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootEnvironment.swift; sourceTree = ""; }; 87320BCD27A5AD2100360667 /* RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; - 87320BCE27A5AD2100360667 /* RootState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootState.swift; sourceTree = ""; }; - 87320BCF27A5AD2100360667 /* RootReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootReducer.swift; sourceTree = ""; }; 87320BD227A5AD2100360667 /* TodoModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoModel.swift; sourceTree = ""; }; 87320BD427A5AD2100360667 /* ButtonReloadMainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonReloadMainTableViewCell.swift; sourceTree = ""; }; 87320BD527A5AD2100360667 /* CreateTitleMainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateTitleMainTableViewCell.swift; sourceTree = ""; }; 87320BD727A5AD2100360667 /* MainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTableViewCell.swift; sourceTree = ""; }; 87320BD927A5AD2100360667 /* View+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+.swift"; sourceTree = ""; }; 876AF6CD27A5DCE6009A0148 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; - 876AF6CF27A5DD1B009A0148 /* BaseMainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseMainTableViewCell.swift; sourceTree = ""; }; + 876AF6CF27A5DD1B009A0148 /* BaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewCell.swift; sourceTree = ""; }; 87BB88F527A59474000B269B /* Todo+ReactiveSwift+UIKit(iOS13).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Todo+ReactiveSwift+UIKit(iOS13).app"; sourceTree = BUILT_PRODUCTS_DIR; }; 87BB88FC27A59475000B269B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 87BB88FF27A59475000B269B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; @@ -74,8 +52,10 @@ files = ( 87320BF227A5AD6800360667 /* ComposableArchitecture in Frameworks */, 87320BFB27A5ADE100360667 /* ReactiveCocoa in Frameworks */, + EBA469A22ACFAE950060376F /* Json in Frameworks */, + EBA469A62ACFAF980060376F /* Transform in Frameworks */, + EBA4699F2ACFAE7B0060376F /* SwiftLogger in Frameworks */, 87320BF527A5AD8500360667 /* ReactiveSwiftRequest in Frameworks */, - 87320BF827A5ADA200360667 /* ConvertSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -94,58 +74,23 @@ 87320BBC27A5AD2100360667 /* TodoApp */ = { isa = PBXGroup; children = ( - 87320BBD27A5AD2100360667 /* AppScreens */, + EBA469A32ACFAEC10060376F /* Bases */, + 87320BBD27A5AD2100360667 /* ViewControllers */, 87320BD027A5AD2100360667 /* Models */, 87320BD327A5AD2100360667 /* Views */, - 87320BD827A5AD2100360667 /* View+ */, + 87320BD827A5AD2100360667 /* ViewExt */, ); path = TodoApp; sourceTree = ""; }; - 87320BBD27A5AD2100360667 /* AppScreens */ = { - isa = PBXGroup; - children = ( - 87320BBE27A5AD2100360667 /* MainScreen */, - 87320BC427A5AD2100360667 /* AuthScreen */, - 87320BCA27A5AD2100360667 /* RootScreen */, - ); - path = AppScreens; - sourceTree = ""; - }; - 87320BBE27A5AD2100360667 /* MainScreen */ = { - isa = PBXGroup; - children = ( - 87320BBF27A5AD2100360667 /* MainViewController.swift */, - 87320BC227A5AD2100360667 /* MainState.swift */, - 87320BC327A5AD2100360667 /* MainAction.swift */, - 87320BC127A5AD2100360667 /* MainEnvironment.swift */, - 87320BC027A5AD2100360667 /* MainReducer.swift */, - ); - path = MainScreen; - sourceTree = ""; - }; - 87320BC427A5AD2100360667 /* AuthScreen */ = { + 87320BBD27A5AD2100360667 /* ViewControllers */ = { isa = PBXGroup; children = ( 87320BC527A5AD2100360667 /* AuthViewController.swift */, - 87320BC627A5AD2100360667 /* AuthState.swift */, - 87320BC827A5AD2100360667 /* AuthAction.swift */, - 87320BC927A5AD2100360667 /* AuthEnvironment.swift */, - 87320BC727A5AD2100360667 /* AuthReducer.swift */, - ); - path = AuthScreen; - sourceTree = ""; - }; - 87320BCA27A5AD2100360667 /* RootScreen */ = { - isa = PBXGroup; - children = ( 87320BCD27A5AD2100360667 /* RootViewController.swift */, - 87320BCE27A5AD2100360667 /* RootState.swift */, - 87320BCB27A5AD2100360667 /* RootAction.swift */, - 87320BCC27A5AD2100360667 /* RootEnvironment.swift */, - 87320BCF27A5AD2100360667 /* RootReducer.swift */, + 87320BBF27A5AD2100360667 /* MainViewController.swift */, ); - path = RootScreen; + path = ViewControllers; sourceTree = ""; }; 87320BD027A5AD2100360667 /* Models */ = { @@ -162,18 +107,16 @@ 87320BD427A5AD2100360667 /* ButtonReloadMainTableViewCell.swift */, 87320BD527A5AD2100360667 /* CreateTitleMainTableViewCell.swift */, 87320BD727A5AD2100360667 /* MainTableViewCell.swift */, - 876AF6CD27A5DCE6009A0148 /* BaseViewController.swift */, - 876AF6CF27A5DD1B009A0148 /* BaseMainTableViewCell.swift */, ); path = Views; sourceTree = ""; }; - 87320BD827A5AD2100360667 /* View+ */ = { + 87320BD827A5AD2100360667 /* ViewExt */ = { isa = PBXGroup; children = ( 87320BD927A5AD2100360667 /* View+.swift */, ); - path = "View+"; + path = ViewExt; sourceTree = ""; }; 87BB88EC27A59474000B269B = { @@ -181,6 +124,7 @@ children = ( 87BB88F727A59474000B269B /* Todo+ReactiveSwift+UIKit(iOS13) */, 87BB88F627A59474000B269B /* Products */, + EBA469A42ACFAF980060376F /* Frameworks */, ); sourceTree = ""; }; @@ -210,6 +154,22 @@ path = "Preview Content"; sourceTree = ""; }; + EBA469A32ACFAEC10060376F /* Bases */ = { + isa = PBXGroup; + children = ( + 876AF6CD27A5DCE6009A0148 /* BaseViewController.swift */, + 876AF6CF27A5DD1B009A0148 /* BaseTableViewCell.swift */, + ); + path = Bases; + sourceTree = ""; + }; + EBA469A42ACFAF980060376F /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -229,8 +189,10 @@ packageProductDependencies = ( 87320BF127A5AD6800360667 /* ComposableArchitecture */, 87320BF427A5AD8500360667 /* ReactiveSwiftRequest */, - 87320BF727A5ADA200360667 /* ConvertSwift */, 87320BFA27A5ADE100360667 /* ReactiveCocoa */, + EBA4699E2ACFAE7B0060376F /* SwiftLogger */, + EBA469A12ACFAE950060376F /* Json */, + EBA469A52ACFAF980060376F /* Transform */, ); productName = "Todo+ReactiveSwift+UIKit(iOS13)"; productReference = 87BB88F527A59474000B269B /* Todo+ReactiveSwift+UIKit(iOS13).app */; @@ -265,6 +227,8 @@ 87320BF327A5AD8500360667 /* XCRemoteSwiftPackageReference "Networking" */, 87320BF627A5ADA200360667 /* XCRemoteSwiftPackageReference "SwiftExtension" */, 87320BF927A5ADE100360667 /* XCRemoteSwiftPackageReference "ReactiveCocoa" */, + EBA4699D2ACFAE7B0060376F /* XCRemoteSwiftPackageReference "swift-logger" */, + EBA469A02ACFAE950060376F /* XCRemoteSwiftPackageReference "swift-json" */, ); productRefGroup = 87BB88F627A59474000B269B /* Products */; projectDirPath = ""; @@ -293,28 +257,16 @@ buildActionMask = 2147483647; files = ( 87320BDA27A5AD2100360667 /* TodoApp.swift in Sources */, - 87320BE527A5AD2100360667 /* RootAction.swift in Sources */, - 87320BE627A5AD2100360667 /* RootEnvironment.swift in Sources */, 876AF6CE27A5DCE6009A0148 /* BaseViewController.swift in Sources */, 87320BEC27A5AD2100360667 /* CreateTitleMainTableViewCell.swift in Sources */, 87320BEB27A5AD2100360667 /* ButtonReloadMainTableViewCell.swift in Sources */, - 87320BDE27A5AD2100360667 /* MainState.swift in Sources */, - 87320BDF27A5AD2100360667 /* MainAction.swift in Sources */, - 87320BE227A5AD2100360667 /* AuthReducer.swift in Sources */, - 876AF6D027A5DD1B009A0148 /* BaseMainTableViewCell.swift in Sources */, + 876AF6D027A5DD1B009A0148 /* BaseTableViewCell.swift in Sources */, 87320BEA27A5AD2100360667 /* TodoModel.swift in Sources */, 87320BE027A5AD2100360667 /* AuthViewController.swift in Sources */, 87320BEE27A5AD2100360667 /* MainTableViewCell.swift in Sources */, - 87320BDC27A5AD2100360667 /* MainReducer.swift in Sources */, - 87320BE127A5AD2100360667 /* AuthState.swift in Sources */, - 87320BDD27A5AD2100360667 /* MainEnvironment.swift in Sources */, - 87320BE927A5AD2100360667 /* RootReducer.swift in Sources */, 87320BEF27A5AD2100360667 /* View+.swift in Sources */, - 87320BE827A5AD2100360667 /* RootState.swift in Sources */, 87320BE727A5AD2100360667 /* RootViewController.swift in Sources */, 87320BDB27A5AD2100360667 /* MainViewController.swift in Sources */, - 87320BE427A5AD2100360667 /* AuthEnvironment.swift in Sources */, - 87320BE327A5AD2100360667 /* AuthAction.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -523,24 +475,24 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/FullStack-Swift/reactiveswift-composable-architecture"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; 87320BF327A5AD8500360667 /* XCRemoteSwiftPackageReference "Networking" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/FullStack-Swift/Networking"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; 87320BF627A5ADA200360667 /* XCRemoteSwiftPackageReference "SwiftExtension" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/FullStack-Swift/SwiftExtension"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; 87320BF927A5ADE100360667 /* XCRemoteSwiftPackageReference "ReactiveCocoa" */ = { @@ -551,6 +503,22 @@ version = 12.0.0; }; }; + EBA4699D2ACFAE7B0060376F /* XCRemoteSwiftPackageReference "swift-logger" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-logger"; + requirement = { + branch = main; + kind = branch; + }; + }; + EBA469A02ACFAE950060376F /* XCRemoteSwiftPackageReference "swift-json" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FullStack-Swift/swift-json"; + requirement = { + branch = main; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -564,16 +532,26 @@ package = 87320BF327A5AD8500360667 /* XCRemoteSwiftPackageReference "Networking" */; productName = ReactiveSwiftRequest; }; - 87320BF727A5ADA200360667 /* ConvertSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 87320BF627A5ADA200360667 /* XCRemoteSwiftPackageReference "SwiftExtension" */; - productName = ConvertSwift; - }; 87320BFA27A5ADE100360667 /* ReactiveCocoa */ = { isa = XCSwiftPackageProductDependency; package = 87320BF927A5ADE100360667 /* XCRemoteSwiftPackageReference "ReactiveCocoa" */; productName = ReactiveCocoa; }; + EBA4699E2ACFAE7B0060376F /* SwiftLogger */ = { + isa = XCSwiftPackageProductDependency; + package = EBA4699D2ACFAE7B0060376F /* XCRemoteSwiftPackageReference "swift-logger" */; + productName = SwiftLogger; + }; + EBA469A12ACFAE950060376F /* Json */ = { + isa = XCSwiftPackageProductDependency; + package = EBA469A02ACFAE950060376F /* XCRemoteSwiftPackageReference "swift-json" */; + productName = Json; + }; + EBA469A52ACFAF980060376F /* Transform */ = { + isa = XCSwiftPackageProductDependency; + package = 87320BF627A5ADA200360667 /* XCRemoteSwiftPackageReference "SwiftExtension" */; + productName = Transform; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 87BB88ED27A59474000B269B /* Project object */; diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 424bdaf..aeb97b0 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,133 +1,203 @@ { - "object": { - "pins": [ - { - "package": "Alamofire", - "repositoryURL": "https://github.com/Alamofire/Alamofire.git", - "state": { - "branch": null, - "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", - "version": "5.5.0" - } - }, - { - "package": "combine-schedulers", - "repositoryURL": "https://github.com/pointfreeco/combine-schedulers", - "state": { - "branch": null, - "revision": "4cf088c29a20f52be0f2ca54992b492c54e0076b", - "version": "0.5.3" - } - }, - { - "package": "Networking", - "repositoryURL": "https://github.com/FullStack-Swift/Networking", - "state": { - "branch": null, - "revision": "fdbb1c94caf8ead0a26c622e8c08cbd6f6ebb8ac", - "version": "1.0.0" - } - }, - { - "package": "ReactiveCocoa", - "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveCocoa", - "state": { - "branch": null, - "revision": "8a5b07b18c6abb8e12fb845bf742675dc4914ed8", - "version": "12.0.0" - } - }, - { - "package": "ReactiveSwift", - "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift", - "state": { - "branch": null, - "revision": "efb2f0a6f6c8739cce8fb14148a5bd3c83f2f91d", - "version": "7.0.0" - } - }, - { - "package": "reactiveswift-composable-architecture", - "repositoryURL": "https://github.com/FullStack-Swift/reactiveswift-composable-architecture", - "state": { - "branch": null, - "revision": "b7123f667c6ad50a6445badcc4e62293ec00c6e9", - "version": "1.0.0" - } - }, - { - "package": "RxSwift", - "repositoryURL": "https://github.com/ReactiveX/RxSwift.git", - "state": { - "branch": null, - "revision": "b4307ba0b6425c0ba4178e138799946c3da594f8", - "version": "6.5.0" - } - }, - { - "package": "Starscream", - "repositoryURL": "https://github.com/daltoniam/Starscream.git", - "state": { - "branch": null, - "revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version": "4.0.4" - } - }, - { - "package": "swift-case-paths", - "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", - "state": { - "branch": null, - "revision": "241301b67d8551c26d8f09bd2c0e52cc49f18007", - "version": "0.8.0" - } - }, - { - "package": "swift-collections", - "repositoryURL": "https://github.com/apple/swift-collections", - "state": { - "branch": null, - "revision": "48254824bb4248676bf7ce56014ff57b142b77eb", - "version": "1.0.2" - } - }, - { - "package": "swift-custom-dump", - "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump", - "state": { - "branch": null, - "revision": "51698ece74ecf31959d3fa81733f0a5363ef1b4e", - "version": "0.3.0" - } - }, - { - "package": "swift-identified-collections", - "repositoryURL": "https://github.com/pointfreeco/swift-identified-collections", - "state": { - "branch": null, - "revision": "680bf440178a78a627b1c2c64c0855f6523ad5b9", - "version": "0.3.2" - } - }, - { - "package": "SwiftExtension", - "repositoryURL": "https://github.com/FullStack-Swift/SwiftExtension", - "state": { - "branch": null, - "revision": "cdbd56e6cf32fa0eb97a1fba445736cbe8b8e622", - "version": "1.0.0" - } - }, - { - "package": "xctest-dynamic-overlay", - "repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state": { - "branch": null, - "revision": "50a70a9d3583fe228ce672e8923010c8df2deddd", - "version": "0.2.1" - } - } - ] - }, - "version": 1 + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "b2fa556e4e48cbf06cf8c63def138c98f4b811fa", + "version" : "5.8.0" + } + }, + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb", + "version" : "1.0.0" + } + }, + { + "identity" : "networking", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/Networking", + "state" : { + "branch" : "main", + "revision" : "23e446cfffd8a5f554fd564fc7568eeaa85843e4" + } + }, + { + "identity" : "reactivecocoa", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveCocoa/ReactiveCocoa", + "state" : { + "revision" : "8a5b07b18c6abb8e12fb845bf742675dc4914ed8", + "version" : "12.0.0" + } + }, + { + "identity" : "reactiveswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveCocoa/ReactiveSwift", + "state" : { + "revision" : "40c465af19b993344e84355c00669ba2022ca3cd", + "version" : "7.1.1" + } + }, + { + "identity" : "reactiveswift-composable-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/reactiveswift-composable-architecture", + "state" : { + "branch" : "main", + "revision" : "f0463f0b8cde504d625f755ce61dd70cbb76d61c" + } + }, + { + "identity" : "rxswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveX/RxSwift.git", + "state" : { + "revision" : "9dcaa4b333db437b0fbfaf453fad29069044a8b4", + "version" : "6.6.0" + } + }, + { + "identity" : "socket.io-client-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/socketio/socket.io-client-swift", + "state" : { + "revision" : "af5ce97b755d964235348d96f6db5cbdcbe334a5", + "version" : "16.0.1" + } + }, + { + "identity" : "starscream", + "kind" : "remoteSourceControl", + "location" : "https://github.com/daltoniam/Starscream.git", + "state" : { + "revision" : "df8d82047f6654d8e4b655d1b1525c64e1059d21", + "version" : "4.0.4" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms", + "state" : { + "revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a", + "version" : "0.1.0" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "5da6989aae464f324eef5c5b52bdb7974725ab81", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "d1fd837326aa719bee979bdde1f53cd5797443eb", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "ea631ce892687f5432a833312292b80db238186a", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "3efbfba0e4e56c7187cc19137ee16b7c95346b79", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "4e1eb6e28afe723286d8cc60611237ffbddba7c5", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8", + "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", + "location" : "https://github.com/FullStack-Swift/SwiftExtension", + "state" : { + "branch" : "main", + "revision" : "ccbf2fddb982267be28705b3dd8b29ee3c4d149e" + } + }, + { + "identity" : "swiftui-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swiftui-navigation", + "state" : { + "revision" : "6eb293c49505d86e9e24232cb6af6be7fff93bd5", + "version" : "1.0.2" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631", + "version" : "1.0.2" + } + } + ], + "version" : 2 } diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp.swift index e1b7b94..a31f7c9 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp.swift @@ -1,12 +1,23 @@ import SwiftUI -import ComposableArchitecture +@_exported import ComposableArchitecture +@_exported import MReactiveSwiftRequest +@_exported import ReactiveSwift +@_exported import ReactiveCocoa +@_exported import Transform @main struct TodoApp: App { var body: some Scene { WindowGroup { - let vc = RootViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) + RootViewController().toSwiftUI() } } } + +public extension DependencyValues { + var urlString: String { + "http://127.0.0.1:8080/todos" + } +} + +public var isUsingPublisher: Bool = true diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift deleted file mode 100644 index effce91..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift +++ /dev/null @@ -1,11 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum AuthAction: Equatable { - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case none - case login - case changeRootScreen(RootScreen) -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift deleted file mode 100644 index a96bc7e..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct AuthEnvironment { - -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift deleted file mode 100644 index 01fca41..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift +++ /dev/null @@ -1,21 +0,0 @@ -import ComposableArchitecture -import Foundation - -let AuthReducer = Reducer.combine( - Reducer { state, action, environment in - switch action { - case .viewDidLoad: - break - case .viewWillAppear: - break - case .viewWillDisappear: - break - case .login: - return Effect(value: .changeRootScreen(.main)) - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift deleted file mode 100644 index 0f0ea3d..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct AuthState: Equatable { - -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift deleted file mode 100644 index e676a5b..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift +++ /dev/null @@ -1,35 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum MainAction: Equatable { - // MARK: - View Action - /// lifecycle action - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case viewDeinit - /// navigation view - case logout - case changeRootScreen(RootScreen) - - /// binding - case changeText(String) - /// event network - case viewCreateTodo - case viewReloadTodo - case viewToggleTodo(TodoModel) - case viewDeleteTodo(TodoModel) - // MARK: - Store Action - case resetText - /// network Action - case getTodo - case responseGetTodo(Data) - case createOrUpdateTodo(TodoModel) - case responseCreateOrUpdateTodo(Data) - case updateTodo(TodoModel) - case responseUpdateTodo(Data) - case deleteTodo(TodoModel) - case reponseDeleteTodo(Data) - // MARK: - none - case none -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift deleted file mode 100644 index 179c54c..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift +++ /dev/null @@ -1,8 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct MainEnvironment { - let urlString: String = "https://todolistappproj.herokuapp.com/todos" - init() { - } -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift deleted file mode 100644 index 701d254..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift +++ /dev/null @@ -1,131 +0,0 @@ -import ComposableArchitecture -import ReactiveSwiftRequest -import ConvertSwift - -let MainReducer = Reducer.combine( - Reducer { state, action, environment in - switch action { - /// view action - case .viewDidLoad: - return Effect(value: MainAction.viewReloadTodo) - case .viewWillAppear: - break - case .viewWillDisappear: - break - case .viewDeinit: - break - /// navigation view - case .logout: - return Effect(value: MainAction.changeRootScreen(.auth)) - case .changeText(let text): - state.title = text - case .resetText: - state.title = "" - /// event network - case .viewCreateTodo: - if state.title.isEmpty { - return .none - } - var title = state.title - let id = UUID() - let todo = TodoModel(id: id, title: title, isCompleted: false) - let resetTitleEffect = Effect(value: MainAction.resetText) - .delay(0.3, on: QueueScheduler.main) - .eraseToEffect() - return Effect.merge( - resetTitleEffect, - Effect(value: MainAction.createOrUpdateTodo(todo)) - ) - case .viewReloadTodo: - if state.isLoading { - return .none - } - state.todos.removeAll() - state.isLoading = true - return Effect(value: MainAction.getTodo) - .delay(0.3, on: QueueScheduler.main) - .eraseToEffect() - case .viewToggleTodo(let todo): - var todo = todo - todo.isCompleted.toggle() - return Effect(value: MainAction.updateTodo(todo)) - case .viewDeleteTodo(let todo): - return Effect(value: MainAction.deleteTodo(todo)) - /// network action - case .getTodo: - let request = MRequest { - RMethod(.get) - RUrl(urlString: environment.urlString) - } - return request - .producer - .compactMap {$0.data} - .map(MainAction.responseGetTodo) - .eraseToEffect() - case .responseGetTodo(let data): - state.isLoading = false - guard let todos = data.toModel([TodoModel].self) else { - return .none - } - for todo in todos { - state.todos.updateOrAppend(todo) - } - case .createOrUpdateTodo(let todo): - let request = MRequest { - RUrl(urlString: environment.urlString) - REncoding(.json) - RMethod(.post) - Rbody(todo.toData()) - } - return request - .producer - .compactMap {$0.data} - .map(MainAction.responseCreateOrUpdateTodo) - .eraseToEffect() - case .responseCreateOrUpdateTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.append(todo) - case .updateTodo(let todo): - let request = MRequest { - REncoding(.json) - RUrl(urlString: environment.urlString) - .withPath(todo.id.toString()) - RMethod(.post) - Rbody(todo.toData()) - } - return request - .producer - .compactMap {$0.data} - .map(MainAction.responseUpdateTodo) - .eraseToEffect() - case .responseUpdateTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.updateOrAppend(todo) - case .deleteTodo(let todo): - let request = MRequest { - RUrl(urlString: environment.urlString) - .withPath(todo.id.toString()) - RMethod(.delete) - } - return request - .producer - .compactMap {$0.data} - .map(MainAction.reponseDeleteTodo) - .eraseToEffect() - case .reponseDeleteTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.remove(todo) - break - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift deleted file mode 100644 index 28ade31..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift +++ /dev/null @@ -1,8 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct MainState: Equatable { - var title: String = "" - var todos: IdentifiedArrayOf = [] - var isLoading: Bool = false -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift deleted file mode 100644 index abedb91..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift +++ /dev/null @@ -1,154 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import UIKit -import ConvertSwift -import ReactiveCocoa - -final class MainViewController: BaseViewController { - - private let store: Store - - private let viewStore: ViewStore - - private let tableView: UITableView = UITableView() - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: MainState(), reducer: MainReducer, environment: MainEnvironment()) - self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - viewStore.send(.viewDidLoad) - // navigationView - let buttonLogout = UIButton(type: .system) - buttonLogout.setTitle("Logout", for: .normal) - buttonLogout.titleLabel?.font = UIFont.boldSystemFont(ofSize: 15) - buttonLogout.setTitleColor(UIColor(Color.blue), for: .normal) - let rightBarButtonItem = UIBarButtonItem(customView: buttonLogout) - navigationController?.navigationBar.prefersLargeTitles = true - navigationItem.largeTitleDisplayMode = .always - navigationItem.rightBarButtonItem = rightBarButtonItem - // tableView - view.addSubview(tableView) - tableView.register(MainTableViewCell.self) - tableView.register(ButtonReloadMainTableViewCell.self) - tableView.register(CreateTitleMainTableViewCell.self) - tableView.showsVerticalScrollIndicator = false - tableView.showsHorizontalScrollIndicator = false - tableView.delegate = self - tableView.dataSource = self - tableView.translatesAutoresizingMaskIntoConstraints = false - tableView.isUserInteractionEnabled = true - // contraint - NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), - tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10), - tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10), - tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10) - ]) - - //bind view to viewstore - disposables += viewStore.action <~ buttonLogout.reactive.controlEvents(.touchUpInside).map {_ in MainAction.logout} - - //bind viewstore to view - disposables += viewStore.publisher.todos.producer - .startWithValues({ [weak self] _ in - guard let self = self else {return} - self.tableView.reloadData() - }) - disposables += reactive.title <~ viewStore.publisher.todos.count.producer.map {$0.toString() + " Todos"} - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - viewStore.send(.viewWillAppear) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - viewStore.send(.viewWillDisappear) - } - - deinit { - viewStore.send(.viewDeinit) - } -} - -extension MainViewController: UITableViewDataSource { - func numberOfSections(in tableView: UITableView) -> Int { - return 3 - } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 0: - return 1 - case 1: - return 1 - case 2: - return viewStore.todos.count - default: - return 0 - } - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.section { - case 0: - let cell = tableView.dequeueReusableCell(ButtonReloadMainTableViewCell.self, for: indexPath) - cell.selectionStyle = .none - cell.disposables += viewStore.publisher.isLoading.producer.startWithValues({ value in - cell.buttonReload.isHidden = value - if value { - cell.activityIndicator.startAnimating() - } else { - cell.activityIndicator.stopAnimating() - } - }) - cell.disposables += viewStore.action <~ cell.buttonReload.reactive.controlEvents(.touchUpInside).map {_ in MainAction.viewReloadTodo} - return cell - case 1: - let cell = tableView.dequeueReusableCell(CreateTitleMainTableViewCell.self, for: indexPath) - cell.disposables += cell.titleTextField.reactive.text <~ viewStore.publisher.title.producer - cell.disposables += viewStore.publisher.title.isEmpty.producer.startWithValues { value in - cell.createButton.setTitleColor(value ? UIColor(Color.gray) : UIColor(Color.green), for: .normal) - } - cell.disposables += viewStore.action <~ cell.createButton.reactive.controlEvents(.touchUpInside).map {_ in MainAction.viewCreateTodo} - cell.disposables += viewStore.action <~ cell.titleTextField.reactive.continuousTextValues.map {MainAction.changeText($0)} - return cell - case 2: - let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) - let todo = viewStore.todos[indexPath.row] - cell.bind(todo) - cell.disposables += viewStore.action <~ cell.deleteButton.reactive.controlEvents(.touchUpInside).map { _ in MainAction.viewDeleteTodo(todo)} - cell.disposables += viewStore.action <~ cell.tapGesture.reactive.stateChanged.map { _ in MainAction.viewToggleTodo(todo)} - return cell - default: - let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) - return cell - } - } -} - -extension MainViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 60 - } -} - -struct MainViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = MainViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift deleted file mode 100644 index 675506b..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift +++ /dev/null @@ -1,11 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum RootAction: Equatable { - case authAction(AuthAction) - case mainAction(MainAction) - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case none -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift deleted file mode 100644 index b7caae1..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct RootEnvironment { - -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift deleted file mode 100644 index 06e5b96..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift +++ /dev/null @@ -1,30 +0,0 @@ -import ComposableArchitecture -import Foundation - -let RootReducer = Reducer.combine( - AuthReducer.pullback(state: \.authState, action: /RootAction.authAction, environment: { _ in - .init() - }), - MainReducer.pullback(state: \.mainState, action: /RootAction.mainAction, environment: { _ in - .init() - }), - Reducer { state, action, environment in - switch action { - case .authAction(.changeRootScreen(let screen)): - state.rootScreen = screen - case .mainAction(.changeRootScreen(let screen)): - state = RootState() - state.rootScreen = screen - case .viewDidLoad: - break - case .viewWillAppear: - break - case .viewWillDisappear: - break - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift deleted file mode 100644 index b0b3276..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift +++ /dev/null @@ -1,13 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct RootState: Equatable { - var authState = AuthState() - var mainState = MainState() - var rootScreen: RootScreen = .main -} - -enum RootScreen: Equatable { - case main - case auth -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift deleted file mode 100644 index 9adca22..0000000 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift +++ /dev/null @@ -1,68 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import UIKit - -final class RootViewController: BaseViewController { - - private let store: Store - - private let viewStore: ViewStore - - private var viewController = UIViewController() { - willSet { - viewController.willMove(toParent: nil) - viewController.view.removeFromSuperview() - viewController.removeFromParent() - addChild(newValue) - newValue.view.frame = self.view.frame - view.addSubview(newValue.view) - newValue.didMove(toParent: self) - } - } - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: RootState(), reducer: RootReducer, environment: RootEnvironment()) - self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - viewStore.send(.viewDidLoad) - //bind view to viewstore - disposables += viewStore.publisher.rootScreen.producer.startWithValues { [weak self] screen in - guard let self = self else {return} - switch screen { - case .main: - let vc = MainViewController(store: self.store.scope(state: \.mainState, action: RootAction.mainAction)) - let nav = UINavigationController(rootViewController: vc) - self.viewController = nav - case .auth: - let vc = AuthViewController(store: self.store.scope(state: \.authState, action: RootAction.authAction)) - self.viewController = vc - } - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - viewStore.send(.viewWillAppear) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - viewStore.send(.viewWillDisappear) - } -} - -struct RootViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = RootViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } -} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift similarity index 83% rename from BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift rename to BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift index 97ace3d..6e54d26 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift @@ -1,7 +1,7 @@ import UIKit import ReactiveSwift -class BaseMainTableViewCell: UITableViewCell { +class BaseTableViewCell: UITableViewCell { private(set) var disposables = CompositeDisposable() diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift similarity index 100% rename from BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift rename to BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift index f113757..1240ba8 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/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/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift similarity index 54% rename from BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift rename to BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift index ab56568..75b56f8 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift @@ -1,19 +1,53 @@ -import ComposableArchitecture import SwiftUI import UIKit -import ReactiveSwift -import ReactiveCocoa + +struct AuthReducer: Reducer { + + struct State: Equatable { + + } + + enum Action { + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case none + case login + case changeRootScreen(RootReducer.RootScreen) + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .viewDidLoad: + break + case .viewWillAppear: + break + case .viewWillDisappear: + break + case .login: + return .send(.changeRootScreen(.main)) + default: + break + } + return .none + } + } + +} final class AuthViewController: BaseViewController { - private let store: Store + private let store: StoreOf - private let viewStore: ViewStore + private var viewStore: ViewStoreOf - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: AuthState(), reducer: AuthReducer, environment: AuthEnvironment()) + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: AuthReducer.State()) { + AuthReducer() + } self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) + self.viewStore = ViewStore(unwrapStore, observe: {$0}) super.init(nibName: nil, bundle: nil) } @@ -36,7 +70,7 @@ final class AuthViewController: BaseViewController { ]) //bind view to viewstore - disposables += viewStore.action <~ buttonLogin.reactive.controlEvents(.touchUpInside).map{_ in AuthAction.login} + disposables += viewStore.action <~ buttonLogin.reactive.controlEvents(.touchUpInside).map{_ in AuthReducer.Action.login} } override func viewWillAppear(_ animated: Bool) { @@ -50,9 +84,6 @@ final class AuthViewController: BaseViewController { } } -struct AuthViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = AuthViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } +#Preview { + AuthViewController().toSwiftUI() } diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift new file mode 100644 index 0000000..2c76159 --- /dev/null +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift @@ -0,0 +1,328 @@ +import SwiftUI +import UIKit + +struct MainReducer: Reducer { + + struct State: Equatable { + var text: String = "" + var todos: IdentifiedArrayOf = [] + var isLoading: Bool = false + } + + enum Action { + // MARK: - View Action + /// lifecycle action + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case viewDeinit + /// navigation view + case logout + case changeRootScreen(RootReducer.RootScreen) + + /// binding + case changeText(String) + /// event network + case viewCreateTodo + case viewReloadTodo + case viewToggleTodo(TodoModel) + case viewDeleteTodo(TodoModel) + // MARK: - Store Action + case resetText + /// network Action + case getTodo + case responseGetTodo(Data) + case createOrUpdateTodo(TodoModel) + case responseCreateOrUpdateTodo(Data) + case updateTodo(TodoModel) + case responseUpdateTodo(Data) + case deleteTodo(TodoModel) + case reponseDeleteTodo(Data) + // MARK: - none + case none + } + + // MARK: Dependency + @Dependency(\.uuid) var uuid + @Dependency(\.urlString) var urlString + + var body: some ReducerOf { + Reduce { state, action in + switch action { + /// view action + case .viewDidLoad: + return .send(.viewReloadTodo) + case .viewWillAppear: + break + case .viewWillDisappear: + break + case .viewDeinit: + break + /// navigation view + case .logout: + return .send(.changeRootScreen(.auth)) + case .changeText(let text): + state.text = text + case .resetText: + state.text = "" + /// event network + case .viewCreateTodo: + if state.text.isEmpty { + return .none + } + let text = state.text + let id = UUID() + let todo = TodoModel(id: id, text: text, isCompleted: false) + return Effect.merge( + .publisher { + SignalProducer(value: MainReducer.Action.resetText) + .delay(0.3, on: QueueScheduler.main) + }, + .send(.createOrUpdateTodo(todo)) + ) + case .viewReloadTodo: + if state.isLoading { + return .none + } + state.todos.removeAll() + state.isLoading = true + return .publisher { + SignalProducer(value: MainReducer.Action.getTodo) + .delay(0.3, on: QueueScheduler.main) + } + case .viewToggleTodo(let todo): + var todo = todo + todo.isCompleted.toggle() + return .send(.updateTodo(todo)) + case .viewDeleteTodo(let todo): + return .send(.deleteTodo(todo)) + /// network action + case .getTodo: + let request = MRequest { + RMethod(.get) + RUrl(urlString) + } + return .publisher { + request + .producer + .compactMap {$0.data} + .map(Action.responseGetTodo) + } + case .responseGetTodo(let data): + state.isLoading = false + guard let todos = data.toModel([TodoModel].self) else { + return .none + } + for todo in todos { + state.todos.updateOrAppend(todo) + } + case .createOrUpdateTodo(let todo): + return .publisher { + let request = MRequest { + RUrl(urlString) + REncoding(JSONEncoding.default) + RMethod(.post) + Rbody(todo.toData()) + } + return request + .producer + .compactMap {$0.data} + .map(Action.responseCreateOrUpdateTodo) + } + case .responseCreateOrUpdateTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.append(todo) + case .updateTodo(let todo): + let request = MRequest { + REncoding(JSONEncoding.default) + RUrl(urlString) + .withPath(todo.id.toString()) + RMethod(.post) + Rbody(todo.toData()) + } + return .publisher { + request + .producer + .compactMap {$0.data} + .map(Action.responseUpdateTodo) + } + case .responseUpdateTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.updateOrAppend(todo) + case .deleteTodo(let todo): + let request = MRequest { + RUrl(urlString) + .withPath(todo.id.toString()) + RMethod(.delete) + } + return .publisher { + request + .producer + .compactMap {$0.data} + .map(Action.reponseDeleteTodo) + } + case .reponseDeleteTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.remove(todo) + break + default: + break + } + return .none + } + } +} + +final class MainViewController: BaseViewController { + + private let store: StoreOf + + private var viewStore: ViewStoreOf + + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: MainReducer.State()) { + MainReducer() + } + self.store = unwrapStore + self.viewStore = ViewStore(unwrapStore, observe: {$0}) + super.init(nibName: nil, bundle: nil) + } + + private let tableView: UITableView = UITableView() + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + viewStore.send(.viewDidLoad) + // navigationView + let buttonLogout = UIButton(type: .system) + buttonLogout.setTitle("Logout", for: .normal) + buttonLogout.titleLabel?.font = UIFont.boldSystemFont(ofSize: 15) + buttonLogout.setTitleColor(UIColor(Color.blue), for: .normal) + let rightBarButtonItem = UIBarButtonItem(customView: buttonLogout) + navigationController?.navigationBar.prefersLargeTitles = true + navigationItem.largeTitleDisplayMode = .always + navigationItem.rightBarButtonItem = rightBarButtonItem + // tableView + view.addSubview(tableView) + tableView.register(MainTableViewCell.self) + tableView.register(ButtonReloadMainTableViewCell.self) + tableView.register(CreateTitleMainTableViewCell.self) + tableView.showsVerticalScrollIndicator = false + tableView.showsHorizontalScrollIndicator = false + tableView.delegate = self + tableView.dataSource = self + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.isUserInteractionEnabled = true + // contraint + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), + tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10), + tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10), + tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10) + ]) + + //bind view to viewstore + disposables += viewStore.action <~ buttonLogout.reactive.controlEvents(.touchUpInside).map {_ in MainReducer.Action.logout} + + //bind viewstore to view + disposables += viewStore.publisher.todos.producer + .startWithValues({ [weak self] _ in + guard let self = self else {return} + self.tableView.reloadData() + }) + disposables += reactive.title <~ viewStore.publisher.todos.count.producer.map {$0.toString() + " Todos"} + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewStore.send(.viewWillAppear) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + viewStore.send(.viewWillDisappear) + } + + deinit { + viewStore.send(.viewDeinit) + } +} + +extension MainViewController: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return 3 + } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch section { + case 0: + return 1 + case 1: + return 1 + case 2: + return viewStore.todos.count + default: + return 0 + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch indexPath.section { + case 0: + let cell = tableView.dequeueReusableCell(ButtonReloadMainTableViewCell.self, for: indexPath) + cell.selectionStyle = .none + cell.disposables += viewStore.publisher.isLoading.producer.startWithValues({ value in + cell.buttonReload.isHidden = value + if value { + cell.activityIndicator.startAnimating() + } else { + cell.activityIndicator.stopAnimating() + } + }) + cell.disposables += viewStore.action <~ cell.buttonReload.reactive.controlEvents(.touchUpInside).map {_ in MainReducer.Action.viewReloadTodo} + return cell + case 1: + let cell = tableView.dequeueReusableCell(CreateTitleMainTableViewCell.self, for: indexPath) + cell.disposables += cell.titleTextField.reactive.text <~ viewStore.publisher.text.producer + cell.disposables += viewStore.publisher.text.isEmpty.producer.startWithValues { value in + cell.createButton.setTitleColor(value ? UIColor(Color.gray) : UIColor(Color.green), for: .normal) + } + cell.disposables += viewStore.action <~ cell.createButton.reactive.controlEvents(.touchUpInside).map {_ in MainReducer.Action.viewCreateTodo} + cell.disposables += viewStore.action <~ cell.titleTextField.reactive.continuousTextValues.map {MainReducer.Action.changeText($0)} + return cell + case 2: + let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) + let todo = viewStore.todos[indexPath.row] + cell.bind(todo) + cell.disposables += viewStore.action <~ cell.deleteButton.reactive.controlEvents(.touchUpInside).map { _ in MainReducer.Action.viewDeleteTodo(todo)} + cell.disposables += viewStore.action <~ cell.tapGesture.reactive.stateChanged.map { _ in MainReducer.Action.viewToggleTodo(todo)} + return cell + default: + let cell = tableView.dequeueReusableCell(MainTableViewCell.self, for: indexPath) + return cell + } + } +} + +extension MainViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 60 + } +} + +#Preview { + MainViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift new file mode 100644 index 0000000..1a8506b --- /dev/null +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift @@ -0,0 +1,119 @@ +import SwiftUI +import UIKit + +struct RootReducer: Reducer { + struct State: Equatable { + var authState = AuthReducer.State() + var mainState = MainReducer.State() + var rootScreen: RootScreen = .main + } + + enum Action { + case authAction(AuthReducer.Action) + case mainAction(MainReducer.Action) + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case none + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .authAction(.changeRootScreen(let screen)): + state.rootScreen = screen + case .mainAction(.changeRootScreen(let screen)): + state = .init() + state.rootScreen = screen + case .viewDidLoad: + break + case .viewWillAppear: + break + case .viewWillDisappear: + break + default: + break + } + return .none + } + ._printChanges() + Scope(state: \.authState, action: /Action.authAction) { + AuthReducer() + } + Scope(state: \.mainState, action: /Action.mainAction) { + MainReducer() + } + } + + + enum RootScreen: Equatable { + case main + case auth + } + +} + +final class RootViewController: BaseViewController { + + private let store: StoreOf + + private var viewStore: ViewStoreOf + + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: RootReducer.State()) { + RootReducer() + } + self.store = unwrapStore + self.viewStore = ViewStore(unwrapStore, observe: {$0}) + super.init(nibName: nil, bundle: nil) + } + + private var viewController = UIViewController() { + willSet { + viewController.willMove(toParent: nil) + viewController.view.removeFromSuperview() + viewController.removeFromParent() + addChild(newValue) + newValue.view.frame = self.view.frame + view.addSubview(newValue.view) + newValue.didMove(toParent: self) + } + } + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + viewStore.send(.viewDidLoad) + //bind view to viewstore + disposables += viewStore.publisher.rootScreen.producer.startWithValues { [weak self] screen in + guard let self = self else {return} + switch screen { + case .main: + let vc = MainViewController(store: self.store.scope(state: \.mainState, action: RootReducer.Action.mainAction)) + let nav = UINavigationController(rootViewController: vc) + self.viewController = nav + case .auth: + let vc = AuthViewController(store: self.store.scope(state: \.authState, action: RootReducer.Action.authAction)) + self.viewController = vc + } + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewStore.send(.viewWillAppear) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + viewStore.send(.viewWillDisappear) + } +} + +#Preview { + RootViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift similarity index 100% rename from BasicApp/UIKit13+/Todo+Combine+UIKit(iOS13)/Todo+Combine+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift rename to BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift index daf11b7..f716124 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class ButtonReloadMainTableViewCell: BaseMainTableViewCell { +class ButtonReloadMainTableViewCell: BaseTableViewCell { let buttonReload = UIButton(type: .system) let activityIndicator = UIActivityIndicatorView() diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift index ad5437b..18bb405 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift @@ -1,7 +1,6 @@ import UIKit -import SwiftUI -class CreateTitleMainTableViewCell: BaseMainTableViewCell { +class CreateTitleMainTableViewCell: BaseTableViewCell { let createButton = UIButton(type: .system) let titleTextField = UITextField() @@ -13,7 +12,7 @@ class CreateTitleMainTableViewCell: BaseMainTableViewCell { // createButton createButton.setTitle("Create", for: .normal) createButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17) - createButton.setTitleColor(UIColor(Color.green), for: .normal) + createButton.setTitleColor(UIColor.green, for: .normal) createButton.translatesAutoresizingMaskIntoConstraints = false // titleTextField titleTextField.placeholder = "title" diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift index d41bef1..7ade2f9 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class MainTableViewCell: BaseMainTableViewCell { +class MainTableViewCell: BaseTableViewCell { let image = UIImageView(image: UIImage(systemName: "square")) let titleView = UILabel() @@ -46,6 +46,6 @@ class MainTableViewCell: BaseMainTableViewCell { return } image.image = data.isCompleted ? UIImage(systemName: "checkmark.square") : UIImage(systemName: "square") - titleView.text = data.title + titleView.text = data.text } } diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.pbxproj b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.pbxproj index 812b4b6..e5144bb 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.pbxproj +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.pbxproj @@ -8,55 +8,31 @@ /* Begin PBXBuildFile section */ 876AF6D227A5E1D8009A0148 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6D127A5E1D8009A0148 /* BaseViewController.swift */; }; - 876AF6D427A5E211009A0148 /* BaseMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6D327A5E211009A0148 /* BaseMainTableViewCell.swift */; }; + 876AF6D427A5E211009A0148 /* BaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 876AF6D327A5E211009A0148 /* BaseTableViewCell.swift */; }; 87767A4727A5B237002659D6 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 87767A4627A5B237002659D6 /* ComposableArchitecture */; }; - 87767A4D27A5B27A002659D6 /* ConvertSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 87767A4C27A5B27A002659D6 /* ConvertSwift */; }; 87767A6E27A5B2E8002659D6 /* TodoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A4F27A5B2E8002659D6 /* TodoApp.swift */; }; 87767A6F27A5B2E9002659D6 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5327A5B2E8002659D6 /* MainViewController.swift */; }; - 87767A7027A5B2E9002659D6 /* MainReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5427A5B2E8002659D6 /* MainReducer.swift */; }; - 87767A7127A5B2E9002659D6 /* MainEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5527A5B2E8002659D6 /* MainEnvironment.swift */; }; - 87767A7227A5B2E9002659D6 /* MainState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5627A5B2E8002659D6 /* MainState.swift */; }; - 87767A7327A5B2E9002659D6 /* MainAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5727A5B2E8002659D6 /* MainAction.swift */; }; 87767A7427A5B2E9002659D6 /* AuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5927A5B2E8002659D6 /* AuthViewController.swift */; }; - 87767A7527A5B2E9002659D6 /* AuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5A27A5B2E8002659D6 /* AuthState.swift */; }; - 87767A7627A5B2E9002659D6 /* AuthReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5B27A5B2E8002659D6 /* AuthReducer.swift */; }; - 87767A7727A5B2E9002659D6 /* AuthAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5C27A5B2E8002659D6 /* AuthAction.swift */; }; - 87767A7827A5B2E9002659D6 /* AuthEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5D27A5B2E8002659D6 /* AuthEnvironment.swift */; }; - 87767A7927A5B2E9002659D6 /* RootAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A5F27A5B2E8002659D6 /* RootAction.swift */; }; - 87767A7A27A5B2E9002659D6 /* RootEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6027A5B2E8002659D6 /* RootEnvironment.swift */; }; 87767A7B27A5B2E9002659D6 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6127A5B2E8002659D6 /* RootViewController.swift */; }; - 87767A7C27A5B2E9002659D6 /* RootState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6227A5B2E8002659D6 /* RootState.swift */; }; - 87767A7D27A5B2E9002659D6 /* RootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6327A5B2E8002659D6 /* RootReducer.swift */; }; 87767A7E27A5B2E9002659D6 /* TodoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6627A5B2E8002659D6 /* TodoModel.swift */; }; 87767A7F27A5B2E9002659D6 /* ButtonReloadMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6827A5B2E8002659D6 /* ButtonReloadMainTableViewCell.swift */; }; 87767A8027A5B2E9002659D6 /* CreateTitleMainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6927A5B2E8002659D6 /* CreateTitleMainTableViewCell.swift */; }; 87767A8227A5B2E9002659D6 /* MainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6B27A5B2E8002659D6 /* MainTableViewCell.swift */; }; 87767A8327A5B2E9002659D6 /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87767A6D27A5B2E8002659D6 /* View+.swift */; }; 87767A8627A5B324002659D6 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 87767A8527A5B324002659D6 /* RxCocoa */; }; - 87767A8927A5B34F002659D6 /* RxSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = 87767A8827A5B34F002659D6 /* RxSwiftRequest */; }; 87BB893127A5949A000B269B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87BB893027A5949A000B269B /* Assets.xcassets */; }; 87BB893427A5949A000B269B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87BB893327A5949A000B269B /* Preview Assets.xcassets */; }; + EBA469992ACFA74D0060376F /* Transform in Frameworks */ = {isa = PBXBuildFile; productRef = EBA469982ACFA74D0060376F /* Transform */; }; + EBA4699B2ACFA7880060376F /* RxSwiftRequest in Frameworks */ = {isa = PBXBuildFile; productRef = EBA4699A2ACFA7880060376F /* RxSwiftRequest */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 876AF6D127A5E1D8009A0148 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; - 876AF6D327A5E211009A0148 /* BaseMainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseMainTableViewCell.swift; sourceTree = ""; }; + 876AF6D327A5E211009A0148 /* BaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewCell.swift; sourceTree = ""; }; 87767A4F27A5B2E8002659D6 /* TodoApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoApp.swift; sourceTree = ""; }; 87767A5327A5B2E8002659D6 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - 87767A5427A5B2E8002659D6 /* MainReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainReducer.swift; sourceTree = ""; }; - 87767A5527A5B2E8002659D6 /* MainEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainEnvironment.swift; sourceTree = ""; }; - 87767A5627A5B2E8002659D6 /* MainState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainState.swift; sourceTree = ""; }; - 87767A5727A5B2E8002659D6 /* MainAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainAction.swift; sourceTree = ""; }; 87767A5927A5B2E8002659D6 /* AuthViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthViewController.swift; sourceTree = ""; }; - 87767A5A27A5B2E8002659D6 /* AuthState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = ""; }; - 87767A5B27A5B2E8002659D6 /* AuthReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthReducer.swift; sourceTree = ""; }; - 87767A5C27A5B2E8002659D6 /* AuthAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthAction.swift; sourceTree = ""; }; - 87767A5D27A5B2E8002659D6 /* AuthEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthEnvironment.swift; sourceTree = ""; }; - 87767A5F27A5B2E8002659D6 /* RootAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootAction.swift; sourceTree = ""; }; - 87767A6027A5B2E8002659D6 /* RootEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootEnvironment.swift; sourceTree = ""; }; 87767A6127A5B2E8002659D6 /* RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; - 87767A6227A5B2E8002659D6 /* RootState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootState.swift; sourceTree = ""; }; - 87767A6327A5B2E8002659D6 /* RootReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootReducer.swift; sourceTree = ""; }; 87767A6627A5B2E8002659D6 /* TodoModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoModel.swift; sourceTree = ""; }; 87767A6827A5B2E8002659D6 /* ButtonReloadMainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonReloadMainTableViewCell.swift; sourceTree = ""; }; 87767A6927A5B2E8002659D6 /* CreateTitleMainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateTitleMainTableViewCell.swift; sourceTree = ""; }; @@ -73,9 +49,9 @@ buildActionMask = 2147483647; files = ( 87767A4727A5B237002659D6 /* ComposableArchitecture in Frameworks */, + EBA469992ACFA74D0060376F /* Transform in Frameworks */, + EBA4699B2ACFA7880060376F /* RxSwiftRequest in Frameworks */, 87767A8627A5B324002659D6 /* RxCocoa in Frameworks */, - 87767A8927A5B34F002659D6 /* RxSwiftRequest in Frameworks */, - 87767A4D27A5B27A002659D6 /* ConvertSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -94,58 +70,23 @@ 87767A5027A5B2E8002659D6 /* TodoApp */ = { isa = PBXGroup; children = ( - 87767A5127A5B2E8002659D6 /* AppScreens */, + EBA4699C2ACFAD5F0060376F /* Bases */, + 87767A5127A5B2E8002659D6 /* ViewControllers */, 87767A6427A5B2E8002659D6 /* Models */, 87767A6727A5B2E8002659D6 /* Views */, - 87767A6C27A5B2E8002659D6 /* View+ */, + 87767A6C27A5B2E8002659D6 /* ViewExt */, ); path = TodoApp; sourceTree = ""; }; - 87767A5127A5B2E8002659D6 /* AppScreens */ = { - isa = PBXGroup; - children = ( - 87767A5227A5B2E8002659D6 /* MainScreen */, - 87767A5827A5B2E8002659D6 /* AuthScreen */, - 87767A5E27A5B2E8002659D6 /* RootScreen */, - ); - path = AppScreens; - sourceTree = ""; - }; - 87767A5227A5B2E8002659D6 /* MainScreen */ = { + 87767A5127A5B2E8002659D6 /* ViewControllers */ = { isa = PBXGroup; children = ( 87767A5327A5B2E8002659D6 /* MainViewController.swift */, - 87767A5627A5B2E8002659D6 /* MainState.swift */, - 87767A5727A5B2E8002659D6 /* MainAction.swift */, - 87767A5527A5B2E8002659D6 /* MainEnvironment.swift */, - 87767A5427A5B2E8002659D6 /* MainReducer.swift */, - ); - path = MainScreen; - sourceTree = ""; - }; - 87767A5827A5B2E8002659D6 /* AuthScreen */ = { - isa = PBXGroup; - children = ( 87767A5927A5B2E8002659D6 /* AuthViewController.swift */, - 87767A5A27A5B2E8002659D6 /* AuthState.swift */, - 87767A5C27A5B2E8002659D6 /* AuthAction.swift */, - 87767A5D27A5B2E8002659D6 /* AuthEnvironment.swift */, - 87767A5B27A5B2E8002659D6 /* AuthReducer.swift */, - ); - path = AuthScreen; - sourceTree = ""; - }; - 87767A5E27A5B2E8002659D6 /* RootScreen */ = { - isa = PBXGroup; - children = ( 87767A6127A5B2E8002659D6 /* RootViewController.swift */, - 87767A6227A5B2E8002659D6 /* RootState.swift */, - 87767A5F27A5B2E8002659D6 /* RootAction.swift */, - 87767A6027A5B2E8002659D6 /* RootEnvironment.swift */, - 87767A6327A5B2E8002659D6 /* RootReducer.swift */, ); - path = RootScreen; + path = ViewControllers; sourceTree = ""; }; 87767A6427A5B2E8002659D6 /* Models */ = { @@ -162,18 +103,16 @@ 87767A6827A5B2E8002659D6 /* ButtonReloadMainTableViewCell.swift */, 87767A6927A5B2E8002659D6 /* CreateTitleMainTableViewCell.swift */, 87767A6B27A5B2E8002659D6 /* MainTableViewCell.swift */, - 876AF6D127A5E1D8009A0148 /* BaseViewController.swift */, - 876AF6D327A5E211009A0148 /* BaseMainTableViewCell.swift */, ); path = Views; sourceTree = ""; }; - 87767A6C27A5B2E8002659D6 /* View+ */ = { + 87767A6C27A5B2E8002659D6 /* ViewExt */ = { isa = PBXGroup; children = ( 87767A6D27A5B2E8002659D6 /* View+.swift */, ); - path = "View+"; + path = ViewExt; sourceTree = ""; }; 87767A8727A5B34F002659D6 /* Frameworks */ = { @@ -218,6 +157,15 @@ path = "Preview Content"; sourceTree = ""; }; + EBA4699C2ACFAD5F0060376F /* Bases */ = { + isa = PBXGroup; + children = ( + 876AF6D327A5E211009A0148 /* BaseTableViewCell.swift */, + 876AF6D127A5E1D8009A0148 /* BaseViewController.swift */, + ); + path = Bases; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -236,9 +184,9 @@ name = "Todo+RxSwift+UIKit(iOS13)"; packageProductDependencies = ( 87767A4627A5B237002659D6 /* ComposableArchitecture */, - 87767A4C27A5B27A002659D6 /* ConvertSwift */, 87767A8527A5B324002659D6 /* RxCocoa */, - 87767A8827A5B34F002659D6 /* RxSwiftRequest */, + EBA469982ACFA74D0060376F /* Transform */, + EBA4699A2ACFA7880060376F /* RxSwiftRequest */, ); productName = "Todo+RxSwift+UIKit(iOS13)"; productReference = 87BB892927A59499000B269B /* Todo+RxSwift+UIKit(iOS13).app */; @@ -301,28 +249,16 @@ buildActionMask = 2147483647; files = ( 87767A6E27A5B2E8002659D6 /* TodoApp.swift in Sources */, - 87767A7927A5B2E9002659D6 /* RootAction.swift in Sources */, - 87767A7A27A5B2E9002659D6 /* RootEnvironment.swift in Sources */, 876AF6D227A5E1D8009A0148 /* BaseViewController.swift in Sources */, 87767A8027A5B2E9002659D6 /* CreateTitleMainTableViewCell.swift in Sources */, 87767A7F27A5B2E9002659D6 /* ButtonReloadMainTableViewCell.swift in Sources */, - 87767A7227A5B2E9002659D6 /* MainState.swift in Sources */, - 87767A7327A5B2E9002659D6 /* MainAction.swift in Sources */, - 87767A7627A5B2E9002659D6 /* AuthReducer.swift in Sources */, - 876AF6D427A5E211009A0148 /* BaseMainTableViewCell.swift in Sources */, + 876AF6D427A5E211009A0148 /* BaseTableViewCell.swift in Sources */, 87767A7E27A5B2E9002659D6 /* TodoModel.swift in Sources */, 87767A7427A5B2E9002659D6 /* AuthViewController.swift in Sources */, 87767A8227A5B2E9002659D6 /* MainTableViewCell.swift in Sources */, - 87767A7027A5B2E9002659D6 /* MainReducer.swift in Sources */, - 87767A7527A5B2E9002659D6 /* AuthState.swift in Sources */, - 87767A7127A5B2E9002659D6 /* MainEnvironment.swift in Sources */, - 87767A7D27A5B2E9002659D6 /* RootReducer.swift in Sources */, 87767A8327A5B2E9002659D6 /* View+.swift in Sources */, - 87767A7C27A5B2E9002659D6 /* RootState.swift in Sources */, 87767A7B27A5B2E9002659D6 /* RootViewController.swift in Sources */, 87767A6F27A5B2E9002659D6 /* MainViewController.swift in Sources */, - 87767A7827A5B2E9002659D6 /* AuthEnvironment.swift in Sources */, - 87767A7727A5B2E9002659D6 /* AuthAction.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -533,24 +469,24 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/FullStack-Swift/rxswift-composable-architecture"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; 87767A4827A5B263002659D6 /* XCRemoteSwiftPackageReference "Networking" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/FullStack-Swift/Networking"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; 87767A4B27A5B279002659D6 /* XCRemoteSwiftPackageReference "SwiftExtension" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/FullStack-Swift/SwiftExtension"; requirement = { - kind = exactVersion; - version = 1.0.0; + branch = main; + kind = branch; }; }; 87767A8427A5B324002659D6 /* XCRemoteSwiftPackageReference "RxSwift" */ = { @@ -558,7 +494,7 @@ repositoryURL = "https://github.com/ReactiveX/RxSwift.git"; requirement = { kind = exactVersion; - version = 6.5.0; + version = 6.6.0; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -569,17 +505,17 @@ package = 87767A4527A5B237002659D6 /* XCRemoteSwiftPackageReference "rxswift-composable-architecture" */; productName = ComposableArchitecture; }; - 87767A4C27A5B27A002659D6 /* ConvertSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 87767A4B27A5B279002659D6 /* XCRemoteSwiftPackageReference "SwiftExtension" */; - productName = ConvertSwift; - }; 87767A8527A5B324002659D6 /* RxCocoa */ = { isa = XCSwiftPackageProductDependency; package = 87767A8427A5B324002659D6 /* XCRemoteSwiftPackageReference "RxSwift" */; productName = RxCocoa; }; - 87767A8827A5B34F002659D6 /* RxSwiftRequest */ = { + EBA469982ACFA74D0060376F /* Transform */ = { + isa = XCSwiftPackageProductDependency; + package = 87767A4B27A5B279002659D6 /* XCRemoteSwiftPackageReference "SwiftExtension" */; + productName = Transform; + }; + EBA4699A2ACFA7880060376F /* RxSwiftRequest */ = { isa = XCSwiftPackageProductDependency; package = 87767A4827A5B263002659D6 /* XCRemoteSwiftPackageReference "Networking" */; productName = RxSwiftRequest; diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7db0ca6..b167a99 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,124 +1,176 @@ { - "object": { - "pins": [ - { - "package": "Alamofire", - "repositoryURL": "https://github.com/Alamofire/Alamofire.git", - "state": { - "branch": null, - "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", - "version": "5.5.0" - } - }, - { - "package": "combine-schedulers", - "repositoryURL": "https://github.com/pointfreeco/combine-schedulers", - "state": { - "branch": null, - "revision": "4cf088c29a20f52be0f2ca54992b492c54e0076b", - "version": "0.5.3" - } - }, - { - "package": "Networking", - "repositoryURL": "https://github.com/FullStack-Swift/Networking", - "state": { - "branch": null, - "revision": "fdbb1c94caf8ead0a26c622e8c08cbd6f6ebb8ac", - "version": "1.0.0" - } - }, - { - "package": "ReactiveSwift", - "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift.git", - "state": { - "branch": null, - "revision": "efb2f0a6f6c8739cce8fb14148a5bd3c83f2f91d", - "version": "7.0.0" - } - }, - { - "package": "RxSwift", - "repositoryURL": "https://github.com/ReactiveX/RxSwift.git", - "state": { - "branch": null, - "revision": "b4307ba0b6425c0ba4178e138799946c3da594f8", - "version": "6.5.0" - } - }, - { - "package": "rxswift-composable-architecture", - "repositoryURL": "https://github.com/FullStack-Swift/rxswift-composable-architecture", - "state": { - "branch": null, - "revision": "eb0cd2b10cc8064e4efeace95096836c75396568", - "version": "1.0.0" - } - }, - { - "package": "Starscream", - "repositoryURL": "https://github.com/daltoniam/Starscream.git", - "state": { - "branch": null, - "revision": "df8d82047f6654d8e4b655d1b1525c64e1059d21", - "version": "4.0.4" - } - }, - { - "package": "swift-case-paths", - "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", - "state": { - "branch": null, - "revision": "241301b67d8551c26d8f09bd2c0e52cc49f18007", - "version": "0.8.0" - } - }, - { - "package": "swift-collections", - "repositoryURL": "https://github.com/apple/swift-collections", - "state": { - "branch": null, - "revision": "48254824bb4248676bf7ce56014ff57b142b77eb", - "version": "1.0.2" - } - }, - { - "package": "swift-custom-dump", - "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump", - "state": { - "branch": null, - "revision": "51698ece74ecf31959d3fa81733f0a5363ef1b4e", - "version": "0.3.0" - } - }, - { - "package": "swift-identified-collections", - "repositoryURL": "https://github.com/pointfreeco/swift-identified-collections", - "state": { - "branch": null, - "revision": "680bf440178a78a627b1c2c64c0855f6523ad5b9", - "version": "0.3.2" - } - }, - { - "package": "SwiftExtension", - "repositoryURL": "https://github.com/FullStack-Swift/SwiftExtension", - "state": { - "branch": null, - "revision": "cdbd56e6cf32fa0eb97a1fba445736cbe8b8e622", - "version": "1.0.0" - } - }, - { - "package": "xctest-dynamic-overlay", - "repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay", - "state": { - "branch": null, - "revision": "50a70a9d3583fe228ce672e8923010c8df2deddd", - "version": "0.2.1" - } - } - ] - }, - "version": 1 + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "b2fa556e4e48cbf06cf8c63def138c98f4b811fa", + "version" : "5.8.0" + } + }, + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb", + "version" : "1.0.0" + } + }, + { + "identity" : "networking", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/Networking", + "state" : { + "branch" : "main", + "revision" : "23e446cfffd8a5f554fd564fc7568eeaa85843e4" + } + }, + { + "identity" : "reactiveswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveCocoa/ReactiveSwift.git", + "state" : { + "revision" : "40c465af19b993344e84355c00669ba2022ca3cd", + "version" : "7.1.1" + } + }, + { + "identity" : "rxswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ReactiveX/RxSwift.git", + "state" : { + "revision" : "9dcaa4b333db437b0fbfaf453fad29069044a8b4", + "version" : "6.6.0" + } + }, + { + "identity" : "rxswift-composable-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/rxswift-composable-architecture", + "state" : { + "branch" : "main", + "revision" : "61fe1aba2012b6a35c9cce6fc7924767873a231b" + } + }, + { + "identity" : "socket.io-client-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/socketio/socket.io-client-swift", + "state" : { + "revision" : "175da8b5156f6b132436f0676cc84c2f6a766b6e", + "version" : "16.1.0" + } + }, + { + "identity" : "starscream", + "kind" : "remoteSourceControl", + "location" : "https://github.com/daltoniam/Starscream.git", + "state" : { + "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", + "version" : "4.0.6" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms", + "state" : { + "revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a", + "version" : "0.1.0" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "5da6989aae464f324eef5c5b52bdb7974725ab81", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "d1fd837326aa719bee979bdde1f53cd5797443eb", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "ea631ce892687f5432a833312292b80db238186a", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "3efbfba0e4e56c7187cc19137ee16b7c95346b79", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "4e1eb6e28afe723286d8cc60611237ffbddba7c5", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8", + "version" : "1.0.0" + } + }, + { + "identity" : "swiftextension", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FullStack-Swift/SwiftExtension", + "state" : { + "branch" : "main", + "revision" : "ccbf2fddb982267be28705b3dd8b29ee3c4d149e" + } + }, + { + "identity" : "swiftui-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swiftui-navigation", + "state" : { + "revision" : "6eb293c49505d86e9e24232cb6af6be7fff93bd5", + "version" : "1.0.2" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631", + "version" : "1.0.2" + } + } + ], + "version" : 2 } diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp.swift index ba657c2..a89bfca 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp.swift @@ -1,11 +1,23 @@ import SwiftUI -import ComposableArchitecture +@_exported import ComposableArchitecture +@_exported import MRxSwiftRequest +@_exported import RxCocoa +@_exported import RxSwift +@_exported import Transform @main struct TodoApp: App { var body: some Scene { WindowGroup { - let vc = RootViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) } + RootViewController().toSwiftUI() + } } } + +public extension DependencyValues { + var urlString: String { + "http://127.0.0.1:8080/todos" + } +} + +public var isUsingPublisher: Bool = true diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift deleted file mode 100644 index effce91..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthAction.swift +++ /dev/null @@ -1,11 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum AuthAction: Equatable { - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case none - case login - case changeRootScreen(RootScreen) -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift deleted file mode 100644 index a96bc7e..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthEnvironment.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct AuthEnvironment { - -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift deleted file mode 100644 index 01fca41..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthReducer.swift +++ /dev/null @@ -1,21 +0,0 @@ -import ComposableArchitecture -import Foundation - -let AuthReducer = Reducer.combine( - Reducer { state, action, environment in - switch action { - case .viewDidLoad: - break - case .viewWillAppear: - break - case .viewWillDisappear: - break - case .login: - return Effect(value: .changeRootScreen(.main)) - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift deleted file mode 100644 index 0f0ea3d..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthState.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct AuthState: Equatable { - -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift deleted file mode 100644 index ee9c139..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainAction.swift +++ /dev/null @@ -1,36 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum MainAction: Equatable { - // MARK: - View Action - /// lifecycle action - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case viewDeinit - /// navigation view - case logout - case changeRootScreen(RootScreen) - - /// binding - case changeText(String) - /// event network - case viewCreateTodo - case viewReloadTodo - case viewToggleTodo(TodoModel) - case viewDeleteTodo(TodoModel) - // MARK: - Store Action - case resetText - /// network Action - case getTodo - case responseGetTodo(Data) - case createOrUpdateTodo(TodoModel) - case responseCreateOrUpdateTodo(Data) - case updateTodo(TodoModel) - case responseUpdateTodo(Data) - case deleteTodo(TodoModel) - case reponseDeleteTodo(Data) - // MARK: - none - case none -} - diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift deleted file mode 100644 index 179c54c..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainEnvironment.swift +++ /dev/null @@ -1,8 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct MainEnvironment { - let urlString: String = "https://todolistappproj.herokuapp.com/todos" - init() { - } -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift deleted file mode 100644 index be3dd57..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainReducer.swift +++ /dev/null @@ -1,127 +0,0 @@ -import ComposableArchitecture -import RxSwiftRequest -import ConvertSwift - -let MainReducer = Reducer.combine( - Reducer { state, action, environment in - switch action { - /// view action - case .viewDidLoad: - return Effect(value: MainAction.viewReloadTodo) - case .viewWillAppear: - break - case .viewWillDisappear: - break - case .viewDeinit: - break - /// navigation view - case .logout: - return Effect(value: MainAction.changeRootScreen(.auth)) - case .changeText(let text): - state.title = text - case .resetText: - state.title = "" - /// event network - case .viewCreateTodo: - if state.title.isEmpty { - return .none - } - var title = state.title - let id = UUID() - let todo = TodoModel(id: id, title: title, isCompleted: false) - let resetTitleEffect = Effect(value: MainAction.resetText) - .delay(.microseconds(300), scheduler: MainScheduler.instance) - .eraseToEffect() - return Effect.merge( - resetTitleEffect, - Effect(value: MainAction.createOrUpdateTodo(todo)) - ) - case .viewReloadTodo: - if state.isLoading { - return .none - } - state.todos.removeAll() - state.isLoading = true - return Effect(value: MainAction.getTodo) - .delay(.microseconds(300), scheduler: MainScheduler.instance) - .eraseToEffect() - case .viewToggleTodo(let todo): - var todo = todo - todo.isCompleted.toggle() - return Effect(value: MainAction.updateTodo(todo)) - case .viewDeleteTodo(let todo): - return Effect(value: MainAction.deleteTodo(todo)) - /// network action - case .getTodo: - let request = MRequest { - RMethod(.get) - RUrl(urlString: environment.urlString) - } - return request - .compactMap {$0.data} - .map(MainAction.responseGetTodo) - .eraseToEffect() - case .responseGetTodo(let data): - state.isLoading = false - guard let todos = data.toModel([TodoModel].self) else { - return .none - } - for todo in todos { - state.todos.updateOrAppend(todo) - } - case .createOrUpdateTodo(let todo): - let request = MRequest { - RUrl(urlString: environment.urlString) - REncoding(.json) - RMethod(.post) - Rbody(todo.toData()) - } - return request - .compactMap {$0.data} - .map(MainAction.responseCreateOrUpdateTodo) - .eraseToEffect() - case .responseCreateOrUpdateTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.append(todo) - case .updateTodo(let todo): - let request = MRequest { - REncoding(.json) - RUrl(urlString: environment.urlString) - .withPath(todo.id.toString()) - RMethod(.post) - Rbody(todo.toData()) - } - return request - .compactMap {$0.data} - .map(MainAction.responseUpdateTodo) - .eraseToEffect() - case .responseUpdateTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.updateOrAppend(todo) - case .deleteTodo(let todo): - let request = MRequest { - RUrl(urlString: environment.urlString) - .withPath(todo.id.toString()) - RMethod(.delete) - } - return request - .compactMap {$0.data} - .map(MainAction.reponseDeleteTodo) - .eraseToEffect() - case .reponseDeleteTodo(let data): - guard let todo = data.toModel(TodoModel.self) else { - return .none - } - state.todos.remove(todo) - break - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift deleted file mode 100644 index 28ade31..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainState.swift +++ /dev/null @@ -1,8 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct MainState: Equatable { - var title: String = "" - var todos: IdentifiedArrayOf = [] - var isLoading: Bool = false -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift deleted file mode 100644 index 675506b..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootAction.swift +++ /dev/null @@ -1,11 +0,0 @@ -import ComposableArchitecture -import Foundation - -enum RootAction: Equatable { - case authAction(AuthAction) - case mainAction(MainAction) - case viewDidLoad - case viewWillAppear - case viewWillDisappear - case none -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift deleted file mode 100644 index b7caae1..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootEnvironment.swift +++ /dev/null @@ -1,6 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct RootEnvironment { - -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift deleted file mode 100644 index 06e5b96..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootReducer.swift +++ /dev/null @@ -1,30 +0,0 @@ -import ComposableArchitecture -import Foundation - -let RootReducer = Reducer.combine( - AuthReducer.pullback(state: \.authState, action: /RootAction.authAction, environment: { _ in - .init() - }), - MainReducer.pullback(state: \.mainState, action: /RootAction.mainAction, environment: { _ in - .init() - }), - Reducer { state, action, environment in - switch action { - case .authAction(.changeRootScreen(let screen)): - state.rootScreen = screen - case .mainAction(.changeRootScreen(let screen)): - state = RootState() - state.rootScreen = screen - case .viewDidLoad: - break - case .viewWillAppear: - break - case .viewWillDisappear: - break - default: - break - } - return .none - } -) - .debug() diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift deleted file mode 100644 index b0b3276..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootState.swift +++ /dev/null @@ -1,13 +0,0 @@ -import ComposableArchitecture -import Foundation - -struct RootState: Equatable { - var authState = AuthState() - var mainState = MainState() - var rootScreen: RootScreen = .main -} - -enum RootScreen: Equatable { - case main - case auth -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift deleted file mode 100644 index 9944046..0000000 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/RootScreen/RootViewController.swift +++ /dev/null @@ -1,71 +0,0 @@ -import ComposableArchitecture -import SwiftUI -import UIKit - -final class RootViewController: BaseViewController { - - private let store: Store - - private let viewStore: ViewStore - - private var viewController = UIViewController() { - willSet { - viewController.willMove(toParent: nil) - viewController.view.removeFromSuperview() - viewController.removeFromParent() - addChild(newValue) - newValue.view.frame = self.view.frame - view.addSubview(newValue.view) - newValue.didMove(toParent: self) - } - } - - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: RootState(), reducer: RootReducer, environment: RootEnvironment()) - self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - viewStore.send(.viewDidLoad) - //bind view to viewstore - viewStore.publisher.rootScreen.subscribe(onNext: { [weak self] screen in - guard let self = self else {return} - switch screen { - case .main: - let vc = MainViewController(store: self.store.scope(state: \.mainState, action: RootAction.mainAction)) - let nav = UINavigationController(rootViewController: vc) - self.viewController = nav - case .auth: - let vc = AuthViewController(store: self.store.scope(state: \.authState, action: RootAction.authAction)) - let nav = UINavigationController(rootViewController: vc) - self.viewController = nav - } - }) - .disposed(by: disposeBag) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - viewStore.send(.viewWillAppear) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - viewStore.send(.viewWillDisappear) - } -} - -struct RootViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = RootViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } -} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift similarity index 78% rename from BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift rename to BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift index e1d8884..b589c5d 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseTableViewCell.swift @@ -1,7 +1,7 @@ import UIKit import RxSwift -class BaseMainTableViewCell: UITableViewCell { +class BaseTableViewCell: UITableViewCell { var disposeBag = DisposeBag() diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift similarity index 100% rename from BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/BaseViewController.swift rename to BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Bases/BaseViewController.swift diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift index f113757..1240ba8 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Models/TodoModel.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/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/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift similarity index 55% rename from BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift rename to BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift index 734b542..3793701 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/AuthScreen/AuthViewController.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/AuthViewController.swift @@ -1,18 +1,52 @@ -import ComposableArchitecture import SwiftUI import UIKit -import RxCocoa + +struct AuthReducer: Reducer { + + struct State: Equatable { + + } + + enum Action { + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case none + case login + case changeRootScreen(RootReducer.RootScreen) + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .viewDidLoad: + break + case .viewWillAppear: + break + case .viewWillDisappear: + break + case .login: + return .send(.changeRootScreen(.main)) + default: + break + } + return .none + } + } +} final class AuthViewController: BaseViewController { - private let store: Store + private let store: StoreOf - private let viewStore: ViewStore + private var viewStore: ViewStoreOf - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: AuthState(), reducer: AuthReducer, environment: AuthEnvironment()) + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: AuthReducer.State()) { + AuthReducer() + } self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) + self.viewStore = ViewStore(unwrapStore, observe: {$0}) super.init(nibName: nil, bundle: nil) } @@ -36,7 +70,7 @@ final class AuthViewController: BaseViewController { //bind view to viewstore buttonLogin.rx.tap - .map { AuthAction.login } + .map { AuthReducer.Action.login } .bind(to: viewStore.action) .disposed(by: disposeBag) } @@ -51,3 +85,7 @@ final class AuthViewController: BaseViewController { viewStore.send(.viewWillDisappear) } } + +#Preview { + AuthViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift similarity index 85% rename from BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift rename to BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift index 1d94d6f..488b0a1 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/AppScreens/MainScreen/MainViewController.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/MainViewController.swift @@ -1,24 +1,26 @@ -import ComposableArchitecture import SwiftUI import UIKit -import ConvertSwift +import RxSwift import RxCocoa +import RxRelay final class MainViewController: BaseViewController { - private let store: Store + private let store: StoreOf - private let viewStore: ViewStore + private var viewStore: ViewStoreOf - private let tableView: UITableView = UITableView() - - init(store: Store? = nil) { - let unwrapStore = store ?? Store(initialState: MainState(), reducer: MainReducer, environment: MainEnvironment()) + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: MainReducer.State()) { + MainReducer() + } self.store = unwrapStore - self.viewStore = ViewStore(unwrapStore) + self.viewStore = ViewStore(unwrapStore, observe: {$0}) super.init(nibName: nil, bundle: nil) } + private let tableView: UITableView = UITableView() + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -56,7 +58,7 @@ final class MainViewController: BaseViewController { //bind view to viewstore buttonLogout.rx.tap - .map{MainAction.logout} + .map{MainReducer.Action.logout} .subscribe(viewStore.action) .disposed(by: disposeBag) @@ -127,29 +129,29 @@ extension MainViewController: UITableViewDataSource { }) .disposed(by: cell.disposeBag) cell.buttonReload.rx.tap - .map{MainAction.viewReloadTodo} + .map{MainReducer.Action.viewReloadTodo} .bind(to: viewStore.action) .disposed(by: cell.disposeBag) return cell case 1: let cell = tableView.dequeueReusableCell(CreateTitleMainTableViewCell.self, for: indexPath) - viewStore.publisher.title + viewStore.publisher.text .bind(to: cell.titleTextField.rx.text) .disposed(by: cell.disposeBag) - viewStore.publisher.title.isEmpty + viewStore.publisher.text.isEmpty .subscribe(onNext: { value in cell.createButton.setTitleColor(value ? UIColor(Color.gray) : UIColor(Color.green), for: .normal) }) .disposed(by: cell.disposeBag) cell.createButton .rx.tap - .map {MainAction.viewCreateTodo} + .map {MainReducer.Action.viewCreateTodo} .bind(to: viewStore.action) .disposed(by: cell.disposeBag) cell.titleTextField .rx.text.orEmpty .compactMap{$0} - .map{MainAction.changeText($0)} + .map{MainReducer.Action.changeText($0)} .bind(to: viewStore.action) .disposed(by: cell.disposeBag) return cell @@ -159,12 +161,12 @@ extension MainViewController: UITableViewDataSource { cell.bind(todo) cell.deleteButton .rx.tap - .map{MainAction.viewDeleteTodo(todo)} + .map{MainReducer.Action.viewDeleteTodo(todo)} .bind(to: viewStore.action) .disposed(by: cell.disposeBag) cell.tapGesture .rx.event - .map {_ in MainAction.viewToggleTodo(todo)} + .map {_ in MainReducer.Action.viewToggleTodo(todo)} .bind(to: viewStore.action) .disposed(by: cell.disposeBag) return cell @@ -181,9 +183,6 @@ extension MainViewController: UITableViewDelegate { } } -struct MainViewController_Previews: PreviewProvider { - static var previews: some View { - let vc = MainViewController() - UIViewRepresented(makeUIView: { _ in vc.view }) - } +#Preview { + MainViewController().toSwiftUI() } diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift new file mode 100644 index 0000000..0755ed2 --- /dev/null +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewControllers/RootViewController.swift @@ -0,0 +1,294 @@ +import SwiftUI +import UIKit + +struct MainReducer: Reducer { + struct State: Equatable { + var text: String = "" + var todos: IdentifiedArrayOf = [] + var isLoading: Bool = false + } + + enum Action: Equatable { + // MARK: - View Action + /// lifecycle action + case viewDidLoad + case viewWillAppear + case viewWillDisappear + case viewDeinit + /// navigation view + case logout + case changeRootScreen(RootReducer.RootScreen) + + /// binding + case changeText(String) + /// event network + case viewCreateTodo + case viewReloadTodo + case viewToggleTodo(TodoModel) + case viewDeleteTodo(TodoModel) + // MARK: - Store Action + case resetText + /// network Action + case getTodo + case responseGetTodo(Data) + case createOrUpdateTodo(TodoModel) + case responseCreateOrUpdateTodo(Data) + case updateTodo(TodoModel) + case responseUpdateTodo(Data) + case deleteTodo(TodoModel) + case reponseDeleteTodo(Data) + // MARK: - none + case none + } + + // MARK: Dependency + @Dependency(\.uuid) var uuid + @Dependency(\.urlString) var urlString + + var body: some ReducerOf { + Reduce { state, action in + switch action { + // MARK: - View Action + case .viewDidLoad: + return .send(.viewReloadTodo) + case .viewWillAppear: + break + case .viewWillDisappear: + break + case .viewDeinit: + break + /// navigation view + case .logout: + return .send(.changeRootScreen(.auth)) + case .changeText(let text): + state.text = text + case .resetText: + state.text = "" + /// event network + case .viewCreateTodo: + if state.text.isEmpty { + return .none + } + let text = state.text + let id = UUID() + let todo = TodoModel(id: id, text: text, isCompleted: false) + return Effect.merge( + .publisher { + .just(.resetText) + .delay(.microseconds(300), scheduler: MainScheduler.instance) + }, + .send(.createOrUpdateTodo(todo)) + ) + case .viewReloadTodo: + if state.isLoading { + return .none + } + state.todos.removeAll() + state.isLoading = true + return .publisher { + .just(.getTodo) + .delay(.microseconds(300), scheduler: MainScheduler.instance) + } + case .viewToggleTodo(let todo): + var todo = todo + todo.isCompleted.toggle() + return .send(.updateTodo(todo)) + case .viewDeleteTodo(let todo): + return .send(.deleteTodo(todo)) + /// network action + case .getTodo: + let request = MRequest { + RMethod(.get) + RUrl(urlString) + } + return .publisher { + request + .compactMap {$0.data} + .map(Action.responseGetTodo) + } + case .responseGetTodo(let data): + state.isLoading = false + guard let todos = data.toModel([TodoModel].self) else { + return .none + } + for todo in todos { + state.todos.updateOrAppend(todo) + } + case .createOrUpdateTodo(let todo): + return .publisher { + let request = MRequest { + RUrl(urlString) + REncoding(JSONEncoding.default) + RMethod(.post) + Rbody(todo.toData()) + } + return request + .compactMap {$0.data} + .map(Action.responseCreateOrUpdateTodo) + } + case .responseCreateOrUpdateTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.append(todo) + case .updateTodo(let todo): + let request = MRequest { + REncoding(JSONEncoding.default) + RUrl(urlString) + .withPath(todo.id.toString()) + RMethod(.post) + Rbody(todo.toData()) + } + return .publisher { + request + .compactMap {$0.data} + .map(Action.responseUpdateTodo) + } + case .responseUpdateTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.updateOrAppend(todo) + case .deleteTodo(let todo): + let request = MRequest { + RUrl(urlString) + .withPath(todo.id.toString()) + RMethod(.delete) + } + return .publisher { + request + .compactMap {$0.data} + .map(Action.reponseDeleteTodo) + } + case .reponseDeleteTodo(let data): + guard let todo = data.toModel(TodoModel.self) else { + return .none + } + state.todos.remove(todo) + break + default: + break + } + return .none + } + } + +} + +struct RootReducer: Reducer { + + struct State: Equatable { + var authState = AuthReducer.State() + var mainState = MainReducer.State() + var rootScreen: RootScreen = .main + } + + enum Action { + case authAction(AuthReducer.Action) + case mainAction(MainReducer.Action) + case viewDidLoad + case viewWillAppear + case viewWillDisappear + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .authAction(.changeRootScreen(let screen)): + state.rootScreen = screen + case .mainAction(.changeRootScreen(let screen)): + state = .init() + state.rootScreen = screen + case .viewDidLoad: + break + case .viewWillAppear: + break + case .viewWillDisappear: + break + default: + break + } + return .none + } + ._printChanges() + Scope(state: \.authState, action: /Action.authAction) { + AuthReducer() + } + Scope(state: \.mainState, action: /Action.mainAction) { + MainReducer() + } + } + + enum RootScreen: Equatable { + case main + case auth + } + +} + +final class RootViewController: BaseViewController { + + private let store: StoreOf + + private var viewStore: ViewStoreOf + + init(store: StoreOf? = nil) { + let unwrapStore = store ?? Store(initialState: RootReducer.State()) { + RootReducer() + } + self.store = unwrapStore + self.viewStore = ViewStore(unwrapStore, observe: {$0}) + super.init(nibName: nil, bundle: nil) + } + + + private var viewController = UIViewController() { + willSet { + viewController.willMove(toParent: nil) + viewController.view.removeFromSuperview() + viewController.removeFromParent() + addChild(newValue) + newValue.view.frame = self.view.frame + view.addSubview(newValue.view) + newValue.didMove(toParent: self) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + viewStore.send(.viewDidLoad) + //bind view to viewstore + viewStore.publisher.rootScreen.subscribe(onNext: { [weak self] screen in + guard let self = self else {return} + switch screen { + case .main: + let vc = MainViewController(store: self.store.scope(state: \.mainState, action: RootReducer.Action.mainAction)) + let nav = UINavigationController(rootViewController: vc) + self.viewController = nav + case .auth: + let vc = AuthViewController(store: self.store.scope(state: \.authState, action: RootReducer.Action.authAction)) + let nav = UINavigationController(rootViewController: vc) + self.viewController = nav + } + }) + .disposed(by: disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + viewStore.send(.viewWillAppear) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + viewStore.send(.viewWillDisappear) + } +} + +#Preview { + RootViewController().toSwiftUI() +} diff --git a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift similarity index 88% rename from BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift rename to BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift index ed1b0cd..428a0a7 100644 --- a/BasicApp/UIKit13+/Todo+ReactiveSwift+UIKit(iOS13)/Todo+ReactiveSwift+UIKit(iOS13)/CoreApp/TodoApp/View+/View+.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/ViewExt/View+.swift @@ -33,3 +33,11 @@ public struct UIViewRepresented: UIViewRepresentable where UIViewTyp self.updateUIView(uiView, context) } } + +extension UIViewController { + public func toSwiftUI() -> some View { + UIViewRepresented { context in + self.view + } + } +} diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift index de60cc9..3046c28 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/ButtonReloadMainTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class ButtonReloadMainTableViewCell: BaseMainTableViewCell { +class ButtonReloadMainTableViewCell: BaseTableViewCell { let buttonReload = UIButton(type: .system) let activityIndicator = UIActivityIndicatorView() diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift index ad5437b..18bb405 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/CreateTitleMainTableViewCell.swift @@ -1,7 +1,6 @@ import UIKit -import SwiftUI -class CreateTitleMainTableViewCell: BaseMainTableViewCell { +class CreateTitleMainTableViewCell: BaseTableViewCell { let createButton = UIButton(type: .system) let titleTextField = UITextField() @@ -13,7 +12,7 @@ class CreateTitleMainTableViewCell: BaseMainTableViewCell { // createButton createButton.setTitle("Create", for: .normal) createButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17) - createButton.setTitleColor(UIColor(Color.green), for: .normal) + createButton.setTitleColor(UIColor.green, for: .normal) createButton.translatesAutoresizingMaskIntoConstraints = false // titleTextField titleTextField.placeholder = "title" diff --git a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift index 89c3bab..eef315c 100644 --- a/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift +++ b/BasicApp/UIKit13+/Todo+RxSwift+UIKit(iOS13)/Todo+RxSwift+UIKit(iOS13)/CoreApp/TodoApp/Views/MainTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit -class MainTableViewCell: BaseMainTableViewCell { +class MainTableViewCell: BaseTableViewCell { let image = UIImageView(image: UIImage(systemName: "square")) let titleView = UILabel() @@ -46,7 +46,7 @@ class MainTableViewCell: BaseMainTableViewCell { return } image.image = data.isCompleted ? UIImage(systemName: "checkmark.square") : UIImage(systemName: "square") - titleView.text = data.title + titleView.text = data.text } } 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/.swiftpm/xcode/xcshareddata/xcschemes/TodoListServer.xcscheme b/TodoListServer/.swiftpm/xcode/xcshareddata/xcschemes/TodoListServer.xcscheme new file mode 100644 index 0000000..db4d527 --- /dev/null +++ b/TodoListServer/.swiftpm/xcode/xcshareddata/xcschemes/TodoListServer.xcscheme @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 0000000..1994dea Binary files /dev/null and b/TodoListServer/db.sqlite differ