diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index f5894901a..3c570b1af 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -7,6 +7,5 @@ set -eo pipefail
xcodebuild -workspace Mastodon.xcworkspace \
-scheme Mastodon \
- -destination "platform=iOS Simulator,name=iPhone SE (2nd generation)" \
clean \
build | xcpretty
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index d8a01b818..30f9c0c2d 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -4109,7 +4109,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.7;
+ MARKETING_VERSION = 1.4.5;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4139,7 +4139,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.7;
+ MARKETING_VERSION = 1.4.5;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4312,7 +4312,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.7;
+ MARKETING_VERSION = 1.4.5;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4609,7 +4609,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.7;
+ MARKETING_VERSION = 1.4.5;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index 498c362d6..21906eb03 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -112,12 +112,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 7
+ 25
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 6
+ 24
SuppressBuildableAutocreation
diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
index ebcacb501..4ee0ebeb7 100644
--- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,241 +1,239 @@
{
- "object": {
- "pins": [
- {
- "package": "Alamofire",
- "repositoryURL": "https://github.com/Alamofire/Alamofire.git",
- "state": {
- "branch": null,
- "revision": "354dda32d89fc8cd4f5c46487f64957d355f53d8",
- "version": "5.6.1"
- }
- },
- {
- "package": "AlamofireImage",
- "repositoryURL": "https://github.com/Alamofire/AlamofireImage.git",
- "state": {
- "branch": null,
- "revision": "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10",
- "version": "4.2.0"
- }
- },
- {
- "package": "CommonOSLog",
- "repositoryURL": "https://github.com/MainasuK/CommonOSLog",
- "state": {
- "branch": null,
- "revision": "c121624a30698e9886efe38aebb36ff51c01b6c2",
- "version": "0.1.1"
- }
- },
- {
- "package": "FaviconFinder",
- "repositoryURL": "https://github.com/will-lumley/FaviconFinder.git",
- "state": {
- "branch": null,
- "revision": "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a",
- "version": "3.3.0"
- }
- },
- {
- "package": "FLAnimatedImage",
- "repositoryURL": "https://github.com/Flipboard/FLAnimatedImage.git",
- "state": {
- "branch": null,
- "revision": "e7f9fd4681ae41bf6f3056db08af4f401d61da52",
- "version": "1.0.16"
- }
- },
- {
- "package": "FPSIndicator",
- "repositoryURL": "https://github.com/MainasuK/FPSIndicator.git",
- "state": {
- "branch": null,
- "revision": "e4a5067ccd5293b024c767f09e51056afd4a4796",
- "version": "1.1.0"
- }
- },
- {
- "package": "Fuzi",
- "repositoryURL": "https://github.com/cezheng/Fuzi.git",
- "state": {
- "branch": null,
- "revision": "f08c8323da21e985f3772610753bcfc652c2103f",
- "version": "3.1.3"
- }
- },
- {
- "package": "KeychainAccess",
- "repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git",
- "state": {
- "branch": null,
- "revision": "84e546727d66f1adc5439debad16270d0fdd04e7",
- "version": "4.2.2"
- }
- },
- {
- "package": "MetaTextKit",
- "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git",
- "state": {
- "branch": null,
- "revision": "dcd5255d6930c2fab408dc8562c577547e477624",
- "version": "2.2.5"
- }
- },
- {
- "package": "Nuke",
- "repositoryURL": "https://github.com/kean/Nuke.git",
- "state": {
- "branch": null,
- "revision": "0ea7545b5c918285aacc044dc75048625c8257cc",
- "version": "10.8.0"
- }
- },
- {
- "package": "NukeFLAnimatedImagePlugin",
- "repositoryURL": "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
- "state": {
- "branch": null,
- "revision": "b59c346a7d536336db3b0f12c72c6e53ee709e16",
- "version": "8.0.0"
- }
- },
- {
- "package": "Pageboy",
- "repositoryURL": "https://github.com/uias/Pageboy",
- "state": {
- "branch": null,
- "revision": "34ecb6e7c4e0e07494960ab2f7cc9a02293915a6",
- "version": "3.6.2"
- }
- },
- {
- "package": "PanModal",
- "repositoryURL": "https://github.com/slackhq/PanModal.git",
- "state": {
- "branch": null,
- "revision": "b012aecb6b67a8e46369227f893c12544846613f",
- "version": "1.2.7"
- }
- },
- {
- "package": "SDWebImage",
- "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
- "state": {
- "branch": null,
- "revision": "2e63d0061da449ad0ed130768d05dceb1496de44",
- "version": "5.12.5"
- }
- },
- {
- "package": "swift-collections",
- "repositoryURL": "https://github.com/apple/swift-collections.git",
- "state": {
- "branch": null,
- "revision": "f504716c27d2e5d4144fa4794b12129301d17729",
- "version": "1.0.3"
- }
- },
- {
- "package": "swift-nio",
- "repositoryURL": "https://github.com/apple/swift-nio.git",
- "state": {
- "branch": null,
- "revision": "546610d52b19be3e19935e0880bb06b9c03f5cef",
- "version": "1.14.4"
- }
- },
- {
- "package": "swift-nio-zlib-support",
- "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git",
- "state": {
- "branch": null,
- "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd",
- "version": "1.0.0"
- }
- },
- {
- "package": "SwiftSoup",
- "repositoryURL": "https://github.com/scinfu/SwiftSoup.git",
- "state": {
- "branch": null,
- "revision": "41e7c263fb8c277e980ebcb9b0b5f6031d3d4886",
- "version": "2.4.2"
- }
- },
- {
- "package": "Introspect",
- "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git",
- "state": {
- "branch": null,
- "revision": "f2616860a41f9d9932da412a8978fec79c06fe24",
- "version": "0.1.4"
- }
- },
- {
- "package": "SwiftyJSON",
- "repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON.git",
- "state": {
- "branch": null,
- "revision": "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07",
- "version": "5.0.1"
- }
- },
- {
- "package": "TabBarPager",
- "repositoryURL": "https://github.com/TwidereProject/TabBarPager.git",
- "state": {
- "branch": null,
- "revision": "488aa66d157a648901b61721212c0dec23d27ee5",
- "version": "0.1.0"
- }
- },
- {
- "package": "Tabman",
- "repositoryURL": "https://github.com/uias/Tabman",
- "state": {
- "branch": null,
- "revision": "4a4f7c755b875ffd4f9ef10d67a67883669d2465",
- "version": "2.13.0"
- }
- },
- {
- "package": "ThirdPartyMailer",
- "repositoryURL": "https://github.com/vtourraine/ThirdPartyMailer.git",
- "state": {
- "branch": null,
- "revision": "44c1cfaa6969963f22691aa67f88a69e3b6d651f",
- "version": "2.1.0"
- }
- },
- {
- "package": "TOCropViewController",
- "repositoryURL": "https://github.com/TimOliver/TOCropViewController.git",
- "state": {
- "branch": null,
- "revision": "d0470491f56e734731bbf77991944c0dfdee3e0e",
- "version": "2.6.1"
- }
- },
- {
- "package": "UIHostingConfigurationBackport",
- "repositoryURL": "https://github.com/woxtu/UIHostingConfigurationBackport.git",
- "state": {
- "branch": null,
- "revision": "6091f2d38faa4b24fc2ca0389c651e2f666624a3",
- "version": "0.1.0"
- }
- },
- {
- "package": "UITextView+Placeholder",
- "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder.git",
- "state": {
- "branch": null,
- "revision": "20f513ded04a040cdf5467f0891849b1763ede3b",
- "version": "1.4.1"
- }
+ "pins" : [
+ {
+ "identity" : "alamofire",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/Alamofire/Alamofire.git",
+ "state" : {
+ "revision" : "354dda32d89fc8cd4f5c46487f64957d355f53d8",
+ "version" : "5.6.1"
}
- ]
- },
- "version": 1
+ },
+ {
+ "identity" : "alamofireimage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/Alamofire/AlamofireImage.git",
+ "state" : {
+ "revision" : "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10",
+ "version" : "4.2.0"
+ }
+ },
+ {
+ "identity" : "commonoslog",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/MainasuK/CommonOSLog",
+ "state" : {
+ "revision" : "c121624a30698e9886efe38aebb36ff51c01b6c2",
+ "version" : "0.1.1"
+ }
+ },
+ {
+ "identity" : "faviconfinder",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/will-lumley/FaviconFinder.git",
+ "state" : {
+ "revision" : "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a",
+ "version" : "3.3.0"
+ }
+ },
+ {
+ "identity" : "flanimatedimage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/Flipboard/FLAnimatedImage.git",
+ "state" : {
+ "revision" : "e7f9fd4681ae41bf6f3056db08af4f401d61da52",
+ "version" : "1.0.16"
+ }
+ },
+ {
+ "identity" : "fpsindicator",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/MainasuK/FPSIndicator.git",
+ "state" : {
+ "revision" : "e4a5067ccd5293b024c767f09e51056afd4a4796",
+ "version" : "1.1.0"
+ }
+ },
+ {
+ "identity" : "fuzi",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/cezheng/Fuzi.git",
+ "state" : {
+ "revision" : "f08c8323da21e985f3772610753bcfc652c2103f",
+ "version" : "3.1.3"
+ }
+ },
+ {
+ "identity" : "keychainaccess",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/kishikawakatsumi/KeychainAccess.git",
+ "state" : {
+ "revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
+ "version" : "4.2.2"
+ }
+ },
+ {
+ "identity" : "metatextkit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/TwidereProject/MetaTextKit.git",
+ "state" : {
+ "revision" : "dcd5255d6930c2fab408dc8562c577547e477624",
+ "version" : "2.2.5"
+ }
+ },
+ {
+ "identity" : "nuke",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/kean/Nuke.git",
+ "state" : {
+ "revision" : "0ea7545b5c918285aacc044dc75048625c8257cc",
+ "version" : "10.8.0"
+ }
+ },
+ {
+ "identity" : "nuke-flanimatedimage-plugin",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
+ "state" : {
+ "revision" : "b59c346a7d536336db3b0f12c72c6e53ee709e16",
+ "version" : "8.0.0"
+ }
+ },
+ {
+ "identity" : "pageboy",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/uias/Pageboy",
+ "state" : {
+ "revision" : "34ecb6e7c4e0e07494960ab2f7cc9a02293915a6",
+ "version" : "3.6.2"
+ }
+ },
+ {
+ "identity" : "panmodal",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/slackhq/PanModal.git",
+ "state" : {
+ "revision" : "b012aecb6b67a8e46369227f893c12544846613f",
+ "version" : "1.2.7"
+ }
+ },
+ {
+ "identity" : "sdwebimage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SDWebImage/SDWebImage.git",
+ "state" : {
+ "revision" : "2e63d0061da449ad0ed130768d05dceb1496de44",
+ "version" : "5.12.5"
+ }
+ },
+ {
+ "identity" : "swift-collections",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-collections.git",
+ "state" : {
+ "revision" : "f504716c27d2e5d4144fa4794b12129301d17729",
+ "version" : "1.0.3"
+ }
+ },
+ {
+ "identity" : "swift-nio",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-nio.git",
+ "state" : {
+ "revision" : "546610d52b19be3e19935e0880bb06b9c03f5cef",
+ "version" : "1.14.4"
+ }
+ },
+ {
+ "identity" : "swift-nio-zlib-support",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-nio-zlib-support.git",
+ "state" : {
+ "revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd",
+ "version" : "1.0.0"
+ }
+ },
+ {
+ "identity" : "swiftsoup",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/scinfu/SwiftSoup.git",
+ "state" : {
+ "revision" : "41e7c263fb8c277e980ebcb9b0b5f6031d3d4886",
+ "version" : "2.4.2"
+ }
+ },
+ {
+ "identity" : "swiftui-introspect",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/siteline/SwiftUI-Introspect.git",
+ "state" : {
+ "revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
+ "version" : "0.1.4"
+ }
+ },
+ {
+ "identity" : "swiftyjson",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SwiftyJSON/SwiftyJSON.git",
+ "state" : {
+ "revision" : "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07",
+ "version" : "5.0.1"
+ }
+ },
+ {
+ "identity" : "tabbarpager",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/TwidereProject/TabBarPager.git",
+ "state" : {
+ "revision" : "488aa66d157a648901b61721212c0dec23d27ee5",
+ "version" : "0.1.0"
+ }
+ },
+ {
+ "identity" : "tabman",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/uias/Tabman",
+ "state" : {
+ "revision" : "4a4f7c755b875ffd4f9ef10d67a67883669d2465",
+ "version" : "2.13.0"
+ }
+ },
+ {
+ "identity" : "thirdpartymailer",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/vtourraine/ThirdPartyMailer.git",
+ "state" : {
+ "revision" : "44c1cfaa6969963f22691aa67f88a69e3b6d651f",
+ "version" : "2.1.0"
+ }
+ },
+ {
+ "identity" : "tocropviewcontroller",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/TimOliver/TOCropViewController.git",
+ "state" : {
+ "revision" : "d0470491f56e734731bbf77991944c0dfdee3e0e",
+ "version" : "2.6.1"
+ }
+ },
+ {
+ "identity" : "uihostingconfigurationbackport",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/woxtu/UIHostingConfigurationBackport.git",
+ "state" : {
+ "revision" : "6091f2d38faa4b24fc2ca0389c651e2f666624a3",
+ "version" : "0.1.0"
+ }
+ },
+ {
+ "identity" : "uitextview-placeholder",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/MainasuK/UITextView-Placeholder.git",
+ "state" : {
+ "revision" : "20f513ded04a040cdf5467f0891849b1763ede3b",
+ "version" : "1.4.1"
+ }
+ }
+ ],
+ "version" : 2
}
diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift
index 3aeafaabd..ae8d81d25 100644
--- a/Mastodon/Coordinator/SceneCoordinator.swift
+++ b/Mastodon/Coordinator/SceneCoordinator.swift
@@ -22,7 +22,7 @@ final public class SceneCoordinator {
private weak var sceneDelegate: SceneDelegate!
private weak var appContext: AppContext!
- private var authContext: AuthContext?
+ private(set) var authContext: AuthContext?
let id = UUID().uuidString
@@ -45,100 +45,83 @@ final public class SceneCoordinator {
appContext.notificationService.requestRevealNotificationPublisher
.receive(on: DispatchQueue.main)
- .compactMap { [weak self] pushNotification -> AnyPublisher in
- guard let self = self else { return Just(nil).eraseToAnyPublisher() }
- // skip if no available account
- guard let currentActiveAuthenticationBox = appContext.authenticationService.activeMastodonAuthenticationBox.value else {
- return Just(nil).eraseToAnyPublisher()
- }
-
- let accessToken = pushNotification.accessToken // use raw accessToken value without normalize
- if currentActiveAuthenticationBox.userAuthorization.accessToken == accessToken {
- // do nothing if notification for current account
- return Just(pushNotification).eraseToAnyPublisher()
- } else {
- // switch to notification's account
- let request = MastodonAuthentication.sortedFetchRequest
- request.predicate = MastodonAuthentication.predicate(userAccessToken: accessToken)
- request.returnsObjectsAsFaults = false
- request.fetchLimit = 1
- do {
- guard let authentication = try appContext.managedObjectContext.fetch(request).first else {
- return Just(nil).eraseToAnyPublisher()
- }
- let domain = authentication.domain
- let userID = authentication.userID
- return appContext.authenticationService.activeMastodonUser(domain: domain, userID: userID)
- .receive(on: DispatchQueue.main)
- .map { [weak self] result -> MastodonPushNotification? in
- guard let self = self else { return nil }
- switch result {
- case .success:
- // reset view hierarchy
- self.setup()
- return pushNotification
- case .failure:
- return nil
- }
- }
- .delay(for: 1, scheduler: DispatchQueue.main) // set delay to slow transition (not must)
- .eraseToAnyPublisher()
- } catch {
- assertionFailure(error.localizedDescription)
- return Just(nil).eraseToAnyPublisher()
- }
- }
- }
- .switchToLatest()
- .receive(on: DispatchQueue.main)
- .sink { [weak self] pushNotification in
+ .sink(receiveValue: { [weak self] pushNotification in
guard let self = self else { return }
- guard let pushNotification = pushNotification else { return }
-
- // redirect to notification tab
- self.switchToTabBar(tab: .notification)
-
-
- // Delay in next run loop
- DispatchQueue.main.async { [weak self] in
- guard let self = self else { return }
-
- // Note:
- // show (push) on phone and pad
- let from: UIViewController? = {
- if let splitViewController = self.splitViewController {
- if splitViewController.compactMainTabBarViewController.topMost?.view.window != nil {
- // compact
- return splitViewController.compactMainTabBarViewController.topMost
- } else {
- // expand
- return splitViewController.contentSplitViewController.mainTabBarController.topMost
+ Task {
+ guard let currentActiveAuthenticationBox = self.authContext?.mastodonAuthenticationBox else { return }
+ let accessToken = pushNotification.accessToken // use raw accessToken value without normalize
+ if currentActiveAuthenticationBox.userAuthorization.accessToken == accessToken {
+ // do nothing if notification for current account
+ return
+ } else {
+ // switch to notification's account
+ let request = MastodonAuthentication.sortedFetchRequest
+ request.predicate = MastodonAuthentication.predicate(userAccessToken: accessToken)
+ request.returnsObjectsAsFaults = false
+ request.fetchLimit = 1
+ do {
+ guard let authentication = try appContext.managedObjectContext.fetch(request).first else {
+ return
}
- } else {
- return self.tabBarController.topMost
+ let domain = authentication.domain
+ let userID = authentication.userID
+ let isSuccess = try await appContext.authenticationService.activeMastodonUser(domain: domain, userID: userID)
+ guard isSuccess else { return }
+
+ self.setup()
+ try await Task.sleep(nanoseconds: .second * 1)
+
+ // redirect to notification tab
+ self.switchToTabBar(tab: .notification)
+
+ // Delay in next run loop
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
+
+ // Note:
+ // show (push) on phone and pad
+ let from: UIViewController? = {
+ if let splitViewController = self.splitViewController {
+ if splitViewController.compactMainTabBarViewController.topMost?.view.window != nil {
+ // compact
+ return splitViewController.compactMainTabBarViewController.topMost
+ } else {
+ // expand
+ return splitViewController.contentSplitViewController.mainTabBarController.topMost
+ }
+ } else {
+ return self.tabBarController.topMost
+ }
+ }()
+
+ // show notification related content
+ guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return }
+ guard let authContext = self.authContext else { return }
+ let notificationID = String(pushNotification.notificationID)
+
+ switch type {
+ case .follow:
+ let profileViewModel = RemoteProfileViewModel(context: appContext, authContext: authContext, notificationID: notificationID)
+ _ = self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show)
+ case .followRequest:
+ // do nothing
+ break
+ case .mention, .reblog, .favourite, .poll, .status:
+ let threadViewModel = RemoteThreadViewModel(context: appContext, authContext: authContext, notificationID: notificationID)
+ _ = self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show)
+ case ._other:
+ assertionFailure()
+ break
+ }
+ } // end DispatchQueue.main.async
+
+ } catch {
+ assertionFailure(error.localizedDescription)
+ return
}
- }()
-
- // show notification related content
- guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return }
- let notificationID = String(pushNotification.notificationID)
-
- switch type {
- case .follow:
- let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID)
- self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show)
- case .followRequest:
- // do nothing
- break
- case .mention, .reblog, .favourite, .poll, .status:
- let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID)
- self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show)
- case ._other:
- assertionFailure()
- break
}
- } // end DispatchQueue.main.async
- }
+ } // end Task
+ })
.store(in: &disposeBag)
}
}
@@ -180,7 +163,7 @@ extension SceneCoordinator {
case hashtagTimeline(viewModel: HashtagTimelineViewModel)
// profile
- case accountList
+ case accountList(viewModel: AccountListViewModel)
case profile(viewModel: ProfileViewModel)
case favorite(viewModel: FavoriteViewModel)
case follower(viewModel: FollowerListViewModel)
@@ -260,6 +243,19 @@ extension SceneCoordinator {
transition: .modal(animated: true, completion: nil)
)
}
+ } else {
+ let wizardViewController = WizardViewController()
+ if !wizardViewController.items.isEmpty,
+ let delegate = rootViewController as? WizardViewControllerDelegate
+ {
+ // do not add as child view controller.
+ // otherwise, the tab bar controller will add as a new tab
+ wizardViewController.delegate = delegate
+ wizardViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ wizardViewController.view.frame = rootViewController.view.bounds
+ rootViewController.view.addSubview(wizardViewController.view)
+ self.wizardViewController = wizardViewController
+ }
}
} catch {
@@ -431,8 +427,9 @@ private extension SceneCoordinator {
let _viewController = HashtagTimelineViewController()
_viewController.viewModel = viewModel
viewController = _viewController
- case .accountList:
+ case .accountList(let viewModel):
let _viewController = AccountListViewController()
+ _viewController.viewModel = viewModel
viewController = _viewController
case .profile(let viewModel):
let _viewController = ProfileViewController()
diff --git a/Mastodon/Diffiable/Compose/ComposeStatusAttachmentSection.swift b/Mastodon/Diffiable/Compose/ComposeStatusAttachmentSection.swift
index 4de7653a5..2e2a94206 100644
--- a/Mastodon/Diffiable/Compose/ComposeStatusAttachmentSection.swift
+++ b/Mastodon/Diffiable/Compose/ComposeStatusAttachmentSection.swift
@@ -10,4 +10,3 @@ import Foundation
enum ComposeStatusAttachmentSection: Hashable {
case main
}
-
diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift
index 2910171d1..225b6f46a 100644
--- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift
+++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift
@@ -23,13 +23,16 @@ extension DiscoverySection {
static let logger = Logger(subsystem: "DiscoverySection", category: "logic")
class Configuration {
+ let authContext: AuthContext
weak var profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate?
let familiarFollowers: Published<[Mastodon.Entity.FamiliarFollowers]>.Publisher?
public init(
+ authContext: AuthContext,
profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? = nil,
familiarFollowers: Published<[Mastodon.Entity.FamiliarFollowers]>.Publisher? = nil
) {
+ self.authContext = authContext
self.profileCardTableViewCellDelegate = profileCardTableViewCellDelegate
self.familiarFollowers = familiarFollowers
}
@@ -73,11 +76,9 @@ extension DiscoverySection {
} else {
cell.profileCardView.viewModel.familiarFollowers = nil
}
+ // bind me
+ cell.profileCardView.viewModel.relationshipViewModel.me = configuration.authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user
}
- context.authenticationService.activeMastodonAuthentication
- .map { $0?.user }
- .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel)
- .store(in: &cell.disposeBag)
return cell
case .bottomLoader:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
diff --git a/Mastodon/Diffiable/Notification/NotificationSection.swift b/Mastodon/Diffiable/Notification/NotificationSection.swift
index 6f08a0252..a67d407ee 100644
--- a/Mastodon/Diffiable/Notification/NotificationSection.swift
+++ b/Mastodon/Diffiable/Notification/NotificationSection.swift
@@ -24,6 +24,7 @@ enum NotificationSection: Equatable, Hashable {
extension NotificationSection {
struct Configuration {
+ let authContext: AuthContext
weak var notificationTableViewCellDelegate: NotificationTableViewCellDelegate?
let filterContext: Mastodon.Entity.Filter.Context?
let activeFilters: Published<[Mastodon.Entity.Filter]>.Publisher?
@@ -74,21 +75,20 @@ extension NotificationSection {
viewModel: NotificationTableViewCell.ViewModel,
configuration: Configuration
) {
+ cell.notificationView.viewModel.authContext = configuration.authContext
+
StatusSection.setupStatusPollDataSource(
context: context,
+ authContext: configuration.authContext,
statusView: cell.notificationView.statusView
)
StatusSection.setupStatusPollDataSource(
context: context,
+ authContext: configuration.authContext,
statusView: cell.notificationView.quoteStatusView
)
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.notificationView.viewModel)
- .store(in: &cell.disposeBag)
-
cell.configure(
tableView: tableView,
viewModel: viewModel,
diff --git a/Mastodon/Diffiable/RecommandAccount/RecommendAccountSection.swift b/Mastodon/Diffiable/RecommandAccount/RecommendAccountSection.swift
index fc2d68044..e5aa0a605 100644
--- a/Mastodon/Diffiable/RecommandAccount/RecommendAccountSection.swift
+++ b/Mastodon/Diffiable/RecommandAccount/RecommendAccountSection.swift
@@ -133,6 +133,7 @@ enum RecommendAccountSection: Equatable, Hashable {
extension RecommendAccountSection {
struct Configuration {
+ let authContext: AuthContext
weak var suggestionAccountTableViewCellDelegate: SuggestionAccountTableViewCellDelegate?
}
@@ -150,10 +151,7 @@ extension RecommendAccountSection {
cell.configure(user: user)
}
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.viewModel)
- .store(in: &cell.disposeBag)
+ cell.viewModel.userIdentifier = configuration.authContext.mastodonAuthenticationBox
cell.delegate = configuration.suggestionAccountTableViewCellDelegate
}
return cell
diff --git a/Mastodon/Diffiable/Report/ReportSection.swift b/Mastodon/Diffiable/Report/ReportSection.swift
index 6513c1249..b815975b0 100644
--- a/Mastodon/Diffiable/Report/ReportSection.swift
+++ b/Mastodon/Diffiable/Report/ReportSection.swift
@@ -23,6 +23,7 @@ enum ReportSection: Equatable, Hashable {
extension ReportSection {
struct Configuration {
+ let authContext: AuthContext
}
static func diffableDataSource(
@@ -101,13 +102,11 @@ extension ReportSection {
) {
StatusSection.setupStatusPollDataSource(
context: context,
+ authContext: configuration.authContext,
statusView: cell.statusView
)
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.statusView.viewModel)
- .store(in: &cell.disposeBag)
+ cell.statusView.viewModel.authContext = configuration.authContext
cell.configure(
tableView: tableView,
diff --git a/Mastodon/Diffiable/Search/SearchResultSection.swift b/Mastodon/Diffiable/Search/SearchResultSection.swift
index b7fb09df7..8a5d7e75f 100644
--- a/Mastodon/Diffiable/Search/SearchResultSection.swift
+++ b/Mastodon/Diffiable/Search/SearchResultSection.swift
@@ -25,6 +25,7 @@ extension SearchResultSection {
static let logger = Logger(subsystem: "SearchResultSection", category: "logic")
struct Configuration {
+ let authContext: AuthContext
weak var statusViewTableViewCellDelegate: StatusTableViewCellDelegate?
weak var userTableViewCellDelegate: UserTableViewCellDelegate?
}
@@ -99,13 +100,11 @@ extension SearchResultSection {
) {
StatusSection.setupStatusPollDataSource(
context: context,
+ authContext: configuration.authContext,
statusView: cell.statusView
)
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.statusView.viewModel)
- .store(in: &cell.disposeBag)
+ cell.statusView.viewModel.authContext = configuration.authContext
cell.configure(
tableView: tableView,
@@ -120,7 +119,7 @@ extension SearchResultSection {
cell: UserTableViewCell,
viewModel: UserTableViewCell.ViewModel,
configuration: Configuration
- ) {
+ ) {
cell.configure(
tableView: tableView,
viewModel: viewModel,
diff --git a/Mastodon/Diffiable/Status/StatusSection.swift b/Mastodon/Diffiable/Status/StatusSection.swift
index 08b55bc69..38b8e641f 100644
--- a/Mastodon/Diffiable/Status/StatusSection.swift
+++ b/Mastodon/Diffiable/Status/StatusSection.swift
@@ -27,6 +27,7 @@ extension StatusSection {
static let logger = Logger(subsystem: "StatusSection", category: "logic")
struct Configuration {
+ let authContext: AuthContext
weak var statusTableViewCellDelegate: StatusTableViewCellDelegate?
weak var timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?
let filterContext: Mastodon.Entity.Filter.Context?
@@ -159,6 +160,7 @@ extension StatusSection {
public static func setupStatusPollDataSource(
context: AppContext,
+ authContext: AuthContext,
statusView: StatusView
) {
let managedObjectContext = context.managedObjectContext
@@ -172,10 +174,7 @@ extension StatusSection {
return _cell ?? PollOptionTableViewCell()
}()
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.pollOptionView.viewModel)
- .store(in: &cell.disposeBag)
+ cell.pollOptionView.viewModel.authContext = authContext
managedObjectContext.performAndWait {
guard let option = record.object(in: managedObjectContext) else {
@@ -212,14 +211,13 @@ extension StatusSection {
return true
}()
- if needsUpdatePoll, let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value
- {
+ if needsUpdatePoll {
let pollRecord: ManagedObjectRecord = .init(objectID: option.poll.objectID)
Task { [weak context] in
guard let context = context else { return }
_ = try await context.apiService.poll(
poll: pollRecord,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
}
}
@@ -248,13 +246,11 @@ extension StatusSection {
) {
setupStatusPollDataSource(
context: context,
+ authContext: configuration.authContext,
statusView: cell.statusView
)
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.statusView.viewModel)
- .store(in: &cell.disposeBag)
+ cell.statusView.viewModel.authContext = configuration.authContext
cell.configure(
tableView: tableView,
@@ -277,13 +273,11 @@ extension StatusSection {
) {
setupStatusPollDataSource(
context: context,
+ authContext: configuration.authContext,
statusView: cell.statusView
)
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0 as UserIdentifier? }
- .assign(to: \.userIdentifier, on: cell.statusView.viewModel)
- .store(in: &cell.disposeBag)
+ cell.statusView.viewModel.authContext = configuration.authContext
cell.configure(
tableView: tableView,
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift
index 7166cb39b..2747f4735 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift
@@ -11,16 +11,15 @@ import MastodonCore
extension DataSourceFacade {
static func responseToUserBlockAction(
- dependency: NeedsDependency,
- user: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ dependency: NeedsDependency & AuthContextProvider,
+ user: ManagedObjectRecord
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
_ = try await dependency.context.apiService.toggleBlock(
user: user,
- authenticationBox: authenticationBox
+ authenticationBox: dependency.authContext.mastodonAuthenticationBox
)
} // end func
}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Bookmark.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Bookmark.swift
index 93da15271..b7a793551 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Bookmark.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Bookmark.swift
@@ -12,16 +12,15 @@ import MastodonCore
extension DataSourceFacade {
public static func responseToStatusBookmarkAction(
- provider: DataSourceProvider,
- status: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ provider: DataSourceProvider & AuthContextProvider,
+ status: ManagedObjectRecord
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
_ = try await provider.context.apiService.bookmark(
record: status,
- authenticationBox: authenticationBox
+ authenticationBox: provider.authContext.mastodonAuthenticationBox
)
}
}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Favorite.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Favorite.swift
index 71c02828f..92945b9ee 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Favorite.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Favorite.swift
@@ -12,16 +12,15 @@ import MastodonCore
extension DataSourceFacade {
public static func responseToStatusFavoriteAction(
- provider: DataSourceProvider,
- status: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ provider: DataSourceProvider & AuthContextProvider,
+ status: ManagedObjectRecord
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
_ = try await provider.context.apiService.favorite(
record: status,
- authenticationBox: authenticationBox
+ authenticationBox: provider.authContext.mastodonAuthenticationBox
)
}
}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift
index cd29d2eca..c6e40e7d9 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift
@@ -14,26 +14,24 @@ import MastodonLocalization
extension DataSourceFacade {
static func responseToUserFollowAction(
- dependency: NeedsDependency,
- user: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ dependency: NeedsDependency & AuthContextProvider,
+ user: ManagedObjectRecord
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
_ = try await dependency.context.apiService.toggleFollow(
user: user,
- authenticationBox: authenticationBox
+ authenticationBox: dependency.authContext.mastodonAuthenticationBox
)
} // end func
}
extension DataSourceFacade {
static func responseToUserFollowRequestAction(
- dependency: NeedsDependency,
+ dependency: NeedsDependency & AuthContextProvider,
notification: ManagedObjectRecord,
- query: Mastodon.API.Account.FollowReqeustQuery,
- authenticationBox: MastodonAuthenticationBox
+ query: Mastodon.API.Account.FollowReqeustQuery
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
@@ -72,7 +70,7 @@ extension DataSourceFacade {
_ = try await dependency.context.apiService.followRequest(
userID: userID,
query: query,
- authenticationBox: authenticationBox
+ authenticationBox: dependency.authContext.mastodonAuthenticationBox
)
} catch {
// reset state when failure
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift
index 7abde62fe..43d6b954b 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift
@@ -7,12 +7,13 @@
import UIKit
import CoreDataStack
+import MastodonCore
import MastodonSDK
extension DataSourceFacade {
@MainActor
static func coordinateToHashtagScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
tag: DataSourceItem.TagKind
) async {
switch tag {
@@ -25,11 +26,12 @@ extension DataSourceFacade {
@MainActor
static func coordinateToHashtagScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
tag: Mastodon.Entity.Tag
) async {
let hashtagTimelineViewModel = HashtagTimelineViewModel(
context: provider.context,
+ authContext: provider.authContext,
hashtag: tag.name
)
@@ -42,7 +44,7 @@ extension DataSourceFacade {
@MainActor
static func coordinateToHashtagScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
tag: ManagedObjectRecord
) async {
let managedObjectContext = provider.context.managedObjectContext
@@ -55,6 +57,7 @@ extension DataSourceFacade {
let hashtagTimelineViewModel = HashtagTimelineViewModel(
context: provider.context,
+ authContext: provider.authContext,
hashtag: name
)
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift
index 7e376ed0f..7e0ed37fc 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift
@@ -8,11 +8,12 @@
import Foundation
import CoreDataStack
import MetaTextKit
+import MastodonCore
extension DataSourceFacade {
static func responseToMetaTextAction(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
target: StatusTarget,
status: ManagedObjectRecord,
meta: Meta
@@ -33,7 +34,7 @@ extension DataSourceFacade {
}
static func responseToMetaTextAction(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
status: ManagedObjectRecord,
meta: Meta
) async {
@@ -47,19 +48,20 @@ extension DataSourceFacade {
assertionFailure()
return
}
- if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain,
+ let domain = provider.authContext.mastodonAuthenticationBox.domain
+ if url.host == domain,
url.pathComponents.count >= 4,
url.pathComponents[0] == "/",
url.pathComponents[1] == "web",
url.pathComponents[2] == "statuses" {
let statusID = url.pathComponents[3]
- let threadViewModel = RemoteThreadViewModel(context: provider.context, statusID: statusID)
+ let threadViewModel = RemoteThreadViewModel(context: provider.context, authContext: provider.authContext, statusID: statusID)
await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
} else {
await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
}
case .hashtag(_, let hashtag, _):
- let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, hashtag: hashtag)
+ let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, authContext: provider.authContext, hashtag: hashtag)
await provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show)
case .mention(_, let mention, let userInfo):
await coordinateToProfileScene(
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Mute.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Mute.swift
index b48fbf462..1db94bd4f 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Mute.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Mute.swift
@@ -11,16 +11,15 @@ import MastodonCore
extension DataSourceFacade {
static func responseToUserMuteAction(
- dependency: NeedsDependency,
- user: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ dependency: NeedsDependency & AuthContextProvider,
+ user: ManagedObjectRecord
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
_ = try await dependency.context.apiService.toggleMute(
user: user,
- authenticationBox: authenticationBox
+ authenticationBox: dependency.authContext.mastodonAuthenticationBox
)
} // end func
}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift
index 66259a099..ef01b8394 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift
@@ -7,11 +7,12 @@
import UIKit
import CoreDataStack
+import MastodonCore
extension DataSourceFacade {
static func coordinateToProfileScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
target: StatusTarget,
status: ManagedObjectRecord
) async {
@@ -32,7 +33,7 @@ extension DataSourceFacade {
@MainActor
static func coordinateToProfileScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
user: ManagedObjectRecord
) async {
guard let user = user.object(in: provider.context.managedObjectContext) else {
@@ -42,6 +43,7 @@ extension DataSourceFacade {
let profileViewModel = CachedProfileViewModel(
context: provider.context,
+ authContext: provider.authContext,
mastodonUser: user
)
@@ -57,13 +59,12 @@ extension DataSourceFacade {
extension DataSourceFacade {
static func coordinateToProfileScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
status: ManagedObjectRecord,
mention: String, // username,
userInfo: [AnyHashable: Any]?
) async {
- guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
- let domain = authenticationBox.domain
+ let domain = provider.authContext.mastodonAuthenticationBox.domain
let href = userInfo?["href"] as? String
guard let url = href.flatMap({ URL(string: $0) }) else { return }
@@ -85,8 +86,8 @@ extension DataSourceFacade {
let userID = mention.id
let profileViewModel: ProfileViewModel = {
// check if self
- guard userID != authenticationBox.userID else {
- return MeProfileViewModel(context: provider.context)
+ guard userID != provider.authContext.mastodonAuthenticationBox.userID else {
+ return MeProfileViewModel(context: provider.context, authContext: provider.authContext)
}
let request = MastodonUser.sortedFetchRequest
@@ -95,9 +96,9 @@ extension DataSourceFacade {
let _user = provider.context.managedObjectContext.safeFetch(request).first
if let user = _user {
- return CachedProfileViewModel(context: provider.context, mastodonUser: user)
+ return CachedProfileViewModel(context: provider.context, authContext: provider.authContext, mastodonUser: user)
} else {
- return RemoteProfileViewModel(context: provider.context, userID: userID)
+ return RemoteProfileViewModel(context: provider.context, authContext: provider.authContext, userID: userID)
}
}()
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Reblog.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Reblog.swift
index 283a21dc8..ff3e95820 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Reblog.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Reblog.swift
@@ -12,16 +12,15 @@ import MastodonUI
extension DataSourceFacade {
static func responseToStatusReblogAction(
- provider: DataSourceProvider,
- status: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ provider: DataSourceProvider & AuthContextProvider,
+ status: ManagedObjectRecord
) async throws {
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
await selectionFeedbackGenerator.selectionChanged()
_ = try await provider.context.apiService.reblog(
record: status,
- authenticationBox: authenticationBox
+ authenticationBox: provider.authContext.mastodonAuthenticationBox
)
} // end func
}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift b/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift
index 25ffd4b8e..18d238c02 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift
@@ -12,18 +12,18 @@ import MastodonCore
extension DataSourceFacade {
static func responseToCreateSearchHistory(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
item: DataSourceItem
) async {
switch item {
case .status:
break // not create search history for status
case .user(let record):
- let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value
+ let authenticationBox = provider.authContext.mastodonAuthenticationBox
let managedObjectContext = provider.context.backgroundManagedObjectContext
try? await managedObjectContext.performChanges {
- guard let me = authenticationBox?.authenticationRecord.object(in: managedObjectContext)?.user else { return }
+ guard let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return }
guard let user = record.object(in: managedObjectContext) else { return }
_ = Persistence.SearchHistory.createOrMerge(
in: managedObjectContext,
@@ -35,13 +35,12 @@ extension DataSourceFacade {
)
} // end try? await managedObjectContext.performChanges { … }
case .hashtag(let tag):
- let _authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value
+ let authenticationBox = provider.authContext.mastodonAuthenticationBox
let managedObjectContext = provider.context.backgroundManagedObjectContext
switch tag {
case .entity(let entity):
try? await managedObjectContext.performChanges {
- guard let authenticationBox = _authenticationBox else { return }
guard let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return }
let now = Date()
@@ -67,7 +66,7 @@ extension DataSourceFacade {
} // end try? await managedObjectContext.performChanges { … }
case .record(let record):
try? await managedObjectContext.performChanges {
- guard let authenticationBox = _authenticationBox else { return }
+ let authenticationBox = provider.authContext.mastodonAuthenticationBox
guard let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return }
guard let tag = record.object(in: managedObjectContext) else { return }
@@ -93,13 +92,12 @@ extension DataSourceFacade {
extension DataSourceFacade {
static func responseToDeleteSearchHistory(
- provider: DataSourceProvider
+ provider: DataSourceProvider & AuthContextProvider
) async throws {
- let _authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value
+ let authenticationBox = provider.authContext.mastodonAuthenticationBox
let managedObjectContext = provider.context.backgroundManagedObjectContext
try await managedObjectContext.performChanges {
- guard let authenticationBox = _authenticationBox else { return }
guard let _ = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return }
let request = SearchHistory.sortedFetchRequest
request.predicate = SearchHistory.predicate(
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift
index 25ab53103..aecfe6a8d 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift
@@ -15,13 +15,12 @@ import MastodonLocalization
extension DataSourceFacade {
static func responseToDeleteStatus(
- dependency: NeedsDependency,
- status: ManagedObjectRecord,
- authenticationBox: MastodonAuthenticationBox
+ dependency: NeedsDependency & AuthContextProvider,
+ status: ManagedObjectRecord
) async throws {
_ = try await dependency.context.apiService.deleteStatus(
status: status,
- authenticationBox: authenticationBox
+ authenticationBox: dependency.authContext.mastodonAuthenticationBox
)
}
@@ -81,10 +80,9 @@ extension DataSourceFacade {
extension DataSourceFacade {
@MainActor
static func responseToActionToolbar(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
status: ManagedObjectRecord,
action: ActionToolbarContainer.Action,
- authenticationBox: MastodonAuthenticationBox,
sender: UIButton
) async throws {
let managedObjectContext = provider.context.managedObjectContext
@@ -100,16 +98,15 @@ extension DataSourceFacade {
switch action {
case .reply:
- guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
selectionFeedbackGenerator.selectionChanged()
let composeViewModel = ComposeViewModel(
context: provider.context,
composeKind: .reply(status: status),
- authenticationBox: authenticationBox
+ authContext: provider.authContext
)
- provider.coordinator.present(
+ _ = provider.coordinator.present(
scene: .compose(viewModel: composeViewModel),
from: provider,
transition: .modal(animated: true, completion: nil)
@@ -117,20 +114,17 @@ extension DataSourceFacade {
case .reblog:
try await DataSourceFacade.responseToStatusReblogAction(
provider: provider,
- status: status,
- authenticationBox: authenticationBox
+ status: status
)
case .like:
try await DataSourceFacade.responseToStatusFavoriteAction(
provider: provider,
- status: status,
- authenticationBox: authenticationBox
+ status: status
)
case .bookmark:
try await DataSourceFacade.responseToStatusBookmarkAction(
provider: provider,
- status: status,
- authenticationBox: authenticationBox
+ status: status
)
case .share:
try await DataSourceFacade.responseToStatusShareAction(
@@ -155,10 +149,9 @@ extension DataSourceFacade {
@MainActor
static func responseToMenuAction(
- dependency: NeedsDependency & UIViewController,
+ dependency: UIViewController & NeedsDependency & AuthContextProvider,
action: MastodonMenu.Action,
- menuContext: MenuContext,
- authenticationBox: MastodonAuthenticationBox
+ menuContext: MenuContext
) async throws {
switch action {
case .muteUser(let actionContext):
@@ -181,8 +174,7 @@ extension DataSourceFacade {
guard let user = _user else { return }
try await DataSourceFacade.responseToUserMuteAction(
dependency: dependency,
- user: user,
- authenticationBox: authenticationBox
+ user: user
)
} // end Task
}
@@ -210,8 +202,7 @@ extension DataSourceFacade {
guard let user = _user else { return }
try await DataSourceFacade.responseToUserBlockAction(
dependency: dependency,
- user: user,
- authenticationBox: authenticationBox
+ user: user
)
} // end Task
}
@@ -225,11 +216,12 @@ extension DataSourceFacade {
let reportViewModel = ReportViewModel(
context: dependency.context,
+ authContext: dependency.authContext,
user: user,
status: menuContext.status
)
- dependency.coordinator.present(
+ _ = dependency.coordinator.present(
scene: .report(viewModel: reportViewModel),
from: dependency,
transition: .modal(animated: true, completion: nil)
@@ -246,7 +238,7 @@ extension DataSourceFacade {
user: user
)
guard let activityViewController = _activityViewController else { return }
- dependency.coordinator.present(
+ _ = dependency.coordinator.present(
scene: .activityViewController(
activityViewController: activityViewController,
sourceView: menuContext.button,
@@ -270,8 +262,7 @@ extension DataSourceFacade {
Task {
try await DataSourceFacade.responseToDeleteStatus(
dependency: dependency,
- status: status,
- authenticationBox: authenticationBox
+ status: status
)
} // end Task
}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Thread.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Thread.swift
index 269504215..41f5d58de 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Thread.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Thread.swift
@@ -8,10 +8,11 @@
import Foundation
import CoreData
import CoreDataStack
+import MastodonCore
extension DataSourceFacade {
static func coordinateToStatusThreadScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
target: StatusTarget,
status: ManagedObjectRecord
) async {
@@ -39,14 +40,15 @@ extension DataSourceFacade {
@MainActor
static func coordinateToStatusThreadScene(
- provider: DataSourceProvider,
+ provider: DataSourceProvider & AuthContextProvider,
root: StatusItem.Thread
) async {
let threadViewModel = ThreadViewModel(
context: provider.context,
+ authContext: provider.authContext,
optionalRoot: root
)
- provider.coordinator.present(
+ _ = provider.coordinator.present(
scene: .thread(viewModel: threadViewModel),
from: provider,
transition: .show
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift
index dab46bba8..e868f418f 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift
@@ -7,18 +7,18 @@
import UIKit
import MetaTextKit
-import MastodonUI
import CoreDataStack
+import MastodonCore
+import MastodonUI
// MARK: - Notification AuthorMenuAction
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
menuButton button: UIButton,
didSelectAction action: MastodonMenu.Action
) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
@@ -47,15 +47,14 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
status: nil,
button: button,
barButtonItem: nil
- ),
- authenticationBox: authenticationBox
+ )
)
} // end Task
}
}
// MARK: - Notification Author Avatar
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
@@ -88,7 +87,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - Follow Request
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
@@ -106,15 +105,10 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
return
}
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
try await DataSourceFacade.responseToUserFollowRequestAction(
dependency: self,
notification: notification,
- query: .accept,
- authenticationBox: authenticationBox
+ query: .accept
)
} // end Task
}
@@ -135,15 +129,10 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
return
}
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
try await DataSourceFacade.responseToUserFollowRequestAction(
dependency: self,
notification: notification,
- query: .reject,
- authenticationBox: authenticationBox
+ query: .reject
)
} // end Task
}
@@ -151,7 +140,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - Status Content
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
@@ -279,7 +268,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Med
}
// MARK: - Status Toolbar
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
@@ -287,7 +276,6 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
buttonDidPressed button: UIButton,
action: ActionToolbarContainer.Action
) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
@@ -311,7 +299,6 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
provider: self,
status: status,
action: action,
- authenticationBox: authenticationBox,
sender: button
)
} // end Task
@@ -319,7 +306,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - Status Author Avatar
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
@@ -354,7 +341,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - Status Content
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
@@ -530,7 +517,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: a11y
-extension NotificationTableViewCellDelegate where Self: DataSourceProvider {
+extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, accessibilityActivate: Void) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift
index d02edcc42..82c25d040 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift
@@ -8,10 +8,11 @@
import UIKit
import CoreDataStack
import MetaTextKit
+import MastodonCore
import MastodonUI
// MARK: - header
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
@@ -64,7 +65,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - avatar button
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
@@ -92,7 +93,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - content
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
@@ -169,7 +170,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & MediaPrev
// MARK: - poll
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
@@ -177,7 +178,6 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
pollTableView tableView: UITableView,
didSelectRowAt indexPath: IndexPath
) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let pollTableViewDiffableDataSource = statusView.pollTableViewDiffableDataSource else { return }
guard let pollItem = pollTableViewDiffableDataSource.itemIdentifier(for: indexPath) else { return }
@@ -226,7 +226,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
_ = try await context.apiService.vote(
poll: poll,
choices: [choice],
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): vote poll for \(choice) success")
} catch {
@@ -248,7 +248,6 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
statusView: StatusView,
pollVoteButtonPressed button: UIButton
) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let pollTableViewDiffableDataSource = statusView.pollTableViewDiffableDataSource else { return }
guard let firstPollItem = pollTableViewDiffableDataSource.snapshot().itemIdentifiers.first else { return }
guard case let .option(firstPollOption) = firstPollItem else { return }
@@ -284,7 +283,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
_ = try await context.apiService.vote(
poll: poll,
choices: choices,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): vote poll for \(choices) success")
} catch {
@@ -303,7 +302,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - toolbar
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
statusView: StatusView,
@@ -311,7 +310,6 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
buttonDidPressed button: UIButton,
action: ActionToolbarContainer.Action
) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
@@ -327,7 +325,6 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
provider: self,
status: status,
action: action,
- authenticationBox: authenticationBox,
sender: button
)
} // end Task
@@ -336,14 +333,13 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - menu button
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
statusView: StatusView,
menuButton button: UIButton,
didSelectAction action: MastodonMenu.Action
) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
@@ -372,8 +368,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
status: status,
button: button,
barButtonItem: nil
- ),
- authenticationBox: authenticationBox
+ )
)
} // end Task
}
@@ -475,7 +470,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: - StatusMetricView
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, statusMetricView: StatusMetricView, reblogButtonDidPressed button: UIButton) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
@@ -489,6 +484,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
let userListViewModel = UserListViewModel(
context: context,
+ authContext: authContext,
kind: .rebloggedBy(status: status)
)
await coordinator.present(
@@ -512,6 +508,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
let userListViewModel = UserListViewModel(
context: context,
+ authContext: authContext,
kind: .favoritedBy(status: status)
)
await coordinator.present(
@@ -524,7 +521,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider {
}
// MARK: a11y
-extension StatusTableViewCellDelegate where Self: DataSourceProvider {
+extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, accessibilityActivate: Void) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift
index c80121e98..390f246d4 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift
@@ -8,6 +8,7 @@
import os.log
import UIKit
import CoreDataStack
+import MastodonCore
extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider & StatusTableViewControllerNavigateableRelay {
@@ -30,7 +31,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
}
-extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider {
+extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider & AuthContextProvider {
func statusKeyCommandHandler(_ sender: UIKeyCommand) {
guard let rawValue = sender.propertyList as? String,
@@ -53,7 +54,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
}
// status coordinate
-extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider {
+extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider & AuthContextProvider {
@MainActor
private func statusRecord() async -> ManagedObjectRecord? {
@@ -93,14 +94,13 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
private func replyStatus() async {
guard let status = await statusRecord() else { return }
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
selectionFeedbackGenerator.selectionChanged()
let composeViewModel = ComposeViewModel(
context: self.context,
composeKind: .reply(status: status),
- authenticationBox: authenticationBox
+ authContext: authContext
)
self.coordinator.present(
scene: .compose(viewModel: composeViewModel),
@@ -144,19 +144,16 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
}
// toggle
-extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider {
+extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvider & AuthContextProvider {
@MainActor
private func toggleReblog() async {
guard let status = await statusRecord() else { return }
-
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
do {
try await DataSourceFacade.responseToStatusReblogAction(
provider: self,
- status: status,
- authenticationBox: authenticationBox
+ status: status
)
} catch {
assertionFailure()
@@ -167,13 +164,10 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid
private func toggleFavorite() async {
guard let status = await statusRecord() else { return }
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
-
do {
try await DataSourceFacade.responseToStatusFavoriteAction(
provider: self,
- status: status,
- authenticationBox: authenticationBox
+ status: status
)
} catch {
assertionFailure()
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift
index 50fa17866..35ef7761e 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift
@@ -7,6 +7,7 @@
import os.log
import UIKit
+import MastodonCore
extension TableViewControllerNavigateableCore where Self: TableViewControllerNavigateableRelay {
var navigationKeyCommands: [UIKeyCommand] {
@@ -124,7 +125,7 @@ extension TableViewControllerNavigateableCore {
}
-extension TableViewControllerNavigateableCore where Self: DataSourceProvider {
+extension TableViewControllerNavigateableCore where Self: DataSourceProvider & AuthContextProvider {
func open() {
guard let indexPathForSelectedRow = tableView.indexPathForSelectedRow else { return }
let source = DataSourceItem.Source(indexPath: indexPathForSelectedRow)
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift
index b62064a6f..3a71e5346 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift
@@ -12,7 +12,7 @@ import MastodonCore
import MastodonUI
import MastodonLocalization
-extension UITableViewDelegate where Self: DataSourceProvider {
+extension UITableViewDelegate where Self: DataSourceProvider & AuthContextProvider {
func aspectTableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): indexPath: \(indexPath.debugDescription)")
diff --git a/Mastodon/Scene/Account/AccountListViewModel.swift b/Mastodon/Scene/Account/AccountListViewModel.swift
index 3149b201d..17eab07ea 100644
--- a/Mastodon/Scene/Account/AccountListViewModel.swift
+++ b/Mastodon/Scene/Account/AccountListViewModel.swift
@@ -5,6 +5,7 @@
// Created by Cirno MainasuK on 2021-9-13.
//
+import os.log
import UIKit
import Combine
import CoreData
@@ -14,43 +15,43 @@ import MastodonMeta
import MastodonCore
import MastodonUI
-final class AccountListViewModel {
+final class AccountListViewModel: NSObject {
var disposeBag = Set()
// input
let context: AppContext
+ let authContext: AuthContext
+ let mastodonAuthenticationFetchedResultsController: NSFetchedResultsController
// output
- let authentications = CurrentValueSubject<[Item], Never>([])
- let activeMastodonUserObjectID = CurrentValueSubject(nil)
+ @Published var authentications: [ManagedObjectRecord] = []
+ @Published var items: [Item] = []
+
let dataSourceDidUpdate = PassthroughSubject()
var diffableDataSource: UITableViewDiffableDataSource!
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
+ self.mastodonAuthenticationFetchedResultsController = {
+ let fetchRequest = MastodonAuthentication.sortedFetchRequest
+ fetchRequest.returnsObjectsAsFaults = false
+ fetchRequest.fetchBatchSize = 20
+ let controller = NSFetchedResultsController(
+ fetchRequest: fetchRequest,
+ managedObjectContext: context.managedObjectContext,
+ sectionNameKeyPath: nil,
+ cacheName: nil
+ )
+ return controller
+ }()
+ super.init()
+ // end init
+
+ mastodonAuthenticationFetchedResultsController.delegate = self
- Publishers.CombineLatest(
- context.authenticationService.mastodonAuthentications,
- context.authenticationService.activeMastodonAuthentication
- )
- .sink { [weak self] authentications, activeAuthentication in
- guard let self = self else { return }
- var items: [Item] = []
- var activeMastodonUserObjectID: NSManagedObjectID?
- for authentication in authentications {
- let item = Item.authentication(objectID: authentication.objectID)
- items.append(item)
- if authentication === activeAuthentication {
- activeMastodonUserObjectID = authentication.user.objectID
- }
- }
- self.authentications.value = items
- self.activeMastodonUserObjectID.value = activeMastodonUserObjectID
- }
- .store(in: &disposeBag)
-
- authentications
+ $authentications
.receive(on: DispatchQueue.main)
.sink { [weak self] authentications in
guard let self = self else { return }
@@ -58,7 +59,10 @@ final class AccountListViewModel {
var snapshot = NSDiffableDataSourceSnapshot()
snapshot.appendSections([.main])
- snapshot.appendItems(authentications, toSection: .main)
+ let authenticationItems: [Item] = authentications.map {
+ Item.authentication(record: $0)
+ }
+ snapshot.appendItems(authenticationItems, toSection: .main)
snapshot.appendItems([.addAccount], toSection: .main)
diffableDataSource.apply(snapshot) {
@@ -76,7 +80,7 @@ extension AccountListViewModel {
}
enum Item: Hashable {
- case authentication(objectID: NSManagedObjectID)
+ case authentication(record: ManagedObjectRecord)
case addAccount
}
@@ -86,14 +90,17 @@ extension AccountListViewModel {
) {
diffableDataSource = UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in
switch item {
- case .authentication(let objectID):
- let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication
+ case .authentication(let record):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell
- AccountListViewModel.configure(
- cell: cell,
- authentication: authentication,
- activeMastodonUserObjectID: self.activeMastodonUserObjectID.eraseToAnyPublisher()
- )
+ if let authentication = record.object(in: managedObjectContext),
+ let activeAuthentication = self.authContext.mastodonAuthenticationBox.authenticationRecord.object(in: managedObjectContext)
+ {
+ AccountListViewModel.configure(
+ cell: cell,
+ authentication: authentication,
+ activeAuthentication: activeAuthentication
+ )
+ }
return cell
case .addAccount:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AddAccountTableViewCell.self), for: indexPath) as! AddAccountTableViewCell
@@ -109,7 +116,7 @@ extension AccountListViewModel {
static func configure(
cell: AccountListTableViewCell,
authentication: MastodonAuthentication,
- activeMastodonUserObjectID: AnyPublisher
+ activeAuthentication: MastodonAuthentication
) {
let user = authentication.user
@@ -138,19 +145,14 @@ extension AccountListViewModel {
cell.badgeButton.setBadge(number: count)
// checkmark
- activeMastodonUserObjectID
- .receive(on: DispatchQueue.main)
- .sink { objectID in
- let isCurrentUser = user.objectID == objectID
- cell.tintColor = .label
- cell.checkmarkImageView.isHidden = !isCurrentUser
- if isCurrentUser {
- cell.accessibilityTraits.insert(.selected)
- } else {
- cell.accessibilityTraits.remove(.selected)
- }
- }
- .store(in: &cell.disposeBag)
+ let isActive = activeAuthentication.userID == authentication.userID
+ cell.tintColor = .label
+ cell.checkmarkImageView.isHidden = !isActive
+ if isActive {
+ cell.accessibilityTraits.insert(.selected)
+ } else {
+ cell.accessibilityTraits.remove(.selected)
+ }
cell.accessibilityLabel = [
cell.nameLabel.text,
@@ -161,3 +163,21 @@ extension AccountListViewModel {
.joined(separator: " ")
}
}
+
+// MARK: - NSFetchedResultsControllerDelegate
+extension AccountListViewModel: NSFetchedResultsControllerDelegate {
+
+ public func controllerWillChangeContent(_ controller: NSFetchedResultsController) {
+ os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
+ }
+
+ public func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
+ guard controller === mastodonAuthenticationFetchedResultsController else {
+ assertionFailure()
+ return
+ }
+
+ authentications = mastodonAuthenticationFetchedResultsController.fetchedObjects?.compactMap { $0.asRecrod } ?? []
+ }
+
+}
diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift
index 6a97c6427..ed9f883b4 100644
--- a/Mastodon/Scene/Account/AccountViewController.swift
+++ b/Mastodon/Scene/Account/AccountViewController.swift
@@ -22,7 +22,7 @@ final class AccountListViewController: UIViewController, NeedsDependency {
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
var disposeBag = Set()
- private(set) lazy var viewModel = AccountListViewModel(context: context)
+ var viewModel: AccountListViewModel!
private(set) lazy var addBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem(
@@ -64,7 +64,10 @@ extension AccountListViewController: PanModalPresentable {
return .contentHeight(CGFloat(height))
}
- let count = viewModel.context.authenticationService.mastodonAuthentications.value.count + 1
+ let request = MastodonAuthentication.sortedFetchRequest
+ let authenticationCount = (try? context.managedObjectContext.count(for: request)) ?? 0
+
+ let count = authenticationCount + 1
let height = calculateHeight(of: count)
return .contentHeight(height)
}
@@ -174,16 +177,14 @@ extension AccountListViewController: UITableViewDelegate {
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
switch item {
- case .authentication(let objectID):
+ case .authentication(let record):
assert(Thread.isMainThread)
- let authentication = context.managedObjectContext.object(with: objectID) as! MastodonAuthentication
- context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID)
- .receive(on: DispatchQueue.main)
- .sink { [weak self] result in
- guard let self = self else { return }
- self.coordinator.setup()
- }
- .store(in: &disposeBag)
+ guard let authentication = record.object(in: context.managedObjectContext) else { return }
+ Task { @MainActor in
+ let isActive = try await context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID)
+ guard isActive else { return }
+ self.coordinator.setup()
+ } // end Task
case .addAccount:
// TODO: add dismiss entry for welcome scene
coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
diff --git a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift
index 29016fafb..1d46fb214 100644
--- a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift
+++ b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift
@@ -133,11 +133,6 @@ extension AutoCompleteViewModel.State {
await enter(state: Fail.self)
return
}
-
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- await enter(state: Fail.self)
- return
- }
let searchText = viewModel.inputText.value
let searchType = AutoCompleteViewModel.SearchType(inputText: searchText) ?? .default
@@ -154,7 +149,7 @@ extension AutoCompleteViewModel.State {
do {
let response = try await viewModel.context.apiService.search(
query: query,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
await enter(state: Idle.self)
diff --git a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel.swift b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel.swift
index ecc234612..61715cd63 100644
--- a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel.swift
+++ b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel.swift
@@ -17,6 +17,7 @@ final class AutoCompleteViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
public let inputText = CurrentValueSubject("") // contains "@" or "#" prefix
public let symbolBoundingRect = CurrentValueSubject(.zero)
public let customEmojiViewModel = CurrentValueSubject(nil)
@@ -36,8 +37,9 @@ final class AutoCompleteViewModel {
return stateMachine
}()
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
autoCompleteItems
.receive(on: DispatchQueue.main)
diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift
index 619f6efb1..b9605bb78 100644
--- a/Mastodon/Scene/Compose/ComposeViewController.swift
+++ b/Mastodon/Scene/Compose/ComposeViewController.swift
@@ -137,7 +137,7 @@ final class ComposeViewController: UIViewController, NeedsDependency {
private(set) lazy var autoCompleteViewController: AutoCompleteViewController = {
let viewController = AutoCompleteViewController()
- viewController.viewModel = AutoCompleteViewModel(context: context)
+ viewController.viewModel = AutoCompleteViewModel(context: context, authContext: viewModel.authContext)
viewController.delegate = self
viewController.viewModel.customEmojiViewModel.value = viewModel.customEmojiViewModel
return viewController
diff --git a/Mastodon/Scene/Compose/ComposeViewModel.swift b/Mastodon/Scene/Compose/ComposeViewModel.swift
index 35cc965ed..de088c68b 100644
--- a/Mastodon/Scene/Compose/ComposeViewModel.swift
+++ b/Mastodon/Scene/Compose/ComposeViewModel.swift
@@ -29,8 +29,11 @@ final class ComposeViewModel: NSObject {
// input
let context: AppContext
let composeKind: ComposeStatusSection.ComposeKind
- let authenticationBox: MastodonAuthenticationBox
-
+ let authContext: AuthContext
+
+ var authenticationBox: MastodonAuthenticationBox {
+ authContext.mastodonAuthenticationBox
+ }
@Published var isPollComposing = false
@Published var isCustomEmojiComposing = false
@@ -116,11 +119,12 @@ final class ComposeViewModel: NSObject {
init(
context: AppContext,
composeKind: ComposeStatusSection.ComposeKind,
- authenticationBox: MastodonAuthenticationBox
+ authContext: AuthContext
) {
self.context = context
self.composeKind = composeKind
- self.authenticationBox = authenticationBox
+ self.authContext = authContext
+
self.title = {
switch composeKind {
case .post, .hashtag, .mention: return L10n.Scene.Compose.Title.newPost
@@ -130,8 +134,7 @@ final class ComposeViewModel: NSObject {
self.selectedStatusVisibility = {
// default private when user locked
var visibility: ComposeToolbarView.VisibilitySelectionType = {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value,
- let author = authenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user
+ guard let author = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user
else {
return .public
}
@@ -168,15 +171,12 @@ final class ComposeViewModel: NSObject {
self.instanceConfiguration = {
var configuration: Mastodon.Entity.Instance.Configuration? = nil
context.managedObjectContext.performAndWait {
- guard let authentication = authenticationBox.authenticationRecord.object(in: context.managedObjectContext)
- else {
- return
- }
+ guard let authentication = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext) else { return }
configuration = authentication.instance?.configuration
}
return configuration
}()
- self.customEmojiViewModel = context.emojiService.dequeueCustomEmojiViewModel(for: authenticationBox.domain)
+ self.customEmojiViewModel = context.emojiService.dequeueCustomEmojiViewModel(for: authContext.mastodonAuthenticationBox.domain)
super.init()
// end init
diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
index b8c86974b..d592c3033 100644
--- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
+++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
@@ -116,6 +116,11 @@ extension DiscoveryCommunityViewController {
}
+// MARK: - AuthContextProvider
+extension DiscoveryCommunityViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension DiscoveryCommunityViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:CommunityViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift
index 26335ec3d..64b4d3b6a 100644
--- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift
+++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift
@@ -18,6 +18,7 @@ extension DiscoveryCommunityViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .none,
diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift
index b7b078c7a..cbf292e3b 100644
--- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift
+++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift
@@ -136,11 +136,6 @@ extension DiscoveryCommunityViewModel.State {
break
}
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
-
let maxID = self.maxID
let isReloading = maxID == nil
@@ -156,7 +151,7 @@ extension DiscoveryCommunityViewModel.State {
minID: nil,
limit: 20
),
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
let newMaxID = response.link?.maxID
diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift
index 4c01cb0bc..eaf8646c4 100644
--- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift
+++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift
@@ -22,6 +22,7 @@ final class DiscoveryCommunityViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let viewDidAppeared = PassthroughSubject()
let statusFetchedResultsController: StatusFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -43,20 +44,15 @@ final class DiscoveryCommunityViewModel {
let didLoadLatest = PassthroughSubject()
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
// end init
-
- context.authenticationService.activeMastodonAuthentication
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
-
}
deinit {
diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift
index 3fc2e8944..33bbefaef 100644
--- a/Mastodon/Scene/Discovery/DiscoveryViewController.swift
+++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift
@@ -25,11 +25,8 @@ public class DiscoveryViewController: TabmanViewController, NeedsDependency {
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
-
- private(set) lazy var viewModel = DiscoveryViewModel(
- context: context,
- coordinator: coordinator
- )
+
+ var viewModel: DiscoveryViewModel!
private(set) lazy var buttonBar: TMBar.ButtonBar = {
let buttonBar = TMBar.ButtonBar()
diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift
index d91d9eee1..244a2e8d4 100644
--- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift
+++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift
@@ -18,6 +18,7 @@ final class DiscoveryViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let discoveryPostsViewController: DiscoveryPostsViewController
let discoveryHashtagsViewController: DiscoveryHashtagsViewController
let discoveryNewsViewController: DiscoveryNewsViewController
@@ -26,41 +27,43 @@ final class DiscoveryViewModel {
@Published var viewControllers: [ScrollViewContainer & PageViewController]
- init(context: AppContext, coordinator: SceneCoordinator) {
+ init(context: AppContext, coordinator: SceneCoordinator, authContext: AuthContext) {
+ self.context = context
+ self.authContext = authContext
+
func setupDependency(_ needsDependency: NeedsDependency) {
needsDependency.context = context
needsDependency.coordinator = coordinator
}
- self.context = context
discoveryPostsViewController = {
let viewController = DiscoveryPostsViewController()
setupDependency(viewController)
- viewController.viewModel = DiscoveryPostsViewModel(context: context)
+ viewController.viewModel = DiscoveryPostsViewModel(context: context, authContext: authContext)
return viewController
}()
discoveryHashtagsViewController = {
let viewController = DiscoveryHashtagsViewController()
setupDependency(viewController)
- viewController.viewModel = DiscoveryHashtagsViewModel(context: context)
+ viewController.viewModel = DiscoveryHashtagsViewModel(context: context, authContext: authContext)
return viewController
}()
discoveryNewsViewController = {
let viewController = DiscoveryNewsViewController()
setupDependency(viewController)
- viewController.viewModel = DiscoveryNewsViewModel(context: context)
+ viewController.viewModel = DiscoveryNewsViewModel(context: context, authContext: authContext)
return viewController
}()
discoveryCommunityViewController = {
let viewController = DiscoveryCommunityViewController()
setupDependency(viewController)
- viewController.viewModel = DiscoveryCommunityViewModel(context: context)
+ viewController.viewModel = DiscoveryCommunityViewModel(context: context, authContext: authContext)
return viewController
}()
discoveryForYouViewController = {
let viewController = DiscoveryForYouViewController()
setupDependency(viewController)
- viewController.viewModel = DiscoveryForYouViewModel(context: context)
+ viewController.viewModel = DiscoveryForYouViewModel(context: context, authContext: authContext)
return viewController
}()
self.viewControllers = [
diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift
index aa4d45f6d..ce1aadbb4 100644
--- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift
+++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift
@@ -101,6 +101,11 @@ extension DiscoveryForYouViewController {
}
+// MARK: - AuthContextProvider
+extension DiscoveryForYouViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension DiscoveryForYouViewController: UITableViewDelegate {
@@ -110,9 +115,10 @@ extension DiscoveryForYouViewController: UITableViewDelegate {
guard let user = record.object(in: context.managedObjectContext) else { return }
let profileViewModel = CachedProfileViewModel(
context: context,
+ authContext: viewModel.authContext,
mastodonUser: user
)
- coordinator.present(
+ _ = coordinator.present(
scene: .profile(viewModel: profileViewModel),
from: self,
transition: .show
@@ -128,15 +134,13 @@ extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate {
profileCardView: ProfileCardView,
relationshipButtonDidPressed button: ProfileRelationshipActionButton
) {
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let indexPath = tableView.indexPath(for: cell) else { return }
guard case let .user(record) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
Task {
try await DataSourceFacade.responseToUserFollowAction(
dependency: self,
- user: record,
- authenticationBox: authenticationBox
+ user: record
)
} // end Task
}
@@ -157,9 +161,9 @@ extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate {
return
}
- let familiarFollowersViewModel = FamiliarFollowersViewModel(context: context)
+ let familiarFollowersViewModel = FamiliarFollowersViewModel(context: context, authContext: authContext)
familiarFollowersViewModel.familiarFollowers = familiarFollowers
- coordinator.present(
+ _ = coordinator.present(
scene: .familiarFollowers(viewModel: familiarFollowersViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift
index f93b4c0bd..af8d6ff47 100644
--- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift
+++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift
@@ -19,6 +19,7 @@ extension DiscoveryForYouViewModel {
tableView: tableView,
context: context,
configuration: DiscoverySection.Configuration(
+ authContext: authContext,
profileCardTableViewCellDelegate: profileCardTableViewCellDelegate,
familiarFollowers: $familiarFollowers
)
diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift
index 5073ae200..89122c06e 100644
--- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift
+++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift
@@ -20,6 +20,7 @@ final class DiscoveryForYouViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let userFetchedResultsController: UserFetchedResultsController
@MainActor
@@ -30,19 +31,15 @@ final class DiscoveryForYouViewModel {
var diffableDataSource: UITableViewDiffableDataSource?
let didLoadLatest = PassthroughSubject()
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalPredicate: nil
)
// end init
-
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: userFetchedResultsController)
- .store(in: &disposeBag)
}
deinit {
@@ -59,16 +56,12 @@ extension DiscoveryForYouViewModel {
isFetching = true
defer { isFetching = false }
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- throw APIService.APIError.implicit(.badRequest)
- }
-
do {
let userIDs = try await fetchSuggestionAccounts()
let _familiarFollowersResponse = try? await context.apiService.familiarFollowers(
query: .init(ids: userIDs),
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
familiarFollowers = _familiarFollowersResponse?.value ?? []
userFetchedResultsController.userIDs = userIDs
@@ -78,14 +71,10 @@ extension DiscoveryForYouViewModel {
}
private func fetchSuggestionAccounts() async throws -> [Mastodon.Entity.Account.ID] {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- throw APIService.APIError.implicit(.badRequest)
- }
-
do {
let response = try await context.apiService.suggestionAccountV2(
query: nil,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
let userIDs = response.value.map { $0.account.id }
return userIDs
@@ -93,7 +82,7 @@ extension DiscoveryForYouViewModel {
// fallback V1
let response = try await context.apiService.suggestionAccount(
query: nil,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
let userIDs = response.value.map { $0.id }
return userIDs
diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift
index 8985af2de..e315f04ee 100644
--- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift
+++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift
@@ -107,7 +107,7 @@ extension DiscoveryHashtagsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)")
guard case let .hashtag(tag) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
- let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: tag.name)
+ let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, authContext: viewModel.authContext, hashtag: tag.name)
coordinator.present(
scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel),
from: self,
@@ -217,7 +217,7 @@ extension DiscoveryHashtagsViewController: TableViewControllerNavigateable {
guard let item = diffableDataSource.itemIdentifier(for: indexPathForSelectedRow) else { return }
guard case let .hashtag(tag) = item else { return }
- let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: tag.name)
+ let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, authContext: viewModel.authContext, hashtag: tag.name)
coordinator.present(
scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel),
from: self,
diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift
index 19241d2e6..67362d19e 100644
--- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift
+++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift
@@ -15,7 +15,7 @@ extension DiscoveryHashtagsViewModel {
diffableDataSource = DiscoverySection.diffableDataSource(
tableView: tableView,
context: context,
- configuration: DiscoverySection.Configuration()
+ configuration: DiscoverySection.Configuration(authContext: authContext)
)
var snapshot = NSDiffableDataSourceSnapshot()
diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift
index 5e931063a..7727a2358 100644
--- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift
+++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift
@@ -22,41 +22,37 @@ final class DiscoveryHashtagsViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let viewDidAppeared = PassthroughSubject()
// output
var diffableDataSource: UITableViewDiffableDataSource?
@Published var hashtags: [Mastodon.Entity.Tag] = []
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
// end init
- Publishers.CombineLatest(
- context.authenticationService.activeMastodonAuthenticationBox,
- viewDidAppeared
- )
- .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in
- return authenticationBox
- }
- .throttle(for: 3, scheduler: DispatchQueue.main, latest: true)
- .asyncMap { authenticationBox in
- try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil)
- }
- .retry(3)
- .map { response in Result, Error> { response } }
- .catch { error in Just(Result, Error> { throw error }) }
- .receive(on: DispatchQueue.main)
- .sink { [weak self] result in
- guard let self = self else { return }
- switch result {
- case .success(let response):
- self.hashtags = response.value.filter { !$0.name.isEmpty }
- case .failure:
- break
+ viewDidAppeared
+ .throttle(for: 3, scheduler: DispatchQueue.main, latest: true)
+ .asyncMap { authenticationBox in
+ try await context.apiService.trendHashtags(domain: authContext.mastodonAuthenticationBox.domain, query: nil)
}
- }
- .store(in: &disposeBag)
+ .retry(3)
+ .map { response in Result, Error> { response } }
+ .catch { error in Just(Result, Error> { throw error }) }
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] result in
+ guard let self = self else { return }
+ switch result {
+ case .success(let response):
+ self.hashtags = response.value.filter { !$0.name.isEmpty }
+ case .failure:
+ break
+ }
+ }
+ .store(in: &disposeBag)
}
deinit {
@@ -69,8 +65,7 @@ extension DiscoveryHashtagsViewModel {
@MainActor
func fetch() async throws {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
- let response = try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil)
+ let response = try await context.apiService.trendHashtags(domain: authContext.mastodonAuthenticationBox.domain, query: nil)
hashtags = response.value.filter { !$0.name.isEmpty }
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch tags: \(response.value.count)")
}
diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift
index ab3634a3f..11334dee8 100644
--- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift
+++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift
@@ -16,7 +16,7 @@ extension DiscoveryNewsViewModel {
diffableDataSource = DiscoverySection.diffableDataSource(
tableView: tableView,
context: context,
- configuration: DiscoverySection.Configuration()
+ configuration: DiscoverySection.Configuration(authContext: authContext)
)
stateMachine.enter(State.Reloading.self)
diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift
index 92b84d176..09c3c57bb 100644
--- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift
+++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift
@@ -136,11 +136,6 @@ extension DiscoveryNewsViewModel.State {
default:
break
}
-
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
let offset = self.offset
let isReloading = offset == nil
@@ -148,7 +143,7 @@ extension DiscoveryNewsViewModel.State {
Task {
do {
let response = try await viewModel.context.apiService.trendLinks(
- domain: authenticationBox.domain,
+ domain: viewModel.authContext.mastodonAuthenticationBox.domain,
query: Mastodon.API.Trends.StatusQuery(
offset: offset,
limit: nil
diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift
index 35af8f962..d440e9528 100644
--- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift
+++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift
@@ -20,6 +20,7 @@ final class DiscoveryNewsViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let listBatchFetchViewModel = ListBatchFetchViewModel()
// output
@@ -41,8 +42,9 @@ final class DiscoveryNewsViewModel {
let didLoadLatest = PassthroughSubject()
@Published var isServerSupportEndpoint = true
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
// end init
Task {
@@ -59,11 +61,9 @@ final class DiscoveryNewsViewModel {
extension DiscoveryNewsViewModel {
func checkServerEndpoint() async {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
-
do {
_ = try await context.apiService.trendLinks(
- domain: authenticationBox.domain,
+ domain: authContext.mastodonAuthenticationBox.domain,
query: .init(offset: nil, limit: nil)
)
} catch let error as Mastodon.API.Error where error.httpResponseStatus.code == 404 {
diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift
index 96f20dbcc..ee3538885 100644
--- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift
+++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift
@@ -128,6 +128,11 @@ extension DiscoveryPostsViewController {
}
+// MARK: - AuthContextProvider
+extension DiscoveryPostsViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension DiscoveryPostsViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:DiscoveryPostsViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift
index 5c82384c7..afa0594d5 100644
--- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift
+++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift
@@ -18,6 +18,7 @@ extension DiscoveryPostsViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .none,
diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift
index 2e5ae9847..9dc1e1f29 100644
--- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift
+++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift
@@ -136,11 +136,6 @@ extension DiscoveryPostsViewModel.State {
default:
break
}
-
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
let offset = self.offset
let isReloading = offset == nil
@@ -148,7 +143,7 @@ extension DiscoveryPostsViewModel.State {
Task {
do {
let response = try await viewModel.context.apiService.trendStatuses(
- domain: authenticationBox.domain,
+ domain: viewModel.authContext.mastodonAuthenticationBox.domain,
query: Mastodon.API.Trends.StatusQuery(
offset: offset,
limit: nil
diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift
index ad6639b16..7a1b044fd 100644
--- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift
+++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift
@@ -20,6 +20,7 @@ final class DiscoveryPostsViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let statusFetchedResultsController: StatusFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -41,20 +42,16 @@ final class DiscoveryPostsViewModel {
let didLoadLatest = PassthroughSubject()
@Published var isServerSupportEndpoint = true
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
// end init
- context.authenticationService.activeMastodonAuthentication
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
-
Task {
await checkServerEndpoint()
} // end Task
@@ -68,11 +65,9 @@ final class DiscoveryPostsViewModel {
extension DiscoveryPostsViewModel {
func checkServerEndpoint() async {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
-
do {
_ = try await context.apiService.trendStatuses(
- domain: authenticationBox.domain,
+ domain: authContext.mastodonAuthenticationBox.domain,
query: .init(offset: nil, limit: nil)
)
} catch let error as Mastodon.API.Error where error.httpResponseStatus.code == 404 {
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
index b422481f2..a4818aa71 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
@@ -166,17 +166,21 @@ extension HashtagTimelineViewController {
@objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .hashtag(hashtag: viewModel.hashtag),
- authenticationBox: authenticationBox
+ authContext: viewModel.authContext
)
coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
}
+// MARK: - AuthContextProvider
+extension HashtagTimelineViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension HashtagTimelineViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:HashtagTimelineViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift
index fc80f4846..8d8b0126a 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift
@@ -20,6 +20,7 @@ extension HashtagTimelineViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .none,
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift
index 8e3b6f5d1..57d8c99dd 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift
@@ -135,12 +135,6 @@ extension HashtagTimelineViewModel.State {
break
}
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- assertionFailure()
- stateMachine.enter(Fail.self)
- return
- }
-
// TODO: only set large count when using Wi-Fi
let maxID = self.maxID
let isReloading = maxID == nil
@@ -148,10 +142,10 @@ extension HashtagTimelineViewModel.State {
Task {
do {
let response = try await viewModel.context.apiService.hashtagTimeline(
- domain: authenticationBox.domain,
+ domain: viewModel.authContext.mastodonAuthenticationBox.domain,
maxID: maxID,
hashtag: viewModel.hashtag,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
let newMaxID: String? = {
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift
index 88eb8fcdd..aa57a3930 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift
@@ -26,6 +26,7 @@ final class HashtagTimelineViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let fetchedResultsController: StatusFetchedResultsController
let isFetchingLatestTimeline = CurrentValueSubject(false)
let timelinePredicate = CurrentValueSubject(nil)
@@ -52,20 +53,16 @@ final class HashtagTimelineViewModel {
}()
lazy var loadOldestStateMachinePublisher = CurrentValueSubject(nil)
- init(context: AppContext, hashtag: String) {
+ init(context: AppContext, authContext: AuthContext, hashtag: String) {
self.context = context
+ self.authContext = authContext
self.hashtag = hashtag
self.fetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
// end init
-
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: fetchedResultsController)
- .store(in: &disposeBag)
}
deinit {
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
index 2a26c6cf8..d057c0376 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
@@ -81,8 +81,11 @@ extension HomeTimelineViewController {
},
UIAction(title: "Account Recommend", image: UIImage(systemName: "human"), attributes: []) { [weak self] action in
guard let self = self else { return }
- let suggestionAccountViewModel = SuggestionAccountViewModel(context: self.context)
- self.coordinator.present(
+ let suggestionAccountViewModel = SuggestionAccountViewModel(
+ context: self.context,
+ authContext: self.viewModel.authContext
+ )
+ _ = self.coordinator.present(
scene: .suggestionAccount(viewModel: suggestionAccountViewModel),
from: self,
transition: .modal(animated: true, completion: nil)
@@ -150,7 +153,7 @@ extension HomeTimelineViewController {
children: [
UIAction(title: "Badge +1", image: UIImage(systemName: "app.badge.fill"), attributes: []) { [weak self] action in
guard let self = self else { return }
- guard let accessToken = self.context.authenticationService.activeMastodonAuthentication.value?.userAccessToken else { return }
+ let accessToken = self.viewModel.authContext.mastodonAuthenticationBox.userAuthorization.accessToken
UserDefaults.shared.increaseNotificationCount(accessToken: accessToken)
self.context.notificationService.applicationIconBadgeNeedsUpdate.send()
},
@@ -333,7 +336,8 @@ extension HomeTimelineViewController {
}
@objc private func showAccountList(_ sender: UIAction) {
- coordinator.present(scene: .accountList, from: self, transition: .modal(animated: true, completion: nil))
+ let accountListViewModel = AccountListViewModel(context: context, authContext: viewModel.authContext)
+ coordinator.present(scene: .accountList(viewModel: accountListViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@objc private func showProfileAction(_ sender: UIAction) {
@@ -342,7 +346,7 @@ extension HomeTimelineViewController {
let showAction = UIAlertAction(title: "Show", style: .default) { [weak self, weak alertController] _ in
guard let self = self else { return }
guard let textField = alertController?.textFields?.first else { return }
- let profileViewModel = RemoteProfileViewModel(context: self.context, userID: textField.text ?? "")
+ let profileViewModel = RemoteProfileViewModel(context: self.context, authContext: self.viewModel.authContext, userID: textField.text ?? "")
self.coordinator.present(scene: .profile(viewModel: profileViewModel), from: self, transition: .show)
}
alertController.addAction(showAction)
@@ -357,7 +361,7 @@ extension HomeTimelineViewController {
let showAction = UIAlertAction(title: "Show", style: .default) { [weak self, weak alertController] _ in
guard let self = self else { return }
guard let textField = alertController?.textFields?.first else { return }
- let threadViewModel = RemoteThreadViewModel(context: self.context, statusID: textField.text ?? "")
+ let threadViewModel = RemoteThreadViewModel(context: self.context, authContext: self.viewModel.authContext, statusID: textField.text ?? "")
self.coordinator.present(scene: .thread(viewModel: threadViewModel), from: self, transition: .show)
}
alertController.addAction(showAction)
@@ -367,8 +371,6 @@ extension HomeTimelineViewController {
}
private func showNotification(_ sender: UIAction, notificationType: Mastodon.Entity.Notification.NotificationType) {
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
-
let alertController = UIAlertController(title: "Enter notification ID", message: nil, preferredStyle: .alert)
alertController.addTextField()
@@ -380,7 +382,7 @@ extension HomeTimelineViewController {
else { return }
let pushNotification = MastodonPushNotification(
- accessToken: authenticationBox.userAuthorization.accessToken,
+ accessToken: self.viewModel.authContext.mastodonAuthenticationBox.userAuthorization.accessToken,
notificationID: notificationID,
notificationType: notificationType.rawValue,
preferredLocale: nil,
@@ -393,7 +395,7 @@ extension HomeTimelineViewController {
alertController.addAction(showAction)
// for multiple accounts debug
- let boxes = self.context.authenticationService.mastodonAuthenticationBoxes.value // already sorted
+ let boxes = self.context.authenticationService.mastodonAuthenticationBoxes // already sorted
if boxes.count >= 2 {
let accessToken = boxes[1].userAuthorization.accessToken
let showForSecondaryAction = UIAlertAction(title: "Show for Secondary", style: .default) { [weak self, weak alertController] _ in
@@ -420,12 +422,20 @@ extension HomeTimelineViewController {
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
- self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
+ _ = self.coordinator.present(
+ scene: .alertController(alertController: alertController),
+ from: self,
+ transition: .alertController(animated: true, completion: nil)
+ )
}
@objc private func showSettings(_ sender: UIAction) {
guard let currentSetting = context.settingService.currentSetting.value else { return }
- let settingsViewModel = SettingsViewModel(context: context, setting: currentSetting)
+ let settingsViewModel = SettingsViewModel(
+ context: context,
+ authContext: viewModel.authContext,
+ setting: currentSetting
+ )
coordinator.present(
scene: .settings(viewModel: settingsViewModel),
from: self,
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
index 7be12e8bf..095a362bf 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
@@ -28,7 +28,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
var disposeBag = Set()
- private(set) lazy var viewModel = HomeTimelineViewModel(context: context)
+ var viewModel: HomeTimelineViewModel!
let mediaPreviewTransitionController = MediaPreviewTransitionController()
@@ -373,9 +373,9 @@ extension HomeTimelineViewController {
extension HomeTimelineViewController {
@objc private func findPeopleButtonPressed(_ sender: PrimaryActionButton) {
- let suggestionAccountViewModel = SuggestionAccountViewModel(context: context)
+ let suggestionAccountViewModel = SuggestionAccountViewModel(context: context, authContext: viewModel.authContext)
suggestionAccountViewModel.delegate = viewModel
- coordinator.present(
+ _ = coordinator.present(
scene: .suggestionAccount(viewModel: suggestionAccountViewModel),
from: self,
transition: .modal(animated: true, completion: nil)
@@ -391,7 +391,7 @@ extension HomeTimelineViewController {
@objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let setting = context.settingService.currentSetting.value else { return }
- let settingsViewModel = SettingsViewModel(context: context, setting: setting)
+ let settingsViewModel = SettingsViewModel(context: context, authContext: viewModel.authContext, setting: setting)
coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@@ -403,12 +403,8 @@ extension HomeTimelineViewController {
}
@objc func signOutAction(_ sender: UIAction) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
Task { @MainActor in
- try await context.authenticationService.signOutMastodonUser(authenticationBox: authenticationBox)
+ try await context.authenticationService.signOutMastodonUser(authenticationBox: viewModel.authContext.mastodonAuthenticationBox)
self.coordinator.setup()
}
}
@@ -492,6 +488,11 @@ extension HomeTimelineViewController {
}
}
+// MARK: - AuthContextProvider
+extension HomeTimelineViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension HomeTimelineViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:HomeTimelineViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift
index 92c28242d..9412abad1 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift
@@ -21,6 +21,7 @@ extension HomeTimelineViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate,
filterContext: .home,
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift
index 234504e38..41cea6b58 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift
@@ -63,11 +63,6 @@ extension HomeTimelineViewModel.LoadLatestState {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let activeMastodonAuthenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- // sign out when loading will enter here
- stateMachine.enter(Fail.self)
- return
- }
let latestFeedRecords = viewModel.fetchedResultsController.records.prefix(APIService.onceRequestStatusMaxCount)
let parentManagedObjectContext = viewModel.fetchedResultsController.fetchedResultsController.managedObjectContext
@@ -85,7 +80,7 @@ extension HomeTimelineViewModel.LoadLatestState {
do {
let response = try await viewModel.context.apiService.homeTimeline(
- authenticationBox: activeMastodonAuthenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
await enter(state: Idle.self)
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift
index 1986ac36a..2a0396f20 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift
@@ -64,11 +64,6 @@ extension HomeTimelineViewModel.LoadOldestState {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let activeMastodonAuthenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- assertionFailure()
- stateMachine.enter(Fail.self)
- return
- }
guard let lastFeedRecord = viewModel.fetchedResultsController.records.last else {
stateMachine.enter(Idle.self)
@@ -92,7 +87,7 @@ extension HomeTimelineViewModel.LoadOldestState {
do {
let response = try await viewModel.context.apiService.homeTimeline(
maxID: maxID,
- authenticationBox: activeMastodonAuthenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
let statuses = response.value
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
index 72131f366..4cdd1da55 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
@@ -26,6 +26,7 @@ final class HomeTimelineViewModel: NSObject {
// input
let context: AppContext
+ let authContext: AuthContext
let fetchedResultsController: FeedFetchedResultsController
let homeTimelineNavigationBarTitleViewModel: HomeTimelineNavigationBarTitleViewModel
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -76,25 +77,17 @@ final class HomeTimelineViewModel: NSObject {
var cellFrameCache = NSCache()
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
self.fetchedResultsController = FeedFetchedResultsController(managedObjectContext: context.managedObjectContext)
self.homeTimelineNavigationBarTitleViewModel = HomeTimelineNavigationBarTitleViewModel(context: context)
super.init()
- context.authenticationService.activeMastodonAuthenticationBox
- .sink { [weak self] authenticationBox in
- guard let self = self else { return }
- guard let authenticationBox = authenticationBox else {
- self.fetchedResultsController.predicate = Feed.predicate(kind: .none, acct: .none)
- return
- }
- self.fetchedResultsController.predicate = Feed.predicate(
- kind: .home,
- acct: .mastodon(domain: authenticationBox.domain, userID: authenticationBox.userID)
- )
- }
- .store(in: &disposeBag)
+ fetchedResultsController.predicate = Feed.predicate(
+ kind: .home,
+ acct: .mastodon(domain: authContext.mastodonAuthenticationBox.domain, userID: authContext.mastodonAuthenticationBox.userID)
+ )
homeTimelineNeedRefresh
.sink { [weak self] _ in
@@ -131,7 +124,6 @@ extension HomeTimelineViewModel {
// load timeline gap
func loadMore(item: StatusItem) async {
guard case let .feedLoader(record) = item else { return }
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let diffableDataSource = diffableDataSource else { return }
var snapshot = diffableDataSource.snapshot()
@@ -169,7 +161,7 @@ extension HomeTimelineViewModel {
let maxID = status.id
_ = try await context.apiService.homeTimeline(
maxID: maxID,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
} catch {
do {
diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift
index c549d8f99..00e2a9fc8 100644
--- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift
+++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift
@@ -147,6 +147,11 @@ extension NotificationTimelineViewController {
}
+// MARK: - AuthContextProvider
+extension NotificationTimelineViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:NotificationTimelineViewController.AutoGenerateTableViewDelegate
@@ -297,9 +302,10 @@ extension NotificationTimelineViewController: TableViewControllerNavigateable {
if let stauts = notification.status {
let threadViewModel = ThreadViewModel(
context: self.context,
+ authContext: self.viewModel.authContext,
optionalRoot: .root(context: .init(status: .init(objectID: stauts.objectID)))
)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .thread(viewModel: threadViewModel),
from: self,
transition: .show
@@ -307,9 +313,10 @@ extension NotificationTimelineViewController: TableViewControllerNavigateable {
} else {
let profileViewModel = ProfileViewModel(
context: self.context,
+ authContext: self.viewModel.authContext,
optionalMastodonUser: notification.account
)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .profile(viewModel: profileViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift
index b32eae76b..cb623ff15 100644
--- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift
@@ -20,6 +20,7 @@ extension NotificationTimelineViewModel {
tableView: tableView,
context: context,
configuration: NotificationSection.Configuration(
+ authContext: authContext,
notificationTableViewCellDelegate: notificationTableViewCellDelegate,
filterContext: .notifications,
activeFilters: context.statusFilterService.$activeFilters
diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+LoadOldestState.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+LoadOldestState.swift
index 5461223cb..346692adc 100644
--- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+LoadOldestState.swift
+++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+LoadOldestState.swift
@@ -63,11 +63,6 @@ extension NotificationTimelineViewModel.LoadOldestState {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- assertionFailure()
- stateMachine.enter(Fail.self)
- return
- }
guard let lastFeedRecord = viewModel.feedFetchedResultsController.records.last else {
stateMachine.enter(Fail.self)
@@ -93,7 +88,7 @@ extension NotificationTimelineViewModel.LoadOldestState {
let response = try await viewModel.context.apiService.notifications(
maxID: maxID,
scope: scope,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
let notifications = response.value
diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift
index 5e4f7d7ca..f4ce7c2d7 100644
--- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift
+++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift
@@ -21,6 +21,7 @@ final class NotificationTimelineViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let scope: Scope
let feedFetchedResultsController: FeedFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -47,28 +48,19 @@ final class NotificationTimelineViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
scope: Scope
) {
self.context = context
+ self.authContext = authContext
self.scope = scope
self.feedFetchedResultsController = FeedFetchedResultsController(managedObjectContext: context.managedObjectContext)
// end init
- context.authenticationService.activeMastodonAuthenticationBox
- .sink { [weak self] authenticationBox in
- guard let self = self else { return }
- guard let authenticationBox = authenticationBox else {
- self.feedFetchedResultsController.predicate = Feed.nonePredicate()
- return
- }
-
- let predicate = NotificationTimelineViewModel.feedPredicate(
- authenticationBox: authenticationBox,
- scope: scope
- )
- self.feedFetchedResultsController.predicate = predicate
- }
- .store(in: &disposeBag)
+ feedFetchedResultsController.predicate = NotificationTimelineViewModel.feedPredicate(
+ authenticationBox: authContext.mastodonAuthenticationBox,
+ scope: scope
+ )
}
deinit {
@@ -122,8 +114,6 @@ extension NotificationTimelineViewModel {
// load lastest
func loadLatest() async {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
-
isLoadingLatest = true
defer { isLoadingLatest = false }
@@ -131,7 +121,7 @@ extension NotificationTimelineViewModel {
_ = try await context.apiService.notifications(
maxID: nil,
scope: scope,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
} catch {
didLoadLatest.send()
@@ -142,7 +132,6 @@ extension NotificationTimelineViewModel {
// load timeline gap
func loadMore(item: NotificationItem) async {
guard case let .feedLoader(record) = item else { return }
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let managedObjectContext = context.managedObjectContext
let key = "LoadMore@\(record.objectID)"
@@ -163,7 +152,7 @@ extension NotificationTimelineViewModel {
_ = try await context.apiService.notifications(
maxID: maxID,
scope: scope,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
} catch {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch more failure: \(error.localizedDescription)")
diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift
index 474a778d8..665dffefa 100644
--- a/Mastodon/Scene/Notification/NotificationViewController.swift
+++ b/Mastodon/Scene/Notification/NotificationViewController.swift
@@ -24,7 +24,7 @@ final class NotificationViewController: TabmanViewController, NeedsDependency {
var disposeBag = Set()
var observations = Set()
- private(set) lazy var viewModel = NotificationViewModel(context: context)
+ var viewModel: NotificationViewModel!
let pageSegmentedControl = UISegmentedControl()
@@ -154,6 +154,7 @@ extension NotificationViewController {
viewController.coordinator = coordinator
viewController.viewModel = NotificationTimelineViewModel(
context: context,
+ authContext: viewModel.authContext,
scope: scope
)
return viewController
diff --git a/Mastodon/Scene/Notification/NotificationViewModel.swift b/Mastodon/Scene/Notification/NotificationViewModel.swift
index 313b206c8..2f2be1805 100644
--- a/Mastodon/Scene/Notification/NotificationViewModel.swift
+++ b/Mastodon/Scene/Notification/NotificationViewModel.swift
@@ -19,6 +19,7 @@ final class NotificationViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let viewDidLoad = PassthroughSubject()
// output
@@ -27,8 +28,9 @@ final class NotificationViewModel {
@Published var currentPageIndex = 0
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
// end init
}
}
diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift
index 7845722e5..eb26f75be 100644
--- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift
@@ -182,9 +182,13 @@ extension MastodonPickServerViewController {
authenticationViewModel
.authenticated
- .flatMap { [weak self] (domain, user) -> AnyPublisher, Never> in
- guard let self = self else { return Just(.success(false)).eraseToAnyPublisher() }
- return self.context.authenticationService.activeMastodonUser(domain: domain, userID: user.id)
+ .asyncMap { domain, user -> Result in
+ do {
+ let result = try await self.context.authenticationService.activeMastodonUser(domain: domain, userID: user.id)
+ return .success(result)
+ } catch {
+ return .failure(error)
+ }
}
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift
index 41e77987c..a2b8df83a 100644
--- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift
+++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift
@@ -144,7 +144,7 @@ extension WelcomeViewController {
signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside)
signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside)
- viewModel.needsShowDismissEntry
+ viewModel.$needsShowDismissEntry
.receive(on: DispatchQueue.main)
.sink { [weak self] needsShowDismissEntry in
guard let self = self else { return }
diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift
index d57a6ee5f..e835027f3 100644
--- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift
+++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift
@@ -17,15 +17,14 @@ final class WelcomeViewModel {
let context: AppContext
// output
- let needsShowDismissEntry = CurrentValueSubject(false)
+ @Published var needsShowDismissEntry = false
init(context: AppContext) {
self.context = context
- context.authenticationService.mastodonAuthentications
+ context.authenticationService.$mastodonAuthenticationBoxes
.map { !$0.isEmpty }
- .assign(to: \.value, on: needsShowDismissEntry)
- .store(in: &disposeBag)
+ .assign(to: &$needsShowDismissEntry)
}
}
diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift
index 6d3d80737..b91b90dad 100644
--- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift
+++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift
@@ -134,6 +134,11 @@ extension BookmarkViewController: UITableViewDelegate, AutoGenerateTableViewDele
// MARK: - StatusTableViewCellDelegate
extension BookmarkViewController: StatusTableViewCellDelegate { }
+// MARK: - AuthContextProvider
+extension BookmarkViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
extension BookmarkViewController {
override var keyCommands: [UIKeyCommand]? {
return navigationKeyCommands + statusNavigationKeyCommands
diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift
index 06483012c..69075a8ce 100644
--- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift
+++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift
@@ -17,6 +17,7 @@ extension BookmarkViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .none,
diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+State.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+State.swift
index 085967ec7..21cb8e021 100644
--- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+State.swift
+++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+State.swift
@@ -51,7 +51,7 @@ extension BookmarkViewModel.State {
guard let viewModel = viewModel else { return false }
switch stateClass {
case is Reloading.Type:
- return viewModel.activeMastodonAuthenticationBox.value != nil
+ return true
default:
return false
}
@@ -134,20 +134,15 @@ extension BookmarkViewModel.State {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
if previousState is Reloading {
maxID = nil
}
-
Task {
do {
let response = try await viewModel.context.apiService.bookmarkedStatuses(
maxID: maxID,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
var hasNewStatusesAppend = false
diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel.swift
index df48b68e7..f56e65526 100644
--- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel.swift
+++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel.swift
@@ -18,7 +18,8 @@ final class BookmarkViewModel {
// input
let context: AppContext
- let activeMastodonAuthenticationBox: CurrentValueSubject
+ let authContext: AuthContext
+
let statusFetchedResultsController: StatusFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -37,23 +38,14 @@ final class BookmarkViewModel {
return stateMachine
}()
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
- self.activeMastodonAuthenticationBox = CurrentValueSubject(context.authenticationService.activeMastodonAuthenticationBox.value)
+ self.authContext = authContext
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
-
- context.authenticationService.activeMastodonAuthenticationBox
- .assign(to: \.value, on: activeMastodonAuthenticationBox)
- .store(in: &disposeBag)
-
- activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
}
}
diff --git a/Mastodon/Scene/Profile/CachedProfileViewModel.swift b/Mastodon/Scene/Profile/CachedProfileViewModel.swift
index f30fac4ea..cdd572fc4 100644
--- a/Mastodon/Scene/Profile/CachedProfileViewModel.swift
+++ b/Mastodon/Scene/Profile/CachedProfileViewModel.swift
@@ -11,8 +11,8 @@ import MastodonCore
final class CachedProfileViewModel: ProfileViewModel {
- init(context: AppContext, mastodonUser: MastodonUser) {
- super.init(context: context, optionalMastodonUser: mastodonUser)
+ init(context: AppContext, authContext: AuthContext, mastodonUser: MastodonUser) {
+ super.init(context: context, authContext: authContext, optionalMastodonUser: mastodonUser)
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Profile] user[\(mastodonUser.id)] profile: \(mastodonUser.acctWithDomain)")
}
diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift
index c82b8b3ad..b6d6f8313 100644
--- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift
+++ b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift
@@ -75,6 +75,13 @@ extension FamiliarFollowersViewController {
}
+// MARK: - AuthContextProvider
+extension FamiliarFollowersViewController: AuthContextProvider {
+ var authContext: AuthContext {
+ viewModel.authContext
+ }
+}
+
// MARK: - UITableViewDelegate
extension FamiliarFollowersViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:FamiliarFollowersViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel.swift
index 065ede47c..40d4eb14f 100644
--- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel.swift
+++ b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel.swift
@@ -17,6 +17,7 @@ final class FamiliarFollowersViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let userFetchedResultsController: UserFetchedResultsController
@Published var familiarFollowers: Mastodon.Entity.FamiliarFollowers?
@@ -24,20 +25,16 @@ final class FamiliarFollowersViewModel {
// output
var diffableDataSource: UITableViewDiffableDataSource?
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalPredicate: nil
)
// end init
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: userFetchedResultsController)
- .store(in: &disposeBag)
-
$familiarFollowers
.map { familiarFollowers -> [MastodonUser.ID] in
guard let familiarFollowers = familiarFollowers else { return [] }
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
index d3cdb2b8e..0b113345e 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
@@ -104,6 +104,11 @@ extension FavoriteViewController {
}
+// MARK: - AuthContextProvider
+extension FavoriteViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension FavoriteViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:FavoriteViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift
index 58109247e..3723dae5d 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift
@@ -17,6 +17,7 @@ extension FavoriteViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .none,
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift
index 84f2da1db..b583ec139 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift
@@ -51,7 +51,7 @@ extension FavoriteViewModel.State {
guard let viewModel = viewModel else { return false }
switch stateClass {
case is Reloading.Type:
- return viewModel.activeMastodonAuthenticationBox.value != nil
+ return true
default:
return false
}
@@ -134,10 +134,6 @@ extension FavoriteViewModel.State {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
if previousState is Reloading {
maxID = nil
}
@@ -147,7 +143,7 @@ extension FavoriteViewModel.State {
do {
let response = try await viewModel.context.apiService.favoritedStatuses(
maxID: maxID,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
var hasNewStatusesAppend = false
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel.swift
index 0570df2e9..0dd3c7203 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel.swift
@@ -18,7 +18,7 @@ final class FavoriteViewModel {
// input
let context: AppContext
- let activeMastodonAuthenticationBox: CurrentValueSubject
+ let authContext: AuthContext
let statusFetchedResultsController: StatusFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -37,23 +37,14 @@ final class FavoriteViewModel {
return stateMachine
}()
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
- self.activeMastodonAuthenticationBox = CurrentValueSubject(context.authenticationService.activeMastodonAuthenticationBox.value)
+ self.authContext = authContext
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
-
- context.authenticationService.activeMastodonAuthenticationBox
- .assign(to: \.value, on: activeMastodonAuthenticationBox)
- .store(in: &disposeBag)
-
- activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
}
}
diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
index ff2977d45..57e068c72 100644
--- a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
+++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
@@ -82,15 +82,15 @@ extension FollowerListViewController {
// trigger user timeline loading
Publishers.CombineLatest(
- viewModel.domain.removeDuplicates().eraseToAnyPublisher(),
- viewModel.userID.removeDuplicates().eraseToAnyPublisher()
+ viewModel.$domain.removeDuplicates(),
+ viewModel.$userID.removeDuplicates()
)
- .receive(on: DispatchQueue.main)
- .sink { [weak self] _ in
- guard let self = self else { return }
- self.viewModel.stateMachine.enter(FollowerListViewModel.State.Reloading.self)
- }
- .store(in: &disposeBag)
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] _ in
+ guard let self = self else { return }
+ self.viewModel.stateMachine.enter(FollowerListViewModel.State.Reloading.self)
+ }
+ .store(in: &disposeBag)
}
override func viewWillAppear(_ animated: Bool) {
@@ -101,6 +101,12 @@ extension FollowerListViewController {
}
+// MARK: - AuthContextProvider
+extension FollowerListViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
+
// MARK: - UITableViewDelegate
extension FollowerListViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:FollowerListViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift
index 15cc1be13..7a30c3234 100644
--- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift
+++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift
@@ -50,10 +50,10 @@ extension FollowerListViewModel {
case is State.Idle, is State.Loading, is State.Fail:
snapshot.appendItems([.bottomLoader], toSection: .main)
case is State.NoMore:
- guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value,
- let userID = self.userID.value,
- userID != activeMastodonAuthenticationBox.userID
+ guard let userID = self.userID,
+ userID != self.authContext.mastodonAuthenticationBox.userID
else { break }
+ // display hint footer exclude self
let text = L10n.Scene.Follower.footer
snapshot.appendItems([.bottomHeader(text: text)], toSection: .main)
default:
diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift
index ffedeae46..fe336f39f 100644
--- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift
+++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift
@@ -51,7 +51,7 @@ extension FollowerListViewModel.State {
guard let viewModel = viewModel else { return false }
switch stateClass {
case is Reloading.Type:
- return viewModel.userID.value != nil
+ return viewModel.userID != nil
default:
return false
}
@@ -139,12 +139,7 @@ extension FollowerListViewModel.State {
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let userID = viewModel.userID.value, !userID.isEmpty else {
- stateMachine.enter(Fail.self)
- return
- }
-
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
+ guard let userID = viewModel.userID, !userID.isEmpty else {
stateMachine.enter(Fail.self)
return
}
@@ -154,7 +149,7 @@ extension FollowerListViewModel.State {
let response = try await viewModel.context.apiService.followers(
userID: userID,
maxID: maxID,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch \(response.value.count) followers")
diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift
index af0f6b139..1b0d505b5 100644
--- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift
+++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift
@@ -20,11 +20,13 @@ final class FollowerListViewModel {
// input
let context: AppContext
- let domain: CurrentValueSubject
- let userID: CurrentValueSubject
+ let authContext: AuthContext
let userFetchedResultsController: UserFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
+ @Published var domain: String?
+ @Published var userID: String?
+
// output
var diffableDataSource: UITableViewDiffableDataSource?
private(set) lazy var stateMachine: GKStateMachine = {
@@ -40,16 +42,21 @@ final class FollowerListViewModel {
return stateMachine
}()
- init(context: AppContext, domain: String?, userID: String?) {
+ init(
+ context: AppContext,
+ authContext: AuthContext,
+ domain: String?,
+ userID: String?
+ ) {
self.context = context
+ self.authContext = authContext
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
domain: domain,
additionalPredicate: nil
)
- self.domain = CurrentValueSubject(domain)
- self.userID = CurrentValueSubject(userID)
- // super.init()
-
+ self.domain = domain
+ self.userID = userID
+ // end init
}
}
diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift
index 18994d26b..ccf0f1819 100644
--- a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift
+++ b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift
@@ -82,8 +82,8 @@ extension FollowingListViewController {
// trigger user timeline loading
Publishers.CombineLatest(
- viewModel.domain.removeDuplicates().eraseToAnyPublisher(),
- viewModel.userID.removeDuplicates().eraseToAnyPublisher()
+ viewModel.$domain.removeDuplicates(),
+ viewModel.$userID.removeDuplicates()
)
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
@@ -101,6 +101,11 @@ extension FollowingListViewController {
}
+// MARK: - AuthContextProvider
+extension FollowingListViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension FollowingListViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:FollowingListViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift
index 116e7567c..e022c5736 100644
--- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift
+++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift
@@ -7,6 +7,7 @@
import UIKit
import MastodonAsset
+import MastodonCore
import MastodonLocalization
extension FollowingListViewModel {
@@ -44,23 +45,23 @@ extension FollowingListViewModel {
snapshot.appendSections([.main])
let items = records.map { UserItem.user(record: $0) }
snapshot.appendItems(items, toSection: .main)
-
+
if let currentState = self.stateMachine.currentState {
switch currentState {
case is State.Idle, is State.Loading, is State.Fail:
snapshot.appendItems([.bottomLoader], toSection: .main)
case is State.NoMore:
- guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value,
- let userID = self.userID.value,
- userID != activeMastodonAuthenticationBox.userID
+ guard let userID = self.userID,
+ userID != self.authContext.mastodonAuthenticationBox.userID
else { break }
+ // display footer exclude self
let text = L10n.Scene.Following.footer
snapshot.appendItems([.bottomHeader(text: text)], toSection: .main)
default:
break
}
}
-
+
diffableDataSource.apply(snapshot, animatingDifferences: false)
}
.store(in: &disposeBag)
diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift
index c01a9c8c6..d8c1f765a 100644
--- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift
+++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift
@@ -50,7 +50,7 @@ extension FollowingListViewModel.State {
guard let viewModel = viewModel else { return false }
switch stateClass {
case is Reloading.Type:
- return viewModel.userID.value != nil
+ return viewModel.userID != nil
default:
return false
}
@@ -138,12 +138,7 @@ extension FollowingListViewModel.State {
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let userID = viewModel.userID.value, !userID.isEmpty else {
- stateMachine.enter(Fail.self)
- return
- }
-
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
+ guard let userID = viewModel.userID, !userID.isEmpty else {
stateMachine.enter(Fail.self)
return
}
@@ -153,7 +148,7 @@ extension FollowingListViewModel.State {
let response = try await viewModel.context.apiService.following(
userID: userID,
maxID: maxID,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch \(response.value.count)")
diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift
index a809e14d0..12b294b8b 100644
--- a/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift
+++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift
@@ -19,11 +19,13 @@ final class FollowingListViewModel {
// input
let context: AppContext
- let domain: CurrentValueSubject
- let userID: CurrentValueSubject
+ let authContext: AuthContext
let userFetchedResultsController: UserFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
+ @Published var domain: String?
+ @Published var userID: String?
+
// output
var diffableDataSource: UITableViewDiffableDataSource?
private(set) lazy var stateMachine: GKStateMachine = {
@@ -39,15 +41,21 @@ final class FollowingListViewModel {
return stateMachine
}()
- init(context: AppContext, domain: String?, userID: String?) {
+ init(
+ context: AppContext,
+ authContext: AuthContext,
+ domain: String?,
+ userID: String?
+ ) {
self.context = context
+ self.authContext = authContext
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
domain: domain,
additionalPredicate: nil
)
- self.domain = CurrentValueSubject(domain)
- self.userID = CurrentValueSubject(userID)
+ self.domain = domain
+ self.userID = userID
// super.init()
}
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
index 5c7ce808a..c5dbbecd4 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
@@ -332,10 +332,11 @@ extension ProfileHeaderViewController: ProfileHeaderViewDelegate {
else { return }
let followerListViewModel = FollowerListViewModel(
context: context,
+ authContext: viewModel.authContext,
domain: domain,
userID: userID
)
- coordinator.present(
+ _ = coordinator.present(
scene: .follower(viewModel: followerListViewModel),
from: self,
transition: .show
@@ -346,10 +347,11 @@ extension ProfileHeaderViewController: ProfileHeaderViewDelegate {
else { return }
let followingListViewModel = FollowingListViewModel(
context: context,
+ authContext: viewModel.authContext,
domain: domain,
userID: userID
)
- coordinator.present(
+ _ = coordinator.present(
scene: .following(viewModel: followingListViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
index 15a13de84..65f15efa7 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
@@ -24,6 +24,8 @@ final class ProfileHeaderViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
+
@Published var user: MastodonUser?
@Published var relationshipActionOptionSet: RelationshipActionOptionSet = .none
@@ -41,8 +43,9 @@ final class ProfileHeaderViewModel {
@Published var isTitleViewDisplaying = false
@Published var isTitleViewContentOffsetSet = false
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
$accountForEdit
.receive(on: DispatchQueue.main)
diff --git a/Mastodon/Scene/Profile/MeProfileViewModel.swift b/Mastodon/Scene/Profile/MeProfileViewModel.swift
index d6a30fd04..995e32002 100644
--- a/Mastodon/Scene/Profile/MeProfileViewModel.swift
+++ b/Mastodon/Scene/Profile/MeProfileViewModel.swift
@@ -15,10 +15,12 @@ import MastodonSDK
final class MeProfileViewModel: ProfileViewModel {
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
+ let user = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user
super.init(
context: context,
- optionalMastodonUser: context.authenticationService.activeMastodonAuthentication.value?.user
+ authContext: authContext,
+ optionalMastodonUser: user
)
$me
diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift
index 3393a2edf..30c37473e 100644
--- a/Mastodon/Scene/Profile/ProfileViewController.swift
+++ b/Mastodon/Scene/Profile/ProfileViewController.swift
@@ -111,7 +111,7 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
let viewController = ProfileHeaderViewController()
viewController.context = context
viewController.coordinator = coordinator
- viewController.viewModel = ProfileHeaderViewModel(context: context)
+ viewController.viewModel = ProfileHeaderViewModel(context: context, authContext: viewModel.authContext)
return viewController
}()
@@ -460,14 +460,14 @@ extension ProfileViewController {
switch meta {
case .url(_, _, let url, _):
guard let url = URL(string: url) else { return }
- coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
+ _ = coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
case .mention(_, _, let userInfo):
guard let href = userInfo?["href"] as? String,
let url = URL(string: href) else { return }
- coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
+ _ = coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
case .hashtag(_, let hashtag, _):
- let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag)
- coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: nil, transition: .show)
+ let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, authContext: viewModel.authContext, hashtag: hashtag)
+ _ = coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: nil, transition: .show)
case .email, .emoji:
break
}
@@ -485,7 +485,7 @@ extension ProfileViewController {
@objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let setting = context.settingService.currentSetting.value else { return }
- let settingsViewModel = SettingsViewModel(context: context, setting: setting)
+ let settingsViewModel = SettingsViewModel(context: context, authContext: viewModel.authContext, setting: setting)
coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@@ -513,24 +513,23 @@ extension ProfileViewController {
@objc private func favoriteBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- let favoriteViewModel = FavoriteViewModel(context: context)
+ let favoriteViewModel = FavoriteViewModel(context: context, authContext: viewModel.authContext)
coordinator.present(scene: .favorite(viewModel: favoriteViewModel), from: self, transition: .show)
}
@objc private func bookmarkBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- let bookmarkViewModel = BookmarkViewModel(context: context)
+ let bookmarkViewModel = BookmarkViewModel(context: context, authContext: viewModel.authContext)
coordinator.present(scene: .bookmark(viewModel: bookmarkViewModel), from: self, transition: .show)
}
@objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let mastodonUser = viewModel.user else { return }
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .mention(user: .init(objectID: mastodonUser.objectID)),
- authenticationBox: authenticationBox
+ authContext: viewModel.authContext
)
coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@@ -671,6 +670,11 @@ extension ProfileViewController: TabBarPagerDataSource {
//
//}
+// MARK: - AuthContextProvider
+extension ProfileViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - ProfileHeaderViewControllerDelegate
extension ProfileViewController: ProfileHeaderViewControllerDelegate {
func profileHeaderViewController(
@@ -760,16 +764,13 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
case .follow, .request, .pending, .following:
guard let user = viewModel.user else { return }
let reocrd = ManagedObjectRecord(objectID: user.objectID)
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
Task {
try await DataSourceFacade.responseToUserFollowAction(
dependency: self,
- user: reocrd,
- authenticationBox: authenticationBox
+ user: reocrd
)
}
case .muting:
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let user = viewModel.user else { return }
let name = user.displayNameWithFallback
@@ -784,8 +785,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
Task {
try await DataSourceFacade.responseToUserMuteAction(
dependency: self,
- user: record,
- authenticationBox: authenticationBox
+ user: record
)
}
}
@@ -794,7 +794,6 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
case .blocking:
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let user = viewModel.user else { return }
let name = user.displayNameWithFallback
@@ -809,8 +808,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
Task {
try await DataSourceFacade.responseToUserBlockAction(
dependency: self,
- user: record,
- authenticationBox: authenticationBox
+ user: record
)
}
}
@@ -852,7 +850,6 @@ extension ProfileViewController: ProfileAboutViewControllerDelegate {
// MARK: - MastodonMenuDelegate
extension ProfileViewController: MastodonMenuDelegate {
func menuAction(_ action: MastodonMenu.Action) {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
guard let user = viewModel.user else { return }
let userRecord: ManagedObjectRecord = .init(objectID: user.objectID)
@@ -866,8 +863,7 @@ extension ProfileViewController: MastodonMenuDelegate {
status: nil,
button: nil,
barButtonItem: self.moreMenuBarButtonItem
- ),
- authenticationBox: authenticationBox
+ )
)
} // end Task
}
diff --git a/Mastodon/Scene/Profile/ProfileViewModel.swift b/Mastodon/Scene/Profile/ProfileViewModel.swift
index 3893c80a1..e23b465d4 100644
--- a/Mastodon/Scene/Profile/ProfileViewModel.swift
+++ b/Mastodon/Scene/Profile/ProfileViewModel.swift
@@ -35,6 +35,7 @@ class ProfileViewModel: NSObject {
// input
let context: AppContext
+ let authContext: AuthContext
@Published var me: MastodonUser?
@Published var user: MastodonUser?
@@ -58,21 +59,25 @@ class ProfileViewModel: NSObject {
// @Published var protected: Bool? = nil
// let needsPagePinToTop = CurrentValueSubject(false)
- init(context: AppContext, optionalMastodonUser mastodonUser: MastodonUser?) {
+ init(context: AppContext, authContext: AuthContext, optionalMastodonUser mastodonUser: MastodonUser?) {
self.context = context
+ self.authContext = authContext
self.user = mastodonUser
self.postsUserTimelineViewModel = UserTimelineViewModel(
context: context,
+ authContext: authContext,
title: L10n.Scene.Profile.SegmentedControl.posts,
queryFilter: .init(excludeReplies: true)
)
self.repliesUserTimelineViewModel = UserTimelineViewModel(
context: context,
+ authContext: authContext,
title: L10n.Scene.Profile.SegmentedControl.postsAndReplies,
queryFilter: .init(excludeReplies: false)
)
self.mediaUserTimelineViewModel = UserTimelineViewModel(
context: context,
+ authContext: authContext,
title: L10n.Scene.Profile.SegmentedControl.media,
queryFilter: .init(onlyMedia: true)
)
@@ -80,13 +85,7 @@ class ProfileViewModel: NSObject {
super.init()
// bind me
- context.authenticationService.activeMastodonAuthenticationBox
- .receive(on: DispatchQueue.main)
- .sink { [weak self] authenticationBox in
- guard let self = self else { return }
- self.me = authenticationBox?.authenticationRecord.object(in: context.managedObjectContext)?.user
- }
- .store(in: &disposeBag)
+ self.me = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user
$me
.assign(to: \.me, on: relationshipViewModel)
.store(in: &disposeBag)
@@ -132,21 +131,18 @@ class ProfileViewModel: NSObject {
let pendingRetryPublisher = CurrentValueSubject(1)
// observe friendship
- Publishers.CombineLatest3(
+ Publishers.CombineLatest(
userRecord,
- context.authenticationService.activeMastodonAuthenticationBox,
pendingRetryPublisher
)
- .sink { [weak self] userRecord, authenticationBox, _ in
+ .sink { [weak self] userRecord, _ in
guard let self = self else { return }
- guard let userRecord = userRecord,
- let authenticationBox = authenticationBox
- else { return }
+ guard let userRecord = userRecord else { return }
Task {
do {
let response = try await self.updateRelationship(
record: userRecord,
- authenticationBox: authenticationBox
+ authenticationBox: self.authContext.mastodonAuthenticationBox
)
// there are seconds delay after request follow before requested -> following. Query again when needs
guard let relationship = response.value.first else { return }
@@ -216,10 +212,7 @@ extension ProfileViewModel {
headerProfileInfo: ProfileHeaderViewModel.ProfileInfo,
aboutProfileInfo: ProfileAboutViewModel.ProfileInfo
) async throws -> Mastodon.Response.Content {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- throw APIService.APIError.implicit(.badRequest)
- }
-
+ let authenticationBox = authContext.mastodonAuthenticationBox
let domain = authenticationBox.domain
let authorization = authenticationBox.userAuthorization
diff --git a/Mastodon/Scene/Profile/RemoteProfileViewModel.swift b/Mastodon/Scene/Profile/RemoteProfileViewModel.swift
index cb1f0e4c3..1e1388c95 100644
--- a/Mastodon/Scene/Profile/RemoteProfileViewModel.swift
+++ b/Mastodon/Scene/Profile/RemoteProfileViewModel.swift
@@ -14,14 +14,11 @@ import MastodonCore
final class RemoteProfileViewModel: ProfileViewModel {
- init(context: AppContext, userID: Mastodon.Entity.Account.ID) {
- super.init(context: context, optionalMastodonUser: nil)
+ init(context: AppContext, authContext: AuthContext, userID: Mastodon.Entity.Account.ID) {
+ super.init(context: context, authContext: authContext, optionalMastodonUser: nil)
- guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
- let domain = activeMastodonAuthenticationBox.domain
- let authorization = activeMastodonAuthenticationBox.userAuthorization
+ let domain = authContext.mastodonAuthenticationBox.domain
+ let authorization = authContext.mastodonAuthenticationBox.userAuthorization
Just(userID)
.asyncMap { userID in
try await context.apiService.accountInfo(
@@ -54,23 +51,19 @@ final class RemoteProfileViewModel: ProfileViewModel {
.store(in: &disposeBag)
}
- init(context: AppContext, notificationID: Mastodon.Entity.Notification.ID) {
- super.init(context: context, optionalMastodonUser: nil)
-
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
+ init(context: AppContext, authContext: AuthContext, notificationID: Mastodon.Entity.Notification.ID) {
+ super.init(context: context, authContext: authContext, optionalMastodonUser: nil)
Task { @MainActor in
let response = try await context.apiService.notification(
notificationID: notificationID,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
let userID = response.value.account.id
let _user: MastodonUser? = try await context.managedObjectContext.perform {
let request = MastodonUser.sortedFetchRequest
- request.predicate = MastodonUser.predicate(domain: authenticationBox.domain, id: userID)
+ request.predicate = MastodonUser.predicate(domain: authContext.mastodonAuthenticationBox.domain, id: userID)
request.fetchLimit = 1
return context.managedObjectContext.safeFetch(request).first
}
@@ -79,14 +72,14 @@ final class RemoteProfileViewModel: ProfileViewModel {
self.user = user
} else {
_ = try await context.apiService.accountInfo(
- domain: authenticationBox.domain,
+ domain: authContext.mastodonAuthenticationBox.domain,
userID: userID,
- authorization: authenticationBox.userAuthorization
+ authorization: authContext.mastodonAuthenticationBox.userAuthorization
)
let _user: MastodonUser? = try await context.managedObjectContext.perform {
let request = MastodonUser.sortedFetchRequest
- request.predicate = MastodonUser.predicate(domain: authenticationBox.domain, id: userID)
+ request.predicate = MastodonUser.predicate(domain: authContext.mastodonAuthenticationBox.domain, id: userID)
request.fetchLimit = 1
return context.managedObjectContext.safeFetch(request).first
}
diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift
index beed25086..8a983da33 100644
--- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift
+++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift
@@ -103,6 +103,11 @@ extension UserTimelineViewController: CellFrameCacheContainer {
}
}
+// MARK: - AuthContextProvider
+extension UserTimelineViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension UserTimelineViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:UserTimelineViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift
index 7f7341aa6..863d7b44e 100644
--- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift
@@ -18,6 +18,7 @@ extension UserTimelineViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .none,
diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift
index 17409a2bc..b87d4305e 100644
--- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift
+++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift
@@ -138,10 +138,6 @@ extension UserTimelineViewModel.State {
return
}
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
let queryFilter = viewModel.queryFilter
Task {
@@ -154,7 +150,7 @@ extension UserTimelineViewModel.State {
excludeReplies: queryFilter.excludeReplies,
excludeReblogs: queryFilter.excludeReblogs,
onlyMedia: queryFilter.onlyMedia,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
var hasNewStatusesAppend = false
diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift
index bd28d2c79..0d85b6807 100644
--- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift
+++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift
@@ -20,6 +20,7 @@ final class UserTimelineViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let title: String
let statusFetchedResultsController: StatusFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -50,23 +51,19 @@ final class UserTimelineViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
title: String,
queryFilter: QueryFilter
) {
self.context = context
+ self.authContext = authContext
self.title = title
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
self.queryFilter = queryFilter
- // super.init()
-
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
}
deinit {
diff --git a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift
index 5d9a20610..ebce374e7 100644
--- a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift
+++ b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift
@@ -93,6 +93,11 @@ extension FavoritedByViewController {
}
+// MARK: - AuthContextProvider
+extension FavoritedByViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension FavoritedByViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:FavoritedByViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift
index 3f3e239a1..0688bcccb 100644
--- a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift
+++ b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift
@@ -93,6 +93,11 @@ extension RebloggedByViewController {
}
+// MARK: - AuthContextProvider
+extension RebloggedByViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - UITableViewDelegate
extension RebloggedByViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:RebloggedByViewController.AutoGenerateTableViewDelegate
diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift
index 9098c7f81..18c37c403 100644
--- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift
+++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift
@@ -137,10 +137,6 @@ extension UserListViewModel.State {
}
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
let maxID = self.maxID
@@ -152,13 +148,13 @@ extension UserListViewModel.State {
response = try await viewModel.context.apiService.favoritedBy(
status: status,
query: .init(maxID: maxID, limit: nil),
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
case .rebloggedBy(let status):
response = try await viewModel.context.apiService.rebloggedBy(
status: status,
query: .init(maxID: maxID, limit: nil),
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
}
diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift
index f8d9a3bd6..2a0ed0271 100644
--- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift
+++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift
@@ -19,6 +19,7 @@ final class UserListViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let kind: Kind
let userFetchedResultsController: UserFetchedResultsController
let listBatchFetchViewModel = ListBatchFetchViewModel()
@@ -39,21 +40,18 @@ final class UserListViewModel {
public init(
context: AppContext,
+ authContext: AuthContext,
kind: Kind
) {
self.context = context
+ self.authContext = authContext
self.kind = kind
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalPredicate: nil
)
// end init
-
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: userFetchedResultsController)
- .store(in: &disposeBag)
}
}
diff --git a/Mastodon/Scene/Report/Report/ReportViewController.swift b/Mastodon/Scene/Report/Report/ReportViewController.swift
index 57107be47..f1418c5a1 100644
--- a/Mastodon/Scene/Report/Report/ReportViewController.swift
+++ b/Mastodon/Scene/Report/Report/ReportViewController.swift
@@ -94,22 +94,23 @@ extension ReportViewController: ReportReasonViewControllerDelegate {
case .dislike:
let reportResultViewModel = ReportResultViewModel(
context: context,
+ authContext: viewModel.authContext,
user: viewModel.user,
isReported: false
)
- coordinator.present(
+ _ = coordinator.present(
scene: .reportResult(viewModel: reportResultViewModel),
from: self,
transition: .show
)
case .violateRule:
- coordinator.present(
+ _ = coordinator.present(
scene: .reportServerRules(viewModel: viewModel.reportServerRulesViewModel),
from: self,
transition: .show
)
case .spam, .other:
- coordinator.present(
+ _ = coordinator.present(
scene: .reportStatus(viewModel: viewModel.reportStatusViewModel),
from: self,
transition: .show
@@ -144,7 +145,7 @@ extension ReportViewController: ReportStatusViewControllerDelegate {
}
private func coordinateToReportSupplementary() {
- coordinator.present(
+ _ = coordinator.present(
scene: .reportSupplementary(viewModel: viewModel.reportSupplementaryViewModel),
from: self,
transition: .show
@@ -170,11 +171,12 @@ extension ReportViewController: ReportSupplementaryViewControllerDelegate {
let reportResultViewModel = ReportResultViewModel(
context: context,
+ authContext: viewModel.authContext,
user: viewModel.user,
isReported: true
)
- coordinator.present(
+ _ = coordinator.present(
scene: .reportResult(viewModel: reportResultViewModel),
from: self,
transition: .show
@@ -184,7 +186,7 @@ extension ReportViewController: ReportSupplementaryViewControllerDelegate {
let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert)
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil)
alertController.addAction(okAction)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
diff --git a/Mastodon/Scene/Report/Report/ReportViewModel.swift b/Mastodon/Scene/Report/Report/ReportViewModel.swift
index 4e59cb440..c368ce42c 100644
--- a/Mastodon/Scene/Report/Report/ReportViewModel.swift
+++ b/Mastodon/Scene/Report/Report/ReportViewModel.swift
@@ -28,6 +28,7 @@ class ReportViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let user: ManagedObjectRecord
let status: ManagedObjectRecord?
@@ -37,22 +38,20 @@ class ReportViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
user: ManagedObjectRecord,
status: ManagedObjectRecord?
) {
self.context = context
+ self.authContext = authContext
self.user = user
self.status = status
self.reportReasonViewModel = ReportReasonViewModel(context: context)
self.reportServerRulesViewModel = ReportServerRulesViewModel(context: context)
- self.reportStatusViewModel = ReportStatusViewModel(context: context, user: user, status: status)
- self.reportSupplementaryViewModel = ReportSupplementaryViewModel(context: context, user: user)
+ self.reportStatusViewModel = ReportStatusViewModel(context: context, authContext: authContext, user: user, status: status)
+ self.reportSupplementaryViewModel = ReportSupplementaryViewModel(context: context, authContext: authContext, user: user)
// end init
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
// setup reason viewModel
if status != nil {
reportReasonViewModel.headline = L10n.Scene.Report.StepOne.whatsWrongWithThisPost
@@ -74,7 +73,7 @@ class ReportViewModel {
// bind server rules
Task { @MainActor in
do {
- let response = try await context.apiService.instance(domain: authenticationBox.domain)
+ let response = try await context.apiService.instance(domain: authContext.mastodonAuthenticationBox.domain)
.timeout(3, scheduler: DispatchQueue.main)
.singleOutput()
let rules = response.value.rules ?? []
@@ -95,12 +94,7 @@ class ReportViewModel {
extension ReportViewModel {
@MainActor
func report() async throws {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value,
- !isReporting
- else {
- assertionFailure()
- return
- }
+ guard !isReporting else { return }
let managedObjectContext = context.managedObjectContext
let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform {
diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift
index b1ad76415..75021934b 100644
--- a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift
+++ b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift
@@ -156,65 +156,69 @@ struct ReportActionButton: View {
}
-#if DEBUG
-struct ReportResultView_Previews: PreviewProvider {
-
- static func viewModel(isReported: Bool) -> ReportResultViewModel {
- let context = AppContext.shared
- let request = MastodonUser.sortedFetchRequest
- request.fetchLimit = 1
-
- let property = MastodonUser.Property(
- identifier: "1",
- domain: "domain.com",
- id: "1",
- acct: "@user@domain.com",
- username: "user",
- displayName: "User",
- avatar: "",
- avatarStatic: "",
- header: "",
- headerStatic: "",
- note: "",
- url: "",
- statusesCount: Int64(100),
- followingCount: Int64(100),
- followersCount: Int64(100),
- locked: false,
- bot: false,
- suspended: false,
- createdAt: Date(),
- updatedAt: Date(),
- emojis: [],
- fields: []
- )
- let user = try! context.managedObjectContext.fetch(request).first ?? MastodonUser.insert(into: context.managedObjectContext, property: property)
-
- return ReportResultViewModel(
- context: context,
- user: .init(objectID: user.objectID),
- isReported: isReported
- )
- }
- static var previews: some View {
- Group {
- NavigationView {
- ReportResultView(viewModel: viewModel(isReported: true))
- .navigationBarTitle(Text(""))
- .navigationBarTitleDisplayMode(.inline)
- }
- NavigationView {
- ReportResultView(viewModel: viewModel(isReported: false))
- .navigationBarTitle(Text(""))
- .navigationBarTitleDisplayMode(.inline)
- }
- NavigationView {
- ReportResultView(viewModel: viewModel(isReported: true))
- .navigationBarTitle(Text(""))
- .navigationBarTitleDisplayMode(.inline)
- }
- .preferredColorScheme(.dark)
- }
- }
-}
-#endif
+//#if DEBUG
+//
+//struct ReportResultView_Previews: PreviewProvider {
+//
+// static func viewModel(isReported: Bool) -> ReportResultViewModel {
+// let context = AppContext.shared
+// let request = MastodonUser.sortedFetchRequest
+// request.fetchLimit = 1
+//
+// let property = MastodonUser.Property(
+// identifier: "1",
+// domain: "domain.com",
+// id: "1",
+// acct: "@user@domain.com",
+// username: "user",
+// displayName: "User",
+// avatar: "",
+// avatarStatic: "",
+// header: "",
+// headerStatic: "",
+// note: "",
+// url: "",
+// statusesCount: Int64(100),
+// followingCount: Int64(100),
+// followersCount: Int64(100),
+// locked: false,
+// bot: false,
+// suspended: false,
+// createdAt: Date(),
+// updatedAt: Date(),
+// emojis: [],
+// fields: []
+// )
+// let user = try! context.managedObjectContext.fetch(request).first ?? MastodonUser.insert(into: context.managedObjectContext, property: property)
+//
+// return ReportResultViewModel(
+// context: context,
+// authContext: nil,
+// user: .init(objectID: user.objectID),
+// isReported: isReported
+// )
+// }
+// static var previews: some View {
+// Group {
+// NavigationView {
+// ReportResultView(viewModel: viewModel(isReported: true))
+// .navigationBarTitle(Text(""))
+// .navigationBarTitleDisplayMode(.inline)
+// }
+// NavigationView {
+// ReportResultView(viewModel: viewModel(isReported: false))
+// .navigationBarTitle(Text(""))
+// .navigationBarTitleDisplayMode(.inline)
+// }
+// NavigationView {
+// ReportResultView(viewModel: viewModel(isReported: true))
+// .navigationBarTitle(Text(""))
+// .navigationBarTitleDisplayMode(.inline)
+// }
+// .preferredColorScheme(.dark)
+// }
+// }
+//
+//}
+//
+//#endif
diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift
index 1a5aabb67..10dcdf373 100644
--- a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift
+++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift
@@ -93,17 +93,13 @@ extension ReportResultViewController {
.throttle(for: 0.3, scheduler: DispatchQueue.main, latest: false)
.sink { [weak self] in
guard let self = self else { return }
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
Task { @MainActor in
guard !self.viewModel.isRequestFollow else { return }
self.viewModel.isRequestFollow = true
do {
try await DataSourceFacade.responseToUserFollowAction(
dependency: self,
- user: self.viewModel.user,
- authenticationBox: authenticationBox
+ user: self.viewModel.user
)
} catch {
// handle error
@@ -117,17 +113,13 @@ extension ReportResultViewController {
.throttle(for: 0.3, scheduler: DispatchQueue.main, latest: false)
.sink { [weak self] in
guard let self = self else { return }
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
Task { @MainActor in
guard !self.viewModel.isRequestMute else { return }
self.viewModel.isRequestMute = true
do {
try await DataSourceFacade.responseToUserMuteAction(
dependency: self,
- user: self.viewModel.user,
- authenticationBox: authenticationBox
+ user: self.viewModel.user
)
} catch {
// handle error
@@ -141,17 +133,13 @@ extension ReportResultViewController {
.throttle(for: 0.3, scheduler: DispatchQueue.main, latest: false)
.sink { [weak self] in
guard let self = self else { return }
- guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
Task { @MainActor in
guard !self.viewModel.isRequestBlock else { return }
self.viewModel.isRequestBlock = true
do {
try await DataSourceFacade.responseToUserBlockAction(
dependency: self,
- user: self.viewModel.user,
- authenticationBox: authenticationBox
+ user: self.viewModel.user
)
} catch {
// handle error
@@ -176,6 +164,11 @@ extension ReportResultViewController {
}
+// MARK: - AuthContextProvider
+extension ReportResultViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - PanPopableViewController
extension ReportResultViewController: PanPopableViewController {
var isPanPopable: Bool { false }
diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift
index 8508d1596..8123a8773 100644
--- a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift
+++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift
@@ -23,6 +23,7 @@ class ReportResultViewModel: ObservableObject {
// input
let context: AppContext
+ let authContext: AuthContext
let user: ManagedObjectRecord
let isReported: Bool
@@ -47,17 +48,19 @@ class ReportResultViewModel: ObservableObject {
init(
context: AppContext,
+ authContext: AuthContext,
user: ManagedObjectRecord,
isReported: Bool
) {
self.context = context
+ self.authContext = authContext
self.user = user
self.isReported = isReported
// end init
Task { @MainActor in
guard let user = user.object(in: context.managedObjectContext) else { return }
- guard let me = context.authenticationService.activeMastodonAuthenticationBox.value?.authenticationRecord.object(in: context.managedObjectContext)?.user else { return }
+ guard let me = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user else { return }
self.relationshipViewModel.user = user
self.relationshipViewModel.me = me
diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift
index 4610a38d3..9879863d6 100644
--- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift
+++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift
@@ -25,7 +25,7 @@ extension ReportStatusViewModel {
diffableDataSource = ReportSection.diffableDataSource(
tableView: tableView,
context: context,
- configuration: ReportSection.Configuration()
+ configuration: ReportSection.Configuration(authContext: authContext)
)
var snapshot = NSDiffableDataSourceSnapshot()
diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift
index 6e9d48af0..01e8715d1 100644
--- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift
+++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift
@@ -76,10 +76,6 @@ extension ReportStatusViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
let maxID = viewModel.statusFetchedResultsController.statusIDs.last
@@ -102,7 +98,7 @@ extension ReportStatusViewModel.State {
excludeReplies: true,
excludeReblogs: true,
onlyMedia: false,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
var hasNewStatusesAppend = false
diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift
index b539909da..5b80a9f3a 100644
--- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift
+++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift
@@ -24,6 +24,7 @@ class ReportStatusViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let user: ManagedObjectRecord
let status: ManagedObjectRecord?
let statusFetchedResultsController: StatusFetchedResultsController
@@ -50,15 +51,17 @@ class ReportStatusViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
user: ManagedObjectRecord,
status: ManagedObjectRecord?
) {
self.context = context
+ self.authContext = authContext
self.user = user
self.status = status
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
// end init
@@ -66,12 +69,7 @@ class ReportStatusViewModel {
if let status = status {
selectStatuses.append(status)
}
-
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
-
+
$selectStatuses
.map { statuses -> Bool in
return status == nil ? !statuses.isEmpty : statuses.count > 1
diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift
index 8cbc16242..099f542b7 100644
--- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift
+++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift
@@ -25,7 +25,7 @@ extension ReportSupplementaryViewModel {
diffableDataSource = ReportSection.diffableDataSource(
tableView: tableView,
context: context,
- configuration: ReportSection.Configuration()
+ configuration: ReportSection.Configuration(authContext: authContext)
)
var snapshot = NSDiffableDataSourceSnapshot()
diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift
index 8ddc2d91a..a4239bbc4 100644
--- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift
+++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift
@@ -16,7 +16,8 @@ class ReportSupplementaryViewModel {
weak var delegate: ReportSupplementaryViewControllerDelegate?
// Input
- var context: AppContext
+ let context: AppContext
+ let authContext: AuthContext
let user: ManagedObjectRecord
let commentContext = ReportItem.CommentContext()
@@ -29,9 +30,11 @@ class ReportSupplementaryViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
user: ManagedObjectRecord
) {
self.context = context
+ self.authContext = authContext
self.user = user
// end init
diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift
index 503c56de5..3f4758e8e 100644
--- a/Mastodon/Scene/Root/ContentSplitViewController.swift
+++ b/Mastodon/Scene/Root/ContentSplitViewController.swift
@@ -32,7 +32,7 @@ final class ContentSplitViewController: UIViewController, NeedsDependency {
let sidebarViewController = SidebarViewController()
sidebarViewController.context = context
sidebarViewController.coordinator = coordinator
- sidebarViewController.viewModel = SidebarViewModel(context: context)
+ sidebarViewController.viewModel = SidebarViewModel(context: context, authContext: authContext)
sidebarViewController.delegate = self
return sidebarViewController
}()
@@ -111,8 +111,14 @@ extension ContentSplitViewController: SidebarViewControllerDelegate {
func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView) {
guard case let .tab(tab) = item, tab == .me else { return }
+ guard let authContext = authContext else { return }
- let accountListViewController = coordinator.present(scene: .accountList, from: nil, transition: .popover(sourceView: sourceView)) as! AccountListViewController
+ let accountListViewModel = AccountListViewModel(context: context, authContext: authContext)
+ let accountListViewController = coordinator.present(
+ scene: .accountList(viewModel: accountListViewModel),
+ from: nil,
+ transition: .popover(sourceView: sourceView)
+ ) as! AccountListViewController
accountListViewController.dragIndicatorView.barView.isHidden = true
// content width needs > 300 to make checkmark display
accountListViewController.preferredContentSize = CGSize(width: 375, height: 400)
diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift
index 5c910390c..31d7d9fde 100644
--- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift
+++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift
@@ -105,18 +105,24 @@ class MainTabBarController: UITabBarController {
}
}
- func viewController(context: AppContext, coordinator: SceneCoordinator) -> UIViewController {
+ func viewController(context: AppContext, authContext: AuthContext?, coordinator: SceneCoordinator) -> UIViewController {
+ guard let authContext = authContext else {
+ return UITableViewController()
+ }
+
let viewController: UIViewController
switch self {
case .home:
let _viewController = HomeTimelineViewController()
_viewController.context = context
_viewController.coordinator = coordinator
+ _viewController.viewModel = .init(context: context, authContext: authContext)
viewController = _viewController
case .search:
let _viewController = SearchViewController()
_viewController.context = context
_viewController.coordinator = coordinator
+ _viewController.viewModel = .init(context: context, authContext: authContext)
viewController = _viewController
case .compose:
viewController = UIViewController()
@@ -124,12 +130,13 @@ class MainTabBarController: UITabBarController {
let _viewController = NotificationViewController()
_viewController.context = context
_viewController.coordinator = coordinator
+ _viewController.viewModel = .init(context: context, authContext: authContext)
viewController = _viewController
case .me:
let _viewController = ProfileViewController()
_viewController.context = context
_viewController.coordinator = coordinator
- _viewController.viewModel = MeProfileViewModel(context: context)
+ _viewController.viewModel = MeProfileViewModel(context: context, authContext: authContext)
viewController = _viewController
}
viewController.title = self.title
@@ -185,7 +192,7 @@ extension MainTabBarController {
// seealso: `ThemeService.apply(theme:)`
let tabs = Tab.allCases
let viewControllers: [UIViewController] = tabs.map { tab in
- let viewController = tab.viewController(context: context, coordinator: coordinator)
+ let viewController = tab.viewController(context: context, authContext: authContext, coordinator: coordinator)
viewController.tabBarItem.tag = tab.tag
viewController.tabBarItem.title = tab.title // needs for acessiblity large content label
viewController.tabBarItem.image = tab.image.imageWithoutBaseline()
@@ -256,18 +263,18 @@ extension MainTabBarController {
// handle push notification.
// toggle entry when finish fetch latest notification
- Publishers.CombineLatest3(
- context.authenticationService.activeMastodonAuthentication,
+ Publishers.CombineLatest(
context.notificationService.unreadNotificationCountDidUpdate,
$currentTab
)
.receive(on: DispatchQueue.main)
- .sink { [weak self] authentication, _, currentTab in
+ .sink { [weak self] authentication, currentTab in
guard let self = self else { return }
guard let notificationViewController = self.notificationViewController else { return }
+ let authentication = self.authContext?.mastodonAuthenticationBox.userAuthorization
let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in
- let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken)
+ let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.accessToken)
return count > 0
} ?? false
@@ -297,43 +304,31 @@ extension MainTabBarController {
)
}
.store(in: &disposeBag)
- context.authenticationService.activeMastodonAuthentication
- .receive(on: DispatchQueue.main)
- .sink { [weak self] activeMastodonAuthentication in
- guard let self = self else { return }
-
- if let user = activeMastodonAuthentication?.user {
- self.avatarURLObserver = user.publisher(for: \.avatar)
- .sink { [weak self, weak user] _ in
- guard let self = self else { return }
- guard let user = user else { return }
- guard user.managedObjectContext != nil else { return }
- self.avatarURL = user.avatarImageURL()
- }
- } else {
- self.avatarURLObserver = nil
+
+ if let user = authContext?.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user {
+ self.avatarURLObserver = user.publisher(for: \.avatar)
+ .sink { [weak self, weak user] _ in
+ guard let self = self else { return }
+ guard let user = user else { return }
+ guard user.managedObjectContext != nil else { return }
+ self.avatarURL = user.avatarImageURL()
}
-
- // a11y
- let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
- guard let profileTabItem = _profileTabItem else { return }
-
- let currentUserDisplayName = activeMastodonAuthentication?.user.displayNameWithFallback ?? "no user"
- profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName)
- }
- .store(in: &disposeBag)
+
+ // a11y
+ let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
+ guard let profileTabItem = _profileTabItem else { return }
+ let currentUserDisplayName = user.displayNameWithFallback ?? "no user"
+ profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName)
+
+ } else {
+ self.avatarURLObserver = nil
+ }
let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer()
tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:)))
tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer)
- context.authenticationService.activeMastodonAuthenticationBox
- .receive(on: DispatchQueue.main)
- .sink { [weak self] authenticationBox in
- guard let self = self else { return }
- self.isReadyForWizardAvatarButton = authenticationBox != nil
- }
- .store(in: &disposeBag)
+ self.isReadyForWizardAvatarButton = authContext != nil
$currentTab
.receive(on: DispatchQueue.main)
@@ -374,13 +369,13 @@ extension MainTabBarController {
@objc private func composeButtonDidPressed(_ sender: UIButton) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
+ guard let authContext = self.authContext else { return }
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .post,
- authenticationBox: authenticationBox
+ authContext: authContext
)
- coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}
@objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) {
@@ -402,7 +397,9 @@ extension MainTabBarController {
switch tab {
case .me:
- coordinator.present(scene: .accountList, from: self, transition: .panModal)
+ guard let authContext = self.authContext else { return }
+ let accountListViewModel = AccountListViewModel(context: context, authContext: authContext)
+ _ = coordinator.present(scene: .accountList(viewModel: accountListViewModel), from: self, transition: .panModal)
default:
break
}
@@ -726,26 +723,28 @@ extension MainTabBarController {
@objc private func showFavoritesKeyCommandHandler(_ sender: UIKeyCommand) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- let favoriteViewModel = FavoriteViewModel(context: context)
- coordinator.present(scene: .favorite(viewModel: favoriteViewModel), from: nil, transition: .show)
+ guard let authContext = self.authContext else { return }
+ let favoriteViewModel = FavoriteViewModel(context: context, authContext: authContext)
+ _ = coordinator.present(scene: .favorite(viewModel: favoriteViewModel), from: nil, transition: .show)
}
@objc private func openSettingsKeyCommandHandler(_ sender: UIKeyCommand) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
+ guard let authContext = self.authContext else { return }
guard let setting = context.settingService.currentSetting.value else { return }
- let settingsViewModel = SettingsViewModel(context: context, setting: setting)
- coordinator.present(scene: .settings(viewModel: settingsViewModel), from: nil, transition: .modal(animated: true, completion: nil))
+ let settingsViewModel = SettingsViewModel(context: context, authContext: authContext, setting: setting)
+ _ = coordinator.present(scene: .settings(viewModel: settingsViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}
@objc private func composeNewPostKeyCommandHandler(_ sender: UIKeyCommand) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
+ guard let authContext = self.authContext else { return }
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .post,
- authenticationBox: authenticationBox
+ authContext: authContext
)
- coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}
}
diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift
index 3a68d3342..d138f6006 100644
--- a/Mastodon/Scene/Root/RootSplitViewController.swift
+++ b/Mastodon/Scene/Root/RootSplitViewController.swift
@@ -37,6 +37,10 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
let searchViewController = SearchViewController()
searchViewController.context = context
searchViewController.coordinator = coordinator
+ searchViewController.viewModel = .init(
+ context: context,
+ authContext: authContext
+ )
return searchViewController
}()
diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
index 86d549373..98006d4c0 100644
--- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
+++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
@@ -191,9 +191,10 @@ extension SidebarViewController: UICollectionViewDelegate {
case .tab(let tab):
delegate?.sidebarViewController(self, didSelectTab: tab)
case .setting:
+ guard let authContext = viewModel.authContext else { return }
guard let setting = context.settingService.currentSetting.value else { return }
- let settingsViewModel = SettingsViewModel(context: context, setting: setting)
- coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
+ let settingsViewModel = SettingsViewModel(context: context, authContext: authContext, setting: setting)
+ _ = coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
case .compose:
assertionFailure()
}
@@ -201,15 +202,15 @@ extension SidebarViewController: UICollectionViewDelegate {
guard let diffableDataSource = viewModel.secondaryDiffableDataSource else { return }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
+ guard let authContext = viewModel.authContext else { return }
switch item {
case .compose:
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .post,
- authenticationBox: authenticationBox
+ authContext: authContext
)
- coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
default:
assertionFailure()
}
diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift
index 967d10b09..9f0eb1899 100644
--- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift
+++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift
@@ -21,6 +21,7 @@ final class SidebarViewModel {
// input
let context: AppContext
+ let authContext: AuthContext?
@Published private var isSidebarDataSourceReady = false
@Published private var isAvatarButtonDataReady = false
@Published var currentTab: MainTabBarController.Tab = .home
@@ -30,10 +31,9 @@ final class SidebarViewModel {
var secondaryDiffableDataSource: UICollectionViewDiffableDataSource?
@Published private(set) var isReadyForWizardAvatarButton = false
- let activeMastodonAuthenticationObjectID = CurrentValueSubject(nil)
-
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext?) {
self.context = context
+ self.authContext = authContext
Publishers.CombineLatest(
$isSidebarDataSourceReady,
@@ -42,16 +42,7 @@ final class SidebarViewModel {
.map { $0 && $1 }
.assign(to: &$isReadyForWizardAvatarButton)
- context.authenticationService.activeMastodonAuthentication
- .sink { [weak self] authentication in
- guard let self = self else { return }
-
- // bind objectID
- self.activeMastodonAuthenticationObjectID.value = authentication?.objectID
-
- self.isAvatarButtonDataReady = authentication != nil
- }
- .store(in: &disposeBag)
+ self.isAvatarButtonDataReady = authContext != nil
}
}
@@ -81,8 +72,8 @@ extension SidebarViewModel {
let imageURL: URL? = {
switch item {
case .me:
- let authentication = self.context.authenticationService.activeMastodonAuthentication.value
- return authentication?.user.avatarImageURL()
+ let user = self.authContext?.mastodonAuthenticationBox.authenticationRecord.object(in: self.context.managedObjectContext)?.user
+ return user?.avatarImageURL()
default:
return nil
}
@@ -109,18 +100,19 @@ extension SidebarViewModel {
switch item {
case .notification:
- Publishers.CombineLatest3(
- self.context.authenticationService.activeMastodonAuthentication,
+ Publishers.CombineLatest(
self.context.notificationService.unreadNotificationCountDidUpdate,
self.$currentTab
)
.receive(on: DispatchQueue.main)
- .sink { [weak cell] authentication, _, currentTab in
+ .sink { [weak cell] authentication, currentTab in
guard let cell = cell else { return }
- let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in
- let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken)
+
+ let hasUnreadPushNotification: Bool = {
+ guard let accessToken = self.authContext?.mastodonAuthenticationBox.userAuthorization.accessToken else { return false }
+ let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken)
return count > 0
- } ?? false
+ }()
let image: UIImage = {
if currentTab == .notification {
@@ -135,8 +127,8 @@ extension SidebarViewModel {
}
.store(in: &cell.disposeBag)
case .me:
- guard let authentication = self.context.authenticationService.activeMastodonAuthentication.value else { break }
- let currentUserDisplayName = authentication.user.displayNameWithFallback
+ guard let user = self.authContext?.mastodonAuthenticationBox.authenticationRecord.object(in: self.context.managedObjectContext)?.user else { return }
+ let currentUserDisplayName = user.displayNameWithFallback
cell.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName)
default:
break
diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift
index 947c1593d..32f3dbe3d 100644
--- a/Mastodon/Scene/Search/Search/SearchViewController.swift
+++ b/Mastodon/Scene/Search/Search/SearchViewController.swift
@@ -30,7 +30,7 @@ final class SearchViewController: UIViewController, NeedsDependency {
var searchTransitionController = SearchTransitionController()
var disposeBag = Set()
- private(set) lazy var viewModel = SearchViewModel(context: context)
+ var viewModel: SearchViewModel!
// use AutoLayout could set search bar margin automatically to
// layout alongside with split mode button (on iPad)
@@ -49,10 +49,16 @@ final class SearchViewController: UIViewController, NeedsDependency {
let searchBarTapPublisher = PassthroughSubject()
- private(set) lazy var discoveryViewController: DiscoveryViewController = {
+ private(set) lazy var discoveryViewController: DiscoveryViewController? = {
+ guard let authContext = viewModel.authContext else { return nil }
let viewController = DiscoveryViewController()
viewController.context = context
viewController.coordinator = coordinator
+ viewController.viewModel = .init(
+ context: context,
+ coordinator: coordinator,
+ authContext: authContext
+ )
return viewController
}()
@@ -93,6 +99,8 @@ extension SearchViewController {
// collectionView: collectionView
// )
+ guard let discoveryViewController = self.discoveryViewController else { return }
+
addChild(discoveryViewController)
discoveryViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(discoveryViewController.view)
@@ -143,7 +151,8 @@ extension SearchViewController {
.sink { [weak self] in
guard let self = self else { return }
// push to search detail
- let searchDetailViewModel = SearchDetailViewModel()
+ guard let authContext = self.viewModel.authContext else { return }
+ let searchDetailViewModel = SearchDetailViewModel(authContext: authContext)
searchDetailViewModel.needsBecomeFirstResponder = true
self.navigationController?.delegate = self.searchTransitionController
// FIXME:
diff --git a/Mastodon/Scene/Search/Search/SearchViewModel.swift b/Mastodon/Scene/Search/Search/SearchViewModel.swift
index b0eccd49b..51d614280 100644
--- a/Mastodon/Scene/Search/Search/SearchViewModel.swift
+++ b/Mastodon/Scene/Search/Search/SearchViewModel.swift
@@ -20,14 +20,16 @@ final class SearchViewModel: NSObject {
// input
let context: AppContext
+ let authContext: AuthContext?
let viewDidAppeared = PassthroughSubject()
// output
var diffableDataSource: UICollectionViewDiffableDataSource?
@Published var hashtags: [Mastodon.Entity.Tag] = []
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext?) {
self.context = context
+ self.authContext = authContext
super.init()
// Publishers.CombineLatest(
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift
index 0b0a0d003..6ffc90182 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift
@@ -83,7 +83,7 @@ final class SearchDetailViewController: PageboyViewController, NeedsDependency {
let searchHistoryViewController = SearchHistoryViewController()
searchHistoryViewController.context = context
searchHistoryViewController.coordinator = coordinator
- searchHistoryViewController.viewModel = SearchHistoryViewModel(context: context)
+ searchHistoryViewController.viewModel = SearchHistoryViewModel(context: context, authContext: viewModel.authContext)
return searchHistoryViewController
}()
}
@@ -131,7 +131,7 @@ extension SearchDetailViewController {
let searchResultViewController = SearchResultViewController()
searchResultViewController.context = context
searchResultViewController.coordinator = coordinator
- searchResultViewController.viewModel = SearchResultViewModel(context: context, searchScope: scope)
+ searchResultViewController.viewModel = SearchResultViewModel(context: context, authContext: viewModel.authContext, searchScope: scope)
// bind searchText
viewModel.searchText
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewModel.swift
index 140fe14e8..779aaa2dc 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewModel.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewModel.swift
@@ -10,12 +10,14 @@ import Foundation
import CoreGraphics
import Combine
import MastodonSDK
+import MastodonCore
import MastodonAsset
import MastodonLocalization
final class SearchDetailViewModel {
// input
+ let authContext: AuthContext
var needsBecomeFirstResponder = false
let viewDidAppear = PassthroughSubject()
let navigationBarFrame = CurrentValueSubject(.zero)
@@ -26,7 +28,8 @@ final class SearchDetailViewModel {
let searchText: CurrentValueSubject
let searchActionPublisher = PassthroughSubject()
- init(initialSearchText: String = "") {
+ init(authContext: AuthContext, initialSearchText: String = "") {
+ self.authContext = authContext
self.searchText = CurrentValueSubject(initialSearchText)
}
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift
index 7d5f6c60e..52d0ffb9c 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift
@@ -109,6 +109,11 @@ extension SearchHistoryViewController: UICollectionViewDelegate {
}
+// MARK: - AuthContextProvider
+extension SearchHistoryViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
// MARK: - SearchHistorySectionHeaderCollectionReusableViewDelegate
extension SearchHistoryViewController: SearchHistorySectionHeaderCollectionReusableViewDelegate {
func searchHistorySectionHeaderCollectionReusableView(
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift
index b7987413f..1ec06ebe7 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift
@@ -17,23 +17,19 @@ final class SearchHistoryViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let searchHistoryFetchedResultController: SearchHistoryFetchedResultController
// output
var diffableDataSource: UICollectionViewDiffableDataSource?
- init(context: AppContext) {
+ init(context: AppContext, authContext: AuthContext) {
self.context = context
+ self.authContext = authContext
self.searchHistoryFetchedResultController = SearchHistoryFetchedResultController(managedObjectContext: context.managedObjectContext)
- context.authenticationService.activeMastodonAuthenticationBox
- .receive(on: DispatchQueue.main)
- .sink { [weak self] box in
- guard let self = self else { return }
- self.searchHistoryFetchedResultController.domain.value = box?.domain
- self.searchHistoryFetchedResultController.userID.value = box?.userID
- }
- .store(in: &disposeBag)
+ searchHistoryFetchedResultController.domain.value = authContext.mastodonAuthenticationBox.domain
+ searchHistoryFetchedResultController.userID.value = authContext.mastodonAuthenticationBox.userID
}
}
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift
index 87c981071..67de62bf3 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift
@@ -154,10 +154,9 @@ extension SearchResultViewController {
}
// MARK: - StatusTableViewCellDelegate
-//extension SearchResultViewController: StatusTableViewCellDelegate {
-// weak var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { return self }
-// func parent() -> UIViewController { return self }
-//}
+extension SearchResultViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
// MARK: - UITableViewDelegate
extension SearchResultViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+Diffable.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+Diffable.swift
index ff64b80f0..7d243b1fa 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+Diffable.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+Diffable.swift
@@ -18,6 +18,7 @@ extension SearchResultViewModel {
tableView: tableView,
context: context,
configuration: .init(
+ authContext: authContext,
statusViewTableViewCellDelegate: statusTableViewCellDelegate
)
)
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+State.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+State.swift
index cd1579747..b5deb777c 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+State.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel+State.swift
@@ -73,11 +73,6 @@ extension SearchResultViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- assertionFailure()
- stateMachine.enter(Fail.self)
- return
- }
let searchText = viewModel.searchText.value
let searchType = viewModel.searchScope.searchType
@@ -133,7 +128,7 @@ extension SearchResultViewModel.State {
do {
let response = try await viewModel.context.apiService.search(
query: query,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
// discard result when search text is outdated
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift
index a7b97de6b..546920749 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift
@@ -20,6 +20,7 @@ final class SearchResultViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let searchScope: SearchDetailViewModel.SearchScope
let searchText = CurrentValueSubject("")
@Published var hashtags: [Mastodon.Entity.Tag] = []
@@ -48,30 +49,21 @@ final class SearchResultViewModel {
}()
let didDataSourceUpdate = PassthroughSubject()
- init(context: AppContext, searchScope: SearchDetailViewModel.SearchScope) {
+ init(context: AppContext, authContext: AuthContext, searchScope: SearchDetailViewModel.SearchScope) {
self.context = context
+ self.authContext = authContext
self.searchScope = searchScope
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalPredicate: nil
)
self.statusFetchedResultsController = StatusFetchedResultsController(
managedObjectContext: context.managedObjectContext,
- domain: nil,
+ domain: authContext.mastodonAuthenticationBox.domain,
additionalTweetPredicate: nil
)
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: userFetchedResultsController)
- .store(in: &disposeBag)
-
- context.authenticationService.activeMastodonAuthenticationBox
- .map { $0?.domain }
- .assign(to: \.domain, on: statusFetchedResultsController)
- .store(in: &disposeBag)
-
// Publishers.CombineLatest(
// items,
// statusFetchedResultsController.objectIDs.removeDuplicates()
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index edafbe1a3..53a856fd0 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -281,7 +281,7 @@ extension SettingsViewController {
}
alertController.addAction(cancelAction)
alertController.addAction(signOutAction)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: self,
transition: .alertController(animated: true, completion: nil)
@@ -289,15 +289,13 @@ extension SettingsViewController {
}
func signOut() {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
// clear badge before sign-out
context.notificationService.clearNotificationCountForActiveUser()
Task { @MainActor in
- try await context.authenticationService.signOutMastodonUser(authenticationBox: authenticationBox)
+ try await context.authenticationService.signOutMastodonUser(
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
+ )
self.coordinator.setup()
}
}
@@ -372,12 +370,12 @@ extension SettingsViewController: UITableViewDelegate {
feedbackGenerator.impactOccurred()
switch link {
case .accountSettings:
- guard let box = context.authenticationService.activeMastodonAuthenticationBox.value,
- let url = URL(string: "https://\(box.domain)/auth/edit") else { return }
+ let domain = viewModel.authContext.mastodonAuthenticationBox.domain
+ guard let url = URL(string: "https://\(domain)/auth/edit") else { return }
viewModel.openAuthenticationPage(authenticateURL: url, presentationContextProvider: self)
case .github:
guard let url = URL(string: "https://github.com/mastodon/mastodon-ios") else { break }
- coordinator.present(
+ _ = coordinator.present(
scene: .safari(url: url),
from: self,
transition: .safariPresent(animated: true, completion: nil)
@@ -385,7 +383,7 @@ extension SettingsViewController: UITableViewDelegate {
case .termsOfService, .privacyPolicy:
// same URL
guard let url = viewModel.privacyURL else { break }
- coordinator.present(
+ _ = coordinator.present(
scene: .safari(url: url),
from: self,
transition: .safariPresent(animated: true, completion: nil)
diff --git a/Mastodon/Scene/Settings/SettingsViewModel.swift b/Mastodon/Scene/Settings/SettingsViewModel.swift
index ea2275429..8d737b93b 100644
--- a/Mastodon/Scene/Settings/SettingsViewModel.swift
+++ b/Mastodon/Scene/Settings/SettingsViewModel.swift
@@ -19,10 +19,11 @@ class SettingsViewModel {
var disposeBag = Set()
+ // input
let context: AppContext
+ let authContext: AuthContext
var mastodonAuthenticationController: MastodonAuthenticationController?
- // input
let setting: CurrentValueSubject
var updateDisposeBag = Set()
var createDisposeBag = Set()
@@ -42,15 +43,13 @@ class SettingsViewModel {
let updateSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>()
lazy var privacyURL: URL? = {
- guard let box = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value else {
- return nil
- }
-
- return Mastodon.API.privacyURL(domain: box.domain)
+ let domain = authContext.mastodonAuthenticationBox.domain
+ return Mastodon.API.privacyURL(domain: domain)
}()
- init(context: AppContext, setting: Setting) {
+ init(context: AppContext, authContext: AuthContext, setting: Setting) {
self.context = context
+ self.authContext = authContext
self.setting = CurrentValueSubject(setting)
self.setting
@@ -60,10 +59,7 @@ class SettingsViewModel {
})
.store(in: &disposeBag)
- context.authenticationService.activeMastodonAuthenticationBox
- .compactMap { $0?.domain }
- .map { context.apiService.instance(domain: $0) }
- .switchToLatest()
+ context.apiService.instance(domain: authContext.mastodonAuthenticationBox.domain)
.sink { [weak self] completion in
guard let self = self else { return }
switch completion {
diff --git a/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift b/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift
index ed5e68dc7..98d06fd92 100644
--- a/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift
+++ b/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift
@@ -162,42 +162,39 @@ extension NotificationView {
}
}
.store(in: &disposeBag)
+
+ let authContext = viewModel.authContext
// isMuting
- Publishers.CombineLatest(
- viewModel.$userIdentifier,
- author.publisher(for: \.mutingBy)
- )
- .map { userIdentifier, mutingBy in
- guard let userIdentifier = userIdentifier else { return false }
- return mutingBy.contains(where: {
- $0.id == userIdentifier.userID && $0.domain == userIdentifier.domain
- })
- }
- .assign(to: \.isMuting, on: viewModel)
- .store(in: &disposeBag)
+ author.publisher(for: \.mutingBy)
+ .map { mutingBy in
+ guard let authContext = authContext else { return false }
+ return mutingBy.contains(where: {
+ $0.id == authContext.mastodonAuthenticationBox.userID
+ && $0.domain == authContext.mastodonAuthenticationBox.domain
+ })
+ }
+ .assign(to: \.isMuting, on: viewModel)
+ .store(in: &disposeBag)
// isBlocking
- Publishers.CombineLatest(
- viewModel.$userIdentifier,
- author.publisher(for: \.blockingBy)
- )
- .map { userIdentifier, blockingBy in
- guard let userIdentifier = userIdentifier else { return false }
- return blockingBy.contains(where: {
- $0.id == userIdentifier.userID && $0.domain == userIdentifier.domain
- })
- }
- .assign(to: \.isBlocking, on: viewModel)
- .store(in: &disposeBag)
+ author.publisher(for: \.blockingBy)
+ .map { blockingBy in
+ guard let authContext = authContext else { return false }
+ return blockingBy.contains(where: {
+ $0.id == authContext.mastodonAuthenticationBox.userID
+ && $0.domain == authContext.mastodonAuthenticationBox.domain
+ })
+ }
+ .assign(to: \.isBlocking, on: viewModel)
+ .store(in: &disposeBag)
// isMyself
- Publishers.CombineLatest3(
- viewModel.$userIdentifier,
+ Publishers.CombineLatest(
author.publisher(for: \.domain),
author.publisher(for: \.id)
)
- .map { userIdentifier, domain, id in
- guard let userIdentifier = userIdentifier else { return false }
- return userIdentifier.domain == domain
- && userIdentifier.userID == id
+ .map { domain, id in
+ guard let authContext = authContext else { return false }
+ return authContext.mastodonAuthenticationBox.domain == domain
+ && authContext.mastodonAuthenticationBox.userID == id
}
.assign(to: \.isMyself, on: viewModel)
.store(in: &disposeBag)
diff --git a/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift b/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift
index 7d1baa188..334c9ce15 100644
--- a/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift
+++ b/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift
@@ -57,13 +57,13 @@ extension PollOptionView {
option.publisher(for: \.poll),
option.publisher(for: \.votedBy),
option.publisher(for: \.isSelected),
- viewModel.$userIdentifier
+ viewModel.$authContext
)
- .sink { [weak self] poll, optionVotedBy, isSelected, userIdentifier in
+ .sink { [weak self] poll, optionVotedBy, isSelected, authContext in
guard let self = self else { return }
- let domain = userIdentifier?.domain ?? ""
- let userID = userIdentifier?.userID ?? ""
+ let domain = authContext?.mastodonAuthenticationBox.domain ?? ""
+ let userID = authContext?.mastodonAuthenticationBox.userID ?? ""
let options = poll.options
let pollVoteBy = poll.votedBy ?? Set()
diff --git a/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift b/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift
index 78ca7b88d..590b85652 100644
--- a/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift
+++ b/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift
@@ -122,7 +122,7 @@ extension StatusView {
let header = createHeader(name: nil, emojis: nil)
viewModel.header = header
- if let authenticationBox = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value {
+ if let authenticationBox = viewModel.authContext?.mastodonAuthenticationBox {
Just(inReplyToAccountID)
.asyncMap { userID in
return try await AppContext.shared.apiService.accountInfo(
diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift
index 3dfffa540..6e3e73b8a 100644
--- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift
+++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift
@@ -159,7 +159,7 @@ extension SuggestionAccountViewController: UITableViewDelegate {
switch item {
case .account(let record):
guard let account = record.object(in: context.managedObjectContext) else { return }
- let cachedProfileViewModel = CachedProfileViewModel(context: context, mastodonUser: account)
+ let cachedProfileViewModel = CachedProfileViewModel(context: context, authContext: viewModel.authContext, mastodonUser: account)
coordinator.present(
scene: .profile(viewModel: cachedProfileViewModel),
from: self,
@@ -169,6 +169,12 @@ extension SuggestionAccountViewController: UITableViewDelegate {
}
}
+// MARK: - AuthContextProvider
+extension SuggestionAccountViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
+
+// MARK: - SuggestionAccountTableViewCellDelegate
extension SuggestionAccountViewController: SuggestionAccountTableViewCellDelegate {
func suggestionAccountTableViewCell(
_ cell: SuggestionAccountTableViewCell,
@@ -177,7 +183,6 @@ extension SuggestionAccountViewController: SuggestionAccountTableViewCellDelegat
guard let tableViewDiffableDataSource = viewModel.tableViewDiffableDataSource else { return }
guard let indexPath = tableView.indexPath(for: cell) else { return }
guard let item = tableViewDiffableDataSource.itemIdentifier(for: indexPath) else { return }
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
switch item {
case .account(let user):
@@ -186,8 +191,7 @@ extension SuggestionAccountViewController: SuggestionAccountTableViewCellDelegat
do {
try await DataSourceFacade.responseToUserFollowAction(
dependency: self,
- user: user,
- authenticationBox: authenticationBox
+ user: user
)
} catch {
// do noting
diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift
index 4496b9f0a..35ba305bc 100644
--- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift
+++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift
@@ -17,6 +17,7 @@ extension SuggestionAccountViewModel {
tableView: tableView,
context: context,
configuration: RecommendAccountSection.Configuration(
+ authContext: authContext,
suggestionAccountTableViewCellDelegate: suggestionAccountTableViewCellDelegate
)
)
diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift
index 70676bf0f..b8af80bb4 100644
--- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift
+++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift
@@ -25,6 +25,7 @@ final class SuggestionAccountViewModel: NSObject {
// input
let context: AppContext
+ let authContext: AuthContext
let userFetchedResultsController: UserFetchedResultsController
let selectedUserFetchedResultsController: UserFetchedResultsController
@@ -35,9 +36,11 @@ final class SuggestionAccountViewModel: NSObject {
var tableViewDiffableDataSource: UITableViewDiffableDataSource?
init(
- context: AppContext
+ context: AppContext,
+ authContext: AuthContext
) {
self.context = context
+ self.authContext = authContext
self.userFetchedResultsController = UserFetchedResultsController(
managedObjectContext: context.managedObjectContext,
domain: nil,
@@ -50,14 +53,11 @@ final class SuggestionAccountViewModel: NSObject {
)
super.init()
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
- userFetchedResultsController.domain = authenticationBox.domain
- selectedUserFetchedResultsController.domain = authenticationBox.domain
+ userFetchedResultsController.domain = authContext.mastodonAuthenticationBox.domain
+ selectedUserFetchedResultsController.domain = authContext.mastodonAuthenticationBox.domain
selectedUserFetchedResultsController.additionalPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [
- MastodonUser.predicate(followingBy: authenticationBox.userID),
- MastodonUser.predicate(followRequestedBy: authenticationBox.userID)
+ MastodonUser.predicate(followingBy: authContext.mastodonAuthenticationBox.userID),
+ MastodonUser.predicate(followRequestedBy: authContext.mastodonAuthenticationBox.userID)
])
// fetch recomment users
@@ -66,13 +66,13 @@ final class SuggestionAccountViewModel: NSObject {
do {
let response = try await context.apiService.suggestionAccountV2(
query: nil,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
userIDs = response.value.map { $0.account.id }
} catch let error as Mastodon.API.Error where error.httpResponseStatus == .notFound {
let response = try await context.apiService.suggestionAccount(
query: nil,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
userIDs = response.value.map { $0.id }
} catch {
@@ -90,12 +90,9 @@ final class SuggestionAccountViewModel: NSObject {
.sink { [weak self] records in
guard let _ = self else { return }
Task {
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
_ = try await context.apiService.relationship(
records: records,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
}
}
diff --git a/Mastodon/Scene/Thread/CachedThreadViewModel.swift b/Mastodon/Scene/Thread/CachedThreadViewModel.swift
index 0a39db590..00c29e157 100644
--- a/Mastodon/Scene/Thread/CachedThreadViewModel.swift
+++ b/Mastodon/Scene/Thread/CachedThreadViewModel.swift
@@ -10,10 +10,11 @@ import CoreDataStack
import MastodonCore
final class CachedThreadViewModel: ThreadViewModel {
- init(context: AppContext, status: Status) {
+ init(context: AppContext, authContext: AuthContext, status: Status) {
let threadContext = StatusItem.Thread.Context(status: .init(objectID: status.objectID))
super.init(
context: context,
+ authContext: authContext,
optionalRoot: .root(context: threadContext)
)
}
diff --git a/Mastodon/Scene/Thread/RemoteThreadViewModel.swift b/Mastodon/Scene/Thread/RemoteThreadViewModel.swift
index da5a9bba0..e22b11961 100644
--- a/Mastodon/Scene/Thread/RemoteThreadViewModel.swift
+++ b/Mastodon/Scene/Thread/RemoteThreadViewModel.swift
@@ -15,22 +15,20 @@ final class RemoteThreadViewModel: ThreadViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
statusID: Mastodon.Entity.Status.ID
) {
super.init(
context: context,
+ authContext: authContext,
optionalRoot: nil
)
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
Task { @MainActor in
- let domain = authenticationBox.domain
+ let domain = authContext.mastodonAuthenticationBox.domain
let response = try await context.apiService.status(
statusID: statusID,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
let managedObjectContext = context.managedObjectContext
@@ -49,22 +47,20 @@ final class RemoteThreadViewModel: ThreadViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
notificationID: Mastodon.Entity.Notification.ID
) {
super.init(
context: context,
+ authContext: authContext,
optionalRoot: nil
)
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
- return
- }
-
Task { @MainActor in
- let domain = authenticationBox.domain
+ let domain = authContext.mastodonAuthenticationBox.domain
let response = try await context.apiService.notification(
notificationID: notificationID,
- authenticationBox: authenticationBox
+ authenticationBox: authContext.mastodonAuthenticationBox
)
guard let statusID = response.value.status?.id else { return }
diff --git a/Mastodon/Scene/Thread/ThreadViewController.swift b/Mastodon/Scene/Thread/ThreadViewController.swift
index 7915df6e5..fc158919b 100644
--- a/Mastodon/Scene/Thread/ThreadViewController.swift
+++ b/Mastodon/Scene/Thread/ThreadViewController.swift
@@ -112,13 +112,12 @@ extension ThreadViewController {
@objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
guard case let .root(threadContext) = viewModel.root else { return }
- guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .reply(status: threadContext.status),
- authenticationBox: authenticationBox
+ authContext: viewModel.authContext
)
- coordinator.present(
+ _ = coordinator.present(
scene: .compose(viewModel: composeViewModel),
from: self,
transition: .modal(animated: true, completion: nil)
@@ -126,8 +125,10 @@ extension ThreadViewController {
}
}
-//// MARK: - StatusTableViewControllerAspect
-//extension ThreadViewController: StatusTableViewControllerAspect { }
+// MARK: - AuthContextProvider
+extension ThreadViewController: AuthContextProvider {
+ var authContext: AuthContext { viewModel.authContext }
+}
// MARK: - UITableViewDelegate
extension ThreadViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
@@ -178,7 +179,6 @@ extension ThreadViewController: UITableViewDelegate, AutoGenerateTableViewDelega
// MARK: - StatusTableViewCellDelegate
extension ThreadViewController: StatusTableViewCellDelegate { }
-
extension ThreadViewController {
override var keyCommands: [UIKeyCommand]? {
return navigationKeyCommands + statusNavigationKeyCommands
diff --git a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift
index a865dd8f0..7040818e9 100644
--- a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift
+++ b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift
@@ -23,6 +23,7 @@ extension ThreadViewModel {
tableView: tableView,
context: context,
configuration: StatusSection.Configuration(
+ authContext: authContext,
statusTableViewCellDelegate: statusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: nil,
filterContext: .thread,
diff --git a/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift b/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift
index 86fdc2111..4917aacb5 100644
--- a/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift
+++ b/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift
@@ -69,11 +69,7 @@ extension ThreadViewModel.LoadThreadState {
super.didEnter(from: previousState)
guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
- guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else {
- stateMachine.enter(Fail.self)
- return
- }
-
+
guard let threadContext = viewModel.threadContext else {
stateMachine.enter(Fail.self)
return
@@ -83,7 +79,7 @@ extension ThreadViewModel.LoadThreadState {
do {
let response = try await viewModel.context.apiService.statusContext(
statusID: threadContext.statusID,
- authenticationBox: authenticationBox
+ authenticationBox: viewModel.authContext.mastodonAuthenticationBox
)
await enter(state: NoMore.self)
diff --git a/Mastodon/Scene/Thread/ThreadViewModel.swift b/Mastodon/Scene/Thread/ThreadViewModel.swift
index 54c9d1599..735d85cd4 100644
--- a/Mastodon/Scene/Thread/ThreadViewModel.swift
+++ b/Mastodon/Scene/Thread/ThreadViewModel.swift
@@ -26,6 +26,7 @@ class ThreadViewModel {
// input
let context: AppContext
+ let authContext: AuthContext
let mastodonStatusThreadViewModel: MastodonStatusThreadViewModel
// let cellFrameCache = NSCache()
@@ -54,9 +55,11 @@ class ThreadViewModel {
init(
context: AppContext,
+ authContext: AuthContext,
optionalRoot: StatusItem.Thread?
) {
self.context = context
+ self.authContext = authContext
self.root = optionalRoot
self.mastodonStatusThreadViewModel = MastodonStatusThreadViewModel(context: context)
// self.rootNode = CurrentValueSubject(optionalStatus.flatMap { RootNode(domain: $0.domain, statusID: $0.id, replyToID: $0.inReplyToID) })
diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift
index c1e6d7abe..f368fa246 100644
--- a/Mastodon/Supporting Files/SceneDelegate.swift
+++ b/Mastodon/Supporting Files/SceneDelegate.swift
@@ -146,11 +146,11 @@ extension SceneDelegate {
if coordinator?.tabBarController.topMost is ComposeViewController {
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): composing…")
} else {
- if let authenticationBox = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value {
+ if let authContext = coordinator?.authContext {
let composeViewModel = ComposeViewModel(
context: AppContext.shared,
composeKind: .post,
- authenticationBox: authenticationBox
+ authContext: authContext
)
coordinator?.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): present compose scene")
diff --git a/MastodonSDK/Sources/CoreDataStack/Utility/ManagedObjectRecord.swift b/MastodonSDK/Sources/CoreDataStack/Utility/ManagedObjectRecord.swift
index ea087d894..4910145cf 100644
--- a/MastodonSDK/Sources/CoreDataStack/Utility/ManagedObjectRecord.swift
+++ b/MastodonSDK/Sources/CoreDataStack/Utility/ManagedObjectRecord.swift
@@ -30,3 +30,9 @@ public class ManagedObjectRecord: Hashable {
}
}
+
+extension Managed where Self: NSManagedObject {
+ public var asRecrod: ManagedObjectRecord {
+ return .init(objectID: objectID)
+ }
+}
diff --git a/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Notification.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Notification.swift
index 7b2ac57a1..38ed3aa5e 100644
--- a/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Notification.swift
+++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Notification.swift
@@ -1,6 +1,6 @@
//
// UserDefaults+Notification.swift
-// AppShared
+// MastodonCommon
//
// Created by Cirno MainasuK on 2021-10-9.
//
diff --git a/MastodonSDK/Sources/MastodonCore/AppSecret.swift b/MastodonSDK/Sources/MastodonCore/AppSecret.swift
index 59c7a7cb5..687cb6fca 100644
--- a/MastodonSDK/Sources/MastodonCore/AppSecret.swift
+++ b/MastodonSDK/Sources/MastodonCore/AppSecret.swift
@@ -1,6 +1,6 @@
//
// AppSecret.swift
-// MastodonCommon
+// MastodonCore
//
// Created by MainasuK Cirno on 2021-4-27.
//
diff --git a/MastodonSDK/Sources/MastodonCore/Service/AuthenticationService.swift b/MastodonSDK/Sources/MastodonCore/Service/AuthenticationService.swift
index 8d69c3558..afb4e63a9 100644
--- a/MastodonSDK/Sources/MastodonCore/Service/AuthenticationService.swift
+++ b/MastodonSDK/Sources/MastodonCore/Service/AuthenticationService.swift
@@ -23,10 +23,8 @@ public final class AuthenticationService: NSObject {
let mastodonAuthenticationFetchedResultsController: NSFetchedResultsController
// output
- public let mastodonAuthentications = CurrentValueSubject<[MastodonAuthentication], Never>([])
- public let mastodonAuthenticationBoxes = CurrentValueSubject<[MastodonAuthenticationBox], Never>([])
- public let activeMastodonAuthentication = CurrentValueSubject(nil)
- public let activeMastodonAuthenticationBox = CurrentValueSubject(nil)
+ @Published public var mastodonAuthentications: [ManagedObjectRecord] = []
+ @Published public var mastodonAuthenticationBoxes: [MastodonAuthenticationBox] = []
init(
managedObjectContext: NSManagedObjectContext,
@@ -53,38 +51,23 @@ public final class AuthenticationService: NSObject {
mastodonAuthenticationFetchedResultsController.delegate = self
// TODO: verify credentials for active authentication
-
- // bind data
- mastodonAuthentications
- .map { $0.sorted(by: { $0.activedAt > $1.activedAt }).first }
- .assign(to: \.value, on: activeMastodonAuthentication)
- .store(in: &disposeBag)
- mastodonAuthentications
+ $mastodonAuthentications
.map { authentications -> [MastodonAuthenticationBox] in
return authentications
+ .compactMap { $0.object(in: managedObjectContext) }
.sorted(by: { $0.activedAt > $1.activedAt })
.compactMap { authentication -> MastodonAuthenticationBox? in
- return MastodonAuthenticationBox(
- authenticationRecord: .init(objectID: authentication.objectID),
- domain: authentication.domain,
- userID: authentication.userID,
- appAuthorization: Mastodon.API.OAuth.Authorization(accessToken: authentication.appAccessToken),
- userAuthorization: Mastodon.API.OAuth.Authorization(accessToken: authentication.userAccessToken)
- )
+ return MastodonAuthenticationBox(authentication: authentication)
}
}
- .assign(to: \.value, on: mastodonAuthenticationBoxes)
- .store(in: &disposeBag)
-
- mastodonAuthenticationBoxes
- .map { $0.first }
- .assign(to: \.value, on: activeMastodonAuthenticationBox)
- .store(in: &disposeBag)
-
+ .assign(to: &$mastodonAuthenticationBoxes)
+
do {
try mastodonAuthenticationFetchedResultsController.performFetch()
- mastodonAuthentications.value = mastodonAuthenticationFetchedResultsController.fetchedObjects ?? []
+ mastodonAuthentications = mastodonAuthenticationFetchedResultsController.fetchedObjects?
+ .sorted(by: { $0.activedAt > $1.activedAt })
+ .compactMap { $0.asRecrod } ?? []
} catch {
assertionFailure(error.localizedDescription)
}
@@ -94,52 +77,28 @@ public final class AuthenticationService: NSObject {
extension AuthenticationService {
- public func activeMastodonUser(domain: String, userID: MastodonUser.ID) -> AnyPublisher, Never> {
+ public func activeMastodonUser(domain: String, userID: MastodonUser.ID) async throws -> Bool {
var isActive = false
var _mastodonAuthentication: MastodonAuthentication?
- return backgroundManagedObjectContext.performChanges { [weak self] in
- guard let self = self else { return }
-
+ let managedObjectContext = backgroundManagedObjectContext
+
+ try await managedObjectContext.performChanges {
let request = MastodonAuthentication.sortedFetchRequest
request.predicate = MastodonAuthentication.predicate(domain: domain, userID: userID)
request.fetchLimit = 1
- guard let mastodonAuthentication = try? self.backgroundManagedObjectContext.fetch(request).first else {
+ guard let mastodonAuthentication = try? managedObjectContext.fetch(request).first else {
return
}
mastodonAuthentication.update(activedAt: Date())
_mastodonAuthentication = mastodonAuthentication
isActive = true
+ }
- }
- .receive(on: DispatchQueue.main)
- .map { [weak self] result in
- switch result {
- case .success:
- if let self = self,
- let mastodonAuthentication = _mastodonAuthentication
- {
- // force set to avoid delay
- self.activeMastodonAuthentication.value = mastodonAuthentication
- self.activeMastodonAuthenticationBox.value = MastodonAuthenticationBox(
- authenticationRecord: .init(objectID: mastodonAuthentication.objectID),
- domain: mastodonAuthentication.domain,
- userID: mastodonAuthentication.userID,
- appAuthorization: Mastodon.API.OAuth.Authorization(accessToken: mastodonAuthentication.appAccessToken),
- userAuthorization: Mastodon.API.OAuth.Authorization(accessToken: mastodonAuthentication.userAccessToken)
- )
- }
- case .failure:
- break
- }
- return result.map { isActive }
- }
- .eraseToAnyPublisher()
+ return isActive
}
- public func signOutMastodonUser(
- authenticationBox: MastodonAuthenticationBox
- ) async throws {
+ public func signOutMastodonUser(authenticationBox: MastodonAuthenticationBox) async throws {
let managedObjectContext = backgroundManagedObjectContext
try await managedObjectContext.performChanges {
// remove Feed
@@ -176,7 +135,6 @@ extension AuthenticationService {
}
-
// MARK: - NSFetchedResultsControllerDelegate
extension AuthenticationService: NSFetchedResultsControllerDelegate {
@@ -185,10 +143,14 @@ extension AuthenticationService: NSFetchedResultsControllerDelegate {
}
public func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
- if controller === mastodonAuthenticationFetchedResultsController {
- mastodonAuthentications.value = mastodonAuthenticationFetchedResultsController.fetchedObjects ?? []
+ guard controller === mastodonAuthenticationFetchedResultsController else {
+ assertionFailure()
+ return
}
+
+ mastodonAuthentications = mastodonAuthenticationFetchedResultsController.fetchedObjects?
+ .sorted(by: { $0.activedAt > $1.activedAt })
+ .compactMap { $0.asRecrod } ?? []
}
}
-
diff --git a/MastodonSDK/Sources/MastodonCore/Service/BlockDomainService.swift b/MastodonSDK/Sources/MastodonCore/Service/BlockDomainService.swift
index c7b2c2333..02b8bdccd 100644
--- a/MastodonSDK/Sources/MastodonCore/Service/BlockDomainService.swift
+++ b/MastodonSDK/Sources/MastodonCore/Service/BlockDomainService.swift
@@ -14,6 +14,7 @@ import OSLog
import UIKit
public final class BlockDomainService {
+
// input
weak var backgroundManagedObjectContext: NSManagedObjectContext?
weak var authenticationService: AuthenticationService?
@@ -27,21 +28,21 @@ public final class BlockDomainService {
) {
self.backgroundManagedObjectContext = backgroundManagedObjectContext
self.authenticationService = authenticationService
- guard let authorizationBox = authenticationService.activeMastodonAuthenticationBox.value else { return }
- backgroundManagedObjectContext.perform {
- let _blockedDomains: [DomainBlock] = {
- let request = DomainBlock.sortedFetchRequest
- request.predicate = DomainBlock.predicate(domain: authorizationBox.domain, userID: authorizationBox.userID)
- request.returnsObjectsAsFaults = false
- do {
- return try backgroundManagedObjectContext.fetch(request)
- } catch {
- assertionFailure(error.localizedDescription)
- return []
- }
- }()
- self.blockedDomains.value = _blockedDomains.map(\.blockedDomain)
- }
+
+// backgroundManagedObjectContext.perform {
+// let _blockedDomains: [DomainBlock] = {
+// let request = DomainBlock.sortedFetchRequest
+// request.predicate = DomainBlock.predicate(domain: authorizationBox.domain, userID: authorizationBox.userID)
+// request.returnsObjectsAsFaults = false
+// do {
+// return try backgroundManagedObjectContext.fetch(request)
+// } catch {
+// assertionFailure(error.localizedDescription)
+// return []
+// }
+// }()
+// self.blockedDomains.value = _blockedDomains.map(\.blockedDomain)
+// }
}
// func blockDomain(
diff --git a/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift b/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift
index 7632704b0..c63e965bd 100644
--- a/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift
+++ b/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift
@@ -33,9 +33,9 @@ public final class InstanceService {
self.apiService = apiService
self.authenticationService = authenticationService
- authenticationService.activeMastodonAuthenticationBox
+ authenticationService.$mastodonAuthenticationBoxes
.receive(on: DispatchQueue.main)
- .compactMap { $0?.domain }
+ .compactMap { $0.first?.domain }
.removeDuplicates() // prevent infinity loop
.sink { [weak self] domain in
guard let self = self else { return }
diff --git a/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift b/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift
index fff84cd4e..18ff2e508 100644
--- a/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift
+++ b/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift
@@ -39,7 +39,7 @@ public final class NotificationService {
self.apiService = apiService
self.authenticationService = authenticationService
- authenticationService.mastodonAuthentications
+ authenticationService.$mastodonAuthentications
.sink(receiveValue: { [weak self] mastodonAuthentications in
guard let self = self else { return }
@@ -61,16 +61,16 @@ public final class NotificationService {
.store(in: &disposeBag)
Publishers.CombineLatest(
- authenticationService.mastodonAuthentications,
+ authenticationService.$mastodonAuthenticationBoxes,
applicationIconBadgeNeedsUpdate
)
.receive(on: DispatchQueue.main)
- .sink { [weak self] mastodonAuthentications, _ in
+ .sink { [weak self] mastodonAuthenticationBoxes, _ in
guard let self = self else { return }
var count = 0
- for authentication in mastodonAuthentications {
- count += UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken)
+ for authenticationBox in mastodonAuthenticationBoxes {
+ count += UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authenticationBox.userAuthorization.accessToken)
}
UserDefaults.shared.notificationBadgeCount = count
@@ -143,7 +143,7 @@ extension NotificationService {
extension NotificationService {
public func clearNotificationCountForActiveUser() {
guard let authenticationService = self.authenticationService else { return }
- if let accessToken = authenticationService.activeMastodonAuthentication.value?.userAccessToken {
+ if let accessToken = authenticationService.mastodonAuthenticationBoxes.first?.userAuthorization.accessToken {
UserDefaults.shared.setNotificationCountWithAccessToken(accessToken: accessToken, value: 0)
}
diff --git a/MastodonSDK/Sources/MastodonCore/Service/SettingService.swift b/MastodonSDK/Sources/MastodonCore/Service/SettingService.swift
index b0932450b..48c66baef 100644
--- a/MastodonSDK/Sources/MastodonCore/Service/SettingService.swift
+++ b/MastodonSDK/Sources/MastodonCore/Service/SettingService.swift
@@ -43,7 +43,7 @@ public final class SettingService {
)
// create setting (if non-exist) for authenticated users
- authenticationService.mastodonAuthenticationBoxes
+ authenticationService.$mastodonAuthenticationBoxes
.compactMap { [weak self] mastodonAuthenticationBoxes -> AnyPublisher<[MastodonAuthenticationBox], Never>? in
guard let self = self else { return nil }
guard let authenticationService = self.authenticationService else { return nil }
@@ -72,15 +72,15 @@ public final class SettingService {
// bind current setting
Publishers.CombineLatest(
- authenticationService.activeMastodonAuthenticationBox,
+ authenticationService.$mastodonAuthenticationBoxes,
settingFetchedResultController.settings
)
- .sink { [weak self] activeMastodonAuthenticationBox, settings in
+ .sink { [weak self] mastodonAuthenticationBoxes, settings in
guard let self = self else { return }
- guard let activeMastodonAuthenticationBox = activeMastodonAuthenticationBox else { return }
+ guard let activeMastodonAuthenticationBox = mastodonAuthenticationBoxes.first else { return }
let currentSetting = settings.first(where: { setting in
- return setting.domain == activeMastodonAuthenticationBox.domain &&
- setting.userID == activeMastodonAuthenticationBox.userID
+ return setting.domain == activeMastodonAuthenticationBox.domain
+ && setting.userID == activeMastodonAuthenticationBox.userID
})
self.currentSetting.value = currentSetting
}
@@ -114,13 +114,13 @@ public final class SettingService {
Publishers.CombineLatest3(
notificationService.deviceToken,
currentSetting.eraseToAnyPublisher(),
- authenticationService.activeMastodonAuthenticationBox
+ authenticationService.$mastodonAuthenticationBoxes
)
- .compactMap { [weak self] deviceToken, setting, activeMastodonAuthenticationBox -> AnyPublisher, Error>? in
+ .compactMap { [weak self] deviceToken, setting, mastodonAuthenticationBoxes -> AnyPublisher, Error>? in
guard let self = self else { return nil }
guard let deviceToken = deviceToken else { return nil }
guard let setting = setting else { return nil }
- guard let authenticationBox = activeMastodonAuthenticationBox else { return nil }
+ guard let authenticationBox = mastodonAuthenticationBoxes.first else { return nil }
guard let subscription = setting.activeSubscription else { return nil }
diff --git a/MastodonSDK/Sources/MastodonCore/Service/StatusFilterService.swift b/MastodonSDK/Sources/MastodonCore/Service/StatusFilterService.swift
index 92bb10def..e752a022e 100644
--- a/MastodonSDK/Sources/MastodonCore/Service/StatusFilterService.swift
+++ b/MastodonSDK/Sources/MastodonCore/Service/StatusFilterService.swift
@@ -44,13 +44,12 @@ public final class StatusFilterService {
.subscribe(filterUpdatePublisher)
.store(in: &disposeBag)
- let activeMastodonAuthenticationBox = authenticationService.activeMastodonAuthenticationBox
Publishers.CombineLatest(
- activeMastodonAuthenticationBox,
+ authenticationService.$mastodonAuthenticationBoxes,
filterUpdatePublisher
)
- .flatMap { box, _ -> AnyPublisher, Error>, Never> in
- guard let box = box else {
+ .flatMap { mastodonAuthenticationBoxes, _ -> AnyPublisher, Error>, Never> in
+ guard let box = mastodonAuthenticationBoxes.first else {
return Just(Result { throw APIService.APIError.implicit(.authenticationMissing) }).eraseToAnyPublisher()
}
return apiService.filters(mastodonAuthenticationBox: box)
diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift
index 974069801..032760983 100644
--- a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift
+++ b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift
@@ -24,7 +24,7 @@ extension NotificationView {
let logger = Logger(subsystem: "NotificationView", category: "ViewModel")
- @Published public var userIdentifier: UserIdentifier? // me
+ @Published public var authContext: AuthContext?
@Published public var notificationIndicatorText: MetaContent?
@@ -55,11 +55,11 @@ extension NotificationView.ViewModel {
bindAuthorMenu(notificationView: notificationView)
bindFollowRequest(notificationView: notificationView)
- $userIdentifier
- .assign(to: \.userIdentifier, on: notificationView.statusView.viewModel)
+ $authContext
+ .assign(to: \.authContext, on: notificationView.statusView.viewModel)
.store(in: &disposeBag)
- $userIdentifier
- .assign(to: \.userIdentifier, on: notificationView.quoteStatusView.viewModel)
+ $authContext
+ .assign(to: \.authContext, on: notificationView.quoteStatusView.viewModel)
.store(in: &disposeBag)
}
diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift
index cacb56a8a..2db731971 100644
--- a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift
+++ b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift
@@ -164,6 +164,8 @@ public final class NotificationView: UIView {
disposeBag.removeAll()
viewModel.objects.removeAll()
+
+ viewModel.authContext = nil
viewModel.authorAvatarImageURL = nil
avatarButton.avatarImageView.cancelTask()
diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift
index b6ea11d49..a91f57dc2 100644
--- a/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift
+++ b/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift
@@ -30,7 +30,7 @@ extension PollOptionView {
let layoutDidUpdate = PassthroughSubject()
- @Published public var userIdentifier: UserIdentifier?
+ @Published public var authContext: AuthContext?
@Published public var style: PollOptionView.Style?
diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift
index 648f256b6..cb542da7c 100644
--- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift
+++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift
@@ -9,14 +9,14 @@ import os.log
import UIKit
import Combine
import CoreData
-import Meta
-import MastodonSDK
-import MastodonCore
-import MastodonAsset
-import MastodonLocalization
-import MastodonExtension
-import MastodonCommon
import CoreDataStack
+import Meta
+import MastodonAsset
+import MastodonCore
+import MastodonCommon
+import MastodonExtension
+import MastodonLocalization
+import MastodonSDK
extension StatusView {
public final class ViewModel: ObservableObject {
@@ -26,7 +26,7 @@ extension StatusView {
let logger = Logger(subsystem: "StatusView", category: "ViewModel")
- @Published public var userIdentifier: UserIdentifier? // me
+ public var authContext: AuthContext?
// Header
@Published public var header: Header = .none
@@ -127,6 +127,8 @@ extension StatusView {
}
public func prepareForReuse() {
+ authContext = nil
+
authorAvatarImageURL = nil
isContentSensitive = false
diff --git a/Podfile.lock b/Podfile.lock
index 453610694..0cec6626a 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -37,6 +37,6 @@ SPEC CHECKSUMS:
"UITextField+Shake": 298ac5a0f239d731bdab999b19b628c956ca0ac3
XLPagerTabStrip: 61c57fd61f611ee5f01ff1495ad6fbee8bf496c5
-PODFILE CHECKSUM: d95968ab70ea5121c21dfd801aa36b12bcd59c9d
+PODFILE CHECKSUM: 50ec5b2c4aa189024cc5ab41039f983dc5609040
COCOAPODS: 1.11.3