Add JSON-based account-persistence (IOS-192)
This is per user. Also: Fetch authenticated accounts regularly Also: Move Persistence-stuff to MastodonCore because.
This commit is contained in:
parent
d3c7ba2c7c
commit
60aafe6330
@ -60,7 +60,6 @@
|
|||||||
2AE202AC297FE19100F66E55 /* FollowersCountIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE202AB297FE19100F66E55 /* FollowersCountIntentHandler.swift */; };
|
2AE202AC297FE19100F66E55 /* FollowersCountIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE202AB297FE19100F66E55 /* FollowersCountIntentHandler.swift */; };
|
||||||
2AE202AD297FE1CD00F66E55 /* WidgetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A72813E297EC762004138C5 /* WidgetExtension.swift */; };
|
2AE202AD297FE1CD00F66E55 /* WidgetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A72813E297EC762004138C5 /* WidgetExtension.swift */; };
|
||||||
2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */; };
|
2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */; };
|
||||||
2AF2E7BF2B19DC6E00D98917 /* FileManager+Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF2E7BE2B19DC6E00D98917 /* FileManager+Timeline.swift */; };
|
|
||||||
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; };
|
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; };
|
||||||
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.swift */; };
|
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.swift */; };
|
||||||
2D206B8625F5FB0900143C56 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B8525F5FB0900143C56 /* Double.swift */; };
|
2D206B8625F5FB0900143C56 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B8525F5FB0900143C56 /* Double.swift */; };
|
||||||
@ -162,8 +161,6 @@
|
|||||||
D886FBD329DF710F00272017 /* WelcomeSeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D886FBD229DF710F00272017 /* WelcomeSeparatorView.swift */; };
|
D886FBD329DF710F00272017 /* WelcomeSeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D886FBD229DF710F00272017 /* WelcomeSeparatorView.swift */; };
|
||||||
D8916DC029211BE500124085 /* ContentSizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8916DBF29211BE500124085 /* ContentSizedTableView.swift */; };
|
D8916DC029211BE500124085 /* ContentSizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8916DBF29211BE500124085 /* ContentSizedTableView.swift */; };
|
||||||
D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */; };
|
D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */; };
|
||||||
D8AC98762B0F61680045EC2B /* FileManager+SearchHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8AC98752B0F61680045EC2B /* FileManager+SearchHistory.swift */; };
|
|
||||||
D8AC98792B0F622B0045EC2B /* SearchHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8AC98782B0F622B0045EC2B /* SearchHistory.swift */; };
|
|
||||||
D8B5E4EE2A4EB8930008970C /* NotificationSettingTableViewToggleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */; };
|
D8B5E4EE2A4EB8930008970C /* NotificationSettingTableViewToggleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */; };
|
||||||
D8B5E4F02A4EB8A00008970C /* NotificationSettingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */; };
|
D8B5E4F02A4EB8A00008970C /* NotificationSettingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */; };
|
||||||
D8B5E4F22A4EBCF90008970C /* NotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */; };
|
D8B5E4F22A4EBCF90008970C /* NotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */; };
|
||||||
@ -694,7 +691,6 @@
|
|||||||
2AE202A9297FDDF500F66E55 /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = "<group>"; };
|
2AE202A9297FDDF500F66E55 /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||||
2AE202AB297FE19100F66E55 /* FollowersCountIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersCountIntentHandler.swift; sourceTree = "<group>"; };
|
2AE202AB297FE19100F66E55 /* FollowersCountIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersCountIntentHandler.swift; sourceTree = "<group>"; };
|
||||||
2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SFSymbols.swift"; sourceTree = "<group>"; };
|
2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SFSymbols.swift"; sourceTree = "<group>"; };
|
||||||
2AF2E7BE2B19DC6E00D98917 /* FileManager+Timeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Timeline.swift"; sourceTree = "<group>"; };
|
|
||||||
2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = "<group>"; };
|
2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = "<group>"; };
|
||||||
2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = "<group>"; };
|
2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = "<group>"; };
|
||||||
2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
|
2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
|
||||||
@ -833,8 +829,6 @@
|
|||||||
D8A6FE6429325F5900666A47 /* StringsConvertor */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = StringsConvertor; sourceTree = "<group>"; };
|
D8A6FE6429325F5900666A47 /* StringsConvertor */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = StringsConvertor; sourceTree = "<group>"; };
|
||||||
D8A6FE6529325F5900666A47 /* ios-infoPlist.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ios-infoPlist.json"; sourceTree = "<group>"; };
|
D8A6FE6529325F5900666A47 /* ios-infoPlist.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ios-infoPlist.json"; sourceTree = "<group>"; };
|
||||||
D8A6FE6629325F5900666A47 /* Localizable.stringsdict */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = "<group>"; };
|
D8A6FE6629325F5900666A47 /* Localizable.stringsdict */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
D8AC98752B0F61680045EC2B /* FileManager+SearchHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+SearchHistory.swift"; sourceTree = "<group>"; };
|
|
||||||
D8AC98782B0F622B0045EC2B /* SearchHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistory.swift; sourceTree = "<group>"; };
|
|
||||||
D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationSettingTableViewToggleCell.swift; sourceTree = "<group>"; };
|
D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationSettingTableViewToggleCell.swift; sourceTree = "<group>"; };
|
||||||
D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingTableViewCell.swift; sourceTree = "<group>"; };
|
D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettings.swift; sourceTree = "<group>"; };
|
D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettings.swift; sourceTree = "<group>"; };
|
||||||
@ -1892,21 +1886,10 @@
|
|||||||
D8AC98742B0F615E0045EC2B /* Persistence */ = {
|
D8AC98742B0F615E0045EC2B /* Persistence */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D8AC98772B0F62230045EC2B /* Model */,
|
|
||||||
D8AC98752B0F61680045EC2B /* FileManager+SearchHistory.swift */,
|
|
||||||
2AF2E7BE2B19DC6E00D98917 /* FileManager+Timeline.swift */,
|
|
||||||
);
|
);
|
||||||
path = Persistence;
|
path = Persistence;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D8AC98772B0F62230045EC2B /* Model */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D8AC98782B0F622B0045EC2B /* SearchHistory.swift */,
|
|
||||||
);
|
|
||||||
path = Model;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D8E5C347296DB896007E76A7 /* Edit History */ = {
|
D8E5C347296DB896007E76A7 /* Edit History */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -3856,7 +3839,6 @@
|
|||||||
2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */,
|
2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */,
|
||||||
DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */,
|
DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */,
|
||||||
DB697DD1278F4871004EF2F7 /* AutoGenerateTableViewDelegate.swift in Sources */,
|
DB697DD1278F4871004EF2F7 /* AutoGenerateTableViewDelegate.swift in Sources */,
|
||||||
D8AC98792B0F622B0045EC2B /* SearchHistory.swift in Sources */,
|
|
||||||
DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */,
|
DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */,
|
||||||
DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */,
|
DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */,
|
||||||
DB1FD44425F26CCC004CFCFC /* PickServerSection.swift in Sources */,
|
DB1FD44425F26CCC004CFCFC /* PickServerSection.swift in Sources */,
|
||||||
@ -3864,7 +3846,6 @@
|
|||||||
DB6180E626391B550018D199 /* MediaPreviewTransitionController.swift in Sources */,
|
DB6180E626391B550018D199 /* MediaPreviewTransitionController.swift in Sources */,
|
||||||
DB0FCB922796DE19006C02E2 /* TrendSectionHeaderCollectionReusableView.swift in Sources */,
|
DB0FCB922796DE19006C02E2 /* TrendSectionHeaderCollectionReusableView.swift in Sources */,
|
||||||
DB2F073525E8ECF000957B2D /* AuthenticationViewModel.swift in Sources */,
|
DB2F073525E8ECF000957B2D /* AuthenticationViewModel.swift in Sources */,
|
||||||
D8AC98762B0F61680045EC2B /* FileManager+SearchHistory.swift in Sources */,
|
|
||||||
DB63F779279ABF9C00455B82 /* DataSourceFacade+Reblog.swift in Sources */,
|
DB63F779279ABF9C00455B82 /* DataSourceFacade+Reblog.swift in Sources */,
|
||||||
DB4F0963269ED06300D62E92 /* SearchResultViewController.swift in Sources */,
|
DB4F0963269ED06300D62E92 /* SearchResultViewController.swift in Sources */,
|
||||||
DB603111279EB38500A935FE /* DataSourceFacade+Mute.swift in Sources */,
|
DB603111279EB38500A935FE /* DataSourceFacade+Mute.swift in Sources */,
|
||||||
@ -3969,7 +3950,6 @@
|
|||||||
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */,
|
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */,
|
||||||
D8318A802A4466D300C0FB73 /* SettingsCoordinator.swift in Sources */,
|
D8318A802A4466D300C0FB73 /* SettingsCoordinator.swift in Sources */,
|
||||||
DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */,
|
DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */,
|
||||||
2AF2E7BF2B19DC6E00D98917 /* FileManager+Timeline.swift in Sources */,
|
|
||||||
DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */,
|
DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */,
|
||||||
DB0F9D56283EB46200379AF8 /* ProfileHeaderView+Configuration.swift in Sources */,
|
DB0F9D56283EB46200379AF8 /* ProfileHeaderView+Configuration.swift in Sources */,
|
||||||
DB6746F0278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift in Sources */,
|
DB6746F0278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift in Sources */,
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
// Created by Marcus Kida on 17.11.22.
|
// Created by Marcus Kida on 17.11.22.
|
||||||
//
|
//
|
||||||
|
|
||||||
import CoreData
|
|
||||||
import CoreDataStack
|
|
||||||
import MastodonCore
|
import MastodonCore
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import MastodonCore
|
|
||||||
import MastodonSDK
|
|
||||||
|
|
||||||
extension Persistence.SearchHistory {
|
|
||||||
struct Item: Codable, Hashable, Equatable {
|
|
||||||
let updatedAt: Date
|
|
||||||
let userID: Mastodon.Entity.Account.ID
|
|
||||||
|
|
||||||
let account: Mastodon.Entity.Account?
|
|
||||||
let hashtag: Mastodon.Entity.Tag?
|
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
|
||||||
hasher.combine(userID)
|
|
||||||
hasher.combine(account)
|
|
||||||
hasher.combine(hashtag)
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func == (lhs: Persistence.SearchHistory.Item, rhs: Persistence.SearchHistory.Item) -> Bool {
|
|
||||||
return lhs.account == rhs.account && lhs.hashtag == rhs.hashtag && lhs.userID == rhs.userID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -39,21 +39,19 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
|
|||||||
break
|
break
|
||||||
case .reply:
|
case .reply:
|
||||||
guard let replyToAccountID = status.entity.inReplyToAccountID else { return }
|
guard let replyToAccountID = status.entity.inReplyToAccountID else { return }
|
||||||
#warning("TODO: Implement Domain")
|
await DataSourceFacade.coordinateToProfileScene(provider: self,
|
||||||
await DataSourceFacade.coordinateToProfileScene(provider: self,
|
domain: domain,
|
||||||
domain: "",
|
accountID: replyToAccountID)
|
||||||
accountID: replyToAccountID)
|
|
||||||
|
|
||||||
case .repost:
|
case .repost:
|
||||||
await DataSourceFacade.coordinateToProfileScene(
|
await DataSourceFacade.coordinateToProfileScene(
|
||||||
provider: self,
|
provider: self,
|
||||||
target: .reblog, // keep the wrapper for header author
|
target: .reblog, // keep the wrapper for header author
|
||||||
status: status
|
status: status
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - avatar button
|
// MARK: - avatar button
|
||||||
|
@ -92,6 +92,7 @@ extension HomeTimelineViewModel.LoadLatestState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
await AuthenticationServiceProvider.shared.fetchAccounts(apiService: viewModel.context.apiService)
|
||||||
let response = try await viewModel.context.apiService.homeTimeline(
|
let response = try await viewModel.context.apiService.homeTimeline(
|
||||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||||
)
|
)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import GameplayKit
|
import GameplayKit
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
import MastodonCore
|
||||||
|
|
||||||
extension HomeTimelineViewModel {
|
extension HomeTimelineViewModel {
|
||||||
class LoadOldestState: GKState {
|
class LoadOldestState: GKState {
|
||||||
@ -60,6 +61,8 @@ extension HomeTimelineViewModel.LoadOldestState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
await AuthenticationServiceProvider.shared.fetchAccounts(apiService: viewModel.context.apiService)
|
||||||
|
|
||||||
let response = try await viewModel.context.apiService.homeTimeline(
|
let response = try await viewModel.context.apiService.homeTimeline(
|
||||||
maxID: maxID,
|
maxID: maxID,
|
||||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||||
|
@ -147,7 +147,9 @@ extension HomeTimelineViewModel {
|
|||||||
// reconfigure item
|
// reconfigure item
|
||||||
snapshot.reconfigureItems([item])
|
snapshot.reconfigureItems([item])
|
||||||
await updateSnapshotUsingReloadData(snapshot: snapshot)
|
await updateSnapshotUsingReloadData(snapshot: snapshot)
|
||||||
|
|
||||||
|
await AuthenticationServiceProvider.shared.fetchAccounts(apiService: context.apiService)
|
||||||
|
|
||||||
// fetch data
|
// fetch data
|
||||||
let maxID = status.id
|
let maxID = status.id
|
||||||
_ = try? await context.apiService.homeTimeline(
|
_ = try? await context.apiService.homeTimeline(
|
||||||
|
@ -89,7 +89,7 @@ class MainTabBarController: UITabBarController {
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func viewController(context: AppContext, authContext: AuthContext?, coordinator: SceneCoordinator) async -> UIViewController {
|
func viewController(context: AppContext, authContext: AuthContext?, coordinator: SceneCoordinator) async -> UIViewController {
|
||||||
guard let authContext = authContext else {
|
guard let authContext, let me = authContext.mastodonAuthenticationBox.authentication.account() else {
|
||||||
return UITableViewController()
|
return UITableViewController()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +116,6 @@ class MainTabBarController: UITabBarController {
|
|||||||
_viewController.viewModel = .init(context: context, authContext: authContext)
|
_viewController.viewModel = .init(context: context, authContext: authContext)
|
||||||
viewController = _viewController
|
viewController = _viewController
|
||||||
case .me:
|
case .me:
|
||||||
let me = authContext.mastodonAuthenticationBox.authentication.account()
|
|
||||||
let _viewController = ProfileViewController()
|
let _viewController = ProfileViewController()
|
||||||
_viewController.context = context
|
_viewController.context = context
|
||||||
_viewController.coordinator = coordinator
|
_viewController.coordinator = coordinator
|
||||||
@ -133,7 +132,6 @@ class MainTabBarController: UITabBarController {
|
|||||||
private(set) var isReadyForWizardAvatarButton = false
|
private(set) var isReadyForWizardAvatarButton = false
|
||||||
|
|
||||||
// output
|
// output
|
||||||
var avatarURLObserver: AnyCancellable?
|
|
||||||
@Published var avatarURL: URL?
|
@Published var avatarURL: URL?
|
||||||
|
|
||||||
// haptic feedback
|
// haptic feedback
|
||||||
@ -268,28 +266,20 @@ extension MainTabBarController {
|
|||||||
NotificationCenter.default.publisher(for: .userFetched)
|
NotificationCenter.default.publisher(for: .userFetched)
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
if let user = self.authContext?.mastodonAuthenticationBox.authentication.user(in: self.context.managedObjectContext) {
|
if let account = self.authContext?.mastodonAuthenticationBox.authentication.account() {
|
||||||
self.avatarURLObserver = user.publisher(for: \.avatar)
|
self.avatarURL = account.avatarImageURL()
|
||||||
.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
|
// a11y
|
||||||
let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
|
let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
|
||||||
guard let profileTabItem = _profileTabItem else { return }
|
guard let profileTabItem = _profileTabItem else { return }
|
||||||
profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(user.displayNameWithFallback)
|
profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(account.displayNameWithFallback)
|
||||||
|
|
||||||
self.context.authenticationService.updateActiveUserAccountPublisher
|
self.context.authenticationService.updateActiveUserAccountPublisher
|
||||||
.sink { [weak self] in
|
.sink { [weak self] in
|
||||||
self?.updateUserAccount()
|
self?.updateUserAccount()
|
||||||
}
|
}
|
||||||
.store(in: &self.disposeBag)
|
.store(in: &self.disposeBag)
|
||||||
} else {
|
|
||||||
self.avatarURLObserver = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
@ -122,8 +122,6 @@ public class AppContext: ObservableObject {
|
|||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppContext {
|
extension AppContext {
|
||||||
|
@ -54,21 +54,21 @@ public extension AuthenticationServiceProvider {
|
|||||||
func getAuthentication(matching userAccessToken: String) -> MastodonAuthentication? {
|
func getAuthentication(matching userAccessToken: String) -> MastodonAuthentication? {
|
||||||
authentications.first(where: { $0.userAccessToken == userAccessToken })
|
authentications.first(where: { $0.userAccessToken == userAccessToken })
|
||||||
}
|
}
|
||||||
|
|
||||||
func authenticationSortedByActivation() -> [MastodonAuthentication] { // fixme: why do we need this?
|
func authenticationSortedByActivation() -> [MastodonAuthentication] { // fixme: why do we need this?
|
||||||
return authentications.sorted(by: { $0.activedAt > $1.activedAt })
|
return authentications.sorted(by: { $0.activedAt > $1.activedAt })
|
||||||
}
|
}
|
||||||
|
|
||||||
func restore() {
|
func restore() {
|
||||||
authentications = Self.keychain.allKeys().compactMap {
|
authentications = Self.keychain.allKeys().compactMap {
|
||||||
guard
|
guard
|
||||||
let encoded = Self.keychain[$0],
|
let encoded = Self.keychain[$0],
|
||||||
let data = Data(base64Encoded: encoded)
|
let data = Data(base64Encoded: encoded)
|
||||||
else { return nil }
|
else { return nil }
|
||||||
return try? JSONDecoder().decode(MastodonAuthentication.self, from: data)
|
return try? JSONDecoder().decode(MastodonAuthentication.self, from: data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateLegacyAuthentications(in context: NSManagedObjectContext) {
|
func migrateLegacyAuthentications(in context: NSManagedObjectContext) {
|
||||||
do {
|
do {
|
||||||
let legacyAuthentications = try context.fetch(MastodonAuthenticationLegacy.sortedFetchRequest)
|
let legacyAuthentications = try context.fetch(MastodonAuthenticationLegacy.sortedFetchRequest)
|
||||||
@ -101,10 +101,29 @@ public extension AuthenticationServiceProvider {
|
|||||||
logger.log(level: .error, "Could not migrate legacy authentications")
|
logger.log(level: .error, "Could not migrate legacy authentications")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var authenticationMigrationRequired: Bool {
|
var authenticationMigrationRequired: Bool {
|
||||||
userDefaults.didMigrateAuthentications == false
|
userDefaults.didMigrateAuthentications == false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchAccounts(apiService: APIService, completion: (() -> Void)? = nil) async {
|
||||||
|
// FIXME: This is a dirty hack to make the performance-stuff work.
|
||||||
|
// Problem is, that we don't persist the user on disk anymore. So we have to fetch
|
||||||
|
// it when we need it to display on the home timeline.
|
||||||
|
// We need this (also) for the Account-list, but it might be the wrong place. App Startup might be more appropriate
|
||||||
|
for authentication in authentications {
|
||||||
|
guard let account = try? await apiService.accountInfo(domain: authentication.domain,
|
||||||
|
userID: authentication.userID,
|
||||||
|
authorization: Mastodon.API.OAuth.Authorization(accessToken: authentication.userAccessToken)).value else { continue }
|
||||||
|
|
||||||
|
FileManager.default.store(account: account, forUserID: authentication.userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .userFetched, object: nil)
|
||||||
|
|
||||||
|
completion?()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
@ -10,6 +10,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
import MastodonCore
|
||||||
|
|
||||||
final public class FeedFetchedResultsController {
|
final public class FeedFetchedResultsController {
|
||||||
|
|
||||||
@ -80,15 +81,16 @@ final public class FeedFetchedResultsController {
|
|||||||
private extension FeedFetchedResultsController {
|
private extension FeedFetchedResultsController {
|
||||||
func load(kind: MastodonFeed.Kind, sinceId: MastodonStatus.ID?) async throws -> [MastodonFeed] {
|
func load(kind: MastodonFeed.Kind, sinceId: MastodonStatus.ID?) async throws -> [MastodonFeed] {
|
||||||
switch kind {
|
switch kind {
|
||||||
case .home:
|
case .home:
|
||||||
return try await context.apiService.homeTimeline(sinceID: sinceId, authenticationBox: authContext.mastodonAuthenticationBox)
|
await context.authenticationService.authenticationServiceProvider.fetchAccounts(apiService: context.apiService)
|
||||||
.value.map { .fromStatus(.fromEntity($0), kind: .home) }
|
return try await context.apiService.homeTimeline(sinceID: sinceId, authenticationBox: authContext.mastodonAuthenticationBox)
|
||||||
case .notificationAll:
|
.value.map { .fromStatus(.fromEntity($0), kind: .home) }
|
||||||
return try await context.apiService.notifications(maxID: nil, scope: .everything, authenticationBox: authContext.mastodonAuthenticationBox)
|
case .notificationAll:
|
||||||
.value.map { .fromNotification($0, kind: .notificationAll) }
|
return try await context.apiService.notifications(maxID: nil, scope: .everything, authenticationBox: authContext.mastodonAuthenticationBox)
|
||||||
case .notificationMentions:
|
.value.map { .fromNotification($0, kind: .notificationAll) }
|
||||||
return try await context.apiService.notifications(maxID: nil, scope: .mentions, authenticationBox: authContext.mastodonAuthenticationBox)
|
case .notificationMentions:
|
||||||
.value.map { .fromNotification($0, kind: .notificationMentions) }
|
return try await context.apiService.notifications(maxID: nil, scope: .mentions, authenticationBox: authContext.mastodonAuthenticationBox)
|
||||||
|
.value.map { .fromNotification($0, kind: .notificationMentions) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,10 +99,10 @@ public struct MastodonAuthentication: Codable, Hashable {
|
|||||||
return MastodonUser.findOrFetch(in: context, matching: userPredicate)
|
return MastodonUser.findOrFetch(in: context, matching: userPredicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func account() -> Mastodon.Entity.Account {
|
public func account() -> Mastodon.Entity.Account? {
|
||||||
// store accounts
|
let account = FileManager.default.accounts(forUserID: userID).first(where: { $0.id == userID })
|
||||||
#warning("TODO: Implement")
|
|
||||||
return Mastodon.Entity.Account.placeholder()
|
return account
|
||||||
}
|
}
|
||||||
|
|
||||||
func updating(instance: Instance) -> Self {
|
func updating(instance: Instance) -> Self {
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
extension FileManager {
|
||||||
|
public func store(account: Mastodon.Entity.Account, forUserID userID: String) {
|
||||||
|
// store accounts for each loged in user
|
||||||
|
var accounts = accounts(forUserID: userID)
|
||||||
|
|
||||||
|
if let index = accounts.firstIndex(of: account) {
|
||||||
|
accounts.remove(at: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts.append(account)
|
||||||
|
|
||||||
|
storeJSON(accounts, userID: userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func accounts(forUserID userID: String) -> [Mastodon.Entity.Account] {
|
||||||
|
guard let documentsDirectory else { return [] }
|
||||||
|
|
||||||
|
let accountPath = Persistence.accounts(userID: userID).filepath(baseURL: documentsDirectory)
|
||||||
|
|
||||||
|
guard let data = try? Data(contentsOf: accountPath) else { return [] }
|
||||||
|
|
||||||
|
let jsonDecoder = JSONDecoder()
|
||||||
|
jsonDecoder.dateDecodingStrategy = .iso8601
|
||||||
|
|
||||||
|
do {
|
||||||
|
let accounts = try jsonDecoder.decode([Mastodon.Entity.Account].self, from: data)
|
||||||
|
return accounts
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func storeJSON(_ encodable: Encodable, userID: String) {
|
||||||
|
guard let documentsDirectory else { return }
|
||||||
|
|
||||||
|
let jsonEncoder = JSONEncoder()
|
||||||
|
jsonEncoder.dateEncodingStrategy = .iso8601
|
||||||
|
do {
|
||||||
|
let data = try jsonEncoder.encode(encodable)
|
||||||
|
|
||||||
|
let accountsPath = Persistence.accounts(userID: userID).filepath(baseURL: documentsDirectory)
|
||||||
|
try data.write(to: accountsPath)
|
||||||
|
} catch {
|
||||||
|
debugPrint(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,11 +4,11 @@ import Foundation
|
|||||||
import MastodonCore
|
import MastodonCore
|
||||||
|
|
||||||
extension FileManager {
|
extension FileManager {
|
||||||
func searchItems(forUser userID: String) throws -> [Persistence.SearchHistory.Item] {
|
public func searchItems(forUser userID: String) throws -> [Persistence.SearchHistory.Item] {
|
||||||
return try searchItems().filter { $0.userID == userID }
|
return try searchItems().filter { $0.userID == userID }
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchItems() throws -> [Persistence.SearchHistory.Item] {
|
public func searchItems() throws -> [Persistence.SearchHistory.Item] {
|
||||||
guard let documentsDirectory else { return [] }
|
guard let documentsDirectory else { return [] }
|
||||||
|
|
||||||
let searchHistoryPath = Persistence.searchHistory.filepath(baseURL: documentsDirectory)
|
let searchHistoryPath = Persistence.searchHistory.filepath(baseURL: documentsDirectory)
|
||||||
@ -28,9 +28,7 @@ extension FileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSearchItem(_ newSearchItem: Persistence.SearchHistory.Item) throws {
|
public func addSearchItem(_ newSearchItem: Persistence.SearchHistory.Item) throws {
|
||||||
guard let documentsDirectory else { return }
|
|
||||||
|
|
||||||
var searchItems = (try? searchItems()) ?? []
|
var searchItems = (try? searchItems()) ?? []
|
||||||
|
|
||||||
if let index = searchItems.firstIndex(of: newSearchItem) {
|
if let index = searchItems.firstIndex(of: newSearchItem) {
|
||||||
@ -58,10 +56,8 @@ extension FileManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeSearchHistory(forUser userID: String) {
|
public func removeSearchHistory(forUser userID: String) {
|
||||||
guard let documentsDirectory else { return }
|
let searchItems = (try? searchItems()) ?? []
|
||||||
|
|
||||||
var searchItems = (try? searchItems()) ?? []
|
|
||||||
let newSearchItems = searchItems.filter { $0.userID != userID }
|
let newSearchItems = searchItems.filter { $0.userID != userID }
|
||||||
|
|
||||||
storeJSON(newSearchItems, .searchHistory)
|
storeJSON(newSearchItems, .searchHistory)
|
@ -1,22 +1,21 @@
|
|||||||
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import MastodonCore
|
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
|
||||||
extension FileManager {
|
extension FileManager {
|
||||||
private static let cacheItemsLimit: Int = 100 // max number of items to cache
|
private static let cacheItemsLimit: Int = 100 // max number of items to cache
|
||||||
|
|
||||||
// Retrieve
|
// Retrieve
|
||||||
func cachedHomeTimeline(for userId: UserIdentifier) throws -> [MastodonStatus] {
|
public func cachedHomeTimeline(for userId: UserIdentifier) throws -> [MastodonStatus] {
|
||||||
try cached(timeline: .homeTimeline(userId)).map(MastodonStatus.fromEntity)
|
try cached(timeline: .homeTimeline(userId)).map(MastodonStatus.fromEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cachedNotificationsAll(for userId: UserIdentifier) throws -> [Mastodon.Entity.Notification] {
|
public func cachedNotificationsAll(for userId: UserIdentifier) throws -> [Mastodon.Entity.Notification] {
|
||||||
try cached(timeline: .notificationsAll(userId))
|
try cached(timeline: .notificationsAll(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func cachedNotificationsMentions(for userId: UserIdentifier) throws -> [Mastodon.Entity.Notification] {
|
public func cachedNotificationsMentions(for userId: UserIdentifier) throws -> [Mastodon.Entity.Notification] {
|
||||||
try cached(timeline: .notificationsMentions(userId))
|
try cached(timeline: .notificationsMentions(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,15 +37,15 @@ extension FileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
func cacheHomeTimeline(items: [MastodonStatus], for userIdentifier: UserIdentifier) {
|
public func cacheHomeTimeline(items: [MastodonStatus], for userIdentifier: UserIdentifier) {
|
||||||
cache(items.map { $0.entity }, timeline: .homeTimeline(userIdentifier))
|
cache(items.map { $0.entity }, timeline: .homeTimeline(userIdentifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
func cacheNotificationsAll(items: [Mastodon.Entity.Notification], for userIdentifier: UserIdentifier) {
|
public func cacheNotificationsAll(items: [Mastodon.Entity.Notification], for userIdentifier: UserIdentifier) {
|
||||||
cache(items, timeline: .notificationsAll(userIdentifier))
|
cache(items, timeline: .notificationsAll(userIdentifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
func cacheNotificationsMentions(items: [Mastodon.Entity.Notification], for userIdentifier: UserIdentifier) {
|
public func cacheNotificationsMentions(items: [Mastodon.Entity.Notification], for userIdentifier: UserIdentifier) {
|
||||||
cache(items, timeline: .notificationsMentions(userIdentifier))
|
cache(items, timeline: .notificationsMentions(userIdentifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,15 +70,15 @@ extension FileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
func invalidateHomeTimelineCache(for userId: UserIdentifier) {
|
public func invalidateHomeTimelineCache(for userId: UserIdentifier) {
|
||||||
invalidate(timeline: .homeTimeline(userId))
|
invalidate(timeline: .homeTimeline(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func invalidateNotificationsAll(for userId: UserIdentifier) {
|
public func invalidateNotificationsAll(for userId: UserIdentifier) {
|
||||||
invalidate(timeline: .notificationsAll(userId))
|
invalidate(timeline: .notificationsAll(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func invalidateNotificationsMentions(for userId: UserIdentifier) {
|
public func invalidateNotificationsMentions(for userId: UserIdentifier) {
|
||||||
invalidate(timeline: .notificationsMentions(userId))
|
invalidate(timeline: .notificationsMentions(userId))
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
extension Persistence.SearchHistory {
|
||||||
|
public struct Item: Codable, Hashable, Equatable {
|
||||||
|
public let updatedAt: Date
|
||||||
|
public let userID: Mastodon.Entity.Account.ID
|
||||||
|
|
||||||
|
public let account: Mastodon.Entity.Account?
|
||||||
|
public let hashtag: Mastodon.Entity.Tag?
|
||||||
|
|
||||||
|
public init(updatedAt: Date, userID: Mastodon.Entity.Account.ID, account: Mastodon.Entity.Account?, hashtag: Mastodon.Entity.Tag?) {
|
||||||
|
self.updatedAt = updatedAt
|
||||||
|
self.userID = userID
|
||||||
|
self.account = account
|
||||||
|
self.hashtag = hashtag
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
hasher.combine(userID)
|
||||||
|
hasher.combine(account)
|
||||||
|
hasher.combine(hashtag)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func == (lhs: Persistence.SearchHistory.Item, rhs: Persistence.SearchHistory.Item) -> Bool {
|
||||||
|
return lhs.account == rhs.account && lhs.hashtag == rhs.hashtag && lhs.userID == rhs.userID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,12 @@ public enum Persistence {
|
|||||||
case homeTimeline(UserIdentifier)
|
case homeTimeline(UserIdentifier)
|
||||||
case notificationsMentions(UserIdentifier)
|
case notificationsMentions(UserIdentifier)
|
||||||
case notificationsAll(UserIdentifier)
|
case notificationsAll(UserIdentifier)
|
||||||
|
case accounts(userID: String)
|
||||||
|
|
||||||
|
private func uniqueUserDomainIdentifier(for userIdentifier: UserIdentifier) -> String {
|
||||||
|
"\(userIdentifier.userID)@\(userIdentifier.domain)"
|
||||||
|
}
|
||||||
|
|
||||||
private var filename: String {
|
private var filename: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .searchHistory:
|
case .searchHistory:
|
||||||
@ -23,7 +28,9 @@ public enum Persistence {
|
|||||||
case let .notificationsMentions(userIdentifier):
|
case let .notificationsMentions(userIdentifier):
|
||||||
return "notifications_mentions_\(userIdentifier.uniqueUserDomainIdentifier)"
|
return "notifications_mentions_\(userIdentifier.uniqueUserDomainIdentifier)"
|
||||||
case let .notificationsAll(userIdentifier):
|
case let .notificationsAll(userIdentifier):
|
||||||
return "notifications_all_\(userIdentifier.uniqueUserDomainIdentifier)"
|
return "notifications_all_\(uniqueUserDomainIdentifier(for: userIdentifier))"
|
||||||
|
case .accounts(let userID):
|
||||||
|
return "account_\(userID)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,29 +34,6 @@ extension APIService {
|
|||||||
authorization: authorization
|
authorization: authorization
|
||||||
).singleOutput()
|
).singleOutput()
|
||||||
|
|
||||||
let managedObjectContext = self.backgroundManagedObjectContext
|
|
||||||
try await managedObjectContext.performChanges {
|
|
||||||
let me = authenticationBox.authentication.user(in: managedObjectContext)
|
|
||||||
|
|
||||||
for entity in response.value {
|
|
||||||
let result = Persistence.MastodonUser.createOrMerge(
|
|
||||||
in: managedObjectContext,
|
|
||||||
context: Persistence.MastodonUser.PersistContext(
|
|
||||||
domain: domain,
|
|
||||||
entity: entity,
|
|
||||||
cache: nil,
|
|
||||||
networkDate: response.networkDate
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if let me = me {
|
|
||||||
let user = result.user
|
|
||||||
user.update(isFollowing: true, by: me)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ extension APIService {
|
|||||||
limit: limit,
|
limit: limit,
|
||||||
local: local
|
local: local
|
||||||
)
|
)
|
||||||
|
|
||||||
let response = try await Mastodon.API.Timeline.home(
|
let response = try await Mastodon.API.Timeline.home(
|
||||||
session: session,
|
session: session,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
@ -54,18 +54,6 @@ extension APIService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This is a dirty hack to make the performance-stuff work.
|
|
||||||
// Problem is, that we don't persist the user on disk anymore. So we have to fetch
|
|
||||||
// it when we need it to display on the home timeline.
|
|
||||||
// We need this (also) for the Account-list, but it might be the wrong place. App Startup might be more appropriate
|
|
||||||
for authentication in AuthenticationServiceProvider.shared.authentications {
|
|
||||||
_ = try? await accountInfo(domain: authentication.domain,
|
|
||||||
userID: authentication.userID,
|
|
||||||
authorization: Mastodon.API.OAuth.Authorization(accessToken: authentication.userAccessToken)).value
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationCenter.default.post(name: .userFetched, object: nil)
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,13 @@ public final class AuthenticationService: NSObject {
|
|||||||
|
|
||||||
// output
|
// output
|
||||||
@Published public var mastodonAuthenticationBoxes: [MastodonAuthenticationBox] = []
|
@Published public var mastodonAuthenticationBoxes: [MastodonAuthenticationBox] = []
|
||||||
|
|
||||||
private func fetchFollowedBlockedUserIds(
|
private func fetchFollowedBlockedUserIds(
|
||||||
_ authBox: MastodonAuthenticationBox,
|
_ authBox: MastodonAuthenticationBox,
|
||||||
_ previousFollowingIDs: [String]? = nil,
|
_ previousFollowingIDs: [String]? = nil,
|
||||||
_ maxID: String? = nil
|
_ maxID: String? = nil
|
||||||
) async throws {
|
) async throws {
|
||||||
guard let apiService = apiService else { return }
|
guard let apiService else { return }
|
||||||
|
|
||||||
let followingResponse = try await fetchFollowing(maxID, apiService, authBox)
|
let followingResponse = try await fetchFollowing(maxID, apiService, authBox)
|
||||||
let followingIds = (previousFollowingIDs ?? []) + followingResponse.ids
|
let followingIds = (previousFollowingIDs ?? []) + followingResponse.ids
|
||||||
|
Loading…
x
Reference in New Issue
Block a user