mastodon-ios/MastodonSDK/Sources/MastodonCore/Service/SettingService.swift

150 lines
6.2 KiB
Swift

//
// SettingService.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-4-25.
//
import UIKit
import Combine
import CoreDataStack
import MastodonSDK
import MastodonAsset
import MastodonLocalization
import MastodonCommon
public final class SettingService {
var disposeBag = Set<AnyCancellable>()
// input
weak var apiService: APIService?
weak var authenticationService: AuthenticationService?
weak var notificationService: NotificationService?
// output
let settingFetchedResultController: SettingFetchedResultController
public let currentSetting = CurrentValueSubject<Setting?, Never>(nil)
init(
apiService: APIService,
authenticationService: AuthenticationService,
notificationService: NotificationService
) {
self.apiService = apiService
self.authenticationService = authenticationService
self.notificationService = notificationService
self.settingFetchedResultController = SettingFetchedResultController(
managedObjectContext: authenticationService.managedObjectContext,
additionalPredicate: nil
)
// create setting (if non-exist) for authenticated users
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 }
let managedObjectContext = authenticationService.backgroundManagedObjectContext
return managedObjectContext.performChanges {
for authenticationBox in mastodonAuthenticationBoxes {
let domain = authenticationBox.domain
let userID = authenticationBox.userID
_ = APIService.CoreData.createOrMergeSetting(
into: managedObjectContext,
property: Setting.Property(
domain: domain,
userID: userID
)
)
} // end for
}
.map { _ in mastodonAuthenticationBoxes }
.eraseToAnyPublisher()
}
.sink { _ in
// do nothing
}
.store(in: &disposeBag)
// bind current setting
Publishers.CombineLatest(
authenticationService.$mastodonAuthenticationBoxes,
settingFetchedResultController.settings
)
.sink { [weak self] mastodonAuthenticationBoxes, settings in
guard let self = self 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
})
self.currentSetting.value = currentSetting
}
.store(in: &disposeBag)
Publishers.CombineLatest3(
notificationService.deviceToken,
currentSetting.eraseToAnyPublisher(),
authenticationService.$mastodonAuthenticationBoxes
)
.compactMap { [weak self] deviceToken, setting, mastodonAuthenticationBoxes -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Subscription>, 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 = mastodonAuthenticationBoxes.first else { return nil }
guard let subscription = setting.activeSubscription else { return nil }
guard setting.domain == authenticationBox.domain,
setting.userID == authenticationBox.userID else { return nil }
let _viewModel = self.notificationService?.dequeueNotificationViewModel(
mastodonAuthenticationBox: authenticationBox
)
guard let viewModel = _viewModel else { return nil }
let queryData = Mastodon.API.Subscriptions.QueryData(
policy: subscription.policy,
alerts: Mastodon.API.Subscriptions.QueryData.Alerts(
favourite: subscription.alert.favourite,
follow: subscription.alert.follow,
reblog: subscription.alert.reblog,
mention: subscription.alert.mention,
poll: subscription.alert.poll
)
)
let query = viewModel.createSubscribeQuery(
deviceToken: deviceToken,
queryData: queryData,
mastodonAuthenticationBox: authenticationBox
)
return apiService.createSubscription(
subscriptionObjectID: subscription.objectID,
query: query,
mastodonAuthenticationBox: authenticationBox
)
}
.debounce(for: .seconds(3), scheduler: DispatchQueue.main) // limit subscribe request emit time interval
.sink(receiveValue: { _ in
})
.store(in: &disposeBag)
}
}
extension SettingService {
public static func openSettingsAlertController(title: String, message: String) -> UIAlertController {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let settingAction = UIAlertAction(title: L10n.Common.Controls.Actions.settings, style: .default) { _ in
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
alertController.addAction(settingAction)
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel, handler: nil)
alertController.addAction(cancelAction)
return alertController
}
}