From 4b7b018530fa284f02ae8524622ae82d9dde617a Mon Sep 17 00:00:00 2001 From: Chihchy Date: Sat, 27 Jan 2024 23:00:44 +0800 Subject: [PATCH] Migrate to TCA 1.0 [WIP] --- .../App/Tools/Clients/AppDelegateClient.swift | 10 +-- .../Tools/Clients/AuthorizationClient.swift | 2 +- .../App/Tools/Clients/ClipboardClient.swift | 4 +- EhPanda/App/Tools/Clients/CookieClient.swift | 20 ++--- EhPanda/App/Tools/Clients/DFClient.swift | 2 +- .../App/Tools/Clients/DatabaseClient.swift | 72 +++++++-------- EhPanda/App/Tools/Clients/FileClient.swift | 6 +- EhPanda/App/Tools/Clients/ImageClient.swift | 10 +-- EhPanda/App/Tools/Clients/LibraryClient.swift | 10 +-- EhPanda/App/Tools/Clients/LoggerClient.swift | 4 +- .../Tools/Clients/UIApplicationClient.swift | 12 +-- .../Tools/Clients/UserDefaultsClient.swift | 2 +- .../Tools/Extensions/Reducer_Extension.swift | 2 +- EhPanda/DataFlow/AppDelegateReducer.swift | 6 +- EhPanda/DataFlow/AppLockReducer.swift | 8 +- EhPanda/DataFlow/AppReducer.swift | 58 ++++++------ EhPanda/DataFlow/AppRouteReducer.swift | 32 +++---- EhPanda/Network/Request.swift | 2 +- .../Detail/Archives/ArchivesReducer.swift | 6 +- .../View/Detail/Archives/ArchivesView.swift | 10 +-- .../Detail/Comments/CommentsReducer.swift | 34 +++---- .../View/Detail/Comments/CommentsView.swift | 14 +-- EhPanda/View/Detail/DetailReducer.swift | 50 +++++------ .../DetailSearch/DetailSearchReducer.swift | 14 +-- .../DetailSearch/DetailSearchView.swift | 16 ++-- EhPanda/View/Detail/DetailView.swift | 30 +++---- .../GalleryInfos/GalleryInfosView.swift | 6 +- .../Detail/Previews/PreviewsReducer.swift | 10 +-- .../View/Detail/Previews/PreviewsView.swift | 6 +- .../Detail/Torrents/TorrentsReducer.swift | 4 +- .../View/Detail/Torrents/TorrentsView.swift | 8 +- EhPanda/View/Favorites/FavoritesReducer.swift | 12 +-- EhPanda/View/Favorites/FavoritesView.swift | 14 +-- .../Home/Frontpage/FrontpageReducer.swift | 12 +-- .../View/Home/Frontpage/FrontpageView.swift | 12 +-- .../View/Home/History/HistoryReducer.swift | 8 +- EhPanda/View/Home/History/HistoryView.swift | 12 +-- EhPanda/View/Home/HomeReducer.swift | 24 ++--- EhPanda/View/Home/HomeView.swift | 14 +-- .../View/Home/Popular/PopularReducer.swift | 6 +- EhPanda/View/Home/Popular/PopularView.swift | 12 +-- .../View/Home/Toplists/ToplistsReducer.swift | 14 +-- EhPanda/View/Home/Toplists/ToplistsView.swift | 16 ++-- .../View/Home/Watched/WatchedReducer.swift | 14 +-- EhPanda/View/Home/Watched/WatchedView.swift | 16 ++-- EhPanda/View/Migration/MigrationReducer.swift | 4 +- EhPanda/View/Migration/MigrationView.swift | 6 +- EhPanda/View/Reading/ReadingReducer.swift | 58 ++++++------ EhPanda/View/Reading/ReadingView.swift | 14 +-- EhPanda/View/Search/SearchReducer.swift | 14 +-- EhPanda/View/Search/SearchRootReducer.swift | 20 ++--- EhPanda/View/Search/SearchRootView.swift | 18 ++-- EhPanda/View/Search/SearchView.swift | 16 ++-- .../Search/Support/QuickSearchReducer.swift | 14 +-- .../View/Search/Support/QuickSearchView.swift | 18 ++-- .../AccountSettingReducer.swift | 2 + .../AccountSetting/AccountSettingView.swift | 18 ++-- .../AppearanceSettingView.swift | 6 +- .../Setting/EhSetting/EhSettingView.swift | 14 +-- .../GeneralSettingReducer.swift | 8 +- .../GeneralSetting/GeneralSettingView.swift | 10 +-- EhPanda/View/Setting/Login/LoginReducer.swift | 2 +- EhPanda/View/Setting/Login/LoginView.swift | 12 +-- EhPanda/View/Setting/Logs/LogsView.swift | 6 +- EhPanda/View/Setting/SettingReducer.swift | 88 +++++++++---------- EhPanda/View/Setting/SettingView.swift | 64 +++++++------- EhPanda/View/Support/FiltersReducer.swift | 12 +-- EhPanda/View/Support/FiltersView.swift | 16 ++-- EhPanda/View/TabBar/TabBarView.swift | 4 +- 69 files changed, 551 insertions(+), 549 deletions(-) diff --git a/EhPanda/App/Tools/Clients/AppDelegateClient.swift b/EhPanda/App/Tools/Clients/AppDelegateClient.swift index a904cca7..2bb6074b 100644 --- a/EhPanda/App/Tools/Clients/AppDelegateClient.swift +++ b/EhPanda/App/Tools/Clients/AppDelegateClient.swift @@ -9,8 +9,8 @@ import SwiftUI import ComposableArchitecture struct AppDelegateClient { - let setOrientation: (UIInterfaceOrientationMask) -> EffectTask - let setOrientationMask: (UIInterfaceOrientationMask) -> EffectTask + let setOrientation: (UIInterfaceOrientationMask) -> Effect + let setOrientationMask: (UIInterfaceOrientationMask) -> Effect } extension AppDelegateClient { @@ -27,13 +27,13 @@ extension AppDelegateClient { } ) - func setPortraitOrientation() -> EffectTask { + func setPortraitOrientation() -> Effect { setOrientation(.portrait) } - func setAllOrientationMask() -> EffectTask { + func setAllOrientationMask() -> Effect { setOrientationMask([.all]) } - func setPortraitOrientationMask() -> EffectTask { + func setPortraitOrientationMask() -> Effect { setOrientationMask([.portrait, .portraitUpsideDown]) } } diff --git a/EhPanda/App/Tools/Clients/AuthorizationClient.swift b/EhPanda/App/Tools/Clients/AuthorizationClient.swift index 442811fe..7537a562 100644 --- a/EhPanda/App/Tools/Clients/AuthorizationClient.swift +++ b/EhPanda/App/Tools/Clients/AuthorizationClient.swift @@ -11,7 +11,7 @@ import ComposableArchitecture struct AuthorizationClient { let passcodeNotSet: () -> Bool - let localAuthroize: (String) -> EffectTask + let localAuthroize: (String) -> Effect } extension AuthorizationClient { diff --git a/EhPanda/App/Tools/Clients/ClipboardClient.swift b/EhPanda/App/Tools/Clients/ClipboardClient.swift index 4c72c63f..9a78c64f 100644 --- a/EhPanda/App/Tools/Clients/ClipboardClient.swift +++ b/EhPanda/App/Tools/Clients/ClipboardClient.swift @@ -12,8 +12,8 @@ import UniformTypeIdentifiers struct ClipboardClient { let url: () -> URL? let changeCount: () -> Int - let saveText: (String) -> EffectTask - let saveImage: (UIImage, Bool) -> EffectTask + let saveText: (String) -> Effect + let saveImage: (UIImage, Bool) -> Effect } extension ClipboardClient { diff --git a/EhPanda/App/Tools/Clients/CookieClient.swift b/EhPanda/App/Tools/Clients/CookieClient.swift index 86143d11..fcecc2a0 100644 --- a/EhPanda/App/Tools/Clients/CookieClient.swift +++ b/EhPanda/App/Tools/Clients/CookieClient.swift @@ -9,7 +9,7 @@ import Foundation import ComposableArchitecture struct CookieClient { - let clearAll: () -> EffectTask + let clearAll: () -> Effect let getCookie: (URL, String) -> CookieValue private let removeCookie: (URL, String) -> Void private let checkExistence: (URL, String) -> Bool @@ -108,7 +108,7 @@ extension CookieClient { guard let cookie = newCookie else { return } HTTPCookieStorage.shared.setCookie(cookie) } - func setOrEditCookie(for url: URL, key: String, value: String) -> EffectTask { + func setOrEditCookie(for url: URL, key: String, value: String) -> Effect { .fireAndForget { if checkExistence(url, key) { editCookie(for: url, key: key, value: value) @@ -138,13 +138,13 @@ extension CookieClient { && !getCookie(url, Defaults.Cookie.ipbPassHash).rawValue.isEmpty && getCookie(url, Defaults.Cookie.igneous).rawValue.isEmpty } - func removeYay() -> EffectTask { + func removeYay() -> Effect { .fireAndForget { removeCookie(Defaults.URL.exhentai, Defaults.Cookie.yay) removeCookie(Defaults.URL.sexhentai, Defaults.Cookie.yay) } } - func syncExCookies() -> EffectTask { + func syncExCookies() -> Effect { .merge( [ Defaults.Cookie.ipbMemberId, @@ -160,13 +160,13 @@ extension CookieClient { } ) } - func ignoreOffensive() -> EffectTask { + func ignoreOffensive() -> Effect { .merge( setOrEditCookie(for: Defaults.URL.ehentai, key: Defaults.Cookie.ignoreOffensive, value: "1"), setOrEditCookie(for: Defaults.URL.exhentai, key: Defaults.Cookie.ignoreOffensive, value: "1") ) } - func fulfillAnotherHostField() -> EffectTask { + func fulfillAnotherHostField() -> Effect { let ehURL = Defaults.URL.ehentai let exURL = Defaults.URL.exhentai let memberIdKey = Defaults.Cookie.ipbMemberId @@ -218,8 +218,8 @@ extension CookieClient { // MARK: SetCookies extension CookieClient { - func setCookies(state: CookiesState, trimsSpaces: Bool = true) -> EffectTask { - let effects: [EffectTask] = state.allCases + func setCookies(state: CookiesState, trimsSpaces: Bool = true) -> Effect { + let effects: [Effect] = state.allCases .flatMap { subState in state.host.cookieURLs .map { @@ -233,7 +233,7 @@ extension CookieClient { } return effects.isEmpty ? .none : .merge(effects) } - func setCredentials(response: HTTPURLResponse) -> EffectTask { + func setCredentials(response: HTTPURLResponse) -> Effect { .fireAndForget { guard let setString = response.allHeaderFields["Set-Cookie"] as? String else { return } setString.components(separatedBy: ", ") @@ -252,7 +252,7 @@ extension CookieClient { } } } - func setSkipServer(response: HTTPURLResponse) -> EffectTask { + func setSkipServer(response: HTTPURLResponse) -> Effect { .fireAndForget { guard let setString = response.allHeaderFields["Set-Cookie"] as? String else { return } setString.components(separatedBy: ", ") diff --git a/EhPanda/App/Tools/Clients/DFClient.swift b/EhPanda/App/Tools/Clients/DFClient.swift index 54a900c5..a8a77382 100644 --- a/EhPanda/App/Tools/Clients/DFClient.swift +++ b/EhPanda/App/Tools/Clients/DFClient.swift @@ -10,7 +10,7 @@ import Kingfisher import ComposableArchitecture struct DFClient { - let setActive: (Bool) -> EffectTask + let setActive: (Bool) -> Effect } extension DFClient { diff --git a/EhPanda/App/Tools/Clients/DatabaseClient.swift b/EhPanda/App/Tools/Clients/DatabaseClient.swift index 574f0fb0..5684896d 100644 --- a/EhPanda/App/Tools/Clients/DatabaseClient.swift +++ b/EhPanda/App/Tools/Clients/DatabaseClient.swift @@ -11,8 +11,8 @@ import CoreData import ComposableArchitecture struct DatabaseClient { - let prepareDatabase: () -> EffectTask - let dropDatabase: () -> EffectTask + let prepareDatabase: () -> Effect + let dropDatabase: () -> Effect private let saveContext: () -> Void private let materializedObjects: (NSManagedObjectContext, NSPredicate) -> [NSManagedObject] } @@ -216,7 +216,7 @@ extension DatabaseClient { } return entity } - func fetchAppEnv() -> EffectTask { + func fetchAppEnv() -> Effect { Future { promise in DispatchQueue.main.async { promise(.success(fetchOrCreate(entityType: AppEnvMO.self).toEntity())) @@ -229,7 +229,7 @@ extension DatabaseClient { func fetchAppEnvSynchronously() -> AppEnv { fetchOrCreate(entityType: AppEnvMO.self).toEntity() } - func fetchGalleryState(gid: String) -> EffectTask { + func fetchGalleryState(gid: String) -> Effect { guard gid.isValidGID else { return .none } return Future { promise in DispatchQueue.main.async { @@ -242,7 +242,7 @@ extension DatabaseClient { .receive(on: DispatchQueue.main) .eraseToEffect() } - func fetchHistoryGalleries(fetchLimit: Int = 0) -> EffectTask<[Gallery]> { + func fetchHistoryGalleries(fetchLimit: Int = 0) -> Effect<[Gallery]> { Future { promise in DispatchQueue.main.async { let predicate = NSPredicate(format: "lastOpenDate != nil") @@ -274,13 +274,13 @@ extension DatabaseClient { return fetchAppEnvSynchronously().watchedFilter } } - func fetchHistoryKeywords() -> EffectTask<[String]> { + func fetchHistoryKeywords() -> Effect<[String]> { fetchAppEnv().map(\.historyKeywords) } - func fetchQuickSearchWords() -> EffectTask<[QuickSearchWord]> { + func fetchQuickSearchWords() -> Effect<[QuickSearchWord]> { fetchAppEnv().map(\.quickSearchWords) } - func fetchGalleryPreviewURLs(gid: String) -> EffectTask<[Int: URL]> { + func fetchGalleryPreviewURLs(gid: String) -> Effect<[Int: URL]> { guard gid.isValidGID else { return .none } return fetchGalleryState(gid: gid).map(\.previewURLs) } @@ -288,7 +288,7 @@ extension DatabaseClient { // MARK: UpdateGallery extension DatabaseClient { - func updateGallery(gid: String, key: String, value: Any?) -> EffectTask { + func updateGallery(gid: String, key: String, value: Any?) -> Effect { guard gid.isValidGID else { return .none } return .fireAndForget { DispatchQueue.main.async { @@ -299,11 +299,11 @@ extension DatabaseClient { } } } - func updateLastOpenDate(gid: String, date: Date = .now) -> EffectTask { + func updateLastOpenDate(gid: String, date: Date = .now) -> Effect { guard gid.isValidGID else { return .none } return updateGallery(gid: gid, key: "lastOpenDate", value: date) } - func clearHistoryGalleries() -> EffectTask { + func clearHistoryGalleries() -> Effect { .fireAndForget { DispatchQueue.main.async { let predicate = NSPredicate(format: "lastOpenDate != nil") @@ -315,7 +315,7 @@ extension DatabaseClient { } } } - func cacheGalleries(_ galleries: [Gallery]) -> EffectTask { + func cacheGalleries(_ galleries: [Gallery]) -> Effect { .fireAndForget { DispatchQueue.main.async { for gallery in galleries.filter({ $0.id.isValidGID }) { @@ -348,7 +348,7 @@ extension DatabaseClient { // MARK: UpdateGalleryDetail extension DatabaseClient { - func cacheGalleryDetail(_ detail: GalleryDetail) -> EffectTask { + func cacheGalleryDetail(_ detail: GalleryDetail) -> Effect { guard detail.gid.isValidGID else { return .none } return .fireAndForget { DispatchQueue.main.async { @@ -386,7 +386,7 @@ extension DatabaseClient { // MARK: UpdateGalleryState extension DatabaseClient { - func updateGalleryState(gid: String, commitChanges: @escaping (GalleryStateMO) -> Void) -> EffectTask { + func updateGalleryState(gid: String, commitChanges: @escaping (GalleryStateMO) -> Void) -> Effect { guard gid.isValidGID else { return .none } return .fireAndForget { DispatchQueue.main.async { @@ -397,30 +397,30 @@ extension DatabaseClient { } } } - func updateGalleryState(gid: String, key: String, value: Any?) -> EffectTask { + func updateGalleryState(gid: String, key: String, value: Any?) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid) { stateMO in stateMO.setValue(value, forKeyPath: key) } } - func updateGalleryTags(gid: String, tags: [GalleryTag]) -> EffectTask { + func updateGalleryTags(gid: String, tags: [GalleryTag]) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid, key: "tags", value: tags.toData()) } - func updatePreviewConfig(gid: String, config: PreviewConfig) -> EffectTask { + func updatePreviewConfig(gid: String, config: PreviewConfig) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid, key: "previewConfig", value: config.toData()) } - func updateReadingProgress(gid: String, progress: Int) -> EffectTask { + func updateReadingProgress(gid: String, progress: Int) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid, key: "readingProgress", value: Int64(progress)) } - func updateComments(gid: String, comments: [GalleryComment]) -> EffectTask { + func updateComments(gid: String, comments: [GalleryComment]) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid, key: "comments", value: comments.toData()) } - func removeImageURLs(gid: String) -> EffectTask { + func removeImageURLs(gid: String) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid) { galleryStateMO in galleryStateMO.imageURLs = nil @@ -429,7 +429,7 @@ extension DatabaseClient { galleryStateMO.originalImageURLs = nil } } - func removeImageURLs() -> EffectTask { + func removeImageURLs() -> Effect { .fireAndForget { DispatchQueue.main.async { batchUpdate(entityType: GalleryStateMO.self) { galleryStateMOs in @@ -443,14 +443,14 @@ extension DatabaseClient { } } } - func removeExpiredImageURLs() -> EffectTask { + func removeExpiredImageURLs() -> Effect { fetchHistoryGalleries() .map { $0.filter { Date().timeIntervalSince($0.lastOpenDate ?? .distantPast) > .oneWeek } } .map { $0.map { removeImageURLs(gid: $0.id) } } - .map(EffectTask.merge) + .map(Effect.merge) .fireAndForget() } - func updateThumbnailURLs(gid: String, thumbnailURLs: [Int: URL]) -> EffectTask { + func updateThumbnailURLs(gid: String, thumbnailURLs: [Int: URL]) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid) { galleryStateMO in update(gid: gid, storedData: &galleryStateMO.thumbnailURLs, new: thumbnailURLs) @@ -458,14 +458,14 @@ extension DatabaseClient { } func updateImageURLs( gid: String, imageURLs: [Int: URL], originalImageURLs: [Int: URL] - ) -> EffectTask { + ) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid) { galleryStateMO in update(gid: gid, storedData: &galleryStateMO.imageURLs, new: imageURLs) update(gid: gid, storedData: &galleryStateMO.originalImageURLs, new: originalImageURLs) } } - func updatePreviewURLs(gid: String, previewURLs: [Int: URL]) -> EffectTask { + func updatePreviewURLs(gid: String, previewURLs: [Int: URL]) -> Effect { guard gid.isValidGID else { return .none } return updateGalleryState(gid: gid) { galleryStateMO in update(gid: gid, storedData: &galleryStateMO.previewURLs, new: previewURLs) @@ -489,7 +489,7 @@ extension DatabaseClient { // MARK: UpdateAppEnv extension DatabaseClient { - func updateAppEnv(key: String, value: Any?) -> EffectTask { + func updateAppEnv(key: String, value: Any?) -> Effect { .fireAndForget { DispatchQueue.main.async { update( @@ -499,10 +499,10 @@ extension DatabaseClient { } } } - func updateSetting(_ setting: Setting) -> EffectTask { + func updateSetting(_ setting: Setting) -> Effect { updateAppEnv(key: "setting", value: setting.toData()) } - func updateFilter(_ filter: Filter, range: FilterRange) -> EffectTask { + func updateFilter(_ filter: Filter, range: FilterRange) -> Effect { let key: String switch range { case .search: @@ -514,21 +514,21 @@ extension DatabaseClient { } return updateAppEnv(key: key, value: filter.toData()) } - func updateTagTranslator(_ tagTranslator: TagTranslator) -> EffectTask { + func updateTagTranslator(_ tagTranslator: TagTranslator) -> Effect { updateAppEnv(key: "tagTranslator", value: tagTranslator.toData()) } - func updateUser(_ user: User) -> EffectTask { + func updateUser(_ user: User) -> Effect { updateAppEnv(key: "user", value: user.toData()) } - func updateHistoryKeywords(_ keywords: [String]) -> EffectTask { + func updateHistoryKeywords(_ keywords: [String]) -> Effect { updateAppEnv(key: "historyKeywords", value: keywords.toData()) } - func updateQuickSearchWords(_ words: [QuickSearchWord]) -> EffectTask { + func updateQuickSearchWords(_ words: [QuickSearchWord]) -> Effect { updateAppEnv(key: "quickSearchWords", value: words.toData()) } // Update User - func updateUserProperty(_ commitChanges: @escaping (inout User) -> Void) -> EffectTask { + func updateUserProperty(_ commitChanges: @escaping (inout User) -> Void) -> Effect { fetchAppEnv().map(\.user) .map { (user: User) -> User in var user = user @@ -538,12 +538,12 @@ extension DatabaseClient { .flatMap(updateUser) .eraseToEffect() } - func updateGreeting(_ greeting: Greeting) -> EffectTask { + func updateGreeting(_ greeting: Greeting) -> Effect { updateUserProperty { user in user.greeting = greeting } } - func updateGalleryFunds(galleryPoints: String, credits: String) -> EffectTask { + func updateGalleryFunds(galleryPoints: String, credits: String) -> Effect { updateUserProperty { user in user.credits = credits user.galleryPoints = galleryPoints diff --git a/EhPanda/App/Tools/Clients/FileClient.swift b/EhPanda/App/Tools/Clients/FileClient.swift index 15461dd9..0539e7a5 100644 --- a/EhPanda/App/Tools/Clients/FileClient.swift +++ b/EhPanda/App/Tools/Clients/FileClient.swift @@ -11,9 +11,9 @@ import ComposableArchitecture struct FileClient { let createFile: (String, Data?) -> Bool - let fetchLogs: () -> EffectTask> - let deleteLog: (String) -> EffectTask> - let importTagTranslator: (URL) -> EffectTask> + let fetchLogs: () -> Effect> + let deleteLog: (String) -> Effect> + let importTagTranslator: (URL) -> Effect> } extension FileClient { diff --git a/EhPanda/App/Tools/Clients/ImageClient.swift b/EhPanda/App/Tools/Clients/ImageClient.swift index f31a8638..b5ef848a 100644 --- a/EhPanda/App/Tools/Clients/ImageClient.swift +++ b/EhPanda/App/Tools/Clients/ImageClient.swift @@ -12,10 +12,10 @@ import Kingfisher import ComposableArchitecture struct ImageClient { - let prefetchImages: ([URL]) -> EffectTask - let saveImageToPhotoLibrary: (UIImage, Bool) -> EffectTask - let downloadImage: (URL) -> EffectTask> - let retrieveImage: (String) -> EffectTask> + let prefetchImages: ([URL]) -> Effect + let saveImageToPhotoLibrary: (UIImage, Bool) -> Effect + let downloadImage: (URL) -> Effect> + let retrieveImage: (String) -> Effect> } extension ImageClient { @@ -78,7 +78,7 @@ extension ImageClient { } ) - func fetchImage(url: URL) -> EffectTask> { + func fetchImage(url: URL) -> Effect> { if KingfisherManager.shared.cache.isCached(forKey: url.absoluteString) { return retrieveImage(url.absoluteString) } else { diff --git a/EhPanda/App/Tools/Clients/LibraryClient.swift b/EhPanda/App/Tools/Clients/LibraryClient.swift index 5f566e54..a4063444 100644 --- a/EhPanda/App/Tools/Clients/LibraryClient.swift +++ b/EhPanda/App/Tools/Clients/LibraryClient.swift @@ -14,11 +14,11 @@ import UIImageColors import ComposableArchitecture struct LibraryClient { - let initializeLogger: () -> EffectTask - let initializeWebImage: () -> EffectTask - let clearWebImageDiskCache: () -> EffectTask - let analyzeImageColors: (UIImage) -> EffectTask - let calculateWebImageDiskCacheSize: () -> EffectTask + let initializeLogger: () -> Effect + let initializeWebImage: () -> Effect + let clearWebImageDiskCache: () -> Effect + let analyzeImageColors: (UIImage) -> Effect + let calculateWebImageDiskCacheSize: () -> Effect } extension LibraryClient { diff --git a/EhPanda/App/Tools/Clients/LoggerClient.swift b/EhPanda/App/Tools/Clients/LoggerClient.swift index ebeefb83..6c1a2b63 100644 --- a/EhPanda/App/Tools/Clients/LoggerClient.swift +++ b/EhPanda/App/Tools/Clients/LoggerClient.swift @@ -8,8 +8,8 @@ import ComposableArchitecture struct LoggerClient { - let info: (Any, Any?) -> EffectTask - let error: (Any, Any?) -> EffectTask + let info: (Any, Any?) -> Effect + let error: (Any, Any?) -> Effect } extension LoggerClient { diff --git a/EhPanda/App/Tools/Clients/UIApplicationClient.swift b/EhPanda/App/Tools/Clients/UIApplicationClient.swift index 97aef088..5b684af7 100644 --- a/EhPanda/App/Tools/Clients/UIApplicationClient.swift +++ b/EhPanda/App/Tools/Clients/UIApplicationClient.swift @@ -10,11 +10,11 @@ import Combine import ComposableArchitecture struct UIApplicationClient { - let openURL: (URL) -> EffectTask - let hideKeyboard: () -> EffectTask + let openURL: (URL) -> Effect + let hideKeyboard: () -> Effect let alternateIconName: () -> String? - let setAlternateIconName: (String?) -> EffectTask> - let setUserInterfaceStyle: (UIUserInterfaceStyle) -> EffectTask + let setAlternateIconName: (String?) -> Effect> + let setUserInterfaceStyle: (UIUserInterfaceStyle) -> Effect } extension UIApplicationClient { @@ -51,13 +51,13 @@ extension UIApplicationClient { } } ) - func openSettings() -> EffectTask { + func openSettings() -> Effect { if let url = URL(string: UIApplication.openSettingsURLString) { return openURL(url) } return .none } - func openFileApp() -> EffectTask { + func openFileApp() -> Effect { if let dirPath = FileUtil.logsDirectoryURL?.path, let dirURL = URL(string: "shareddocuments://" + dirPath) { diff --git a/EhPanda/App/Tools/Clients/UserDefaultsClient.swift b/EhPanda/App/Tools/Clients/UserDefaultsClient.swift index c403f278..ab6630f2 100644 --- a/EhPanda/App/Tools/Clients/UserDefaultsClient.swift +++ b/EhPanda/App/Tools/Clients/UserDefaultsClient.swift @@ -9,7 +9,7 @@ import Foundation import ComposableArchitecture struct UserDefaultsClient { - let setValue: (Any, AppUserDefaults) -> EffectTask + let setValue: (Any, AppUserDefaults) -> Effect } extension UserDefaultsClient { diff --git a/EhPanda/App/Tools/Extensions/Reducer_Extension.swift b/EhPanda/App/Tools/Extensions/Reducer_Extension.swift index 1fe1c4ae..459f0249 100644 --- a/EhPanda/App/Tools/Extensions/Reducer_Extension.swift +++ b/EhPanda/App/Tools/Extensions/Reducer_Extension.swift @@ -23,7 +23,7 @@ extension ReducerProtocol { private func onBecomeNonNil( unwrapping enum: @escaping (State) -> Enum?, case casePath: CasePath, - perform additionalEffects: @escaping (inout State, Action) -> EffectTask + perform additionalEffects: @escaping (inout State, Action) -> Effect ) -> some ReducerProtocol { Reduce { state, action in let previousCase = Binding.constant(`enum`(state)).case(casePath).wrappedValue diff --git a/EhPanda/DataFlow/AppDelegateReducer.swift b/EhPanda/DataFlow/AppDelegateReducer.swift index 53efa716..7c76a18b 100644 --- a/EhPanda/DataFlow/AppDelegateReducer.swift +++ b/EhPanda/DataFlow/AppDelegateReducer.swift @@ -36,7 +36,7 @@ struct AppDelegateReducer: ReducerProtocol { cookieClient.syncExCookies().fireAndForget(), cookieClient.ignoreOffensive().fireAndForget(), cookieClient.fulfillAnotherHostField().fireAndForget(), - .init(value: .migration(.prepareDatabase)) + .send(.migration(.prepareDatabase)) ) case .removeExpiredImageURLs: @@ -55,9 +55,9 @@ struct AppDelegateReducer: ReducerProtocol { class AppDelegate: UIResponder, UIApplicationDelegate { let store = Store( initialState: .init(), - reducer: AppReducer() + reducer: AppReducer.init ) - lazy var viewStore = ViewStore(store) + lazy var viewStore = ViewStore(store, observe: { $0 }) static var orientationMask: UIInterfaceOrientationMask = DeviceUtil.isPad ? .all : [.portrait, .portraitUpsideDown] diff --git a/EhPanda/DataFlow/AppLockReducer.swift b/EhPanda/DataFlow/AppLockReducer.swift index daafcc15..0046ce8c 100644 --- a/EhPanda/DataFlow/AppLockReducer.swift +++ b/EhPanda/DataFlow/AppLockReducer.swift @@ -39,11 +39,11 @@ struct AppLockReducer: ReducerProtocol { Date.now.timeIntervalSince(date) >= Double(threshold) { return .merge( - .init(value: .authorize), - .init(value: .lockApp(blurRadius)) + .send(.authorize), + .send(.lockApp(blurRadius)) ) } else { - return .init(value: .unlockApp) + return .send(.unlockApp) } case .onBecomeInactive(let blurRadius): @@ -67,7 +67,7 @@ struct AppLockReducer: ReducerProtocol { .map(Action.authorizeDone) case .authorizeDone(let isSucceeded): - return isSucceeded ? .init(value: .unlockApp) : .none + return isSucceeded ? .send(.unlockApp) : .none } } } diff --git a/EhPanda/DataFlow/AppReducer.swift b/EhPanda/DataFlow/AppReducer.swift index f67bca86..75640e80 100644 --- a/EhPanda/DataFlow/AppReducer.swift +++ b/EhPanda/DataFlow/AppReducer.swift @@ -47,10 +47,10 @@ struct AppReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.appRouteState.$route): - return state.appRouteState.route == nil ? .init(value: .appRoute(.clearSubStates)) : .none + return state.appRouteState.route == nil ? .send(.appRoute(.clearSubStates)) : .none case .binding(\.settingState.$setting): - return .init(value: .setting(.syncSetting)) + return .send(.setting(.syncSetting)) case .binding: return .none @@ -62,11 +62,11 @@ struct AppReducer: ReducerProtocol { case .active: let threshold = state.settingState.setting.autoLockPolicy.rawValue let blurRadius = state.settingState.setting.backgroundBlurRadius - return .init(value: .appLock(.onBecomeActive(threshold, blurRadius))) + return .send(.appLock(.onBecomeActive(threshold, blurRadius))) case .inactive: let blurRadius = state.settingState.setting.backgroundBlurRadius - return .init(value: .appLock(.onBecomeInactive(blurRadius))) + return .send(.appLock(.onBecomeInactive(blurRadius))) default: return .none @@ -74,18 +74,18 @@ struct AppReducer: ReducerProtocol { case .appDelegate(.migration(.onDatabasePreparationSuccess)): return .merge( - .init(value: .appDelegate(.removeExpiredImageURLs)), - .init(value: .setting(.loadUserSettings)) + .send(.appDelegate(.removeExpiredImageURLs)), + .send(.setting(.loadUserSettings)) ) case .appDelegate: return .none case .appRoute(.clearSubStates): - var effects = [EffectTask]() + var effects = [Effect]() if deviceClient.isPad() { state.settingState.route = nil - effects.append(.init(value: .setting(.clearSubStates))) + effects.append(.send(.setting(.clearSubStates))) } return effects.isEmpty ? .none : .merge(effects) @@ -93,11 +93,11 @@ struct AppReducer: ReducerProtocol { return .none case .appLock(.unlockApp): - var effects: [EffectTask] = [ - .init(value: .setting(.fetchGreeting)) + var effects: [Effect] = [ + .send(.setting(.fetchGreeting)) ] if state.settingState.setting.detectsLinksFromClipboard { - effects.append(.init(value: .appRoute(.detectClipboardURL))) + effects.append(.send(.appRoute(.detectClipboardURL))) } return .merge(effects) @@ -105,33 +105,33 @@ struct AppReducer: ReducerProtocol { return .none case .tabBar(.setTabBarItemType(let type)): - var effects = [EffectTask]() - let hapticEffect: EffectTask = .fireAndForget({ hapticsClient.generateFeedback(.soft) }) + var effects = [Effect]() + let hapticEffect: Effect = .fireAndForget({ hapticsClient.generateFeedback(.soft) }) if type == state.tabBarState.tabBarItemType { switch type { case .home: if state.homeState.route != nil { - effects.append(.init(value: .home(.setNavigation(nil)))) + effects.append(.send(.home(.setNavigation(nil)))) } else { - effects.append(.init(value: .home(.fetchAllGalleries))) + effects.append(.send(.home(.fetchAllGalleries))) } case .favorites: if state.favoritesState.route != nil { - effects.append(.init(value: .favorites(.setNavigation(nil)))) + effects.append(.send(.favorites(.setNavigation(nil)))) effects.append(hapticEffect) } else if cookieClient.didLogin { - effects.append(.init(value: .favorites(.fetchGalleries()))) + effects.append(.send(.favorites(.fetchGalleries()))) effects.append(hapticEffect) } case .search: if state.searchRootState.route != nil { - effects.append(.init(value: .searchRoot(.setNavigation(nil)))) + effects.append(.send(.searchRoot(.setNavigation(nil)))) } else { - effects.append(.init(value: .searchRoot(.fetchDatabaseInfos))) + effects.append(.send(.searchRoot(.fetchDatabaseInfos))) } case .setting: if state.settingState.route != nil { - effects.append(.init(value: .setting(.setNavigation(nil)))) + effects.append(.send(.setting(.setNavigation(nil)))) effects.append(hapticEffect) } } @@ -140,7 +140,7 @@ struct AppReducer: ReducerProtocol { } } if type == .setting && deviceClient.isPad() { - effects.append(.init(value: .appRoute(.setNavigation(.setting)))) + effects.append(.send(.appRoute(.setNavigation(.setting)))) } return effects.isEmpty ? .none : .merge(effects) @@ -148,14 +148,14 @@ struct AppReducer: ReducerProtocol { return .none case .home(.watched(.onNotLoginViewButtonTapped)), .favorites(.onNotLoginViewButtonTapped): - var effects: [EffectTask] = [ + var effects: [Effect] = [ .fireAndForget({ hapticsClient.generateFeedback(.soft) }), - .init(value: .tabBar(.setTabBarItemType(.setting))) + .send(.tabBar(.setTabBarItemType(.setting))) ] - effects.append(.init(value: .setting(.setNavigation(.account)))) + effects.append(.send(.setting(.setNavigation(.account)))) if !cookieClient.didLogin { effects.append( - .init(value: .setting(.account(.setNavigation(.login)))) + .send(.setting(.account(.setNavigation(.login)))) .delay( for: .milliseconds(deviceClient.isPad() ? 1200 : 200), scheduler: DispatchQueue.main @@ -175,20 +175,20 @@ struct AppReducer: ReducerProtocol { return .none case .setting(.loadUserSettingsDone): - var effects = [EffectTask]() + var effects = [Effect]() let threshold = state.settingState.setting.autoLockPolicy.rawValue let blurRadius = state.settingState.setting.backgroundBlurRadius if threshold >= 0 { state.appLockState.becameInactiveDate = .distantPast - effects.append(.init(value: .appLock(.onBecomeActive(threshold, blurRadius)))) + effects.append(.send(.appLock(.onBecomeActive(threshold, blurRadius)))) } if state.settingState.setting.detectsLinksFromClipboard { - effects.append(.init(value: .appRoute(.detectClipboardURL))) + effects.append(.send(.appRoute(.detectClipboardURL))) } return effects.isEmpty ? .none : .merge(effects) case .setting(.fetchGreetingDone(let result)): - return .init(value: .appRoute(.fetchGreetingDone(result))) + return .send(.appRoute(.fetchGreetingDone(result))) case .setting: return .none diff --git a/EhPanda/DataFlow/AppRouteReducer.swift b/EhPanda/DataFlow/AppRouteReducer.swift index 9b410b04..df8dd9d0 100644 --- a/EhPanda/DataFlow/AppRouteReducer.swift +++ b/EhPanda/DataFlow/AppRouteReducer.swift @@ -59,14 +59,14 @@ struct AppRouteReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .setHUDConfig(let config): state.hudConfig = config @@ -74,18 +74,18 @@ struct AppRouteReducer: ReducerProtocol { case .clearSubStates: state.detailState = .init() - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .detectClipboardURL: let currentChangeCount = clipboardClient.changeCount() guard currentChangeCount != userDefaultsClient .getValue(.clipboardChangeCount) else { return .none } - var effects: [EffectTask] = [ + var effects: [Effect] = [ userDefaultsClient .setValue(currentChangeCount, .clipboardChangeCount).fireAndForget() ] if let url = clipboardClient.url() { - effects.append(.init(value: .handleDeepLink(url))) + effects.append(.send(.handleDeepLink(url))) } return .merge(effects) @@ -101,32 +101,32 @@ struct AppRouteReducer: ReducerProtocol { let (isGalleryImageURL, _, _) = urlClient.analyzeURL(url) let gid = urlClient.parseGalleryID(url) guard databaseClient.fetchGallery(gid: gid) == nil else { - return .init(value: .handleGalleryLink(url)) + return .send(.handleGalleryLink(url)) .delay(for: .milliseconds(delay + 250), scheduler: DispatchQueue.main).eraseToEffect() } - return .init(value: .fetchGallery(url, isGalleryImageURL)) + return .send(.fetchGallery(url, isGalleryImageURL)) .delay(for: .milliseconds(delay), scheduler: DispatchQueue.main).eraseToEffect() case .handleGalleryLink(let url): let (_, pageIndex, commentID) = urlClient.analyzeURL(url) let gid = urlClient.parseGalleryID(url) - var effects = [EffectTask]() + var effects = [Effect]() state.detailState = .init() - effects.append(.init(value: .detail(.fetchDatabaseInfos(gid)))) + effects.append(.send(.detail(.fetchDatabaseInfos(gid)))) if let pageIndex = pageIndex { - effects.append(.init(value: .updateReadingProgress(gid, pageIndex))) + effects.append(.send(.updateReadingProgress(gid, pageIndex))) effects.append( - .init(value: .detail(.setNavigation(.reading))) + .send(.detail(.setNavigation(.reading))) .delay(for: .milliseconds(500), scheduler: DispatchQueue.main).eraseToEffect() ) } else if let commentID = commentID { state.detailState.commentsState?.scrollCommentID = commentID effects.append( - .init(value: .detail(.setNavigation(.comments(url)))) + .send(.detail(.setNavigation(.comments(url)))) .delay(for: .milliseconds(500), scheduler: DispatchQueue.main).eraseToEffect() ) } - effects.append(.init(value: .setNavigation(.detail(gid)))) + effects.append(.send(.setNavigation(.detail(gid)))) return .merge(effects) case .updateReadingProgress(let gid, let progress): @@ -145,16 +145,16 @@ struct AppRouteReducer: ReducerProtocol { case .success(let gallery): return .merge( databaseClient.cacheGalleries([gallery]).fireAndForget(), - .init(value: .handleGalleryLink(url)) + .send(.handleGalleryLink(url)) ) case .failure: - return .init(value: .setHUDConfig(.error)) + return .send(.setHUDConfig(.error)) .delay(for: .milliseconds(500), scheduler: DispatchQueue.main).eraseToEffect() } case .fetchGreetingDone(let result): if case .success(let greeting) = result, !greeting.gainedNothing { - return .init(value: .setNavigation(.newDawn(greeting))) + return .send(.setNavigation(.newDawn(greeting))) } return .none diff --git a/EhPanda/Network/Request.swift b/EhPanda/Network/Request.swift index d739ee09..4fe237ed 100644 --- a/EhPanda/Network/Request.swift +++ b/EhPanda/Network/Request.swift @@ -16,7 +16,7 @@ protocol Request { var publisher: AnyPublisher { get } } extension Request { - var effect: EffectTask> { + var effect: Effect> { publisher.receive(on: DispatchQueue.main).catchToEffect() } diff --git a/EhPanda/View/Detail/Archives/ArchivesReducer.swift b/EhPanda/View/Detail/Archives/ArchivesReducer.swift index 3e180958..1ee16ead 100644 --- a/EhPanda/View/Detail/Archives/ArchivesReducer.swift +++ b/EhPanda/View/Detail/Archives/ArchivesReducer.swift @@ -85,9 +85,9 @@ struct ArchivesReducer: ReducerProtocol { } state.hathArchives = archive.hathArchives if let galleryPoints = galleryPoints, let credits = credits { - return .init(value: .syncGalleryFunds(galleryPoints, credits)) + return .send(.syncGalleryFunds(galleryPoints, credits)) } else if cookieClient.isSameAccount { - return .init(value: .fetchArchiveFunds(gid, galleryURL)) + return .send(.fetchArchiveFunds(gid, galleryURL)) } else { return .none } @@ -103,7 +103,7 @@ struct ArchivesReducer: ReducerProtocol { case .fetchArchiveFundsDone(let result): if case .success(let (galleryPoints, credits)) = result { - return .init(value: .syncGalleryFunds(galleryPoints, credits)) + return .send(.syncGalleryFunds(galleryPoints, credits)) } return .none diff --git a/EhPanda/View/Detail/Archives/ArchivesView.swift b/EhPanda/View/Detail/Archives/ArchivesView.swift index 9ae731f3..6fca0051 100644 --- a/EhPanda/View/Detail/Archives/ArchivesView.swift +++ b/EhPanda/View/Detail/Archives/ArchivesView.swift @@ -21,7 +21,7 @@ struct ArchivesView: View { gid: String, user: User, galleryURL: URL, archiveURL: URL ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gid = gid self.user = user self.galleryURL = galleryURL @@ -33,7 +33,7 @@ struct ArchivesView: View { NavigationView { ZStack { VStack { - HathArchivesView(archives: viewStore.hathArchives, selection: viewStore.binding(\.$selectedArchive)) + HathArchivesView(archives: viewStore.hathArchives, selection: viewStore.$selectedArchive) Spacer() if let credits = Int(user.credits ?? ""), let galleryPoints = Int(user.galleryPoints ?? "") { ArchiveFundsView(credits: credits, galleryPoints: galleryPoints) @@ -55,12 +55,12 @@ struct ArchivesView: View { } .progressHUD( config: viewStore.communicatingHUDConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /ArchivesReducer.Route.communicatingHUD ) .progressHUD( config: viewStore.messageHUDConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /ArchivesReducer.Route.messageHUD ) .animation(.default, value: viewStore.hathArchives) @@ -223,7 +223,7 @@ struct ArchivesView_Previews: PreviewProvider { ArchivesView( store: .init( initialState: .init(), - reducer: ArchivesReducer() + reducer: ArchivesReducer.init ), gid: .init(), user: .init(), diff --git a/EhPanda/View/Detail/Comments/CommentsReducer.swift b/EhPanda/View/Detail/Comments/CommentsReducer.swift index 98ebffaf..a7f75a1d 100644 --- a/EhPanda/View/Detail/Comments/CommentsReducer.swift +++ b/EhPanda/View/Detail/Comments/CommentsReducer.swift @@ -76,20 +76,20 @@ struct CommentsReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() state.commentContent = .init() state.postCommentFocused = false - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .clearScrollCommentID: state.scrollCommentID = nil @@ -113,11 +113,11 @@ struct CommentsReducer: ReducerProtocol { case .performScrollOpacityEffect: return .merge( - .init(value: .setScrollRowOpacity(0.25)) + .send(.setScrollRowOpacity(0.25)) .delay(for: .milliseconds(750), scheduler: DispatchQueue.main).eraseToEffect(), - .init(value: .setScrollRowOpacity(1)) + .send(.setScrollRowOpacity(1)) .delay(for: .milliseconds(1250), scheduler: DispatchQueue.main).eraseToEffect(), - .init(value: .clearScrollCommentID) + .send(.clearScrollCommentID) .delay(for: .milliseconds(2000), scheduler: DispatchQueue.main).eraseToEffect() ) @@ -128,39 +128,39 @@ struct CommentsReducer: ReducerProtocol { let (isGalleryImageURL, _, _) = urlClient.analyzeURL(url) let gid = urlClient.parseGalleryID(url) guard databaseClient.fetchGallery(gid: gid) == nil else { - return .init(value: .handleGalleryLink(url)) + return .send(.handleGalleryLink(url)) } - return .init(value: .fetchGallery(url, isGalleryImageURL)) + return .send(.fetchGallery(url, isGalleryImageURL)) case .handleGalleryLink(let url): let (_, pageIndex, commentID) = urlClient.analyzeURL(url) let gid = urlClient.parseGalleryID(url) - var effects = [EffectTask]() + var effects = [Effect]() if let pageIndex = pageIndex { - effects.append(.init(value: .updateReadingProgress(gid, pageIndex))) + effects.append(.send(.updateReadingProgress(gid, pageIndex))) effects.append( - .init(value: .detail(.setNavigation(.reading))) + .send(.detail(.setNavigation(.reading))) .delay(for: .milliseconds(750), scheduler: DispatchQueue.main).eraseToEffect() ) } else if let commentID = commentID { state.detailState.commentsState?.scrollCommentID = commentID effects.append( - .init(value: .detail(.setNavigation(.comments(url)))) + .send(.detail(.setNavigation(.comments(url)))) .delay(for: .milliseconds(750), scheduler: DispatchQueue.main).eraseToEffect() ) } - effects.append(.init(value: .setNavigation(.detail(gid)))) + effects.append(.send(.setNavigation(.detail(gid)))) return .merge(effects) case .onPostCommentAppear: - return .init(value: .setPostCommentFocused(true)) + return .send(.setPostCommentFocused(true)) .delay(for: .milliseconds(750), scheduler: DispatchQueue.main).eraseToEffect() case .onAppear: if state.detailState == nil { state.detailState = .init() } - return state.scrollCommentID != nil ? .init(value: .performScrollOpacityEffect) : .none + return state.scrollCommentID != nil ? .send(.performScrollOpacityEffect) : .none case .updateReadingProgress(let gid, let progress): guard !gid.isEmpty else { return .none } @@ -206,10 +206,10 @@ struct CommentsReducer: ReducerProtocol { case .success(let gallery): return .merge( databaseClient.cacheGalleries([gallery]).fireAndForget(), - .init(value: .handleGalleryLink(url)) + .send(.handleGalleryLink(url)) ) case .failure: - return .init(value: .setHUDConfig(.error)) + return .send(.setHUDConfig(.error)) .delay(for: .milliseconds(500), scheduler: DispatchQueue.main).eraseToEffect() } diff --git a/EhPanda/View/Detail/Comments/CommentsView.swift b/EhPanda/View/Detail/Comments/CommentsView.swift index 27534aab..16a68971 100644 --- a/EhPanda/View/Detail/Comments/CommentsView.swift +++ b/EhPanda/View/Detail/Comments/CommentsView.swift @@ -29,7 +29,7 @@ struct CommentsView: View { blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gid = gid self.token = token self.apiKey = apiKey @@ -92,14 +92,14 @@ struct CommentsView: View { } } } - .sheet(unwrapping: viewStore.binding(\.$route), case: /CommentsReducer.Route.postComment) { route in + .sheet(unwrapping: viewStore.$route, case: /CommentsReducer.Route.postComment) { route in let hasCommentID = !route.wrappedValue.isEmpty PostCommentView( title: hasCommentID ? L10n.Localizable.PostCommentView.Title.editComment : L10n.Localizable.PostCommentView.Title.postComment, - content: viewStore.binding(\.$commentContent), - isFocused: viewStore.binding(\.$postCommentFocused), + content: viewStore.$commentContent, + isFocused: viewStore.$postCommentFocused, postAction: { if hasCommentID { viewStore.send(.postComment(galleryURL, route.wrappedValue)) @@ -116,7 +116,7 @@ struct CommentsView: View { } .progressHUD( config: viewStore.hudConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /CommentsReducer.Route.hud ) .animation(.default, value: viewStore.scrollRowOpacity) @@ -143,7 +143,7 @@ struct CommentsView: View { // MARK: NavigationLinks private extension CommentsView { @ViewBuilder var navigationLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /CommentsReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /CommentsReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: CommentsReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -274,7 +274,7 @@ struct CommentsView_Previews: PreviewProvider { CommentsView( store: .init( initialState: .init(), - reducer: CommentsReducer() + reducer: CommentsReducer.init ), gid: .init(), token: .init(), diff --git a/EhPanda/View/Detail/DetailReducer.swift b/EhPanda/View/Detail/DetailReducer.swift index 67b0de73..bbd0fd56 100644 --- a/EhPanda/View/Detail/DetailReducer.swift +++ b/EhPanda/View/Detail/DetailReducer.swift @@ -122,14 +122,14 @@ struct DetailReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.readingState = .init() @@ -142,16 +142,16 @@ struct DetailReducer: ReducerProtocol { state.galleryInfosState = .init() state.detailSearchState = .init() return .merge( - .init(value: .reading(.teardown)), - .init(value: .archives(.teardown)), - .init(value: .torrents(.teardown)), - .init(value: .previews(.teardown)), - .init(value: .comments(.teardown)), - .init(value: .detailSearch(.teardown)) + .send(.reading(.teardown)), + .send(.archives(.teardown)), + .send(.torrents(.teardown)), + .send(.previews(.teardown)), + .send(.comments(.teardown)), + .send(.detailSearch(.teardown)) ) case .onPostCommentAppear: - return .init(value: .setPostCommentFocused(true)) + return .send(.setPostCommentFocused(true)) .delay(for: .milliseconds(750), scheduler: DispatchQueue.main).eraseToEffect() case .onAppear(let gid, let showsNewDawnGreeting): @@ -162,7 +162,7 @@ struct DetailReducer: ReducerProtocol { if state.commentsState == nil { state.commentsState = .init() } - return .init(value: .fetchDatabaseInfos(gid)) + return .send(.fetchDatabaseInfos(gid)) case .toggleShowFullTitle: state.showsFullTitle.toggle() @@ -187,9 +187,9 @@ struct DetailReducer: ReducerProtocol { case .confirmRating(let value): state.updateRating(value: value) return .merge( - .init(value: .rateGallery), + .send(.rateGallery), .fireAndForget({ hapticsClient.generateFeedback(.soft) }), - .init(value: .confirmRatingDone).delay(for: 1, scheduler: DispatchQueue.main).eraseToEffect() + .send(.confirmRatingDone).delay(for: 1, scheduler: DispatchQueue.main).eraseToEffect() ) case .confirmRatingDone: @@ -236,7 +236,7 @@ struct DetailReducer: ReducerProtocol { state.galleryDetail = detail } return .merge( - .init(value: .saveGalleryHistory), + .send(.saveGalleryHistory), databaseClient.fetchGalleryState(gid: state.gallery.id) .map(Action.fetchDatabaseInfosDone).cancellable(id: CancelID.fetchDatabaseInfos) ) @@ -245,7 +245,7 @@ struct DetailReducer: ReducerProtocol { state.galleryTags = galleryState.tags state.galleryPreviewURLs = galleryState.previewURLs state.galleryComments = galleryState.comments - return .init(value: .fetchGalleryDetail) + return .send(.fetchGalleryDetail) case .fetchGalleryDetail: guard state.loadingState != .loading, @@ -259,11 +259,11 @@ struct DetailReducer: ReducerProtocol { state.loadingState = .idle switch result { case .success(let (galleryDetail, galleryState, apiKey, greeting)): - var effects: [EffectTask] = [ - .init(value: .syncGalleryTags), - .init(value: .syncGalleryDetail), - .init(value: .syncGalleryPreviewURLs), - .init(value: .syncGalleryComments) + var effects: [Effect] = [ + .send(.syncGalleryTags), + .send(.syncGalleryDetail), + .send(.syncGalleryPreviewURLs), + .send(.syncGalleryComments) ] state.apiKey = apiKey state.galleryDetail = galleryDetail @@ -272,13 +272,13 @@ struct DetailReducer: ReducerProtocol { state.galleryComments = galleryState.comments state.userRating = Int(galleryDetail.userRating) * 2 if let greeting = greeting { - effects.append(.init(value: .syncGreeting(greeting))) + effects.append(.send(.syncGreeting(greeting))) if !greeting.gainedNothing && state.showsNewDawnGreeting { - effects.append(.init(value: .setNavigation(.newDawn(greeting)))) + effects.append(.send(.setNavigation(.newDawn(greeting)))) } } if let config = galleryState.previewConfig { - effects.append(.init(value: .syncPreviewConfig(config))) + effects.append(.send(.syncPreviewConfig(config))) } return .merge(effects) case .failure(let error): @@ -319,14 +319,14 @@ struct DetailReducer: ReducerProtocol { case .anyGalleryOpsDone(let result): if case .success = result { return .merge( - .init(value: .fetchGalleryDetail), + .send(.fetchGalleryDetail), .fireAndForget({ hapticsClient.generateNotificationFeedback(.success) }) ) } return .fireAndForget({ hapticsClient.generateNotificationFeedback(.error) }) case .reading(.onPerformDismiss): - return .init(value: .setNavigation(nil)) + return .send(.setNavigation(nil)) case .reading: return .none @@ -341,7 +341,7 @@ struct DetailReducer: ReducerProtocol { return .none case .comments(.performCommentActionDone(let result)): - return .init(value: .anyGalleryOpsDone(result)) + return .send(.anyGalleryOpsDone(result)) case .comments(.detail(let recursiveAction)): guard state.commentsState != nil else { return .none } diff --git a/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift b/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift index d1aa1d7b..d94cb0e4 100644 --- a/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift +++ b/EhPanda/View/Detail/DetailSearch/DetailSearchReducer.swift @@ -70,7 +70,7 @@ struct DetailSearchReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding(\.$keyword): if !state.keyword.isEmpty { @@ -83,15 +83,15 @@ struct DetailSearchReducer: ReducerProtocol { case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() state.filtersState = .init() state.quickDetailSearchState = .init() return .merge( - .init(value: .detail(.teardown)), - .init(value: .quickSearch(.teardown)) + .send(.detail(.teardown)), + .send(.quickSearch(.teardown)) ) case .teardown: @@ -116,7 +116,7 @@ struct DetailSearchReducer: ReducerProtocol { guard !galleries.isEmpty else { state.loadingState = .failed(.notFound) guard pageNumber.hasNextPage() else { return .none } - return .init(value: .fetchMoreGalleries) + return .send(.fetchMoreGalleries) } state.pageNumber = pageNumber state.galleries = galleries @@ -145,11 +145,11 @@ struct DetailSearchReducer: ReducerProtocol { state.pageNumber = pageNumber state.insertGalleries(galleries) - var effects: [EffectTask] = [ + var effects: [Effect] = [ databaseClient.cacheGalleries(galleries).fireAndForget() ] if galleries.isEmpty, pageNumber.hasNextPage() { - effects.append(.init(value: .fetchMoreGalleries)) + effects.append(.send(.fetchMoreGalleries)) } else if !galleries.isEmpty { state.loadingState = .idle } diff --git a/EhPanda/View/Detail/DetailSearch/DetailSearchView.swift b/EhPanda/View/Detail/DetailSearch/DetailSearchView.swift index f8567c73..932caad3 100644 --- a/EhPanda/View/Detail/DetailSearch/DetailSearchView.swift +++ b/EhPanda/View/Detail/DetailSearch/DetailSearchView.swift @@ -22,7 +22,7 @@ struct DetailSearchView: View { keyword: String, user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.keyword = keyword self.user = user _setting = setting @@ -45,7 +45,7 @@ struct DetailSearchView: View { } ) .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /DetailSearchReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -58,7 +58,7 @@ struct DetailSearchView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailSearchReducer.Route.quickSearch) { _ in + .sheet(unwrapping: viewStore.$route, case: /DetailSearchReducer.Route.quickSearch) { _ in QuickSearchView( store: store.scope(state: \.quickDetailSearchState, action: DetailSearchReducer.Action.quickSearch) ) { keyword in @@ -68,14 +68,14 @@ struct DetailSearchView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailSearchReducer.Route.filters) { _ in + .sheet(unwrapping: viewStore.$route, case: /DetailSearchReducer.Route.filters) { _ in FiltersView(store: store.scope(state: \.filtersState, action: DetailSearchReducer.Action.filters)) .accentColor(setting.accentColor).autoBlur(radius: blurRadius) } - .searchable(text: viewStore.binding(\.$keyword)) + .searchable(text: viewStore.$keyword) .searchSuggestions { TagSuggestionView( - keyword: viewStore.binding(\.$keyword), translations: tagTranslator.translations, + keyword: viewStore.$keyword, translations: tagTranslator.translations, showsImages: setting.showsImagesInTags, isEnabled: setting.showsTagsSearchSuggestion ) } @@ -96,7 +96,7 @@ struct DetailSearchView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /DetailSearchReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /DetailSearchReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: DetailSearchReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -124,7 +124,7 @@ struct DetailSearchView_Previews: PreviewProvider { DetailSearchView( store: .init( initialState: .init(), - reducer: DetailSearchReducer() + reducer: DetailSearchReducer.init ), keyword: .init(), user: .init(), diff --git a/EhPanda/View/Detail/DetailView.swift b/EhPanda/View/Detail/DetailView.swift index a5946b28..e8b7235a 100644 --- a/EhPanda/View/Detail/DetailView.swift +++ b/EhPanda/View/Detail/DetailView.swift @@ -24,7 +24,7 @@ struct DetailView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gid = gid self.user = user _setting = setting @@ -121,7 +121,7 @@ struct DetailView: View { ErrorView(error: error ?? .unknown, action: error?.isRetryable != false ? retryAction : nil) .opacity(viewStore.galleryDetail == nil && error != nil ? 1 : 0) } - .fullScreenCover(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.reading) { _ in + .fullScreenCover(unwrapping: viewStore.$route, case: /DetailReducer.Route.reading) { _ in ReadingView( store: store.scope(state: \.readingState, action: DetailReducer.Action.reading), gid: gid, setting: $setting, blurRadius: blurRadius @@ -129,7 +129,7 @@ struct DetailView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.archives) { route in + .sheet(unwrapping: viewStore.$route, case: /DetailReducer.Route.archives) { route in let (galleryURL, archiveURL) = route.wrappedValue ArchivesView( store: store.scope(state: \.archivesState, action: DetailReducer.Action.archives), @@ -138,7 +138,7 @@ struct DetailView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.torrents) { _ in + .sheet(unwrapping: viewStore.$route, case: /DetailReducer.Route.torrents) { _ in TorrentsView( store: store.scope(state: \.torrentsState, action: DetailReducer.Action.torrents), gid: gid, token: viewStore.gallery.token, blurRadius: blurRadius @@ -146,15 +146,15 @@ struct DetailView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.share) { route in + .sheet(unwrapping: viewStore.$route, case: /DetailReducer.Route.share) { route in ActivityView(activityItems: [route.wrappedValue]) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.postComment) { _ in + .sheet(unwrapping: viewStore.$route, case: /DetailReducer.Route.postComment) { _ in PostCommentView( title: L10n.Localizable.PostCommentView.Title.postComment, - content: viewStore.binding(\.$commentContent), - isFocused: viewStore.binding(\.$postCommentFocused), + content: viewStore.$commentContent, + isFocused: viewStore.$postCommentFocused, postAction: { if let galleryURL = viewStore.gallery.galleryURL { viewStore.send(.postComment(galleryURL)) @@ -167,10 +167,10 @@ struct DetailView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.newDawn) { route in + .sheet(unwrapping: viewStore.$route, case: /DetailReducer.Route.newDawn) { route in NewDawnView(greeting: route.wrappedValue).autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.tagDetail) { route in + .sheet(unwrapping: viewStore.$route, case: /DetailReducer.Route.tagDetail) { route in TagDetailView(detail: route.wrappedValue).autoBlur(radius: blurRadius) } .animation(.default, value: viewStore.showsUserRating) @@ -189,13 +189,13 @@ struct DetailView: View { // MARK: NavigationLinks private extension DetailView { @ViewBuilder var navigationLinks: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.previews) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /DetailReducer.Route.previews) { _ in PreviewsView( store: store.scope(state: \.previewsState, action: DetailReducer.Action.previews), gid: gid, setting: $setting, blurRadius: blurRadius ) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.comments) { route in + NavigationLink(unwrapping: viewStore.$route, case: /DetailReducer.Route.comments) { route in IfLetStore(store.scope(state: \.commentsState, action: DetailReducer.Action.comments)) { store in CommentsView( store: store, gid: gid, token: viewStore.gallery.token, apiKey: viewStore.apiKey, @@ -205,7 +205,7 @@ private extension DetailView { ) } } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.detailSearch) { route in + NavigationLink(unwrapping: viewStore.$route, case: /DetailReducer.Route.detailSearch) { route in IfLetStore(store.scope(state: \.detailSearchState, action: DetailReducer.Action.detailSearch)) { store in DetailSearchView( store: store, keyword: route.wrappedValue, user: user, setting: $setting, @@ -213,7 +213,7 @@ private extension DetailView { ) } } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /DetailReducer.Route.galleryInfos) { route in + NavigationLink(unwrapping: viewStore.$route, case: /DetailReducer.Route.galleryInfos) { route in let (gallery, galleryDetail) = route.wrappedValue GalleryInfosView( store: store.scope(state: \.galleryInfosState, action: DetailReducer.Action.galleryInfos), @@ -849,7 +849,7 @@ struct DetailView_Previews: PreviewProvider { DetailView( store: .init( initialState: .init(), - reducer: DetailReducer() + reducer: DetailReducer.init ), gid: .init(), user: .init(), diff --git a/EhPanda/View/Detail/GalleryInfos/GalleryInfosView.swift b/EhPanda/View/Detail/GalleryInfos/GalleryInfosView.swift index 09500be6..672ee654 100644 --- a/EhPanda/View/Detail/GalleryInfos/GalleryInfosView.swift +++ b/EhPanda/View/Detail/GalleryInfos/GalleryInfosView.swift @@ -16,7 +16,7 @@ struct GalleryInfosView: View { init(store: StoreOf, gallery: Gallery, galleryDetail: GalleryDetail) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gallery = gallery self.galleryDetail = galleryDetail } @@ -118,7 +118,7 @@ struct GalleryInfosView: View { } .progressHUD( config: viewStore.hudConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /GalleryInfosReducer.Route.hud ) .navigationTitle(L10n.Localizable.GalleryInfosView.Title.galleryInfos) @@ -137,7 +137,7 @@ struct GalleryInfosView_Previews: PreviewProvider { GalleryInfosView( store: .init( initialState: .init(), - reducer: GalleryInfosReducer() + reducer: GalleryInfosReducer.init ), gallery: .preview, galleryDetail: .preview diff --git a/EhPanda/View/Detail/Previews/PreviewsReducer.swift b/EhPanda/View/Detail/Previews/PreviewsReducer.swift index ec25a37b..9b2ac8a5 100644 --- a/EhPanda/View/Detail/Previews/PreviewsReducer.swift +++ b/EhPanda/View/Detail/Previews/PreviewsReducer.swift @@ -62,18 +62,18 @@ struct PreviewsReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.readingState = .init() - return .init(value: .reading(.teardown)) + return .send(.reading(.teardown)) case .syncPreviewURLs(let previewURLs): return databaseClient @@ -119,14 +119,14 @@ struct PreviewsReducer: ReducerProtocol { return .none } state.updatePreviewURLs(previewURLs) - return .init(value: .syncPreviewURLs(previewURLs)) + return .send(.syncPreviewURLs(previewURLs)) case .failure(let error): state.loadingState = .failed(error) } return .none case .reading(.onPerformDismiss): - return .init(value: .setNavigation(nil)) + return .send(.setNavigation(nil)) case .reading: return .none diff --git a/EhPanda/View/Detail/Previews/PreviewsView.swift b/EhPanda/View/Detail/Previews/PreviewsView.swift index 1a255c68..24e67d79 100644 --- a/EhPanda/View/Detail/Previews/PreviewsView.swift +++ b/EhPanda/View/Detail/Previews/PreviewsView.swift @@ -21,7 +21,7 @@ struct PreviewsView: View { gid: String, setting: Binding, blurRadius: Double ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gid = gid _setting = setting self.blurRadius = blurRadius @@ -68,7 +68,7 @@ struct PreviewsView: View { .padding(.bottom) .id(viewStore.databaseLoadingState) } - .fullScreenCover(unwrapping: viewStore.binding(\.$route), case: /PreviewsReducer.Route.reading) { _ in + .fullScreenCover(unwrapping: viewStore.$route, case: /PreviewsReducer.Route.reading) { _ in ReadingView( store: store.scope(state: \.readingState, action: PreviewsReducer.Action.reading), gid: gid, setting: $setting, blurRadius: blurRadius @@ -89,7 +89,7 @@ struct PreviewsView_Previews: PreviewProvider { PreviewsView( store: .init( initialState: .init(gallery: .preview), - reducer: PreviewsReducer() + reducer: PreviewsReducer.init ), gid: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Detail/Torrents/TorrentsReducer.swift b/EhPanda/View/Detail/Torrents/TorrentsReducer.swift index 24e2d304..2d5a50e1 100644 --- a/EhPanda/View/Detail/Torrents/TorrentsReducer.swift +++ b/EhPanda/View/Detail/Torrents/TorrentsReducer.swift @@ -65,7 +65,7 @@ struct TorrentsReducer: ReducerProtocol { case .presentTorrentActivity(let hash, let data): if let url = fileClient.saveTorrent(hash: hash, data: data) { - return .init(value: .setNavigation(.share(url))) + return .send(.setNavigation(.share(url))) } return .none @@ -78,7 +78,7 @@ struct TorrentsReducer: ReducerProtocol { case .fetchTorrentDone(let hash, let result): if case .success(let data) = result, !data.isEmpty { - return .init(value: .presentTorrentActivity(hash, data)) + return .send(.presentTorrentActivity(hash, data)) } return .none diff --git a/EhPanda/View/Detail/Torrents/TorrentsView.swift b/EhPanda/View/Detail/Torrents/TorrentsView.swift index 5a8e1dc3..76de4a79 100644 --- a/EhPanda/View/Detail/Torrents/TorrentsView.swift +++ b/EhPanda/View/Detail/Torrents/TorrentsView.swift @@ -17,7 +17,7 @@ struct TorrentsView: View { init(store: StoreOf, gid: String, token: String, blurRadius: Double) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gid = gid self.token = token self.blurRadius = blurRadius @@ -45,13 +45,13 @@ struct TorrentsView: View { } .opacity(error != nil && viewStore.torrents.isEmpty ? 1 : 0) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /TorrentsReducer.Route.share) { route in + .sheet(unwrapping: viewStore.$route, case: /TorrentsReducer.Route.share) { route in ActivityView(activityItems: [route.wrappedValue]) .autoBlur(radius: blurRadius) } .progressHUD( config: viewStore.hudConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /TorrentsReducer.Route.hud ) .animation(.default, value: viewStore.torrents) @@ -120,7 +120,7 @@ struct TorrentsView_Previews: PreviewProvider { TorrentsView( store: .init( initialState: .init(), - reducer: TorrentsReducer() + reducer: TorrentsReducer.init ), gid: .init(), token: .init(), diff --git a/EhPanda/View/Favorites/FavoritesReducer.swift b/EhPanda/View/Favorites/FavoritesReducer.swift index c2c694cf..7bcd902a 100644 --- a/EhPanda/View/Favorites/FavoritesReducer.swift +++ b/EhPanda/View/Favorites/FavoritesReducer.swift @@ -81,14 +81,14 @@ struct FavoritesReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .setFavoritesIndex(let index): state.index = index @@ -97,7 +97,7 @@ struct FavoritesReducer: ReducerProtocol { case .clearSubStates: state.detailState = .init() - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .onNotLoginViewButtonTapped: return .none @@ -125,7 +125,7 @@ struct FavoritesReducer: ReducerProtocol { guard !galleries.isEmpty else { state.rawLoadingState[targetFavIndex] = .failed(.notFound) guard pageNumber.hasNextPage() else { return .none } - return .init(value: .fetchMoreGalleries) + return .send(.fetchMoreGalleries) } state.rawPageNumber[targetFavIndex] = pageNumber state.rawGalleries[targetFavIndex] = galleries @@ -160,11 +160,11 @@ struct FavoritesReducer: ReducerProtocol { state.insertGalleries(index: targetFavIndex, galleries: galleries) state.sortOrder = sortOrder - var effects: [EffectTask] = [ + var effects: [Effect] = [ databaseClient.cacheGalleries(galleries).fireAndForget() ] if galleries.isEmpty, pageNumber.hasNextPage() { - effects.append(.init(value: .fetchMoreGalleries)) + effects.append(.send(.fetchMoreGalleries)) } else if !galleries.isEmpty { state.rawLoadingState[targetFavIndex] = .idle } diff --git a/EhPanda/View/Favorites/FavoritesView.swift b/EhPanda/View/Favorites/FavoritesView.swift index fea27eea..b2b91ad4 100644 --- a/EhPanda/View/Favorites/FavoritesView.swift +++ b/EhPanda/View/Favorites/FavoritesView.swift @@ -22,7 +22,7 @@ struct FavoritesView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -56,7 +56,7 @@ struct FavoritesView: View { } } .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /FavoritesReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -69,7 +69,7 @@ struct FavoritesView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /FavoritesReducer.Route.quickSearch) { _ in + .sheet(unwrapping: viewStore.$route, case: /FavoritesReducer.Route.quickSearch) { _ in QuickSearchView( store: store.scope(state: \.quickSearchState, action: FavoritesReducer.Action.quickSearch) ) { keyword in @@ -79,10 +79,10 @@ struct FavoritesView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .searchable(text: viewStore.binding(\.$keyword)) + .searchable(text: viewStore.$keyword) .searchSuggestions { TagSuggestionView( - keyword: viewStore.binding(\.$keyword), translations: tagTranslator.translations, + keyword: viewStore.$keyword, translations: tagTranslator.translations, showsImages: setting.showsImagesInTags, isEnabled: setting.showsTagsSearchSuggestion ) } @@ -104,7 +104,7 @@ struct FavoritesView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /FavoritesReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /FavoritesReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: FavoritesReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -137,7 +137,7 @@ struct FavoritesView_Previews: PreviewProvider { FavoritesView( store: .init( initialState: .init(), - reducer: FavoritesReducer() + reducer: FavoritesReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Home/Frontpage/FrontpageReducer.swift b/EhPanda/View/Home/Frontpage/FrontpageReducer.swift index b4574355..8e671789 100644 --- a/EhPanda/View/Home/Frontpage/FrontpageReducer.swift +++ b/EhPanda/View/Home/Frontpage/FrontpageReducer.swift @@ -70,19 +70,19 @@ struct FrontpageReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() state.filtersState = .init() - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .teardown: return .cancel(ids: CancelID.allCases) @@ -103,7 +103,7 @@ struct FrontpageReducer: ReducerProtocol { guard !galleries.isEmpty else { state.loadingState = .failed(.notFound) guard pageNumber.hasNextPage() else { return .none } - return .init(value: .fetchMoreGalleries) + return .send(.fetchMoreGalleries) } state.pageNumber = pageNumber state.galleries = galleries @@ -132,11 +132,11 @@ struct FrontpageReducer: ReducerProtocol { state.pageNumber = pageNumber state.insertGalleries(galleries) - var effects: [EffectTask] = [ + var effects: [Effect] = [ databaseClient.cacheGalleries(galleries).fireAndForget() ] if galleries.isEmpty, pageNumber.hasNextPage() { - effects.append(.init(value: .fetchMoreGalleries)) + effects.append(.send(.fetchMoreGalleries)) } else if !galleries.isEmpty { state.loadingState = .idle } diff --git a/EhPanda/View/Home/Frontpage/FrontpageView.swift b/EhPanda/View/Home/Frontpage/FrontpageView.swift index b82e137b..bf088fb1 100644 --- a/EhPanda/View/Home/Frontpage/FrontpageView.swift +++ b/EhPanda/View/Home/Frontpage/FrontpageView.swift @@ -22,7 +22,7 @@ struct FrontpageView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -44,7 +44,7 @@ struct FrontpageView: View { } ) .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /FrontpageReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -57,11 +57,11 @@ struct FrontpageView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /FrontpageReducer.Route.filters) { _ in + .sheet(unwrapping: viewStore.$route, case: /FrontpageReducer.Route.filters) { _ in FiltersView(store: store.scope(state: \.filtersState, action: FrontpageReducer.Action.filters)) .autoBlur(radius: blurRadius).environment(\.inSheet, true) } - .searchable(text: viewStore.binding(\.$keyword), prompt: L10n.Localizable.Searchable.Prompt.filter) + .searchable(text: viewStore.$keyword, prompt: L10n.Localizable.Searchable.Prompt.filter) .onAppear { if viewStore.galleries.isEmpty { DispatchQueue.main.async { @@ -76,7 +76,7 @@ struct FrontpageView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /FrontpageReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /FrontpageReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: FrontpageReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -100,7 +100,7 @@ struct FrontpageView_Previews: PreviewProvider { FrontpageView( store: .init( initialState: .init(), - reducer: FrontpageReducer() + reducer: FrontpageReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Home/History/HistoryReducer.swift b/EhPanda/View/Home/History/HistoryReducer.swift index 547275c7..abc1d983 100644 --- a/EhPanda/View/Home/History/HistoryReducer.swift +++ b/EhPanda/View/Home/History/HistoryReducer.swift @@ -54,23 +54,23 @@ struct HistoryReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .clearHistoryGalleries: return .merge( databaseClient.clearHistoryGalleries().fireAndForget(), - .init(value: .fetchGalleries) + .send(.fetchGalleries) .delay(for: .milliseconds(200), scheduler: DispatchQueue.main).eraseToEffect() ) diff --git a/EhPanda/View/Home/History/HistoryView.swift b/EhPanda/View/Home/History/HistoryView.swift index 59e409bc..9e49b854 100644 --- a/EhPanda/View/Home/History/HistoryView.swift +++ b/EhPanda/View/Home/History/HistoryView.swift @@ -21,7 +21,7 @@ struct HistoryView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -42,7 +42,7 @@ struct HistoryView: View { } ) .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /HistoryReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -55,7 +55,7 @@ struct HistoryView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .searchable(text: viewStore.binding(\.$keyword), prompt: L10n.Localizable.Searchable.Prompt.filter) + .searchable(text: viewStore.$keyword, prompt: L10n.Localizable.Searchable.Prompt.filter) .onAppear { if viewStore.galleries.isEmpty { DispatchQueue.main.async { @@ -70,7 +70,7 @@ struct HistoryView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /HistoryReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /HistoryReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: HistoryReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -89,7 +89,7 @@ struct HistoryView: View { .disabled(viewStore.loadingState != .idle || viewStore.galleries.isEmpty) .confirmationDialog( message: L10n.Localizable.ConfirmationDialog.Title.clear, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /HistoryReducer.Route.clearHistory ) { Button(L10n.Localizable.ConfirmationDialog.Button.clear, role: .destructive) { @@ -106,7 +106,7 @@ struct HistoryView_Previews: PreviewProvider { HistoryView( store: .init( initialState: .init(), - reducer: HistoryReducer() + reducer: HistoryReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Home/HomeReducer.swift b/EhPanda/View/Home/HomeReducer.swift index 0089bd72..4ff5bb82 100644 --- a/EhPanda/View/Home/HomeReducer.swift +++ b/EhPanda/View/Home/HomeReducer.swift @@ -99,13 +99,13 @@ struct HomeReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + 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 .init(value: .setAllowsCardHitTesting(true)) + return .send(.setAllowsCardHitTesting(true)) .delay(for: .milliseconds(300), scheduler: DispatchQueue.main) .eraseToEffect() @@ -114,7 +114,7 @@ struct HomeReducer: ReducerProtocol { case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.frontpageState = .init() @@ -124,11 +124,11 @@ struct HomeReducer: ReducerProtocol { state.historyState = .init() state.detailState = .init() return .merge( - .init(value: .frontpage(.teardown)), - .init(value: .toplists(.teardown)), - .init(value: .popular(.teardown)), - .init(value: .watched(.teardown)), - .init(value: .detail(.teardown)) + .send(.frontpage(.teardown)), + .send(.toplists(.teardown)), + .send(.popular(.teardown)), + .send(.watched(.teardown)), + .send(.detail(.teardown)) ) case .setAllowsCardHitTesting(let isAllowed): @@ -137,15 +137,15 @@ struct HomeReducer: ReducerProtocol { case .fetchAllGalleries: return .merge( - .init(value: .fetchPopularGalleries), - .init(value: .fetchFrontpageGalleries), - .init(value: .fetchAllToplistsGalleries) + .send(.fetchPopularGalleries), + .send(.fetchFrontpageGalleries), + .send(.fetchAllToplistsGalleries) ) case .fetchAllToplistsGalleries: return .merge( ToplistsType.allCases.map({ Action.fetchToplistsGalleries($0.categoryIndex) }) - .map(EffectTask.init) + .map(Effect.init) ) case .fetchPopularGalleries: diff --git a/EhPanda/View/Home/HomeView.swift b/EhPanda/View/Home/HomeView.swift index 922ee525..e91a9026 100644 --- a/EhPanda/View/Home/HomeView.swift +++ b/EhPanda/View/Home/HomeView.swift @@ -24,7 +24,7 @@ struct HomeView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -40,7 +40,7 @@ struct HomeView: View { if !viewStore.popularGalleries.isEmpty { CardSlideSection( galleries: viewStore.popularGalleries, - pageIndex: viewStore.binding(\.$cardPageIndex), + pageIndex: viewStore.$cardPageIndex, currentID: viewStore.currentCardID, colors: viewStore.cardColors, navigateAction: navigateTo(gid:), @@ -88,7 +88,7 @@ struct HomeView: View { .zIndex(1) } .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /HomeReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -136,7 +136,7 @@ private extension HomeView { sectionLink } var detailViewLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /HomeReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /HomeReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: HomeReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -145,7 +145,7 @@ private extension HomeView { } } var miscGridLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /HomeReducer.Route.misc) { route in + NavigationLink(unwrapping: viewStore.$route, case: /HomeReducer.Route.misc) { route in switch route.wrappedValue { case .popular: PopularView( @@ -166,7 +166,7 @@ private extension HomeView { } } var sectionLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /HomeReducer.Route.section) { route in + NavigationLink(unwrapping: viewStore.$route, case: /HomeReducer.Route.section) { route in switch route.wrappedValue { case .frontpage: FrontpageView( @@ -521,7 +521,7 @@ struct HomeView_Previews: PreviewProvider { HomeView( store: .init( initialState: .init(), - reducer: HomeReducer() + reducer: HomeReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Home/Popular/PopularReducer.swift b/EhPanda/View/Home/Popular/PopularReducer.swift index a6141703..0764e299 100644 --- a/EhPanda/View/Home/Popular/PopularReducer.swift +++ b/EhPanda/View/Home/Popular/PopularReducer.swift @@ -58,19 +58,19 @@ struct PopularReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() state.filtersState = .init() - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .teardown: return .cancel(id: CancelID.fetchGalleries) diff --git a/EhPanda/View/Home/Popular/PopularView.swift b/EhPanda/View/Home/Popular/PopularView.swift index 77a85236..3fa3c749 100644 --- a/EhPanda/View/Home/Popular/PopularView.swift +++ b/EhPanda/View/Home/Popular/PopularView.swift @@ -21,7 +21,7 @@ struct PopularView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -41,7 +41,7 @@ struct PopularView: View { } ) .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /PopularReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -54,11 +54,11 @@ struct PopularView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /PopularReducer.Route.filters) { _ in + .sheet(unwrapping: viewStore.$route, case: /PopularReducer.Route.filters) { _ in FiltersView(store: store.scope(state: \.filtersState, action: PopularReducer.Action.filters)) .autoBlur(radius: blurRadius).environment(\.inSheet, true) } - .searchable(text: viewStore.binding(\.$keyword), prompt: L10n.Localizable.Searchable.Prompt.filter) + .searchable(text: viewStore.$keyword, prompt: L10n.Localizable.Searchable.Prompt.filter) .onAppear { if viewStore.galleries.isEmpty { DispatchQueue.main.async { @@ -73,7 +73,7 @@ struct PopularView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /PopularReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /PopularReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: PopularReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -97,7 +97,7 @@ struct PopularView_Previews: PreviewProvider { PopularView( store: .init( initialState: .init(), - reducer: PopularReducer() + reducer: PopularReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Home/Toplists/ToplistsReducer.swift b/EhPanda/View/Home/Toplists/ToplistsReducer.swift index 6497de5b..1e2e60d9 100644 --- a/EhPanda/View/Home/Toplists/ToplistsReducer.swift +++ b/EhPanda/View/Home/Toplists/ToplistsReducer.swift @@ -91,7 +91,7 @@ struct ToplistsReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding(\.$jumpPageAlertPresented): if !state.jumpPageAlertPresented { @@ -104,7 +104,7 @@ struct ToplistsReducer: ReducerProtocol { case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .setToplistsType(let type): state.type = type @@ -113,7 +113,7 @@ struct ToplistsReducer: ReducerProtocol { case .clearSubStates: state.detailState = .init() - return .init(value: .detail(.teardown)) + return .send(.detail(.teardown)) case .performJumpPage: guard let index = Int(state.jumpPageIndex), @@ -121,7 +121,7 @@ struct ToplistsReducer: ReducerProtocol { index > 0, index <= pageNumber.maximum + 1 else { return .fireAndForget({ hapticsClient.generateNotificationFeedback(.error) }) } - return .init(value: .fetchGalleries(index - 1)) + return .send(.fetchGalleries(index - 1)) case .presentJumpPageAlert: state.jumpPageAlertPresented = true @@ -153,7 +153,7 @@ struct ToplistsReducer: ReducerProtocol { guard !galleries.isEmpty else { state.rawLoadingState[type] = .failed(.notFound) guard pageNumber.hasNextPage() else { return .none } - return .init(value: .fetchMoreGalleries) + return .send(.fetchMoreGalleries) } state.rawPageNumber[type] = pageNumber state.rawGalleries[type] = galleries @@ -181,11 +181,11 @@ struct ToplistsReducer: ReducerProtocol { state.rawPageNumber[type] = pageNumber state.insertGalleries(type: type, galleries: galleries) - var effects: [EffectTask] = [ + var effects: [Effect] = [ databaseClient.cacheGalleries(galleries).fireAndForget() ] if galleries.isEmpty, pageNumber.hasNextPage() { - effects.append(.init(value: .fetchMoreGalleries)) + effects.append(.send(.fetchMoreGalleries)) } else if !galleries.isEmpty { state.rawLoadingState[type] = .idle } diff --git a/EhPanda/View/Home/Toplists/ToplistsView.swift b/EhPanda/View/Home/Toplists/ToplistsView.swift index e68d917a..362c3828 100644 --- a/EhPanda/View/Home/Toplists/ToplistsView.swift +++ b/EhPanda/View/Home/Toplists/ToplistsView.swift @@ -21,7 +21,7 @@ struct ToplistsView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -47,7 +47,7 @@ struct ToplistsView: View { } ) .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /ToplistsReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -61,13 +61,13 @@ struct ToplistsView: View { .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } .jumpPageAlert( - index: viewStore.binding(\.$jumpPageIndex), - isPresented: viewStore.binding(\.$jumpPageAlertPresented), - isFocused: viewStore.binding(\.$jumpPageAlertFocused), + index: viewStore.$jumpPageIndex, + isPresented: viewStore.$jumpPageAlertPresented, + isFocused: viewStore.$jumpPageAlertFocused, pageNumber: viewStore.pageNumber ?? .init(), jumpAction: { viewStore.send(.performJumpPage) } ) - .searchable(text: viewStore.binding(\.$keyword), prompt: L10n.Localizable.Searchable.Prompt.filter) + .searchable(text: viewStore.$keyword, prompt: L10n.Localizable.Searchable.Prompt.filter) .navigationBarBackButtonHidden(viewStore.jumpPageAlertPresented) .animation(.default, value: viewStore.jumpPageAlertPresented) .onAppear { @@ -84,7 +84,7 @@ struct ToplistsView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /ToplistsReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /ToplistsReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: ToplistsReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -155,7 +155,7 @@ struct ToplistsView_Previews: PreviewProvider { ToplistsView( store: .init( initialState: .init(), - reducer: ToplistsReducer() + reducer: ToplistsReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Home/Watched/WatchedReducer.swift b/EhPanda/View/Home/Watched/WatchedReducer.swift index 6f583d64..201f47c8 100644 --- a/EhPanda/View/Home/Watched/WatchedReducer.swift +++ b/EhPanda/View/Home/Watched/WatchedReducer.swift @@ -70,22 +70,22 @@ struct WatchedReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() state.filtersState = .init() state.quickSearchState = .init() return .merge( - .init(value: .detail(.teardown)), - .init(value: .quickSearch(.teardown)) + .send(.detail(.teardown)), + .send(.quickSearch(.teardown)) ) case .onNotLoginViewButtonTapped: @@ -112,7 +112,7 @@ struct WatchedReducer: ReducerProtocol { guard !galleries.isEmpty else { state.loadingState = .failed(.notFound) guard pageNumber.hasNextPage() else { return .none } - return .init(value: .fetchMoreGalleries) + return .send(.fetchMoreGalleries) } state.pageNumber = pageNumber state.galleries = galleries @@ -141,11 +141,11 @@ struct WatchedReducer: ReducerProtocol { state.pageNumber = pageNumber state.insertGalleries(galleries) - var effects: [EffectTask] = [ + var effects: [Effect] = [ databaseClient.cacheGalleries(galleries).fireAndForget() ] if galleries.isEmpty, pageNumber.hasNextPage() { - effects.append(.init(value: .fetchMoreGalleries)) + effects.append(.send(.fetchMoreGalleries)) } else if !galleries.isEmpty { state.loadingState = .idle } diff --git a/EhPanda/View/Home/Watched/WatchedView.swift b/EhPanda/View/Home/Watched/WatchedView.swift index 1612608b..ce34916c 100644 --- a/EhPanda/View/Home/Watched/WatchedView.swift +++ b/EhPanda/View/Home/Watched/WatchedView.swift @@ -21,7 +21,7 @@ struct WatchedView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -49,7 +49,7 @@ struct WatchedView: View { } } .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /WatchedReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -62,7 +62,7 @@ struct WatchedView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /WatchedReducer.Route.quickSearch) { _ in + .sheet(unwrapping: viewStore.$route, case: /WatchedReducer.Route.quickSearch) { _ in QuickSearchView( store: store.scope(state: \.quickSearchState, action: WatchedReducer.Action.quickSearch) ) { keyword in @@ -72,14 +72,14 @@ struct WatchedView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /WatchedReducer.Route.filters) { _ in + .sheet(unwrapping: viewStore.$route, case: /WatchedReducer.Route.filters) { _ in FiltersView(store: store.scope(state: \.filtersState, action: WatchedReducer.Action.filters)) .autoBlur(radius: blurRadius).environment(\.inSheet, true) } - .searchable(text: viewStore.binding(\.$keyword)) + .searchable(text: viewStore.$keyword) .searchSuggestions { TagSuggestionView( - keyword: viewStore.binding(\.$keyword), translations: tagTranslator.translations, + keyword: viewStore.$keyword, translations: tagTranslator.translations, showsImages: setting.showsImagesInTags, isEnabled: setting.showsTagsSearchSuggestion ) } @@ -100,7 +100,7 @@ struct WatchedView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /WatchedReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /WatchedReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: WatchedReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -129,7 +129,7 @@ struct WatchedView_Previews: PreviewProvider { WatchedView( store: .init( initialState: .init(), - reducer: WatchedReducer() + reducer: WatchedReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Migration/MigrationReducer.swift b/EhPanda/View/Migration/MigrationReducer.swift index 3488ed04..5aeb9fde 100644 --- a/EhPanda/View/Migration/MigrationReducer.swift +++ b/EhPanda/View/Migration/MigrationReducer.swift @@ -55,7 +55,7 @@ struct MigrationReducer: ReducerProtocol { return .none } else { state.databaseState = .idle - return .init(value: .onDatabasePreparationSuccess) + return .send(.onDatabasePreparationSuccess) } case .dropDatabase: @@ -70,7 +70,7 @@ struct MigrationReducer: ReducerProtocol { return .none } else { state.databaseState = .idle - return .init(value: .onDatabasePreparationSuccess) + return .send(.onDatabasePreparationSuccess) } } } diff --git a/EhPanda/View/Migration/MigrationView.swift b/EhPanda/View/Migration/MigrationView.swift index 5a2984f1..d103c862 100644 --- a/EhPanda/View/Migration/MigrationView.swift +++ b/EhPanda/View/Migration/MigrationView.swift @@ -19,7 +19,7 @@ struct MigrationView: View { init(store: StoreOf) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) } var body: some View { @@ -36,7 +36,7 @@ struct MigrationView: View { } .confirmationDialog( message: L10n.Localizable.ConfirmationDialog.Title.dropDatabase, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /MigrationReducer.Route.dropDialog ) { Button(L10n.Localizable.ConfirmationDialog.Button.dropDatabase, role: .destructive) { @@ -56,7 +56,7 @@ struct MigrationView_Previews: PreviewProvider { MigrationView( store: .init( initialState: .init(), - reducer: MigrationReducer() + reducer: MigrationReducer.init ) ) } diff --git a/EhPanda/View/Reading/ReadingReducer.swift b/EhPanda/View/Reading/ReadingReducer.swift index 96b5560b..cbc6e285 100644 --- a/EhPanda/View/Reading/ReadingReducer.swift +++ b/EhPanda/View/Reading/ReadingReducer.swift @@ -204,7 +204,7 @@ struct ReadingReducer: ReducerProtocol { return .none case .setOrientationPortrait(let isPortrait): - var effects = [EffectTask]() + var effects = [Effect]() if isPortrait { effects.append(appDelegateClient.setPortraitOrientationMask().fireAndForget()) effects.append(appDelegateClient.setPortraitOrientation().fireAndForget()) @@ -217,11 +217,11 @@ struct ReadingReducer: ReducerProtocol { return .fireAndForget({ hapticsClient.generateFeedback(.light) }) case .onAppear(let gid, let enablesLandscape): - var effects: [EffectTask] = [ - .init(value: .fetchDatabaseInfos(gid)) + var effects: [Effect] = [ + .send(.fetchDatabaseInfos(gid)) ] if enablesLandscape { - effects.append(.init(value: .setOrientationPortrait(false))) + effects.append(.send(.setOrientationPortrait(false))) } return .merge(effects) @@ -263,17 +263,17 @@ struct ReadingReducer: ReducerProtocol { return .none case .copyImage(let imageURL): - return .init(value: .fetchImage(.copy(imageURL.isGIF), imageURL)) + return .send(.fetchImage(.copy(imageURL.isGIF), imageURL)) case .saveImage(let imageURL): - return .init(value: .fetchImage(.save(imageURL.isGIF), imageURL)) + return .send(.fetchImage(.save(imageURL.isGIF), imageURL)) case .saveImageDone(let isSucceeded): state.hudConfig = isSucceeded ? .savedToPhotoLibrary : .error - return .init(value: .setNavigation(.hud)) + return .send(.setNavigation(.hud)) case .shareImage(let imageURL): - return .init(value: .fetchImage(.share(imageURL.isGIF), imageURL)) + return .send(.fetchImage(.share(imageURL.isGIF), imageURL)) case .fetchImage(let action, let imageURL): return imageClient.fetchImage(url: imageURL) @@ -286,7 +286,7 @@ struct ReadingReducer: ReducerProtocol { case .copy(let isAnimated): state.hudConfig = .copiedToClipboardSucceeded return .merge( - .init(value: .setNavigation(.hud)), + .send(.setNavigation(.hud)), clipboardClient.saveImage(image, isAnimated).fireAndForget() ) case .save(let isAnimated): @@ -294,14 +294,14 @@ struct ReadingReducer: ReducerProtocol { .saveImageToPhotoLibrary(image, isAnimated).map(Action.saveImageDone) case .share(let isAnimated): if isAnimated, let data = image.kf.data(format: .GIF) { - return .init(value: .setNavigation(.share(.data(data)))) + return .send(.setNavigation(.share(.data(data)))) } else { - return .init(value: .setNavigation(.share(.image(image)))) + return .send(.setNavigation(.share(.image(image)))) } } } else { state.hudConfig = .error - return .init(value: .setNavigation(.hud)) + return .send(.setNavigation(.hud)) } case .syncReadingProgress(let progress): @@ -322,11 +322,11 @@ struct ReadingReducer: ReducerProtocol { .fireAndForget() case .teardown: - var effects: [EffectTask] = [ + var effects: [Effect] = [ .cancel(ids: CancelID.allCases) ] if !deviceClient.isPad() { - effects.append(.init(value: .setOrientationPortrait(true))) + effects.append(.send(.setOrientationPortrait(true))) } return .merge(effects) @@ -367,7 +367,7 @@ struct ReadingReducer: ReducerProtocol { } state.previewLoadingStates[index] = .idle state.updatePreviewURLs(previewURLs) - return .init(value: .syncPreviewURLs(previewURLs)) + return .send(.syncPreviewURLs(previewURLs)) case .failure(let error): state.previewLoadingStates[index] = .failed(error) } @@ -375,16 +375,16 @@ struct ReadingReducer: ReducerProtocol { case .fetchImageURLs(let index): if state.mpvKey != nil { - return .init(value: .fetchMPVImageURL(index, false)) + return .send(.fetchMPVImageURL(index, false)) } else { - return .init(value: .fetchThumbnailURLs(index)) + return .send(.fetchThumbnailURLs(index)) } case .refetchImageURLs(let index): if state.mpvKey != nil { - return .init(value: .fetchMPVImageURL(index, true)) + return .send(.fetchMPVImageURL(index, true)) } else { - return .init(value: .refetchNormalImageURLs(index)) + return .send(.refetchNormalImageURLs(index)) } case .prefetchImages(let index, let prefetchLimit): @@ -406,7 +406,7 @@ struct ReadingReducer: ReducerProtocol { } var prefetchImageURLs = [URL]() var fetchImageURLIndices = [Int]() - var effects = [EffectTask]() + var effects = [Effect]() let previousUpperBound = max(index - 2, 1) let previousLowerBound = max(previousUpperBound - prefetchLimit / 2, 1) if previousUpperBound - previousLowerBound > 0 { @@ -420,7 +420,7 @@ struct ReadingReducer: ReducerProtocol { fetchImageURLIndices += getFetchImageURLIndices(range: nextLowerBound...nextUpperBound) } fetchImageURLIndices.forEach { - effects.append(.init(value: .fetchImageURLs($0))) + effects.append(.send(.fetchImageURLs($0))) } effects.append(imageClient.prefetchImages(prefetchImageURLs).fireAndForget()) return .merge(effects) @@ -448,12 +448,12 @@ struct ReadingReducer: ReducerProtocol { return .none } if let url = thumbnailURLs[index], urlClient.checkIfMPVURL(url) { - return .init(value: .fetchMPVKeys(index, url)) + return .send(.fetchMPVKeys(index, url)) } else { state.updateThumbnailURLs(thumbnailURLs) return .merge( - .init(value: .syncThumbnailURLs(thumbnailURLs)), - .init(value: .fetchNormalImageURLs(index, thumbnailURLs)) + .send(.syncThumbnailURLs(thumbnailURLs)), + .send(.fetchNormalImageURLs(index, thumbnailURLs)) ) } case .failure(let error): @@ -482,7 +482,7 @@ struct ReadingReducer: ReducerProtocol { state.imageURLLoadingStates[$0] = .idle } state.updateImageURLs(imageURLs, originalImageURLs) - return .init(value: .syncImageURLs(imageURLs, originalImageURLs)) + return .send(.syncImageURLs(imageURLs, originalImageURLs)) case .failure(let error): batchRange.forEach { state.imageURLLoadingStates[$0] = .failed(error) @@ -509,7 +509,7 @@ struct ReadingReducer: ReducerProtocol { case .refetchNormalImageURLsDone(let index, let result): switch result { case .success(let (imageURLs, response)): - var effects = [EffectTask]() + var effects = [Effect]() if let response = response { effects.append(cookieClient.setSkipServer(response: response).fireAndForget()) } @@ -519,7 +519,7 @@ struct ReadingReducer: ReducerProtocol { } state.imageURLLoadingStates[index] = .idle state.updateImageURLs(imageURLs, [:]) - effects.append(.init(value: .syncImageURLs(imageURLs, [:]))) + effects.append(.send(.syncImageURLs(imageURLs, [:]))) return .merge(effects) case .failure(let error): state.imageURLLoadingStates[index] = .failed(error) @@ -548,7 +548,7 @@ struct ReadingReducer: ReducerProtocol { state.mpvImageKeys = mpvImageKeys return .merge( Array(1...min(3, max(1, pageCount))).map { - .init(value: .fetchMPVImageURL($0, false)) + .send(.fetchMPVImageURL($0, false)) } ) case .failure(let error): @@ -582,7 +582,7 @@ struct ReadingReducer: ReducerProtocol { state.imageURLLoadingStates[index] = .idle state.mpvSkipServerIdentifiers[index] = skipServerIdentifier state.updateImageURLs(imageURLs, originalImageURLs) - return .init(value: .syncImageURLs(imageURLs, originalImageURLs)) + return .send(.syncImageURLs(imageURLs, originalImageURLs)) case .failure(let error): state.imageURLLoadingStates[index] = .failed(error) } diff --git a/EhPanda/View/Reading/ReadingView.swift b/EhPanda/View/Reading/ReadingView.swift index cb361eca..72578753 100644 --- a/EhPanda/View/Reading/ReadingView.swift +++ b/EhPanda/View/Reading/ReadingView.swift @@ -30,7 +30,7 @@ struct ReadingView: View { gid: String, setting: Binding, blurRadius: Double ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.gid = gid _setting = setting self.blurRadius = blurRadius @@ -67,8 +67,8 @@ struct ReadingView: View { .id(viewStore.databaseLoadingState) .id(viewStore.forceRefreshID) ControlPanel( - showsPanel: viewStore.binding(\.$showsPanel), - showsSliderPreview: viewStore.binding(\.$showsSliderPreview), + showsPanel: viewStore.$showsPanel, + showsSliderPreview: viewStore.$showsSliderPreview, sliderValue: $pageHandler.sliderValue, setting: $setting, enablesLiveText: $liveTextHandler.enablesLiveText, autoPlayPolicy: .init(get: { autoPlayHandler.policy }, set: setAutoPlayPolocy), @@ -81,7 +81,7 @@ struct ReadingView: View { fetchPreviewURLsAction: { viewStore.send(.fetchPreviewURLs($0)) } ) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /ReadingReducer.Route.readingSetting) { _ in + .sheet(unwrapping: viewStore.$route, case: /ReadingReducer.Route.readingSetting) { _ in NavigationView { ReadingSettingView( readingDirection: $setting.readingDirection, @@ -106,13 +106,13 @@ struct ReadingView: View { .accentColor(setting.accentColor).tint(setting.accentColor) .autoBlur(radius: blurRadius).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /ReadingReducer.Route.share) { route in + .sheet(unwrapping: viewStore.$route, case: /ReadingReducer.Route.share) { route in ActivityView(activityItems: [route.wrappedValue.associatedValue]) .accentColor(setting.accentColor).autoBlur(radius: blurRadius) } .progressHUD( config: viewStore.hudConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /ReadingReducer.Route.hud ) @@ -600,7 +600,7 @@ struct ReadingView_Previews: PreviewProvider { ReadingView( store: .init( initialState: .init(gallery: .empty), - reducer: ReadingReducer() + reducer: ReadingReducer.init ), gid: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Search/SearchReducer.swift b/EhPanda/View/Search/SearchReducer.swift index f4ea5499..12264c0a 100644 --- a/EhPanda/View/Search/SearchReducer.swift +++ b/EhPanda/View/Search/SearchReducer.swift @@ -70,7 +70,7 @@ struct SearchReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding(\.$keyword): if !state.keyword.isEmpty { @@ -83,15 +83,15 @@ struct SearchReducer: ReducerProtocol { case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.detailState = .init() state.filtersState = .init() state.quickSearchState = .init() return .merge( - .init(value: .detail(.teardown)), - .init(value: .quickSearch(.teardown)) + .send(.detail(.teardown)), + .send(.quickSearch(.teardown)) ) case .teardown: @@ -117,7 +117,7 @@ struct SearchReducer: ReducerProtocol { guard !galleries.isEmpty else { state.loadingState = .failed(.notFound) guard pageNumber.hasNextPage() else { return .none } - return .init(value: .fetchMoreGalleries) + return .send(.fetchMoreGalleries) } state.pageNumber = pageNumber state.galleries = galleries @@ -146,11 +146,11 @@ struct SearchReducer: ReducerProtocol { state.pageNumber = pageNumber state.insertGalleries(galleries) - var effects: [EffectTask] = [ + var effects: [Effect] = [ databaseClient.cacheGalleries(galleries).fireAndForget() ] if galleries.isEmpty, pageNumber.hasNextPage() { - effects.append(.init(value: .fetchMoreGalleries)) + effects.append(.send(.fetchMoreGalleries)) } else if !galleries.isEmpty { state.loadingState = .idle } diff --git a/EhPanda/View/Search/SearchRootReducer.swift b/EhPanda/View/Search/SearchRootReducer.swift index a3e23634..5a5ab083 100644 --- a/EhPanda/View/Search/SearchRootReducer.swift +++ b/EhPanda/View/Search/SearchRootReducer.swift @@ -94,8 +94,8 @@ struct SearchRootReducer: ReducerProtocol { case .binding(\.$route): return state.route == nil ? .merge( - .init(value: .clearSubStates), - .init(value: .fetchDatabaseInfos) + .send(.clearSubStates), + .send(.fetchDatabaseInfos) ) : .none @@ -106,8 +106,8 @@ struct SearchRootReducer: ReducerProtocol { state.route = route return route == nil ? .merge( - .init(value: .clearSubStates), - .init(value: .fetchDatabaseInfos) + .send(.clearSubStates), + .send(.fetchDatabaseInfos) ) : .none @@ -121,9 +121,9 @@ struct SearchRootReducer: ReducerProtocol { state.filtersState = .init() state.quickSearchState = .init() return .merge( - .init(value: .search(.teardown)), - .init(value: .quickSearch(.teardown)), - .init(value: .detail(.teardown)) + .send(.search(.teardown)), + .send(.quickSearch(.teardown)), + .send(.detail(.teardown)) ) case .syncHistoryKeywords: @@ -139,11 +139,11 @@ struct SearchRootReducer: ReducerProtocol { case .appendHistoryKeyword(let keyword): state.appendHistoryKeywords([keyword]) - return .init(value: .syncHistoryKeywords) + return .send(.syncHistoryKeywords) case .removeHistoryKeyword(let keyword): state.removeHistoryKeyword(keyword) - return .init(value: .syncHistoryKeywords) + return .send(.syncHistoryKeywords) case .fetchHistoryGalleries: return databaseClient.fetchHistoryGalleries(fetchLimit: 10).map(Action.fetchHistoryGalleriesDone) @@ -158,7 +158,7 @@ struct SearchRootReducer: ReducerProtocol { } else { state.appendHistoryKeywords([state.searchState.lastKeyword]) } - return .init(value: .syncHistoryKeywords) + return .send(.syncHistoryKeywords) case .search: return .none diff --git a/EhPanda/View/Search/SearchRootView.swift b/EhPanda/View/Search/SearchRootView.swift index 52e0a7f0..69abe14c 100644 --- a/EhPanda/View/Search/SearchRootView.swift +++ b/EhPanda/View/Search/SearchRootView.swift @@ -21,7 +21,7 @@ struct SearchRootView: View { user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.user = user _setting = setting self.blurRadius = blurRadius @@ -45,7 +45,7 @@ struct SearchRootView: View { ) } .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /SearchRootReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -58,11 +58,11 @@ struct SearchRootView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /SearchRootReducer.Route.filters) { _ in + .sheet(unwrapping: viewStore.$route, case: /SearchRootReducer.Route.filters) { _ in FiltersView(store: store.scope(state: \.filtersState, action: SearchRootReducer.Action.filters)) .autoBlur(radius: blurRadius).environment(\.inSheet, true) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /SearchRootReducer.Route.quickSearch) { _ in + .sheet(unwrapping: viewStore.$route, case: /SearchRootReducer.Route.quickSearch) { _ in QuickSearchView( store: store.scope(state: \.quickSearchState, action: SearchRootReducer.Action.quickSearch) ) { keyword in @@ -75,10 +75,10 @@ struct SearchRootView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .searchable(text: viewStore.binding(\.$keyword)) + .searchable(text: viewStore.$keyword) .searchSuggestions { TagSuggestionView( - keyword: viewStore.binding(\.$keyword), translations: tagTranslator.translations, + keyword: viewStore.$keyword, translations: tagTranslator.translations, showsImages: setting.showsImagesInTags, isEnabled: setting.showsTagsSearchSuggestion ) } @@ -117,7 +117,7 @@ private extension SearchRootView { searchViewLink } var detailViewLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SearchRootReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /SearchRootReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: SearchRootReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -126,7 +126,7 @@ private extension SearchRootView { } } var searchViewLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SearchRootReducer.Route.search) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SearchRootReducer.Route.search) { _ in SearchView( store: store.scope(state: \.searchState, action: SearchRootReducer.Action.search), keyword: viewStore.keyword, user: user, setting: $setting, @@ -406,7 +406,7 @@ struct SearchRootView_Previews: PreviewProvider { SearchRootView( store: .init( initialState: .init(), - reducer: SearchRootReducer() + reducer: SearchRootReducer.init ), user: .init(), setting: .constant(.init()), diff --git a/EhPanda/View/Search/SearchView.swift b/EhPanda/View/Search/SearchView.swift index 9a637652..72f3043b 100644 --- a/EhPanda/View/Search/SearchView.swift +++ b/EhPanda/View/Search/SearchView.swift @@ -22,7 +22,7 @@ struct SearchView: View { keyword: String, user: User, setting: Binding, blurRadius: Double, tagTranslator: TagTranslator ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.keyword = keyword self.user = user _setting = setting @@ -45,7 +45,7 @@ struct SearchView: View { } ) .sheet( - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /SearchReducer.Route.detail, isEnabled: DeviceUtil.isPad ) { route in @@ -58,7 +58,7 @@ struct SearchView: View { } .autoBlur(radius: blurRadius).environment(\.inSheet, true).navigationViewStyle(.stack) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /SearchReducer.Route.quickSearch) { _ in + .sheet(unwrapping: viewStore.$route, case: /SearchReducer.Route.quickSearch) { _ in QuickSearchView( store: store.scope(state: \.quickSearchState, action: SearchReducer.Action.quickSearch) ) { keyword in @@ -68,14 +68,14 @@ struct SearchView: View { .accentColor(setting.accentColor) .autoBlur(radius: blurRadius) } - .sheet(unwrapping: viewStore.binding(\.$route), case: /SearchReducer.Route.filters) { _ in + .sheet(unwrapping: viewStore.$route, case: /SearchReducer.Route.filters) { _ in FiltersView(store: store.scope(state: \.filtersState, action: SearchReducer.Action.filters)) .accentColor(setting.accentColor).autoBlur(radius: blurRadius) } - .searchable(text: viewStore.binding(\.$keyword)) + .searchable(text: viewStore.$keyword) .searchSuggestions { TagSuggestionView( - keyword: viewStore.binding(\.$keyword), translations: tagTranslator.translations, + keyword: viewStore.$keyword, translations: tagTranslator.translations, showsImages: setting.showsImagesInTags, isEnabled: setting.showsTagsSearchSuggestion ) } @@ -96,7 +96,7 @@ struct SearchView: View { @ViewBuilder private var navigationLink: some View { if DeviceUtil.isPhone { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SearchReducer.Route.detail) { route in + NavigationLink(unwrapping: viewStore.$route, case: /SearchReducer.Route.detail) { route in DetailView( store: store.scope(state: \.detailState, action: SearchReducer.Action.detail), gid: route.wrappedValue, user: user, setting: $setting, @@ -124,7 +124,7 @@ struct SearchView_Previews: PreviewProvider { SearchView( store: .init( initialState: .init(), - reducer: SearchReducer() + reducer: SearchReducer.init ), keyword: .init(), user: .init(), diff --git a/EhPanda/View/Search/Support/QuickSearchReducer.swift b/EhPanda/View/Search/Support/QuickSearchReducer.swift index a1449c90..30bcb7fb 100644 --- a/EhPanda/View/Search/Support/QuickSearchReducer.swift +++ b/EhPanda/View/Search/Support/QuickSearchReducer.swift @@ -67,14 +67,14 @@ struct QuickSearchReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.focusedField = nil @@ -94,26 +94,26 @@ struct QuickSearchReducer: ReducerProtocol { case .appendWord: state.quickSearchWords.append(state.editingWord) - return .init(value: .syncQuickSearchWords) + return .send(.syncQuickSearchWords) case .editWord: if let index = state.quickSearchWords.firstIndex(where: { $0.id == state.editingWord.id }) { state.quickSearchWords[index] = state.editingWord - return .init(value: .syncQuickSearchWords) + return .send(.syncQuickSearchWords) } return .none case .deleteWord(let word): state.quickSearchWords = state.quickSearchWords.filter({ $0 != word }) - return .init(value: .syncQuickSearchWords) + return .send(.syncQuickSearchWords) case .deleteWordWithOffsets(let offsets): state.quickSearchWords.remove(atOffsets: offsets) - return .init(value: .syncQuickSearchWords) + return .send(.syncQuickSearchWords) case .moveWord(let source, let destination): state.quickSearchWords.move(fromOffsets: source, toOffset: destination) - return .init(value: .syncQuickSearchWords) + return .send(.syncQuickSearchWords) case .teardown: return .cancel(id: CancelID.fetchQuickSearchWords) diff --git a/EhPanda/View/Search/Support/QuickSearchView.swift b/EhPanda/View/Search/Support/QuickSearchView.swift index 62e8e591..70e0556d 100644 --- a/EhPanda/View/Search/Support/QuickSearchView.swift +++ b/EhPanda/View/Search/Support/QuickSearchView.swift @@ -17,7 +17,7 @@ struct QuickSearchView: View { init(store: StoreOf, searchAction: @escaping (String) -> Void) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.searchAction = searchAction } @@ -54,7 +54,7 @@ struct QuickSearchView: View { .withArrow(isVisible: !viewStore.isListEditing).padding(5) .confirmationDialog( message: L10n.Localizable.ConfirmationDialog.Title.delete, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /QuickSearchReducer.Route.deleteWord, matching: word ) { route in @@ -82,8 +82,8 @@ struct QuickSearchView: View { && viewStore.quickSearchWords.isEmpty ? 1 : 0 ) } - .synchronize(viewStore.binding(\.$focusedField), $focusedField) - .environment(\.editMode, viewStore.binding(\.$listEditMode)) + .synchronize(viewStore.$focusedField, $focusedField) + .environment(\.editMode, viewStore.$listEditMode) .animation(.default, value: viewStore.quickSearchWords) .animation(.default, value: viewStore.listEditMode) .onAppear { @@ -123,10 +123,10 @@ struct QuickSearchView: View { } } @ViewBuilder private var navigationLinks: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /QuickSearchReducer.Route.newWord) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /QuickSearchReducer.Route.newWord) { _ in EditWordView( title: L10n.Localizable.QuickSearchView.Title.newWord, - word: viewStore.binding(\.$editingWord), + word: viewStore.$editingWord, focusedField: $focusedField, submitAction: onTextFieldSubmitted, confirmAction: { @@ -135,10 +135,10 @@ struct QuickSearchView: View { } ) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /QuickSearchReducer.Route.editWord) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /QuickSearchReducer.Route.editWord) { _ in EditWordView( title: L10n.Localizable.QuickSearchView.Title.editWord, - word: viewStore.binding(\.$editingWord), + word: viewStore.$editingWord, focusedField: $focusedField, submitAction: onTextFieldSubmitted, confirmAction: { @@ -204,7 +204,7 @@ struct QuickSearchView_Previews: PreviewProvider { QuickSearchView( store: .init( initialState: .init(), - reducer: QuickSearchReducer() + reducer: QuickSearchReducer.init ), searchAction: { _ in } ) diff --git a/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift b/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift index 5cc9b7b6..84d86140 100644 --- a/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift +++ b/EhPanda/View/Setting/AccountSetting/AccountSettingReducer.swift @@ -33,8 +33,10 @@ struct AccountSettingReducer: ReducerProtocol { case setNavigation(Route?) case onLogoutConfirmButtonTapped case clearSubStates + case loadCookies case copyCookies(GalleryHost) + case login(LoginReducer.Action) case ehSetting(EhSettingReducer.Action) } diff --git a/EhPanda/View/Setting/AccountSetting/AccountSettingView.swift b/EhPanda/View/Setting/AccountSetting/AccountSettingView.swift index 6e796bd2..a3ede19a 100644 --- a/EhPanda/View/Setting/AccountSetting/AccountSettingView.swift +++ b/EhPanda/View/Setting/AccountSetting/AccountSettingView.swift @@ -22,7 +22,7 @@ struct AccountSettingView: View { bypassesSNIFiltering: Bool, blurRadius: Double ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) _galleryHost = galleryHost _showsNewDawnGreeting = showsNewDawnGreeting self.bypassesSNIFiltering = bypassesSNIFiltering @@ -40,7 +40,7 @@ struct AccountSettingView: View { } .pickerStyle(.segmented) AccountSection( - route: viewStore.binding(\.$route), + route: viewStore.$route, showsNewDawnGreeting: $showsNewDawnGreeting, bypassesSNIFiltering: bypassesSNIFiltering, loginAction: { viewStore.send(.setNavigation(.login)) }, @@ -55,17 +55,17 @@ struct AccountSettingView: View { ) } CookieSection( - ehCookiesState: viewStore.binding(\.$ehCookiesState), - exCookiesState: viewStore.binding(\.$exCookiesState), + ehCookiesState: viewStore.$ehCookiesState, + exCookiesState: viewStore.$exCookiesState, copyAction: { viewStore.send(.copyCookies($0)) } ) } .progressHUD( config: viewStore.hudConfig, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /AccountSettingReducer.Route.hud ) - .sheet(unwrapping: viewStore.binding(\.$route), case: /AccountSettingReducer.Route.webView) { route in + .sheet(unwrapping: viewStore.$route, case: /AccountSettingReducer.Route.webView) { route in WebView(url: route.wrappedValue) .autoBlur(radius: blurRadius) } @@ -78,13 +78,13 @@ struct AccountSettingView: View { // MARK: NavigationLinks private extension AccountSettingView { @ViewBuilder var navigationLinks: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /AccountSettingReducer.Route.login) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /AccountSettingReducer.Route.login) { _ in LoginView( store: store.scope(state: \.loginState, action: AccountSettingReducer.Action.login), bypassesSNIFiltering: bypassesSNIFiltering, blurRadius: blurRadius ) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /AccountSettingReducer.Route.ehSetting) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /AccountSettingReducer.Route.ehSetting) { _ in EhSettingView( store: store.scope(state: \.ehSettingState, action: AccountSettingReducer.Action.ehSetting), bypassesSNIFiltering: bypassesSNIFiltering, blurRadius: blurRadius @@ -224,7 +224,7 @@ struct AccountSettingView_Previews: PreviewProvider { AccountSettingView( store: .init( initialState: .init(), - reducer: AccountSettingReducer() + reducer: AccountSettingReducer.init ), galleryHost: .constant(.ehentai), showsNewDawnGreeting: .constant(false), diff --git a/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingView.swift b/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingView.swift index 82fdcb6b..c1d02791 100644 --- a/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingView.swift +++ b/EhPanda/View/Setting/AppearanceSetting/AppearanceSettingView.swift @@ -31,7 +31,7 @@ struct AppearanceSettingView: View { displaysJapaneseTitle: Binding ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) _preferredColorScheme = preferredColorScheme _accentColor = accentColor _appIconType = appIconType @@ -107,7 +107,7 @@ struct AppearanceSettingView: View { } private var navigationLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /AppearanceSettingReducer.Route.appIcon) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /AppearanceSettingReducer.Route.appIcon) { _ in AppIconView(appIconType: $appIconType) } } @@ -230,7 +230,7 @@ struct AppearanceSettingView_Previews: PreviewProvider { AppearanceSettingView( store: .init( initialState: .init(), - reducer: AppearanceSettingReducer() + reducer: AppearanceSettingReducer.init ), preferredColorScheme: .constant(.automatic), accentColor: .constant(.blue), diff --git a/EhPanda/View/Setting/EhSetting/EhSettingView.swift b/EhPanda/View/Setting/EhSetting/EhSettingView.swift index 102c79b7..ff1c0540 100644 --- a/EhPanda/View/Setting/EhSetting/EhSettingView.swift +++ b/EhPanda/View/Setting/EhSetting/EhSettingView.swift @@ -16,7 +16,7 @@ struct EhSettingView: View { init(store: StoreOf, bypassesSNIFiltering: Bool, blurRadius: Double) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.bypassesSNIFiltering = bypassesSNIFiltering self.blurRadius = blurRadius } @@ -33,8 +33,8 @@ struct EhSettingView: View { .tint(nil) } // Using `Binding.init` will crash the app - else if let ehSetting = Binding(unwrapping: viewStore.binding(\.$ehSetting)), - let ehProfile = Binding(unwrapping: viewStore.binding(\.$ehProfile)) + else if let ehSetting = Binding(unwrapping: viewStore.$ehSetting), + let ehProfile = Binding(unwrapping: viewStore.$ehProfile) { form(ehSetting: ehSetting, ehProfile: ehProfile) .transition(.opacity.animation(.default)) @@ -50,7 +50,7 @@ struct EhSettingView: View { viewStore.send(.setDefaultProfile(profileSet)) } } - .sheet(unwrapping: viewStore.binding(\.$route), case: /EhSettingReducer.Route.webView) { route in + .sheet(unwrapping: viewStore.$route, case: /EhSettingReducer.Route.webView) { route in WebView(url: route.wrappedValue) .autoBlur(radius: blurRadius) } @@ -62,10 +62,10 @@ struct EhSettingView: View { Form { Group { EhProfileSection( - route: viewStore.binding(\.$route), + route: viewStore.$route, ehSetting: ehSetting, ehProfile: ehProfile, - editingProfileName: viewStore.binding(\.$editingProfileName), + editingProfileName: viewStore.$editingProfileName, deleteAction: { if let value = viewStore.ehProfile?.value { DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { @@ -1021,7 +1021,7 @@ struct EhSettingView_Previews: PreviewProvider { EhSettingView( store: .init( initialState: .init(ehSetting: .empty, ehProfile: .empty, loadingState: .idle), - reducer: EhSettingReducer() + reducer: EhSettingReducer.init ), bypassesSNIFiltering: false, blurRadius: 0 diff --git a/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift b/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift index 1fcb65d4..239c4f02 100644 --- a/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift +++ b/EhPanda/View/Setting/GeneralSetting/GeneralSettingReducer.swift @@ -53,18 +53,18 @@ struct GeneralSettingReducer: ReducerProtocol { Reduce { state, action in switch action { case .binding(\.$route): - return state.route == nil ? .init(value: .clearSubStates) : .none + return state.route == nil ? .send(.clearSubStates) : .none case .binding: return .none case .setNavigation(let route): state.route = route - return route == nil ? .init(value: .clearSubStates) : .none + return route == nil ? .send(.clearSubStates) : .none case .clearSubStates: state.logsState = .init() - return .init(value: .logs(.teardown)) + return .send(.logs(.teardown)) case .onTranslationsFilePicked: return .none @@ -76,7 +76,7 @@ struct GeneralSettingReducer: ReducerProtocol { return .merge( libraryClient.clearWebImageDiskCache().fireAndForget(), databaseClient.removeImageURLs().fireAndForget(), - .init(value: .calculateWebImageDiskCache) + .send(.calculateWebImageDiskCache) ) case .checkPasscodeSetting: diff --git a/EhPanda/View/Setting/GeneralSetting/GeneralSettingView.swift b/EhPanda/View/Setting/GeneralSetting/GeneralSettingView.swift index f85c77db..f15be11c 100644 --- a/EhPanda/View/Setting/GeneralSetting/GeneralSettingView.swift +++ b/EhPanda/View/Setting/GeneralSetting/GeneralSettingView.swift @@ -34,7 +34,7 @@ struct GeneralSettingView: View { autoLockPolicy: Binding ) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.tagTranslatorLoadingState = tagTranslatorLoadingState self.tagTranslatorEmpty = tagTranslatorEmpty self.tagTranslatorHasCustomTranslations = tagTranslatorHasCustomTranslations @@ -106,7 +106,7 @@ struct GeneralSettingView: View { ) .confirmationDialog( message: L10n.Localizable.ConfirmationDialog.Title.removeCustomTranslations, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /GeneralSettingReducer.Route.removeCustomTranslations ) { Button(L10n.Localizable.ConfirmationDialog.Button.remove, role: .destructive) { @@ -164,7 +164,7 @@ struct GeneralSettingView: View { } .confirmationDialog( message: L10n.Localizable.ConfirmationDialog.Title.clear, - unwrapping: viewStore.binding(\.$route), + unwrapping: viewStore.$route, case: /GeneralSettingReducer.Route.clearCache ) { Button(L10n.Localizable.ConfirmationDialog.Button.clear, role: .destructive) { @@ -186,7 +186,7 @@ struct GeneralSettingView: View { } private var navigationLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /GeneralSettingReducer.Route.logs) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /GeneralSettingReducer.Route.logs) { _ in LogsView(store: store.scope(state: \.logsState, action: GeneralSettingReducer.Action.logs)) } } @@ -198,7 +198,7 @@ struct GeneralSettingView_Previews: PreviewProvider { GeneralSettingView( store: .init( initialState: .init(), - reducer: GeneralSettingReducer() + reducer: GeneralSettingReducer.init ), tagTranslatorLoadingState: .idle, tagTranslatorEmpty: false, diff --git a/EhPanda/View/Setting/Login/LoginReducer.swift b/EhPanda/View/Setting/Login/LoginReducer.swift index fe2c7803..9cfc5a68 100644 --- a/EhPanda/View/Setting/Login/LoginReducer.swift +++ b/EhPanda/View/Setting/Login/LoginReducer.swift @@ -77,7 +77,7 @@ struct LoginReducer: ReducerProtocol { case .loginDone(let result): state.route = nil - var effects = [EffectTask]() + var effects = [Effect]() if cookieClient.didLogin { state.loginState = .idle effects.append(.fireAndForget({ hapticsClient.generateNotificationFeedback(.success) })) diff --git a/EhPanda/View/Setting/Login/LoginView.swift b/EhPanda/View/Setting/Login/LoginView.swift index eb5bde54..cde08d43 100644 --- a/EhPanda/View/Setting/Login/LoginView.swift +++ b/EhPanda/View/Setting/Login/LoginView.swift @@ -18,7 +18,7 @@ struct LoginView: View { init(store: StoreOf, bypassesSNIFiltering: Bool, blurRadius: Double) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.bypassesSNIFiltering = bypassesSNIFiltering self.blurRadius = blurRadius } @@ -35,11 +35,11 @@ struct LoginView: View { VStack(spacing: 15) { Group { LoginTextField( - focusedField: $focusedField, text: viewStore.binding(\.$username), + focusedField: $focusedField, text: viewStore.$username, description: L10n.Localizable.LoginView.Title.username, isPassword: false ) LoginTextField( - focusedField: $focusedField, text: viewStore.binding(\.$password), + focusedField: $focusedField, text: viewStore.$password, description: L10n.Localizable.LoginView.Title.password, isPassword: true ) } @@ -55,8 +55,8 @@ struct LoginView: View { } } } - .synchronize(viewStore.binding(\.$focusedField), $focusedField) - .sheet(unwrapping: viewStore.binding(\.$route), case: /LoginReducer.Route.webView) { route in + .synchronize(viewStore.$focusedField, $focusedField) + .sheet(unwrapping: viewStore.$route, case: /LoginReducer.Route.webView) { route in WebView(url: route.wrappedValue) { viewStore.send(.loginDone(.success(nil))) } @@ -136,7 +136,7 @@ struct LoginView_Previews: PreviewProvider { LoginView( store: .init( initialState: .init(), - reducer: LoginReducer() + reducer: LoginReducer.init ), bypassesSNIFiltering: false, blurRadius: 0 diff --git a/EhPanda/View/Setting/Logs/LogsView.swift b/EhPanda/View/Setting/Logs/LogsView.swift index 0d519b11..f00c8c8c 100644 --- a/EhPanda/View/Setting/Logs/LogsView.swift +++ b/EhPanda/View/Setting/Logs/LogsView.swift @@ -14,7 +14,7 @@ struct LogsView: View { init(store: StoreOf) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) } var body: some View { @@ -56,7 +56,7 @@ struct LogsView: View { } private var navigationLink: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /LogsReducer.Route.log) { route in + NavigationLink(unwrapping: viewStore.$route, case: /LogsReducer.Route.log) { route in LogView(log: route.wrappedValue) } } @@ -177,7 +177,7 @@ struct LogsView_Previews: PreviewProvider { LogsView( store: .init( initialState: .init(), - reducer: LogsReducer() + reducer: LogsReducer.init ) ) } diff --git a/EhPanda/View/Setting/SettingReducer.swift b/EhPanda/View/Setting/SettingReducer.swift index 6aec4aac..72c0a680 100644 --- a/EhPanda/View/Setting/SettingReducer.swift +++ b/EhPanda/View/Setting/SettingReducer.swift @@ -116,29 +116,29 @@ struct SettingReducer: ReducerProtocol { switch action { case .binding(\.$setting.galleryHost): return .merge( - .init(value: .syncSetting), + .send(.syncSetting), userDefaultsClient .setValue(state.setting.galleryHost.rawValue, .galleryHost).fireAndForget() ) case .binding(\.$setting.enablesTagsExtension): - var effects: [EffectTask] = [ - .init(value: .syncSetting) + var effects: [Effect] = [ + .send(.syncSetting) ] if state.setting.enablesTagsExtension { - effects.append(.init(value: .fetchTagTranslator)) + effects.append(.send(.fetchTagTranslator)) } return .merge(effects) case .binding(\.$setting.preferredColorScheme): return .merge( - .init(value: .syncSetting), - .init(value: .syncUserInterfaceStyle) + .send(.syncSetting), + .send(.syncUserInterfaceStyle) ) case .binding(\.$setting.appIconType): return .merge( - .init(value: .syncSetting), + .send(.syncSetting), uiApplicationClient.setAlternateIconName(state.setting.appIconType.filename) .map { _ in Action.syncAppIconType } ) @@ -149,7 +149,7 @@ struct SettingReducer: ReducerProtocol { { state.setting.backgroundBlurRadius = 10 } - return .init(value: .syncSetting) + return .send(.syncSetting) case .binding(\.$setting.backgroundBlurRadius): if state.setting.autoLockPolicy != .never @@ -157,11 +157,11 @@ struct SettingReducer: ReducerProtocol { { state.setting.autoLockPolicy = .never } - return .init(value: .syncSetting) + return .send(.syncSetting) case .binding(\.$setting.enablesLandscape): - var effects: [EffectTask] = [ - .init(value: .syncSetting) + var effects: [Effect] = [ + .send(.syncSetting) ] if !state.setting.enablesLandscape && !deviceClient.isPad() { effects.append(appDelegateClient.setPortraitOrientationMask().fireAndForget()) @@ -172,32 +172,32 @@ struct SettingReducer: ReducerProtocol { if state.setting.doubleTapScaleFactor > state.setting.maximumScaleFactor { state.setting.doubleTapScaleFactor = state.setting.maximumScaleFactor } - return .init(value: .syncSetting) + return .send(.syncSetting) case .binding(\.$setting.doubleTapScaleFactor): if state.setting.maximumScaleFactor < state.setting.doubleTapScaleFactor { state.setting.maximumScaleFactor = state.setting.doubleTapScaleFactor } - return .init(value: .syncSetting) + return .send(.syncSetting) case .binding(\.$setting.bypassesSNIFiltering): return .merge( - .init(value: .syncSetting), + .send(.syncSetting), .fireAndForget({ hapticsClient.generateFeedback(.soft) }), dfClient.setActive(state.setting.bypassesSNIFiltering).fireAndForget() ) case .binding(\.$setting): - return .init(value: .syncSetting) + return .send(.syncSetting) case .binding(\.$route): return .none case .binding: return .merge( - .init(value: .syncUser), - .init(value: .syncSetting), - .init(value: .syncTagTranslator) + .send(.syncUser), + .send(.syncSetting), + .send(.syncTagTranslator) ) case .setNavigation(let route): @@ -237,10 +237,10 @@ struct SettingReducer: ReducerProtocol { state.setting = appEnv.setting state.tagTranslator = appEnv.tagTranslator state.user = appEnv.user - var effects: [EffectTask] = [ - .init(value: .syncAppIconType), - .init(value: .loadUserSettingsDone), - .init(value: .syncUserInterfaceStyle), + var effects: [Effect] = [ + .send(.syncAppIconType), + .send(.loadUserSettingsDone), + .send(.syncUserInterfaceStyle), dfClient.setActive(state.setting.bypassesSNIFiltering).fireAndForget() ] if let value: String = userDefaultsClient.getValue(.galleryHost), @@ -249,18 +249,18 @@ struct SettingReducer: ReducerProtocol { state.setting.galleryHost = galleryHost } if cookieClient.shouldFetchIgneous { - effects.append(.init(value: .fetchIgneous)) + effects.append(.send(.fetchIgneous)) } if cookieClient.didLogin { effects.append(contentsOf: [ - .init(value: .fetchUserInfo), - .init(value: .fetchGreeting), - .init(value: .fetchFavoriteCategories), - .init(value: .fetchEhProfileIndex) + .send(.fetchUserInfo), + .send(.fetchGreeting), + .send(.fetchFavoriteCategories), + .send(.fetchEhProfileIndex) ]) } if state.setting.enablesTagsExtension { - effects.append(.init(value: .fetchTagTranslator)) + effects.append(.send(.fetchTagTranslator)) } return .merge(effects) @@ -276,11 +276,11 @@ struct SettingReducer: ReducerProtocol { return IgneousRequest().effect.map(Action.fetchIgneousDone) case .fetchIgneousDone(let result): - var effects = [EffectTask]() + var effects = [Effect]() if case .success(let response) = result { effects.append(cookieClient.setCredentials(response: response).fireAndForget()) } - effects.append(.init(value: .account(.loadCookies))) + effects.append(.send(.account(.loadCookies))) return .merge(effects) case .fetchUserInfo: @@ -295,7 +295,7 @@ struct SettingReducer: ReducerProtocol { case .fetchUserInfoDone(let result): if case .success(let user) = result { state.updateUser(user) - return .init(value: .syncUser) + return .send(.syncUser) } return .none @@ -335,13 +335,13 @@ struct SettingReducer: ReducerProtocol { switch result { case .success(let greeting): state.setGreeting(greeting) - return .init(value: .syncUser) + return .send(.syncUser) case .failure(let error): if case .parseFailed = error { var greeting = Greeting() greeting.updateTime = Date() state.setGreeting(greeting) - return .init(value: .syncUser) + return .send(.syncUser) } } return .none @@ -353,10 +353,10 @@ struct SettingReducer: ReducerProtocol { else { return .none } state.tagTranslatorLoadingState = .loading - var databaseEffect: EffectTask? + var databaseEffect: Effect? if state.tagTranslator.language != language { state.tagTranslator = TagTranslator(language: language) - databaseEffect = .init(value: .syncTagTranslator) + databaseEffect = .send(.syncTagTranslator) } let updatedDate = state.tagTranslator.updatedDate let requestEffect = TagTranslatorRequest(language: language, updatedDate: updatedDate) @@ -372,7 +372,7 @@ struct SettingReducer: ReducerProtocol { switch result { case .success(let tagTranslator): state.tagTranslator = tagTranslator - return .init(value: .syncTagTranslator) + return .send(.syncTagTranslator) case .failure(let error): state.tagTranslatorLoadingState = .failed(error) } @@ -383,7 +383,7 @@ struct SettingReducer: ReducerProtocol { return VerifyEhProfileRequest().effect.map(Action.fetchEhProfileIndexDone) case .fetchEhProfileIndexDone(let result): - var effects = [EffectTask]() + var effects = [Effect]() if case .success(let response) = result { if let profileValue = response.profileValue { @@ -401,7 +401,7 @@ struct SettingReducer: ReducerProtocol { ) } } else if response.isProfileNotFound { - effects.append(.init(value: .createDefaultEhProfile)) + effects.append(.send(.createDefaultEhProfile)) } else { let message = "Found profile but failed in parsing value." effects.append(loggerClient.error(message, nil).fireAndForget()) @@ -424,16 +424,16 @@ struct SettingReducer: ReducerProtocol { cookieClient.removeYay().fireAndForget(), cookieClient.syncExCookies().fireAndForget(), cookieClient.fulfillAnotherHostField().fireAndForget(), - .init(value: .fetchIgneous), - .init(value: .fetchUserInfo), - .init(value: .fetchFavoriteCategories), - .init(value: .fetchEhProfileIndex) + .send(.fetchIgneous), + .send(.fetchUserInfo), + .send(.fetchFavoriteCategories), + .send(.fetchEhProfileIndex) ) case .account(.onLogoutConfirmButtonTapped): state.user = User() return .merge( - .init(value: .syncUser), + .send(.syncUser), cookieClient.clearAll().fireAndForget(), databaseClient.removeImageURLs().fireAndForget(), libraryClient.clearWebImageDiskCache().fireAndForget() @@ -448,7 +448,7 @@ struct SettingReducer: ReducerProtocol { case .general(.onRemoveCustomTranslations): state.tagTranslator.hasCustomTranslations = false state.tagTranslator.translations = .init() - return .init(value: .syncTagTranslator) + return .send(.syncTagTranslator) case .general: return .none diff --git a/EhPanda/View/Setting/SettingView.swift b/EhPanda/View/Setting/SettingView.swift index f4d267b2..eed21c61 100644 --- a/EhPanda/View/Setting/SettingView.swift +++ b/EhPanda/View/Setting/SettingView.swift @@ -16,7 +16,7 @@ struct SettingView: View { init(store: StoreOf, blurRadius: Double) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) self.blurRadius = blurRadius } @@ -42,64 +42,64 @@ struct SettingView: View { // MARK: NavigationLinks private extension SettingView { @ViewBuilder var navigationLinks: some View { - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SettingReducer.Route.account) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SettingReducer.Route.account) { _ in AccountSettingView( store: store.scope(state: \.accountSettingState, action: SettingReducer.Action.account), - galleryHost: viewStore.binding(\.$setting.galleryHost), - showsNewDawnGreeting: viewStore.binding(\.$setting.showsNewDawnGreeting), + galleryHost: viewStore.$setting.galleryHost, + showsNewDawnGreeting: viewStore.$setting.showsNewDawnGreeting, bypassesSNIFiltering: viewStore.setting.bypassesSNIFiltering, blurRadius: blurRadius ) .tint(viewStore.setting.accentColor) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SettingReducer.Route.general) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SettingReducer.Route.general) { _ in GeneralSettingView( store: store.scope(state: \.generalSettingState, action: SettingReducer.Action.general), tagTranslatorLoadingState: viewStore.tagTranslatorLoadingState, tagTranslatorEmpty: viewStore.tagTranslator.translations.isEmpty, tagTranslatorHasCustomTranslations: viewStore.tagTranslator.hasCustomTranslations, - enablesTagsExtension: viewStore.binding(\.$setting.enablesTagsExtension), - translatesTags: viewStore.binding(\.$setting.translatesTags), - showsTagsSearchSuggestion: viewStore.binding(\.$setting.showsTagsSearchSuggestion), - showsImagesInTags: viewStore.binding(\.$setting.showsImagesInTags), - redirectsLinksToSelectedHost: viewStore.binding(\.$setting.redirectsLinksToSelectedHost), - detectsLinksFromClipboard: viewStore.binding(\.$setting.detectsLinksFromClipboard), - backgroundBlurRadius: viewStore.binding(\.$setting.backgroundBlurRadius), - autoLockPolicy: viewStore.binding(\.$setting.autoLockPolicy) + enablesTagsExtension: viewStore.$setting.enablesTagsExtension, + translatesTags: viewStore.$setting.translatesTags, + showsTagsSearchSuggestion: viewStore.$setting.showsTagsSearchSuggestion, + showsImagesInTags: viewStore.$setting.showsImagesInTags, + redirectsLinksToSelectedHost: viewStore.$setting.redirectsLinksToSelectedHost, + detectsLinksFromClipboard: viewStore.$setting.detectsLinksFromClipboard, + backgroundBlurRadius: viewStore.$setting.backgroundBlurRadius, + autoLockPolicy: viewStore.$setting.autoLockPolicy ) .tint(viewStore.setting.accentColor) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SettingReducer.Route.appearance) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SettingReducer.Route.appearance) { _ in AppearanceSettingView( store: store.scope(state: \.appearanceSettingState, action: SettingReducer.Action.appearance), - preferredColorScheme: viewStore.binding(\.$setting.preferredColorScheme), - accentColor: viewStore.binding(\.$setting.accentColor), - appIconType: viewStore.binding(\.$setting.appIconType), - listDisplayMode: viewStore.binding(\.$setting.listDisplayMode), - showsTagsInList: viewStore.binding(\.$setting.showsTagsInList), - listTagsNumberMaximum: viewStore.binding(\.$setting.listTagsNumberMaximum), - displaysJapaneseTitle: viewStore.binding(\.$setting.displaysJapaneseTitle) + preferredColorScheme: viewStore.$setting.preferredColorScheme, + accentColor: viewStore.$setting.accentColor, + appIconType: viewStore.$setting.appIconType, + listDisplayMode: viewStore.$setting.listDisplayMode, + showsTagsInList: viewStore.$setting.showsTagsInList, + listTagsNumberMaximum: viewStore.$setting.listTagsNumberMaximum, + displaysJapaneseTitle: viewStore.$setting.displaysJapaneseTitle ) .tint(viewStore.setting.accentColor) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SettingReducer.Route.reading) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SettingReducer.Route.reading) { _ in ReadingSettingView( - readingDirection: viewStore.binding(\.$setting.readingDirection), - prefetchLimit: viewStore.binding(\.$setting.prefetchLimit), - enablesLandscape: viewStore.binding(\.$setting.enablesLandscape), - contentDividerHeight: viewStore.binding(\.$setting.contentDividerHeight), - maximumScaleFactor: viewStore.binding(\.$setting.maximumScaleFactor), - doubleTapScaleFactor: viewStore.binding(\.$setting.doubleTapScaleFactor) + readingDirection: viewStore.$setting.readingDirection, + prefetchLimit: viewStore.$setting.prefetchLimit, + enablesLandscape: viewStore.$setting.enablesLandscape, + contentDividerHeight: viewStore.$setting.contentDividerHeight, + maximumScaleFactor: viewStore.$setting.maximumScaleFactor, + doubleTapScaleFactor: viewStore.$setting.doubleTapScaleFactor ) .tint(viewStore.setting.accentColor) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SettingReducer.Route.laboratory) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SettingReducer.Route.laboratory) { _ in LaboratorySettingView( - bypassesSNIFiltering: viewStore.binding(\.$setting.bypassesSNIFiltering) + bypassesSNIFiltering: viewStore.$setting.bypassesSNIFiltering ) .tint(viewStore.setting.accentColor) } - NavigationLink(unwrapping: viewStore.binding(\.$route), case: /SettingReducer.Route.about) { _ in + NavigationLink(unwrapping: viewStore.$route, case: /SettingReducer.Route.about) { _ in AboutView().tint(viewStore.setting.accentColor) } } @@ -185,7 +185,7 @@ struct SettingView_Previews: PreviewProvider { SettingView( store: .init( initialState: .init(), - reducer: SettingReducer() + reducer: SettingReducer.init ), blurRadius: 0 ) diff --git a/EhPanda/View/Support/FiltersReducer.swift b/EhPanda/View/Support/FiltersReducer.swift index 83121f01..94e4c1c9 100644 --- a/EhPanda/View/Support/FiltersReducer.swift +++ b/EhPanda/View/Support/FiltersReducer.swift @@ -47,15 +47,15 @@ struct FiltersReducer: ReducerProtocol { switch action { case .binding(\.$searchFilter): state.searchFilter.fixInvalidData() - return .init(value: .syncFilter(.search)) + return .send(.syncFilter(.search)) case .binding(\.$globalFilter): state.globalFilter.fixInvalidData() - return .init(value: .syncFilter(.global)) + return .send(.syncFilter(.global)) case .binding(\.$watchedFilter): state.watchedFilter.fixInvalidData() - return .init(value: .syncFilter(.watched)) + return .send(.syncFilter(.watched)) case .binding: return .none @@ -91,13 +91,13 @@ struct FiltersReducer: ReducerProtocol { switch state.filterRange { case .search: state.searchFilter = .init() - return .init(value: .syncFilter(.search)) + return .send(.syncFilter(.search)) case .global: state.globalFilter = .init() - return .init(value: .syncFilter(.global)) + return .send(.syncFilter(.global)) case .watched: state.watchedFilter = .init() - return .init(value: .syncFilter(.watched)) + return .send(.syncFilter(.watched)) } case .fetchFilters: diff --git a/EhPanda/View/Support/FiltersView.swift b/EhPanda/View/Support/FiltersView.swift index 5ac42d18..b2a9d82b 100644 --- a/EhPanda/View/Support/FiltersView.swift +++ b/EhPanda/View/Support/FiltersView.swift @@ -16,17 +16,17 @@ struct FiltersView: View { init(store: StoreOf) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) } private var filter: Binding { switch viewStore.filterRange { case .search: - return viewStore.binding(\.$searchFilter) + return viewStore.$searchFilter case .global: - return viewStore.binding(\.$globalFilter) + return viewStore.$globalFilter case .watched: - return viewStore.binding(\.$watchedFilter) + return viewStore.$watchedFilter } } @@ -35,8 +35,8 @@ struct FiltersView: View { NavigationView { Form { BasicSection( - route: viewStore.binding(\.$route), - filter: filter, filterRange: viewStore.binding(\.$filterRange), + route: viewStore.$route, + filter: filter, filterRange: viewStore.$filterRange, resetFiltersAction: { viewStore.send(.resetFilters) }, resetFiltersDialogAction: { viewStore.send(.setNavigation(.resetFilters)) } ) @@ -45,7 +45,7 @@ struct FiltersView: View { submitAction: { viewStore.send(.onTextFieldSubmitted) } ) } - .synchronize(viewStore.binding(\.$focusedBound), $focusedBound) + .synchronize(viewStore.$focusedBound, $focusedBound) .navigationTitle(L10n.Localizable.FiltersView.Title.filters) .onAppear { viewStore.send(.fetchFilters) } } @@ -242,7 +242,7 @@ struct FiltersView_Previews: PreviewProvider { FiltersView( store: .init( initialState: .init(), - reducer: FiltersReducer() + reducer: FiltersReducer.init ) ) } diff --git a/EhPanda/View/TabBar/TabBarView.swift b/EhPanda/View/TabBar/TabBarView.swift index 5c4a83a3..cfdd66ec 100644 --- a/EhPanda/View/TabBar/TabBarView.swift +++ b/EhPanda/View/TabBar/TabBarView.swift @@ -16,7 +16,7 @@ struct TabBarView: View { init(store: StoreOf) { self.store = store - viewStore = ViewStore(store) + viewStore = ViewStore(store, observe: { $0 }) } var body: some View { @@ -158,7 +158,7 @@ struct TabBarView_Previews: PreviewProvider { TabBarView( store: .init( initialState: .init(), - reducer: AppReducer() + reducer: AppReducer.init ) ) }