User UserIdentification for search and accounts (IOS-192)
Thanks to @kimar!
This commit is contained in:
parent
2a14e293e9
commit
460ede4852
|
@ -27,7 +27,7 @@ extension DataSourceFacade {
|
||||||
hashtag: nil
|
hashtag: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
try? FileManager.default.addSearchItem(searchEntry)
|
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
|
||||||
case .hashtag(let tag):
|
case .hashtag(let tag):
|
||||||
|
|
||||||
let now = Date()
|
let now = Date()
|
||||||
|
@ -39,7 +39,7 @@ extension DataSourceFacade {
|
||||||
hashtag: tag
|
hashtag: tag
|
||||||
)
|
)
|
||||||
|
|
||||||
try? FileManager.default.addSearchItem(searchEntry)
|
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
|
||||||
case .status:
|
case .status:
|
||||||
break
|
break
|
||||||
case .user(_):
|
case .user(_):
|
||||||
|
|
|
@ -139,30 +139,23 @@ class MastodonLoginViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
@objc func login() {
|
@objc func login() {
|
||||||
guard let server = viewModel.selectedServer else { return }
|
guard let server = viewModel.selectedServer else { return }
|
||||||
|
|
||||||
authenticationViewModel
|
authenticationViewModel
|
||||||
.authenticated
|
.authenticated.sink { (domain, account) in
|
||||||
.asyncMap { domain, user -> Result<Mastodon.Entity.Account, Error> in
|
Task {
|
||||||
do {
|
do {
|
||||||
let result = try await self.context.authenticationService.activeMastodonUser(domain: domain, userID: user.id)
|
_ = try await self.context.authenticationService.activeMastodonUser(domain: domain, userID: account.id)
|
||||||
return .success(user)
|
FileManager.default.store(account: account, forUserID: MastodonUserIdentifier(domain: domain, userID: account.id))
|
||||||
} catch {
|
Task { @MainActor in
|
||||||
return .failure(error)
|
self.coordinator.setup()
|
||||||
}
|
}
|
||||||
}
|
} catch {
|
||||||
.receive(on: DispatchQueue.main)
|
assertionFailure(error.localizedDescription)
|
||||||
.sink { [weak self] result in
|
}
|
||||||
guard let self = self else { return }
|
|
||||||
switch result {
|
|
||||||
case .failure(let error):
|
|
||||||
assertionFailure(error.localizedDescription)
|
|
||||||
case .success(let account):
|
|
||||||
FileManager.default.store(account: account, forUserID: account.id)
|
|
||||||
self.coordinator.setup()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
authenticationViewModel.isAuthenticating.send(true)
|
authenticationViewModel.isAuthenticating.send(true)
|
||||||
context.apiService.createApplication(domain: server.domain)
|
context.apiService.createApplication(domain: server.domain)
|
||||||
.tryMap { response -> AuthenticationViewModel.AuthenticateInfo in
|
.tryMap { response -> AuthenticationViewModel.AuthenticateInfo in
|
||||||
|
|
|
@ -50,8 +50,7 @@ extension SearchHistoryViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
let userID = authContext.mastodonAuthenticationBox.userID
|
viewModel.items = (try? FileManager.default.searchItems(for: authContext.mastodonAuthenticationBox)) ?? []
|
||||||
viewModel.items = (try? FileManager.default.searchItems(forUser: userID)) ?? []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,9 +102,7 @@ extension SearchHistoryViewController: SearchHistorySectionHeaderCollectionReusa
|
||||||
_ searchHistorySectionHeaderCollectionReusableView: SearchHistorySectionHeaderCollectionReusableView,
|
_ searchHistorySectionHeaderCollectionReusableView: SearchHistorySectionHeaderCollectionReusableView,
|
||||||
clearButtonDidPressed button: UIButton
|
clearButtonDidPressed button: UIButton
|
||||||
) {
|
) {
|
||||||
let userID = authContext.mastodonAuthenticationBox.userID
|
FileManager.default.removeSearchHistory(for: authContext.mastodonAuthenticationBox)
|
||||||
|
|
||||||
FileManager.default.removeSearchHistory(forUser: userID)
|
|
||||||
viewModel.items = []
|
viewModel.items = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +110,6 @@ extension SearchHistoryViewController: SearchHistorySectionHeaderCollectionReusa
|
||||||
//MARK: - SearchResultOverviewCoordinatorDelegate
|
//MARK: - SearchResultOverviewCoordinatorDelegate
|
||||||
extension SearchHistoryViewController: SearchResultOverviewCoordinatorDelegate {
|
extension SearchHistoryViewController: SearchResultOverviewCoordinatorDelegate {
|
||||||
func newSearchHistoryItemAdded(_ coordinator: SearchResultOverviewCoordinator) {
|
func newSearchHistoryItemAdded(_ coordinator: SearchResultOverviewCoordinator) {
|
||||||
let userID = authContext.mastodonAuthenticationBox.userID
|
viewModel.items = (try? FileManager.default.searchItems(for: authContext.mastodonAuthenticationBox)) ?? []
|
||||||
viewModel.items = (try? FileManager.default.searchItems(forUser: userID)) ?? []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ final class SearchHistoryViewModel {
|
||||||
init(context: AppContext, authContext: AuthContext) {
|
init(context: AppContext, authContext: AuthContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.authContext = authContext
|
self.authContext = authContext
|
||||||
self.items = (try? FileManager.default.searchItems(forUser: authContext.mastodonAuthenticationBox.userID)) ?? []
|
self.items = (try? FileManager.default.searchItems(for: authContext.mastodonAuthenticationBox)) ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ public extension AuthenticationServiceProvider {
|
||||||
userID: authentication.userID,
|
userID: authentication.userID,
|
||||||
authorization: Mastodon.API.OAuth.Authorization(accessToken: authentication.userAccessToken)).value else { continue }
|
authorization: Mastodon.API.OAuth.Authorization(accessToken: authentication.userAccessToken)).value else { continue }
|
||||||
|
|
||||||
FileManager.default.store(account: account, forUserID: authentication.userID)
|
FileManager.default.store(account: account, forUserID: authentication.userIdentifier())
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationCenter.default.post(name: .userFetched, object: nil)
|
NotificationCenter.default.post(name: .userFetched, object: nil)
|
||||||
|
|
|
@ -100,11 +100,19 @@ public struct MastodonAuthentication: Codable, Hashable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func account() -> Mastodon.Entity.Account? {
|
public func account() -> Mastodon.Entity.Account? {
|
||||||
let account = FileManager.default.accounts(forUserID: userID).first(where: { $0.id == userID })
|
|
||||||
|
let account = FileManager
|
||||||
|
.default
|
||||||
|
.accounts(for: self.userIdentifier())
|
||||||
|
.first(where: { $0.id == userID })
|
||||||
|
|
||||||
return account
|
return account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func userIdentifier() -> MastodonUserIdentifier {
|
||||||
|
MastodonUserIdentifier(domain: domain, userID: userID)
|
||||||
|
}
|
||||||
|
|
||||||
func updating(instance: Instance) -> Self {
|
func updating(instance: Instance) -> Self {
|
||||||
copy(instanceObjectIdURI: instance.objectID.uriRepresentation())
|
copy(instanceObjectIdURI: instance.objectID.uriRepresentation())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
|
||||||
extension FileManager {
|
public extension FileManager {
|
||||||
public func store(account: Mastodon.Entity.Account, forUserID userID: String) {
|
func store(account: Mastodon.Entity.Account, forUserID userID: UserIdentifier) {
|
||||||
// store accounts for each loged in user
|
var accounts = accounts(for: userID)
|
||||||
var accounts = accounts(forUserID: userID)
|
|
||||||
|
|
||||||
if let index = accounts.firstIndex(of: account) {
|
if let index = accounts.firstIndex(of: account) {
|
||||||
accounts.remove(at: index)
|
accounts.remove(at: index)
|
||||||
|
@ -17,10 +16,10 @@ extension FileManager {
|
||||||
storeJSON(accounts, userID: userID)
|
storeJSON(accounts, userID: userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func accounts(forUserID userID: String) -> [Mastodon.Entity.Account] {
|
func accounts(for userId: UserIdentifier) -> [Mastodon.Entity.Account] {
|
||||||
guard let documentsDirectory else { return [] }
|
guard let documentsDirectory else { return [] }
|
||||||
|
|
||||||
let accountPath = Persistence.accounts(userID: userID).filepath(baseURL: documentsDirectory)
|
let accountPath = Persistence.accounts(userId).filepath(baseURL: documentsDirectory)
|
||||||
|
|
||||||
guard let data = try? Data(contentsOf: accountPath) else { return [] }
|
guard let data = try? Data(contentsOf: accountPath) else { return [] }
|
||||||
|
|
||||||
|
@ -35,8 +34,10 @@ extension FileManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func storeJSON(_ encodable: Encodable, userID: String) {
|
private extension FileManager {
|
||||||
|
private func storeJSON(_ encodable: Encodable, userID: UserIdentifier) {
|
||||||
guard let documentsDirectory else { return }
|
guard let documentsDirectory else { return }
|
||||||
|
|
||||||
let jsonEncoder = JSONEncoder()
|
let jsonEncoder = JSONEncoder()
|
||||||
|
@ -44,7 +45,7 @@ extension FileManager {
|
||||||
do {
|
do {
|
||||||
let data = try jsonEncoder.encode(encodable)
|
let data = try jsonEncoder.encode(encodable)
|
||||||
|
|
||||||
let accountsPath = Persistence.accounts(userID: userID).filepath(baseURL: documentsDirectory)
|
let accountsPath = Persistence.accounts( userID).filepath(baseURL: documentsDirectory)
|
||||||
try data.write(to: accountsPath)
|
try data.write(to: accountsPath)
|
||||||
} catch {
|
} catch {
|
||||||
debugPrint(error.localizedDescription)
|
debugPrint(error.localizedDescription)
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import MastodonCore
|
|
||||||
|
|
||||||
extension FileManager {
|
public extension FileManager {
|
||||||
public func searchItems(forUser userID: String) throws -> [Persistence.SearchHistory.Item] {
|
func searchItems(for userId: UserIdentifier) throws -> [Persistence.SearchHistory.Item] {
|
||||||
return try searchItems().filter { $0.userID == userID }
|
|
||||||
}
|
|
||||||
|
|
||||||
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(userId).filepath(baseURL: documentsDirectory)
|
||||||
|
|
||||||
guard let data = try? Data(contentsOf: searchHistoryPath) else { return [] }
|
guard let data = try? Data(contentsOf: searchHistoryPath) else { return [] }
|
||||||
|
|
||||||
|
@ -28,16 +23,23 @@ extension FileManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func addSearchItem(_ newSearchItem: Persistence.SearchHistory.Item) throws {
|
func addSearchItem(_ newSearchItem: Persistence.SearchHistory.Item, for userId: UserIdentifier) throws {
|
||||||
var searchItems = (try? searchItems()) ?? []
|
var searchItems = (try? searchItems(for: userId)) ?? []
|
||||||
|
|
||||||
if let index = searchItems.firstIndex(of: newSearchItem) {
|
if let index = searchItems.firstIndex(of: newSearchItem) {
|
||||||
searchItems.remove(at: index)
|
searchItems.remove(at: index)
|
||||||
}
|
}
|
||||||
|
|
||||||
searchItems.append(newSearchItem)
|
searchItems.append(newSearchItem)
|
||||||
|
|
||||||
storeJSON(searchItems, .searchHistory)
|
storeJSON(searchItems, .searchHistory(userId))
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeSearchHistory(for userId: UserIdentifier) {
|
||||||
|
let searchItems = (try? searchItems(for: userId)) ?? []
|
||||||
|
let newSearchItems = searchItems.filter { $0.userID != userId.userID }
|
||||||
|
|
||||||
|
storeJSON(newSearchItems, .searchHistory(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func storeJSON(_ encodable: Encodable, _ persistence: Persistence) {
|
private func storeJSON(_ encodable: Encodable, _ persistence: Persistence) {
|
||||||
|
@ -53,13 +55,5 @@ extension FileManager {
|
||||||
} catch {
|
} catch {
|
||||||
debugPrint(error.localizedDescription)
|
debugPrint(error.localizedDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public func removeSearchHistory(forUser userID: String) {
|
|
||||||
let searchItems = (try? searchItems()) ?? []
|
|
||||||
let newSearchItems = searchItems.filter { $0.userID != userID }
|
|
||||||
|
|
||||||
storeJSON(newSearchItems, .searchHistory)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum Persistence {
|
public enum Persistence {
|
||||||
case searchHistory
|
case searchHistory(UserIdentifier)
|
||||||
case homeTimeline(UserIdentifier)
|
case homeTimeline(UserIdentifier)
|
||||||
case notificationsMentions(UserIdentifier)
|
case notificationsMentions(UserIdentifier)
|
||||||
case notificationsAll(UserIdentifier)
|
case notificationsAll(UserIdentifier)
|
||||||
case accounts(userID: String)
|
case accounts(UserIdentifier)
|
||||||
|
|
||||||
private func uniqueUserDomainIdentifier(for userIdentifier: UserIdentifier) -> String {
|
private func uniqueUserDomainIdentifier(for userIdentifier: UserIdentifier) -> String {
|
||||||
"\(userIdentifier.userID)@\(userIdentifier.domain)"
|
"\(userIdentifier.userID)@\(userIdentifier.domain)"
|
||||||
|
@ -21,16 +21,16 @@ public enum Persistence {
|
||||||
|
|
||||||
private var filename: String {
|
private var filename: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .searchHistory:
|
case .searchHistory(let userIdentifier):
|
||||||
return "search_history" // todo: @zeitschlag should this be user-scoped as well?
|
return "search_history_\(uniqueUserDomainIdentifier(for: userIdentifier))" // todo: @zeitschlag should this be user-scoped as well?
|
||||||
case let .homeTimeline(userIdentifier):
|
case let .homeTimeline(userIdentifier):
|
||||||
return "home_timeline_\(userIdentifier.uniqueUserDomainIdentifier)"
|
return "home_timeline_\(uniqueUserDomainIdentifier(for: userIdentifier))"
|
||||||
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_\(uniqueUserDomainIdentifier(for: userIdentifier))"
|
return "notifications_all_\(uniqueUserDomainIdentifier(for: userIdentifier))"
|
||||||
case .accounts(let userID):
|
case .accounts(let userIdentifier):
|
||||||
return "account_\(userID)"
|
return "account_\(uniqueUserDomainIdentifier(for: userIdentifier))"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue