forked from zelo72/mastodon-ios
feat: add spam and other reason report flow path
This commit is contained in:
parent
2ef6345d83
commit
a88bb763fb
|
@ -24,6 +24,12 @@ class ReportViewController: UIViewController, NeedsDependency, ReportViewControl
|
||||||
|
|
||||||
var viewModel: ReportViewModel!
|
var viewModel: ReportViewModel!
|
||||||
|
|
||||||
|
lazy var cancelBarButtonItem = UIBarButtonItem(
|
||||||
|
barButtonSystemItem: .cancel,
|
||||||
|
target: self,
|
||||||
|
action: #selector(ReportViewController.cancelBarButtonItemDidPressed(_:))
|
||||||
|
)
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||||
}
|
}
|
||||||
|
@ -38,6 +44,8 @@ extension ReportViewController {
|
||||||
setupAppearance()
|
setupAppearance()
|
||||||
defer { setupNavigationBarBackgroundView() }
|
defer { setupNavigationBarBackgroundView() }
|
||||||
|
|
||||||
|
navigationItem.rightBarButtonItem = cancelBarButtonItem
|
||||||
|
|
||||||
viewModel.reportReasonViewModel.delegate = self
|
viewModel.reportReasonViewModel.delegate = self
|
||||||
viewModel.reportServerRulesViewModel.delegate = self
|
viewModel.reportServerRulesViewModel.delegate = self
|
||||||
viewModel.reportStatusViewModel.delegate = self
|
viewModel.reportStatusViewModel.delegate = self
|
||||||
|
@ -62,6 +70,14 @@ extension ReportViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ReportViewController {
|
||||||
|
|
||||||
|
@objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) {
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||||
extension ReportViewController: UIAdaptivePresentationControllerDelegate {
|
extension ReportViewController: UIAdaptivePresentationControllerDelegate {
|
||||||
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
|
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
|
||||||
|
@ -74,14 +90,21 @@ extension ReportViewController: ReportReasonViewControllerDelegate {
|
||||||
func reportReasonViewController(_ viewController: ReportReasonViewController, nextButtonPressed button: UIButton) {
|
func reportReasonViewController(_ viewController: ReportReasonViewController, nextButtonPressed button: UIButton) {
|
||||||
guard let reason = viewController.viewModel.selectReason else { return }
|
guard let reason = viewController.viewModel.selectReason else { return }
|
||||||
switch reason {
|
switch reason {
|
||||||
|
case .dislike:
|
||||||
|
// TODO:
|
||||||
|
break
|
||||||
case .violateRule:
|
case .violateRule:
|
||||||
coordinator.present(
|
coordinator.present(
|
||||||
scene: .reportServerRules(viewModel: viewModel.reportServerRulesViewModel),
|
scene: .reportServerRules(viewModel: viewModel.reportServerRulesViewModel),
|
||||||
from: self,
|
from: self,
|
||||||
transition: .show
|
transition: .show
|
||||||
)
|
)
|
||||||
default:
|
case .spam, .other:
|
||||||
break
|
coordinator.present(
|
||||||
|
scene: .reportStatus(viewModel: viewModel.reportStatusViewModel),
|
||||||
|
from: self,
|
||||||
|
transition: .show
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +113,7 @@ extension ReportViewController: ReportReasonViewControllerDelegate {
|
||||||
extension ReportViewController: ReportServerRulesViewControllerDelegate {
|
extension ReportViewController: ReportServerRulesViewControllerDelegate {
|
||||||
func reportServerRulesViewController(_ viewController: ReportServerRulesViewController, nextButtonPressed button: UIButton) {
|
func reportServerRulesViewController(_ viewController: ReportServerRulesViewController, nextButtonPressed button: UIButton) {
|
||||||
if viewController.viewModel.isDislike {
|
if viewController.viewModel.isDislike {
|
||||||
|
// TODO:
|
||||||
} else if viewController.viewModel.selectRule != nil {
|
} else if viewController.viewModel.selectRule != nil {
|
||||||
coordinator.present(
|
coordinator.present(
|
||||||
scene: .reportStatus(viewModel: viewModel.reportStatusViewModel),
|
scene: .reportStatus(viewModel: viewModel.reportStatusViewModel),
|
||||||
|
|
|
@ -104,6 +104,9 @@ extension ReportViewModel {
|
||||||
let managedObjectContext = context.managedObjectContext
|
let managedObjectContext = context.managedObjectContext
|
||||||
let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform {
|
let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform {
|
||||||
guard let user = self.user.object(in: managedObjectContext) else { return nil }
|
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]? = {
|
let statusIDs: [Status.ID]? = {
|
||||||
if self.reportStatusViewModel.isSkip {
|
if self.reportStatusViewModel.isSkip {
|
||||||
let _id: Status.ID? = self.reportStatusViewModel.status.flatMap { record -> Status.ID? in
|
let _id: Status.ID? = self.reportStatusViewModel.status.flatMap { record -> Status.ID? in
|
||||||
|
@ -118,10 +121,15 @@ extension ReportViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// the user comment is essential step in report flow
|
||||||
|
// only check isSkip or not
|
||||||
let comment: String? = {
|
let comment: String? = {
|
||||||
var suffixes: [String] = []
|
var suffixes: [String] = []
|
||||||
let content: 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 {
|
if let reason = self.reportReasonViewModel.selectReason {
|
||||||
switch reason {
|
switch reason {
|
||||||
case .spam:
|
case .spam:
|
||||||
|
@ -130,9 +138,12 @@ extension ReportViewModel {
|
||||||
suffixes.append(reason.rawValue)
|
suffixes.append(reason.rawValue)
|
||||||
if let rule = self.reportServerRulesViewModel.selectRule {
|
if let rule = self.reportServerRulesViewModel.selectRule {
|
||||||
suffixes.append(rule.text)
|
suffixes.append(rule.text)
|
||||||
|
} else {
|
||||||
|
assertionFailure("should select valid rule")
|
||||||
}
|
}
|
||||||
|
case .dislike:
|
||||||
case .dislike, .other:
|
assertionFailure("should not enter the report flow")
|
||||||
|
case .other:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,11 +173,14 @@ extension ReportViewModel {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
isReporting = true
|
isReporting = true
|
||||||
|
#if DEBUG
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
// let _ = try await context.apiService.report(
|
#else
|
||||||
// query: query,
|
let _ = try await context.apiService.report(
|
||||||
// authenticationBox: authenticationBox
|
query: query,
|
||||||
// )
|
authenticationBox: authenticationBox
|
||||||
|
)
|
||||||
|
#endif
|
||||||
isReportSuccess = true
|
isReportSuccess = true
|
||||||
} catch {
|
} catch {
|
||||||
isReporting = false
|
isReporting = false
|
||||||
|
|
|
@ -30,12 +30,6 @@ final class ReportReasonViewController: UIViewController, NeedsDependency, Repor
|
||||||
var viewModel: ReportReasonViewModel!
|
var viewModel: ReportReasonViewModel!
|
||||||
private(set) lazy var reportReasonView = ReportReasonView(viewModel: viewModel)
|
private(set) lazy var reportReasonView = ReportReasonView(viewModel: viewModel)
|
||||||
|
|
||||||
lazy var cancelBarButtonItem = UIBarButtonItem(
|
|
||||||
barButtonSystemItem: .cancel,
|
|
||||||
target: self,
|
|
||||||
action: #selector(ReportReasonViewController.cancelBarButtonItemDidPressed(_:))
|
|
||||||
)
|
|
||||||
|
|
||||||
let navigationActionView: NavigationActionView = {
|
let navigationActionView: NavigationActionView = {
|
||||||
let navigationActionView = NavigationActionView()
|
let navigationActionView = NavigationActionView()
|
||||||
navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color
|
navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color
|
||||||
|
@ -57,8 +51,6 @@ extension ReportReasonViewController {
|
||||||
setupAppearance()
|
setupAppearance()
|
||||||
defer { setupNavigationBarBackgroundView() }
|
defer { setupNavigationBarBackgroundView() }
|
||||||
|
|
||||||
navigationItem.rightBarButtonItem = cancelBarButtonItem
|
|
||||||
|
|
||||||
let hostingViewController = UIHostingController(rootView: reportReasonView)
|
let hostingViewController = UIHostingController(rootView: reportReasonView)
|
||||||
hostingViewController.view.preservesSuperviewLayoutMargins = true
|
hostingViewController.view.preservesSuperviewLayoutMargins = true
|
||||||
addChild(hostingViewController)
|
addChild(hostingViewController)
|
||||||
|
@ -102,10 +94,6 @@ extension ReportReasonViewController {
|
||||||
|
|
||||||
extension ReportReasonViewController {
|
extension ReportReasonViewController {
|
||||||
|
|
||||||
@objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) {
|
|
||||||
dismiss(animated: true, completion: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func nextButtonPressed(_ sender: UIButton) {
|
@objc private func nextButtonPressed(_ sender: UIButton) {
|
||||||
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,8 @@ extension ReportSupplementaryViewController {
|
||||||
.sink { [weak self] isBusy in
|
.sink { [weak self] isBusy in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.navigationItem.rightBarButtonItem = isBusy ? self.activityIndicatorBarButtonItem : self.cancelBarButtonItem
|
self.navigationItem.rightBarButtonItem = isBusy ? self.activityIndicatorBarButtonItem : self.cancelBarButtonItem
|
||||||
|
self.navigationItem.hidesBackButton = isBusy
|
||||||
|
self.navigationActionView.backButton.isUserInteractionEnabled = !isBusy
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,12 @@ class ReportSupplementaryViewModel {
|
||||||
self.user = user
|
self.user = user
|
||||||
// end init
|
// end init
|
||||||
|
|
||||||
commentContext.$comment
|
Publishers.CombineLatest(
|
||||||
.map { comment -> Bool in
|
commentContext.$comment,
|
||||||
|
$isBusy
|
||||||
|
)
|
||||||
|
.map { comment, isBusy -> Bool in
|
||||||
|
guard !isBusy else { return false }
|
||||||
return !comment.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
return !comment.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||||
}
|
}
|
||||||
.assign(to: &$isNextButtonEnabled)
|
.assign(to: &$isNextButtonEnabled)
|
||||||
|
|
Loading…
Reference in New Issue