From b9c9c17a1a490a945add3e8c9a331f6f3151ccfc Mon Sep 17 00:00:00 2001 From: Chihchy Date: Thu, 11 Jul 2024 13:25:08 +0800 Subject: [PATCH] Migrate to TCA 1.7 (WIP) [skip test] --- EhPanda.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 13 +++++- EhPanda/DataFlow/AppDelegateReducer.swift | 1 + EhPanda/DataFlow/AppLockReducer.swift | 3 +- EhPanda/DataFlow/AppReducer.swift | 13 +++--- EhPanda/DataFlow/AppRouteReducer.swift | 23 +++++----- .../Detail/Archives/ArchivesReducer.swift | 5 ++- .../Detail/Comments/CommentsReducer.swift | 25 +++++------ EhPanda/View/Detail/DetailReducer.swift | 43 ++++++++++--------- .../DetailSearch/DetailSearchReducer.swift | 31 +++++++------ .../GalleryInfos/GalleryInfosReducer.swift | 3 +- .../Detail/Previews/PreviewsReducer.swift | 9 ++-- .../Detail/Torrents/TorrentsReducer.swift | 3 +- EhPanda/View/Favorites/FavoritesReducer.swift | 19 ++++---- .../Home/Frontpage/FrontpageReducer.swift | 17 ++++---- .../View/Home/History/HistoryReducer.swift | 21 ++++----- EhPanda/View/Home/HomeReducer.swift | 41 ++++++++++-------- .../View/Home/Popular/PopularReducer.swift | 19 ++++---- .../View/Home/Toplists/ToplistsReducer.swift | 39 +++++++++-------- .../View/Home/Watched/WatchedReducer.swift | 19 ++++---- EhPanda/View/Migration/MigrationReducer.swift | 3 +- EhPanda/View/Reading/ReadingReducer.swift | 13 +++--- EhPanda/View/Search/SearchReducer.swift | 33 +++++++------- EhPanda/View/Search/SearchRootReducer.swift | 31 +++++++------ .../Search/Support/QuickSearchReducer.swift | 15 ++++--- .../AccountSettingReducer.swift | 29 ++++++------- .../AppearanceSettingReducer.swift | 3 +- .../Setting/EhSetting/EhSettingReducer.swift | 9 ++-- .../GeneralSettingReducer.swift | 9 ++-- EhPanda/View/Setting/Login/LoginReducer.swift | 9 ++-- EhPanda/View/Setting/Logs/LogsReducer.swift | 3 +- EhPanda/View/Setting/SettingReducer.swift | 14 +++--- EhPanda/View/Support/FiltersReducer.swift | 43 +++++++++++-------- EhPanda/View/TabBar/TabBarReducer.swift | 1 + 34 files changed, 305 insertions(+), 259 deletions(-) diff --git a/EhPanda.xcodeproj/project.pbxproj b/EhPanda.xcodeproj/project.pbxproj index fce070fa..09610d26 100644 --- a/EhPanda.xcodeproj/project.pbxproj +++ b/EhPanda.xcodeproj/project.pbxproj @@ -2479,7 +2479,7 @@ repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture.git"; requirement = { kind = exactVersion; - version = 1.5.6; + version = 1.7.3; }; }; ABAC82FC26BC4866009F5026 /* XCRemoteSwiftPackageReference "SwiftyOpenCC" */ = { diff --git a/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c8c973cc..8ab11e4d 100644 --- a/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -105,8 +105,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-composable-architecture.git", "state" : { - "revision" : "3568f01377c6c668aad40d066acf97ce670a1dad", - "version" : "1.5.6" + "revision" : "f815e76b520aacfad4ff35c7e1f036f8add6f4b4", + "version" : "1.7.3" } }, { @@ -145,6 +145,15 @@ "version" : "1.1.0" } }, + { + "identity" : "swift-perception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-perception", + "state" : { + "revision" : "d3ab98dc2887d1cc3bed676f6fa354da4cb22b3c", + "version" : "1.2.4" + } + }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", diff --git a/EhPanda/DataFlow/AppDelegateReducer.swift b/EhPanda/DataFlow/AppDelegateReducer.swift index 39310d20..b9adbf37 100644 --- a/EhPanda/DataFlow/AppDelegateReducer.swift +++ b/EhPanda/DataFlow/AppDelegateReducer.swift @@ -11,6 +11,7 @@ import ComposableArchitecture @Reducer struct AppDelegateReducer { + @ObservableState struct State: Equatable { var migrationState = MigrationReducer.State() } diff --git a/EhPanda/DataFlow/AppLockReducer.swift b/EhPanda/DataFlow/AppLockReducer.swift index e2060ab3..6a3cf513 100644 --- a/EhPanda/DataFlow/AppLockReducer.swift +++ b/EhPanda/DataFlow/AppLockReducer.swift @@ -10,8 +10,9 @@ import ComposableArchitecture @Reducer struct AppLockReducer { + @ObservableState struct State: Equatable { - @BindingState var blurRadius: Double = 0 + var blurRadius: Double = 0 var becameInactiveDate: Date? var isAppLocked = false diff --git a/EhPanda/DataFlow/AppReducer.swift b/EhPanda/DataFlow/AppReducer.swift index 784a3af3..5dcc39dc 100644 --- a/EhPanda/DataFlow/AppReducer.swift +++ b/EhPanda/DataFlow/AppReducer.swift @@ -10,15 +10,16 @@ import ComposableArchitecture @Reducer struct AppReducer { + @ObservableState struct State: Equatable { var appDelegateState = AppDelegateReducer.State() - @BindingState var appRouteState = AppRouteReducer.State() + var appRouteState = AppRouteReducer.State() var appLockState = AppLockReducer.State() var tabBarState = TabBarReducer.State() var homeState = HomeReducer.State() var favoritesState = FavoritesReducer.State() var searchRootState = SearchRootReducer.State() - @BindingState var settingState = SettingReducer.State() + var settingState = SettingReducer.State() } enum Action: BindableAction { @@ -45,14 +46,10 @@ struct AppReducer { LoggingReducer { BindingReducer() .onChange(of: \.appRouteState.route) { _, newValue in - Reduce { _, _ in - return newValue == nil ? .send(.appRoute(.clearSubStates)) : .none - } + Reduce({ _, _ in newValue == nil ? .send(.appRoute(.clearSubStates)) : .none }) } .onChange(of: \.settingState.setting) { _, _ in - Reduce { _, _ in - return .send(.setting(.syncSetting)) - } + Reduce({ _, _ in .send(.setting(.syncSetting)) }) } Reduce { state, action in diff --git a/EhPanda/DataFlow/AppRouteReducer.swift b/EhPanda/DataFlow/AppRouteReducer.swift index 0cf0c40f..ac3a53aa 100644 --- a/EhPanda/DataFlow/AppRouteReducer.swift +++ b/EhPanda/DataFlow/AppRouteReducer.swift @@ -19,14 +19,15 @@ struct AppRouteReducer { case newDawn(Greeting) } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var hudConfig: TTProgressHUDConfig = .loading - @Heap var detailState: DetailReducer.State! + var detailState: Heap! init() { - _detailState = .init(.init()) + detailState = .init(.init()) } } @@ -57,12 +58,12 @@ struct AppRouteReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -75,7 +76,7 @@ struct AppRouteReducer { return .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() return .send(.detail(.teardown)) case .detectClipboardURL: @@ -97,7 +98,7 @@ struct AppRouteReducer { if case .detail = state.route { delay = 1000 state.route = nil - state.detailState = .init() + state.detailState.wrappedValue = .init() } let (isGalleryImageURL, _, _) = urlClient.analyzeURL(url) let gid = urlClient.parseGalleryID(url) @@ -116,7 +117,7 @@ struct AppRouteReducer { let (_, pageIndex, commentID) = urlClient.analyzeURL(url) let gid = urlClient.parseGalleryID(url) var effects = [Effect]() - state.detailState = .init() + state.detailState.wrappedValue = .init() effects.append(.send(.detail(.fetchDatabaseInfos(gid)))) if let pageIndex = pageIndex { effects.append(.send(.updateReadingProgress(gid, pageIndex))) @@ -127,7 +128,7 @@ struct AppRouteReducer { } ) } else if let commentID = commentID { - state.detailState.commentsState?.scrollCommentID = commentID + state.detailState.wrappedValue.commentsState?.scrollCommentID = commentID effects.append( .run { send in try await Task.sleep(for: .milliseconds(500)) @@ -190,6 +191,6 @@ struct AppRouteReducer { hapticsClient: hapticsClient ) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Detail/Archives/ArchivesReducer.swift b/EhPanda/View/Detail/Archives/ArchivesReducer.swift index 4197cee8..e9acdd37 100644 --- a/EhPanda/View/Detail/Archives/ArchivesReducer.swift +++ b/EhPanda/View/Detail/Archives/ArchivesReducer.swift @@ -20,9 +20,10 @@ struct ArchivesReducer { case fetchArchive, fetchArchiveFunds, fetchDownloadResponse } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var selectedArchive: GalleryArchive.HathArchive? + var route: Route? + var selectedArchive: GalleryArchive.HathArchive? var loadingState: LoadingState = .idle var hathArchives = [GalleryArchive.HathArchive]() diff --git a/EhPanda/View/Detail/Comments/CommentsReducer.swift b/EhPanda/View/Detail/Comments/CommentsReducer.swift index 514f42cb..b098eaa0 100644 --- a/EhPanda/View/Detail/Comments/CommentsReducer.swift +++ b/EhPanda/View/Detail/Comments/CommentsReducer.swift @@ -22,19 +22,20 @@ struct CommentsReducer { case postComment, voteComment, fetchGallery } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var commentContent = "" - @BindingState var postCommentFocused = false + var route: Route? + var commentContent = "" + var postCommentFocused = false var hudConfig: TTProgressHUDConfig = .loading var scrollCommentID: String? var scrollRowOpacity: Double = 1 - @Heap var detailState: DetailReducer.State! + var detailState: Heap! init() { - _detailState = .init(.init()) + detailState = .init(.init()) } } @@ -74,12 +75,12 @@ struct CommentsReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -88,7 +89,7 @@ struct CommentsReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() state.commentContent = .init() state.postCommentFocused = false return .send(.detail(.teardown)) @@ -153,7 +154,7 @@ struct CommentsReducer { } ) } else if let commentID = commentID { - state.detailState.commentsState?.scrollCommentID = commentID + state.detailState.wrappedValue.commentsState?.wrappedValue.scrollCommentID = commentID effects.append( .run { send in try await Task.sleep(for: .milliseconds(750)) @@ -171,8 +172,8 @@ struct CommentsReducer { } case .onAppear: - if state.detailState == nil { - state.detailState = .init() + if state.detailState.wrappedValue == nil { + state.detailState.wrappedValue = .init() } return state.scrollCommentID != nil ? .send(.performScrollOpacityEffect) : .none diff --git a/EhPanda/View/Detail/DetailReducer.swift b/EhPanda/View/Detail/DetailReducer.swift index a6661577..fcd6858b 100644 --- a/EhPanda/View/Detail/DetailReducer.swift +++ b/EhPanda/View/Detail/DetailReducer.swift @@ -30,10 +30,11 @@ struct DetailReducer { case fetchDatabaseInfos, fetchGalleryDetail, rateGallery, favorGallery, unfavorGallery, postComment, voteTag } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var commentContent = "" - @BindingState var postCommentFocused = false + var route: Route? + var commentContent = "" + var postCommentFocused = false var showsNewDawnGreeting = false var showsUserRating = false @@ -52,13 +53,13 @@ struct DetailReducer { var archivesState = ArchivesReducer.State() var torrentsState = TorrentsReducer.State() var previewsState = PreviewsReducer.State() - @Heap var commentsState: CommentsReducer.State? + var commentsState: Heap var galleryInfosState = GalleryInfosReducer.State() - @Heap var detailSearchState: DetailSearchReducer.State? + var detailSearchState: Heap init() { - _commentsState = .init(nil) - _detailSearchState = .init(nil) + commentsState = .init(nil) + detailSearchState = .init(nil) } mutating func updateRating(value: DragGesture.Value) { @@ -120,12 +121,12 @@ struct DetailReducer { var body: some Reducer { RecurseReducer { (self) in BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -138,11 +139,11 @@ struct DetailReducer { state.archivesState = .init() state.torrentsState = .init() state.previewsState = .init() - state.commentsState = .init() + state.commentsState.wrappedValue = .init() state.commentContent = .init() state.postCommentFocused = false state.galleryInfosState = .init() - state.detailSearchState = .init() + state.detailSearchState.wrappedValue = .init() return .merge( .send(.reading(.teardown)), .send(.archives(.teardown)), @@ -160,11 +161,11 @@ struct DetailReducer { case .onAppear(let gid, let showsNewDawnGreeting): state.showsNewDawnGreeting = showsNewDawnGreeting - if state.detailSearchState == nil { - state.detailSearchState = .init() + if state.detailSearchState.wrappedValue == nil { + state.detailSearchState.wrappedValue = .init() } - if state.commentsState == nil { - state.commentsState = .init() + if state.commentsState.wrappedValue == nil { + state.commentsState.wrappedValue = .init() } return .send(.fetchDatabaseInfos(gid)) @@ -397,8 +398,8 @@ struct DetailReducer { return .send(.anyGalleryOpsDone(result)) case .comments(.detail(let recursiveAction)): - guard state.commentsState != nil else { return .none } - return self.reduce(into: &state.commentsState!.detailState, action: recursiveAction) + guard state.commentsState.wrappedValue != nil else { return .none } + return self.reduce(into: &state.commentsState.wrappedValue!.detailState, action: recursiveAction) .map({ Action.comments(.detail($0)) }) case .comments: @@ -408,8 +409,8 @@ struct DetailReducer { return .none case .detailSearch(.detail(let recursiveAction)): - guard state.detailSearchState != nil else { return .none } - return self.reduce(into: &state.detailSearchState!.detailState, action: recursiveAction) + guard state.detailSearchState.wrappedValue != nil else { return .none } + return self.reduce(into: &state.detailSearchState.wrappedValue!.detailState, action: recursiveAction) .map({ Action.detailSearch(.detail($0)) }) case .detailSearch: @@ -422,7 +423,7 @@ struct DetailReducer { then: CommentsReducer.init ) .ifLet( - \.detailSearchState, + \.detailSearchState.wrappedValue, action: /Action.detailSearch, then: DetailSearchReducer.init ) diff --git a/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift b/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift index 516a63d7..1aecd13f 100644 --- a/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift +++ b/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift @@ -20,9 +20,10 @@ struct DetailSearchReducer { case fetchGalleries, fetchMoreGalleries } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var lastKeyword = "" var galleries = [Gallery]() @@ -30,12 +31,12 @@ struct DetailSearchReducer { var loadingState: LoadingState = .idle var footerLoadingState: LoadingState = .idle - @Heap var detailState: DetailReducer.State! + var detailState: Heap! var filtersState = FiltersReducer.State() var quickDetailSearchState = QuickSearchReducer.State() init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func insertGalleries(_ galleries: [Gallery]) { @@ -68,18 +69,20 @@ struct DetailSearchReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } + .onChange(of: \.keyword) { _, newValue in + Reduce { state, _ in + if !newValue.isEmpty { + state.lastKeyword = newValue + } + return .none + } + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - - case .binding(\.$keyword): - if !state.keyword.isEmpty { - state.lastKeyword = state.keyword - } - return .none - case .binding: return .none @@ -88,7 +91,7 @@ struct DetailSearchReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() state.filtersState = .init() state.quickDetailSearchState = .init() return .merge( diff --git a/EhPanda/View/Detail/GalleryInfos/GalleryInfosReducer.swift b/EhPanda/View/Detail/GalleryInfos/GalleryInfosReducer.swift index 67ba7331..88f65386 100644 --- a/EhPanda/View/Detail/GalleryInfos/GalleryInfosReducer.swift +++ b/EhPanda/View/Detail/GalleryInfos/GalleryInfosReducer.swift @@ -14,8 +14,9 @@ struct GalleryInfosReducer { case hud } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var hudConfig: TTProgressHUDConfig = .copiedToClipboardSucceeded } diff --git a/EhPanda/View/Detail/Previews/PreviewsReducer.swift b/EhPanda/View/Detail/Previews/PreviewsReducer.swift index 77b718df..c943ed3d 100644 --- a/EhPanda/View/Detail/Previews/PreviewsReducer.swift +++ b/EhPanda/View/Detail/Previews/PreviewsReducer.swift @@ -18,8 +18,9 @@ struct PreviewsReducer { case fetchDatabaseInfos, fetchPreviewURLs } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var gallery: Gallery = .empty var loadingState: LoadingState = .idle @@ -59,12 +60,12 @@ struct PreviewsReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none diff --git a/EhPanda/View/Detail/Torrents/TorrentsReducer.swift b/EhPanda/View/Detail/Torrents/TorrentsReducer.swift index c5b4b8b9..e46757e8 100644 --- a/EhPanda/View/Detail/Torrents/TorrentsReducer.swift +++ b/EhPanda/View/Detail/Torrents/TorrentsReducer.swift @@ -21,8 +21,9 @@ struct TorrentsReducer { case fetchTorrent, fetchGalleryTorrents } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var torrents = [GalleryTorrent]() var loadingState: LoadingState = .idle var hudConfig: TTProgressHUDConfig = .copiedToClipboardSucceeded diff --git a/EhPanda/View/Favorites/FavoritesReducer.swift b/EhPanda/View/Favorites/FavoritesReducer.swift index 2f1a054d..e140de18 100644 --- a/EhPanda/View/Favorites/FavoritesReducer.swift +++ b/EhPanda/View/Favorites/FavoritesReducer.swift @@ -17,9 +17,10 @@ struct FavoritesReducer { case detail(String) } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var index = -1 var sortOrder: FavoritesSortOrder? @@ -42,11 +43,11 @@ struct FavoritesReducer { rawFooterLoadingState[index] } - @Heap var detailState: DetailReducer.State! + var detailState: Heap var quickSearchState = QuickSearchReducer.State() init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func insertGalleries(index: Int, galleries: [Gallery]) { @@ -79,12 +80,12 @@ struct FavoritesReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -98,7 +99,7 @@ struct FavoritesReducer { return .send(.fetchGalleries()) case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() return .send(.detail(.teardown)) case .onNotLoginViewButtonTapped: @@ -196,7 +197,7 @@ struct FavoritesReducer { hapticsClient: hapticsClient ) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) Scope(state: \.quickSearchState, action: /Action.quickSearch, child: QuickSearchReducer.init) } } diff --git a/EhPanda/View/Home/Frontpage/FrontpageReducer.swift b/EhPanda/View/Home/Frontpage/FrontpageReducer.swift index 051234a9..8437e913 100644 --- a/EhPanda/View/Home/Frontpage/FrontpageReducer.swift +++ b/EhPanda/View/Home/Frontpage/FrontpageReducer.swift @@ -19,9 +19,10 @@ struct FrontpageReducer { case fetchGalleries, fetchMoreGalleries } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var filteredGalleries: [Gallery] { guard !keyword.isEmpty else { return galleries } @@ -33,10 +34,10 @@ struct FrontpageReducer { var footerLoadingState: LoadingState = .idle var filtersState = FiltersReducer.State() - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func insertGalleries(_ galleries: [Gallery]) { @@ -68,12 +69,12 @@ struct FrontpageReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -82,7 +83,7 @@ struct FrontpageReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() state.filtersState = .init() return .send(.detail(.teardown)) diff --git a/EhPanda/View/Home/History/HistoryReducer.swift b/EhPanda/View/Home/History/HistoryReducer.swift index d49ced81..97a632c2 100644 --- a/EhPanda/View/Home/History/HistoryReducer.swift +++ b/EhPanda/View/Home/History/HistoryReducer.swift @@ -16,10 +16,11 @@ struct HistoryReducer { case clearHistory } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" - @BindingState var clearDialogPresented = false + var route: Route? + var keyword = "" + var clearDialogPresented = false var filteredGalleries: [Gallery] { guard !keyword.isEmpty else { return galleries } @@ -28,10 +29,10 @@ struct HistoryReducer { var galleries = [Gallery]() var loadingState: LoadingState = .idle - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } } @@ -52,12 +53,12 @@ struct HistoryReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -66,7 +67,7 @@ struct HistoryReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() return .send(.detail(.teardown)) case .clearHistoryGalleries: @@ -100,6 +101,6 @@ struct HistoryReducer { } } - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Home/HomeReducer.swift b/EhPanda/View/Home/HomeReducer.swift index bc26afbd..3cae272a 100644 --- a/EhPanda/View/Home/HomeReducer.swift +++ b/EhPanda/View/Home/HomeReducer.swift @@ -19,10 +19,11 @@ struct HomeReducer { case section(HomeSectionType) } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var cardPageIndex = 1 - @BindingState var currentCardID = "" + var route: Route? + var cardPageIndex = 1 + var currentCardID = "" var allowsCardHitTesting = true var rawCardColors = [String: [Color]]() var cardColors: [Color] { @@ -41,10 +42,10 @@ struct HomeReducer { var popularState = PopularReducer.State() var watchedState = WatchedReducer.State() var historyState = HistoryReducer.State() - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func setPopularGalleries(_ galleries: [Gallery]) { @@ -97,21 +98,23 @@ struct HomeReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } + .onChange(of: \.cardPageIndex) { _, newValue in + Reduce { state, _ in + guard newValue < state.popularGalleries.count else { return .none } + state.currentCardID = state.popularGalleries[state.cardPageIndex].gid + state.allowsCardHitTesting = false + return .run { send in + try await Task.sleep(for: .milliseconds(300)) + await send(.setAllowsCardHitTesting(true)) + } + } + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - - case .binding(\.$cardPageIndex): - guard state.cardPageIndex < state.popularGalleries.count else { return .none } - state.currentCardID = state.popularGalleries[state.cardPageIndex].gid - state.allowsCardHitTesting = false - return .run { send in - try await Task.sleep(for: .milliseconds(300)) - await send(.setAllowsCardHitTesting(true)) - } - case .binding: return .none @@ -125,7 +128,7 @@ struct HomeReducer { state.popularState = .init() state.watchedState = .init() state.historyState = .init() - state.detailState = .init() + state.detailState.wrappedValue = .init() return .merge( .send(.frontpage(.teardown)), .send(.toplists(.teardown)), @@ -266,6 +269,6 @@ struct HomeReducer { Scope(state: \.popularState, action: /Action.popular, child: PopularReducer.init) Scope(state: \.watchedState, action: /Action.watched, child: WatchedReducer.init) Scope(state: \.historyState, action: /Action.history, child: HistoryReducer.init) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Home/Popular/PopularReducer.swift b/EhPanda/View/Home/Popular/PopularReducer.swift index feb01187..b1444906 100644 --- a/EhPanda/View/Home/Popular/PopularReducer.swift +++ b/EhPanda/View/Home/Popular/PopularReducer.swift @@ -19,9 +19,10 @@ struct PopularReducer { case fetchGalleries } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var filteredGalleries: [Gallery] { guard !keyword.isEmpty else { return galleries } @@ -31,10 +32,10 @@ struct PopularReducer { var loadingState: LoadingState = .idle var filtersState = FiltersReducer.State() - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } } @@ -56,12 +57,12 @@ struct PopularReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -70,7 +71,7 @@ struct PopularReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() state.filtersState = .init() return .send(.detail(.teardown)) @@ -116,6 +117,6 @@ struct PopularReducer { ) Scope(state: \.filtersState, action: /Action.filters, child: FiltersReducer.init) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Home/Toplists/ToplistsReducer.swift b/EhPanda/View/Home/Toplists/ToplistsReducer.swift index 28e3046b..c48cf9ed 100644 --- a/EhPanda/View/Home/Toplists/ToplistsReducer.swift +++ b/EhPanda/View/Home/Toplists/ToplistsReducer.swift @@ -18,12 +18,13 @@ struct ToplistsReducer { case fetchGalleries, fetchMoreGalleries } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" - @BindingState var jumpPageIndex = "" - @BindingState var jumpPageAlertFocused = false - @BindingState var jumpPageAlertPresented = false + var route: Route? + var keyword = "" + var jumpPageIndex = "" + var jumpPageAlertFocused = false + var jumpPageAlertPresented = false var type: ToplistsType = .yesterday @@ -50,10 +51,10 @@ struct ToplistsReducer { rawFooterLoadingState[type] } - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func insertGalleries(type: ToplistsType, galleries: [Gallery]) { @@ -89,18 +90,20 @@ struct ToplistsReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } + .onChange(of: \.jumpPageAlertPresented) { _, newValue in + Reduce { state, _ in + if !newValue { + state.jumpPageAlertFocused = false + } + return .none + } + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - - case .binding(\.$jumpPageAlertPresented): - if !state.jumpPageAlertPresented { - state.jumpPageAlertFocused = false - } - return .none - case .binding: return .none @@ -114,7 +117,7 @@ struct ToplistsReducer { return .send(.fetchGalleries()) case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() return .send(.detail(.teardown)) case .performJumpPage: @@ -213,6 +216,6 @@ struct ToplistsReducer { } } - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Home/Watched/WatchedReducer.swift b/EhPanda/View/Home/Watched/WatchedReducer.swift index eae05e1e..1955541d 100644 --- a/EhPanda/View/Home/Watched/WatchedReducer.swift +++ b/EhPanda/View/Home/Watched/WatchedReducer.swift @@ -20,9 +20,10 @@ struct WatchedReducer { case fetchGalleries, fetchMoreGalleries } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var galleries = [Gallery]() var pageNumber = PageNumber() @@ -31,10 +32,10 @@ struct WatchedReducer { var filtersState = FiltersReducer.State() var quickSearchState = QuickSearchReducer.State() - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func insertGalleries(_ galleries: [Gallery]) { @@ -68,12 +69,12 @@ struct WatchedReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none @@ -82,7 +83,7 @@ struct WatchedReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() state.filtersState = .init() state.quickSearchState = .init() return .merge( @@ -189,6 +190,6 @@ struct WatchedReducer { Scope(state: \.filtersState, action: /Action.filters, child: FiltersReducer.init) Scope(state: \.quickSearchState, action: /Action.quickSearch, child: QuickSearchReducer.init) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Migration/MigrationReducer.swift b/EhPanda/View/Migration/MigrationReducer.swift index af26b5eb..83c3bf6b 100644 --- a/EhPanda/View/Migration/MigrationReducer.swift +++ b/EhPanda/View/Migration/MigrationReducer.swift @@ -15,8 +15,9 @@ struct MigrationReducer { case dropDialog } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var databaseState: LoadingState = .loading } diff --git a/EhPanda/View/Reading/ReadingReducer.swift b/EhPanda/View/Reading/ReadingReducer.swift index cdaf3c30..b2f5f4ea 100644 --- a/EhPanda/View/Reading/ReadingReducer.swift +++ b/EhPanda/View/Reading/ReadingReducer.swift @@ -48,8 +48,9 @@ struct ReadingReducer { case fetchMPVImageURL } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var gallery: Gallery = .empty var galleryDetail: GalleryDetail? @@ -73,8 +74,8 @@ struct ReadingReducer { var mpvImageKeys = [Int: String]() var mpvSkipServerIdentifiers = [Int: String]() - @BindingState var showsPanel = false - @BindingState var showsSliderPreview = false + var showsPanel = false + var showsSliderPreview = false // Update func update(stored: inout [Int: T], new: [Int: T], replaceExisting: Bool = true) { @@ -188,12 +189,12 @@ struct ReadingReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.showsSliderPreview) { _, _ in + Reduce({ _, _ in .run(operation: { _ in hapticsClient.generateFeedback(.soft) }) }) + } Reduce { state, action in switch action { - case .binding(\.$showsSliderPreview): - return .run(operation: { _ in hapticsClient.generateFeedback(.soft) }) - case .binding: return .none diff --git a/EhPanda/View/Search/SearchReducer.swift b/EhPanda/View/Search/SearchReducer.swift index 65c061e7..239727b4 100644 --- a/EhPanda/View/Search/SearchReducer.swift +++ b/EhPanda/View/Search/SearchReducer.swift @@ -20,9 +20,10 @@ struct SearchReducer { case fetchGalleries, fetchMoreGalleries } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var lastKeyword = "" var galleries = [Gallery]() @@ -31,11 +32,11 @@ struct SearchReducer { var footerLoadingState: LoadingState = .idle var filtersState = FiltersReducer.State() - @Heap var detailState: DetailReducer.State! + var detailState: Heap var quickSearchState = QuickSearchReducer.State() init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func insertGalleries(_ galleries: [Gallery]) { @@ -68,18 +69,20 @@ struct SearchReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } + .onChange(of: \.keyword) { _, newValue in + Reduce { state, _ in + if !newValue.isEmpty { + state.lastKeyword = newValue + } + return .none + } + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - - case .binding(\.$keyword): - if !state.keyword.isEmpty { - state.lastKeyword = state.keyword - } - return .none - case .binding: return .none @@ -88,7 +91,7 @@ struct SearchReducer { return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: - state.detailState = .init() + state.detailState.wrappedValue = .init() state.filtersState = .init() state.quickSearchState = .init() return .merge( @@ -193,6 +196,6 @@ struct SearchReducer { Scope(state: \.filtersState, action: /Action.filters, child: FiltersReducer.init) Scope(state: \.quickSearchState, action: /Action.quickSearch, child: QuickSearchReducer.init) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Search/SearchRootReducer.swift b/EhPanda/View/Search/SearchRootReducer.swift index f50ffd7d..92b74755 100644 --- a/EhPanda/View/Search/SearchRootReducer.swift +++ b/EhPanda/View/Search/SearchRootReducer.swift @@ -17,9 +17,10 @@ struct SearchRootReducer { case detail(String) } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var keyword = "" + var route: Route? + var keyword = "" var historyGalleries = [Gallery]() var historyKeywords = [String]() @@ -28,10 +29,10 @@ struct SearchRootReducer { var searchState = SearchReducer.State() var filtersState = FiltersReducer.State() var quickSearchState = QuickSearchReducer.State() - @Heap var detailState: DetailReducer.State! + var detailState: Heap init() { - _detailState = .init(.init()) + detailState = .init(.init()) } mutating func appendHistoryKeywords(_ keywords: [String]) { @@ -90,17 +91,19 @@ struct SearchRootReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce { _, _ in + newValue == nil + ? .merge( + .send(.clearSubStates), + .send(.fetchDatabaseInfos) + ) + : .none + } + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil - ? .merge( - .send(.clearSubStates), - .send(.fetchDatabaseInfos) - ) - : .none - case .binding: return .none @@ -119,7 +122,7 @@ struct SearchRootReducer { case .clearSubStates: state.searchState = .init() - state.detailState = .init() + state.detailState.wrappedValue = .init() state.filtersState = .init() state.quickSearchState = .init() return .merge( @@ -197,6 +200,6 @@ struct SearchRootReducer { Scope(state: \.searchState, action: /Action.search, child: SearchReducer.init) Scope(state: \.filtersState, action: /Action.filters, child: FiltersReducer.init) Scope(state: \.quickSearchState, action: /Action.quickSearch, child: QuickSearchReducer.init) - Scope(state: \.detailState, action: /Action.detail, child: DetailReducer.init) + Scope(state: \.detailState.wrappedValue!, action: /Action.detail, child: DetailReducer.init) } } diff --git a/EhPanda/View/Search/Support/QuickSearchReducer.swift b/EhPanda/View/Search/Support/QuickSearchReducer.swift index 59f02d04..56001f1f 100644 --- a/EhPanda/View/Search/Support/QuickSearchReducer.swift +++ b/EhPanda/View/Search/Support/QuickSearchReducer.swift @@ -26,11 +26,12 @@ struct QuickSearchReducer { case fetchQuickSearchWords } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var focusedField: FocusField? - @BindingState var editingWord: QuickSearchWord = .empty - @BindingState var listEditMode: EditMode = .inactive + var route: Route? + var focusedField: FocusField? + var editingWord: QuickSearchWord = .empty + var listEditMode: EditMode = .inactive var isListEditing: Bool { get { listEditMode == .active } set { listEditMode = newValue ? .active : .inactive } @@ -65,12 +66,12 @@ struct QuickSearchReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none diff --git a/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift b/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift index faa8b8de..8910b8cc 100644 --- a/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift +++ b/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift @@ -20,10 +20,11 @@ struct AccountSettingReducer { case webView(URL) } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var ehCookiesState: CookiesState = .empty(.ehentai) - @BindingState var exCookiesState: CookiesState = .empty(.exhentai) + var route: Route? + var ehCookiesState: CookiesState = .empty(.ehentai) + var exCookiesState: CookiesState = .empty(.exhentai) var hudConfig: TTProgressHUDConfig = .copiedToClipboardSucceeded var loginState = LoginReducer.State() @@ -47,22 +48,18 @@ struct AccountSettingReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } + .onChange(of: \.ehCookiesState) { _, newValue in + Reduce({ _, _ in .run(operation: { _ in cookieClient.setCookies(state: newValue) }) }) + } + .onChange(of: \.exCookiesState) { _, newValue in + Reduce({ _, _ in .run(operation: { _ in cookieClient.setCookies(state: newValue) }) }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - - case .binding(\.$ehCookiesState): - return .run { [state] _ in - cookieClient.setCookies(state: state.ehCookiesState) - } - - case .binding(\.$exCookiesState): - return .run { [state] _ in - cookieClient.setCookies(state: state.exCookiesState) - } - case .binding: return .none diff --git a/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingReducer.swift b/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingReducer.swift index c7e57396..1b45dbe4 100644 --- a/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingReducer.swift +++ b/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingReducer.swift @@ -13,8 +13,9 @@ struct AppearanceSettingReducer { case appIcon } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? } enum Action: BindableAction, Equatable { diff --git a/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift b/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift index cd408e3e..26471655 100644 --- a/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift +++ b/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift @@ -20,11 +20,12 @@ struct EhSettingReducer { case fetchEhSetting, submitChanges, performAction } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var editingProfileName = "" - @BindingState var ehSetting: EhSetting? - @BindingState var ehProfile: EhProfile? + var route: Route? + var editingProfileName = "" + var ehSetting: EhSetting? + var ehProfile: EhProfile? var loadingState: LoadingState = .idle var submittingState: LoadingState = .idle diff --git a/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift b/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift index ddf1980c..a2151e0c 100644 --- a/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift +++ b/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift @@ -17,8 +17,9 @@ struct GeneralSettingReducer { case removeCustomTranslations } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var loadingState: LoadingState = .idle var diskImageCacheSize = "0 KB" @@ -50,12 +51,12 @@ struct GeneralSettingReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.route) { _, newValue in + Reduce({ _, _ in newValue == nil ? .send(.clearSubStates) : .none }) + } Reduce { state, action in switch action { - case .binding(\.$route): - return state.route == nil ? .send(.clearSubStates) : .none - case .binding: return .none diff --git a/EhPanda/View/Setting/Login/LoginReducer.swift b/EhPanda/View/Setting/Login/LoginReducer.swift index 7342a31c..e289703e 100644 --- a/EhPanda/View/Setting/Login/LoginReducer.swift +++ b/EhPanda/View/Setting/Login/LoginReducer.swift @@ -23,11 +23,12 @@ struct LoginReducer { case password } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var focusedField: FocusedField? - @BindingState var username = "" - @BindingState var password = "" + var route: Route? + var focusedField: FocusedField? + var username = "" + var password = "" var loginState: LoadingState = .idle var loginButtonDisabled: Bool { diff --git a/EhPanda/View/Setting/Logs/LogsReducer.swift b/EhPanda/View/Setting/Logs/LogsReducer.swift index ea708a4d..906ec4d1 100644 --- a/EhPanda/View/Setting/Logs/LogsReducer.swift +++ b/EhPanda/View/Setting/Logs/LogsReducer.swift @@ -18,8 +18,9 @@ struct LogsReducer { case fetchLogs } + @ObservableState struct State: Equatable { - @BindingState var route: Route? + var route: Route? var loadingState: LoadingState = .idle var logs = [Log]() } diff --git a/EhPanda/View/Setting/SettingReducer.swift b/EhPanda/View/Setting/SettingReducer.swift index 7c206fcf..9ed13e49 100644 --- a/EhPanda/View/Setting/SettingReducer.swift +++ b/EhPanda/View/Setting/SettingReducer.swift @@ -22,15 +22,16 @@ struct SettingReducer { case about } + @ObservableState struct State: Equatable { // AppEnvStorage - @BindingState var setting = Setting() + var setting = Setting() var tagTranslator = TagTranslator() var user = User() var hasLoadedInitialSetting = false - @BindingState var route: Route? + var route: Route? var tagTranslatorLoadingState: LoadingState = .idle var accountSettingState = AccountSettingReducer.State() @@ -113,6 +114,9 @@ struct SettingReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.setting) { _, _ in + Reduce({ _, _ in .send(.syncSetting) }) + } .onChange(of: \.setting.galleryHost) { _, newValue in Reduce { _, _ in .merge( @@ -206,12 +210,6 @@ struct SettingReducer { Reduce { state, action in switch action { - case .binding(\.$setting): - return .send(.syncSetting) - - case .binding(\.$route): - return .none - case .binding: return .merge( .send(.syncUser), diff --git a/EhPanda/View/Support/FiltersReducer.swift b/EhPanda/View/Support/FiltersReducer.swift index 9851b9a4..112ea0a4 100644 --- a/EhPanda/View/Support/FiltersReducer.swift +++ b/EhPanda/View/Support/FiltersReducer.swift @@ -18,14 +18,15 @@ struct FiltersReducer { case upper } + @ObservableState struct State: Equatable { - @BindingState var route: Route? - @BindingState var filterRange: FilterRange = .search - @BindingState var focusedBound: FocusedBound? + var route: Route? + var filterRange: FilterRange = .search + var focusedBound: FocusedBound? - @BindingState var searchFilter = Filter() - @BindingState var globalFilter = Filter() - @BindingState var watchedFilter = Filter() + var searchFilter = Filter() + var globalFilter = Filter() + var watchedFilter = Filter() } enum Action: BindableAction, Equatable { @@ -43,21 +44,27 @@ struct FiltersReducer { var body: some Reducer { BindingReducer() + .onChange(of: \.searchFilter) { _, _ in + Reduce { state, _ in + state.searchFilter.fixInvalidData() + return .send(.syncFilter(.search)) + } + } + .onChange(of: \.globalFilter) { _, _ in + Reduce { state, _ in + state.globalFilter.fixInvalidData() + return .send(.syncFilter(.global)) + } + } + .onChange(of: \.watchedFilter) { _, _ in + Reduce { state, _ in + state.watchedFilter.fixInvalidData() + return .send(.syncFilter(.watched)) + } + } Reduce { state, action in switch action { - case .binding(\.$searchFilter): - state.searchFilter.fixInvalidData() - return .send(.syncFilter(.search)) - - case .binding(\.$globalFilter): - state.globalFilter.fixInvalidData() - return .send(.syncFilter(.global)) - - case .binding(\.$watchedFilter): - state.watchedFilter.fixInvalidData() - return .send(.syncFilter(.watched)) - case .binding: return .none diff --git a/EhPanda/View/TabBar/TabBarReducer.swift b/EhPanda/View/TabBar/TabBarReducer.swift index d5911530..d550073b 100644 --- a/EhPanda/View/TabBar/TabBarReducer.swift +++ b/EhPanda/View/TabBar/TabBarReducer.swift @@ -9,6 +9,7 @@ import ComposableArchitecture @Reducer struct TabBarReducer { + @ObservableState struct State: Equatable { var tabBarItemType: TabBarItemType = .home }