Kurdtvs-Live-Kurdish-TV-Kur.../Mastodon/Scene/Report/Report/ReportViewModel.swift

191 lines
6.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ReportViewModel.swift
// Mastodon
//
// Created by ihugo on 2021/4/19.
//
import Combine
import CoreData
import CoreDataStack
import Foundation
import GameplayKit
import MastodonSDK
import OrderedCollections
import os.log
import UIKit
class ReportViewModel {
var disposeBag = Set<AnyCancellable>()
let reportReasonViewModel: ReportReasonViewModel
let reportServerRulesViewModel: ReportServerRulesViewModel
let reportStatusViewModel: ReportStatusViewModel
let reportSupplementaryViewModel: ReportSupplementaryViewModel
// input
let context: AppContext
let user: ManagedObjectRecord<MastodonUser>
let status: ManagedObjectRecord<Status>?
// output
@Published var isReporting = false
@Published var isReportSuccess = false
init(
context: AppContext,
user: ManagedObjectRecord<MastodonUser>,
status: ManagedObjectRecord<Status>?
) {
self.context = context
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)
// end init
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
return
}
// setup reason viewModel
if status != nil {
// TODO: i18n
reportReasonViewModel.headline = "Whats wrong with post?"
} else {
Task { @MainActor in
let managedObjectContext = context.managedObjectContext
let _username: String? = try? await managedObjectContext.perform {
let user = user.object(in: managedObjectContext)
return user?.acctWithDomain
}
if let username = _username {
reportReasonViewModel.headline = "Whats wrong with @\(username)?"
} else {
reportReasonViewModel.headline = "Whats wrong with this account?"
}
} // end Task
}
// bind server rules
Task { @MainActor in
do {
let response = try await context.apiService.instance(domain: authenticationBox.domain)
.timeout(3, scheduler: DispatchQueue.main)
.singleOutput()
let rules = response.value.rules ?? []
reportReasonViewModel.serverRules = rules
reportServerRulesViewModel.serverRules = rules
} catch {
reportReasonViewModel.serverRules = []
reportServerRulesViewModel.serverRules = []
}
} // end Task
$isReporting
.assign(to: &reportSupplementaryViewModel.$isBusy)
}
}
extension ReportViewModel {
@MainActor
func report() async throws {
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value,
!isReporting
else {
assertionFailure()
return
}
let managedObjectContext = context.managedObjectContext
let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform {
guard let user = self.user.object(in: managedObjectContext) else { return nil }
// the status picker is essential step in report flow
// only check isSkip or not
let statusIDs: [Status.ID]? = {
if self.reportStatusViewModel.isSkip {
let _id: Status.ID? = self.reportStatusViewModel.status.flatMap { record -> Status.ID? in
guard let status = record.object(in: managedObjectContext) else { return nil }
return status.id
}
return _id.flatMap { [$0] }
} else {
return self.reportStatusViewModel.selectStatuses.compactMap { record -> Status.ID? in
guard let status = record.object(in: managedObjectContext) else { return nil }
return status.id
}
}
}()
// the user comment is essential step in report flow
// only check isSkip or not
let comment: String? = {
var suffixes: [String] = []
let content: String?
// the server rules is NOT essential step in report flow
// append suffix depends which reason
if let reason = self.reportReasonViewModel.selectReason {
switch reason {
case .spam:
suffixes.append(reason.rawValue)
case .violateRule:
suffixes.append(reason.rawValue)
if let rule = self.reportServerRulesViewModel.selectRule {
suffixes.append(rule.text)
} else {
assertionFailure("should select valid rule")
}
case .dislike:
assertionFailure("should not enter the report flow")
case .other:
break
}
}
content = self.reportSupplementaryViewModel.isSkip ? nil : self.reportSupplementaryViewModel.commentContext.comment
let suffix: String? = {
let text = suffixes.joined(separator: ". ")
guard !text.isEmpty else { return nil }
return "<" + text + ">"
}()
let comment = [content, suffix]
.compactMap { $0 }
.joined(separator: " ")
return comment.isEmpty ? nil : comment
}()
return Mastodon.API.Reports.FileReportQuery(
accountID: user.id,
statusIDs: statusIDs,
comment: comment,
forward: true
)
}
guard let query = _query else { return }
do {
isReporting = true
#if DEBUG
try await Task.sleep(nanoseconds: .second * 3)
#else
let _ = try await context.apiService.report(
query: query,
authenticationBox: authenticationBox
)
#endif
isReportSuccess = true
} catch {
isReporting = false
throw error
}
}
}