Skip to content
Snippets Groups Projects
Commit 88f47a45 authored by Bruno Muniz's avatar Bruno Muniz :apple:
Browse files

Finished adding report to group

parent a9fc1b33
No related branches found
No related tags found
3 merge requests!71Releasing v1.1.5 (214),!69Implemented filtering for banned/blocked users and reporting,!67v1.1.5 b(203)
import HUD
import UIKit
import Theme
import Models
......@@ -6,8 +7,10 @@ import Combine
import XXModels
import Voxophone
import ChatLayout
import Integration
import DrawerFeature
import DifferenceKit
import ReportingFeature
import ChatInputFeature
import DependencyInjection
......@@ -19,7 +22,11 @@ typealias OutgoingFailedGroupTextCell = CollectionCell<FlexibleSpace, StackMessa
typealias OutgoingFailedGroupReplyCell = CollectionCell<FlexibleSpace, ReplyStackMessageView>
public final class GroupChatController: UIViewController {
@Dependency private var hud: HUD
@Dependency private var session: SessionType
@Dependency private var coordinator: ChatCoordinating
@Dependency private var makeReportDrawer: MakeReportDrawer
@Dependency private var makeAppScreenshot: MakeAppScreenshot
@Dependency private var statusBarController: StatusBarStyleControlling
private let members: MembersController
......@@ -176,6 +183,17 @@ public final class GroupChatController: UIViewController {
}
}.store(in: &cancellables)
viewModel.hudPublisher
.receive(on: DispatchQueue.main)
.sink { [hud] in hud.update(with: $0) }
.store(in: &cancellables)
viewModel.reportPopupPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] contact in
presentReportDrawer(contact)
}.store(in: &cancellables)
viewModel.messages
.receive(on: DispatchQueue.main)
.sink { [unowned self] sections in
......@@ -229,6 +247,19 @@ public final class GroupChatController: UIViewController {
coordinator.toMembersList(members, from: self)
}
private func presentReportDrawer(_ contact: Contact) {
var config = MakeReportDrawer.Config()
config.onReport = { [weak self] in
guard let self = self else { return }
let screenshot = try! self.makeAppScreenshot()
self.viewModel.report(contact: contact, screenshot: screenshot) {
self.collectionView.reloadData()
}
}
let drawer = makeReportDrawer(config)
coordinator.toDrawer(drawer, from: self)
}
private func makeWaitingRoundDrawer() -> UIViewController {
let text = DrawerText(
font: Fonts.Mulish.semiBold.font(size: 14.0),
......@@ -332,8 +363,7 @@ extension GroupChatController: UICollectionViewDataSource {
var isSenderBanned = false
if let database = try? DependencyInjection.Container.shared.resolve() as Database,
let sender = try? database.fetchContacts(.init(id: [item.senderId])).first {
if let sender = try? session.dbManager.fetchContacts(.init(id: [item.senderId])).first {
isSenderBanned = sender.isBanned
}
......@@ -568,6 +598,10 @@ extension GroupChatController: UICollectionViewDelegate {
self?.viewModel.didRequestDelete([item])
}
let report = UIAction(title: Localized.Chat.BubbleMenu.report, state: .off) { [weak self] _ in
self?.viewModel.didRequestReport(item)
}
let retry = UIAction(title: Localized.Chat.BubbleMenu.retry, state: .off) { [weak self] _ in
self?.viewModel.retry(item)
}
......@@ -579,7 +613,7 @@ extension GroupChatController: UICollectionViewDelegate {
} else if item.status == .sending {
menu = UIMenu(title: "", children: [copy])
} else {
menu = UIMenu(title: "", children: [copy, reply, delete])
menu = UIMenu(title: "", children: [copy, reply, delete, report])
}
return menu
......
import HUD
import UIKit
import Models
import Shared
import Combine
import XXModels
import Defaults
import Foundation
import Integration
import ToastFeature
import DifferenceKit
import ReportingFeature
import DependencyInjection
enum GroupChatNavigationRoutes: Equatable {
......@@ -14,6 +19,18 @@ enum GroupChatNavigationRoutes: Equatable {
final class GroupChatViewModel {
@Dependency private var session: SessionType
@Dependency private var sendReport: SendReport
@Dependency private var toastController: ToastController
@KeyObject(.username, defaultValue: nil) var username: String?
var hudPublisher: AnyPublisher<HUDStatus, Never> {
hudSubject.eraseToAnyPublisher()
}
var reportPopupPublisher: AnyPublisher<Contact, Never> {
reportPopupSubject.eraseToAnyPublisher()
}
var replyPublisher: AnyPublisher<(String, String), Never> {
replySubject.eraseToAnyPublisher()
......@@ -26,11 +43,13 @@ final class GroupChatViewModel {
let info: GroupInfo
private var stagedReply: Reply?
private var cancellables = Set<AnyCancellable>()
private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none)
private let reportPopupSubject = PassthroughSubject<Contact, Never>()
private let replySubject = PassthroughSubject<(String, String), Never>()
private let routesSubject = PassthroughSubject<GroupChatNavigationRoutes, Never>()
var messages: AnyPublisher<[ArraySection<ChatSection, Message>], Never> {
session.dbManager.fetchMessagesPublisher(.init(chat: .group(info.group.id), isSenderBanned: false))
session.dbManager.fetchMessagesPublisher(.init(chat: .group(info.group.id)))
.assertNoFailure()
.map { messages -> [ArraySection<ChatSection, Message>] in
let groupedByDate = Dictionary(grouping: messages) { domainModel -> Date in
......@@ -63,6 +82,12 @@ final class GroupChatViewModel {
_ = try? session.dbManager.deleteMessages(.init(id: Set(messages.map(\.id))))
}
func didRequestReport(_ message: Message) {
if let contact = try? session.dbManager.fetchContacts(.init(id: [message.senderId])).first {
reportPopupSubject.send(contact)
}
}
func send(_ text: String) {
session.send(.init(
text: text.trimmingCharacters(in: .whitespacesAndNewlines),
......@@ -117,4 +142,57 @@ final class GroupChatViewModel {
stagedReply = Reply(messageId: networkId, senderId: message.senderId)
replySubject.send(getReplyContent(for: networkId))
}
func report(contact: Contact, screenshot: UIImage, completion: @escaping () -> Void) {
let report = Report(
sender: .init(
userId: contact.id.base64EncodedString(),
username: contact.username!
),
recipient: .init(
userId: session.myId.base64EncodedString(),
username: username!
),
type: .group,
screenshot: screenshot.pngData()!,
partyName: info.group.name,
partyBlob: info.group.id.base64EncodedString(),
partyMembers: info.members.map { Report.ReportUser(
userId: $0.id.base64EncodedString(),
username: $0.username ?? "")
}
)
hudSubject.send(.on)
sendReport(report) { result in
switch result {
case .failure(let error):
DispatchQueue.main.async {
self.hudSubject.send(.error(.init(with: error)))
}
case .success(_):
self.blockContact(contact)
DispatchQueue.main.async {
self.hudSubject.send(.none)
self.presentReportConfirmation(contact: contact)
completion()
}
}
}
}
private func blockContact(_ contact: Contact) {
var contact = contact
contact.isBlocked = true
_ = try? session.dbManager.saveContact(contact)
}
private func presentReportConfirmation(contact: Contact) {
let name = (contact.nickname ?? contact.username) ?? "the contact"
toastController.enqueueToast(model: .init(
title: "Your report has been sent and \(name) is now blocked.",
leftImage: Asset.requestSentToaster.image
))
}
}
......@@ -139,15 +139,11 @@ final class ChatListViewModel {
),
groupChatInfoQuery: GroupChatInfo.Query(
authStatus: [.participating],
isLeaderBlocked: false,
isLeaderBanned: false,
excludeBannedContactsMessages: true
),
groupQuery: Group.Query(
withMessages: false,
authStatus: [.participating],
isLeaderBlocked: false,
isLeaderBanned: false
authStatus: [.participating]
)
))
.assertNoFailure()
......
......@@ -53,7 +53,7 @@ extension Session {
recipientId: nil,
groupId: group.id,
date: group.createdAt,
status: .received,
status: .sent,
isUnread: false,
text: welcome,
replyMessageId: nil,
......
......@@ -5,18 +5,27 @@ public struct Report: Encodable {
sender: ReportUser,
recipient: ReportUser,
type: ReportType,
screenshot: Data
screenshot: Data,
partyName: String? = nil,
partyBlob: String? = nil,
partyMembers: [ReportUser]? = nil
) {
self.sender = sender
self.recipient = recipient
self.type = type
self.screenshot = screenshot
self.partyName = partyName
self.partyBlob = partyBlob
self.partyMembers = partyMembers
}
public var sender: ReportUser
public var recipient: ReportUser
public var type: ReportType
public var screenshot: Data
public var partyName: String?
public var partyBlob: String?
public var partyMembers: [ReportUser]?
}
extension Report {
......
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment