diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 924bda31c6..00fc9a6d1f 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -592,6 +592,8 @@ Tap the + to start adding people."; "room_action_send_sticker" = "Send sticker"; "room_action_send_file" = "Send file"; "room_action_reply" = "Reply"; +"room_action_report" = "Report room"; +"room_action_report_prompt_reason" = "Reason for reporting this room"; "room_replacement_information" = "This room has been replaced and is no longer active."; "room_replacement_link" = "The conversation continues here."; "room_predecessor_information" = "This room is a continuation of another conversation."; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 999f821c35..7826653b20 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -5207,6 +5207,14 @@ public class VectorL10n: NSObject { public static var roomActionReply: String { return VectorL10n.tr("Vector", "room_action_reply") } + /// Report room + public static var roomActionReport: String { + return VectorL10n.tr("Vector", "room_action_report") + } + /// Reason for reporting this room + public static var roomActionReportPromptReason: String { + return VectorL10n.tr("Vector", "room_action_report_prompt_reason") + } /// Send file public static var roomActionSendFile: String { return VectorL10n.tr("Vector", "room_action_send_file") diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index badc664904..ea2853c628 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -224,6 +224,9 @@ extension RoomInfoCoordinator: RoomInfoListCoordinatorDelegate { self.delegate?.roomInfoCoordinatorDidLeaveRoom(self) } + func roomInfoListCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoListCoordinatorType) { + self.delegate?.roomInfoCoordinatorDidRequestReportRoom(self) + } } extension RoomInfoCoordinator: RoomParticipantsViewControllerDelegate { diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift index 39e740bfcc..4484bd0d68 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift @@ -25,6 +25,7 @@ import MatrixSDK func roomInfoCoordinatorBridgePresenterDelegateDidLeaveRoom(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter) func roomInfoCoordinatorBridgePresenter(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter, didReplaceRoomWithReplacementId roomId: String) func roomInfoCoordinatorBridgePresenter(_ coordinator: RoomInfoCoordinatorBridgePresenter, viewEventInTimeline event: MXEvent) + func roomInfoCoordinatorBridgePresenterDidRequestReportRoom(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter) } /// RoomInfoCoordinatorBridgePresenter enables to start RoomInfoCoordinator from a view controller. @@ -131,9 +132,14 @@ extension RoomInfoCoordinatorBridgePresenter: RoomInfoCoordinatorDelegate { func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, didReplaceRoomWithReplacementId roomId: String) { self.delegate?.roomInfoCoordinatorBridgePresenter(self, didReplaceRoomWithReplacementId: roomId) } + func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, viewEventInTimeline event: MXEvent) { self.delegate?.roomInfoCoordinatorBridgePresenter(self, viewEventInTimeline: event) } + + func roomInfoCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoCoordinatorType) { + self.delegate?.roomInfoCoordinatorBridgePresenterDidRequestReportRoom(self) + } } // MARK: - UIAdaptivePresentationControllerDelegate diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift index 2122ddf1df..077ef7b524 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift @@ -25,6 +25,7 @@ protocol RoomInfoCoordinatorDelegate: AnyObject { func roomInfoCoordinatorDidLeaveRoom(_ coordinator: RoomInfoCoordinatorType) func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, didReplaceRoomWithReplacementId roomId: String) func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, viewEventInTimeline event: MXEvent) + func roomInfoCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoCoordinatorType) } /// `RoomInfoCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift index 6da79ca32c..25131222ba 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift @@ -75,4 +75,7 @@ extension RoomInfoListCoordinator: RoomInfoListViewModelCoordinatorDelegate { self.delegate?.roomInfoListCoordinatorDidLeaveRoom(self) } + func roomInfoListViewModelDidRequestReportRoom(_ viewModel: RoomInfoListViewModelType) { + self.delegate?.roomInfoListCoordinatorDidRequestReportRoom(self) + } } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift index 592acd67b2..f17102c1ed 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift @@ -22,6 +22,7 @@ protocol RoomInfoListCoordinatorDelegate: AnyObject { func roomInfoListCoordinator(_ coordinator: RoomInfoListCoordinatorType, wantsToNavigateTo target: RoomInfoListTarget) func roomInfoListCoordinatorDidCancel(_ coordinator: RoomInfoListCoordinatorType) func roomInfoListCoordinatorDidLeaveRoom(_ coordinator: RoomInfoListCoordinatorType) + func roomInfoListCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoListCoordinatorType) } /// `RoomInfoListCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift index 6383d4fb5d..e01bfeefc1 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift @@ -48,4 +48,5 @@ enum RoomInfoListViewAction { case navigate(target: RoomInfoListTarget) case leave case cancel + case report } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift index a879eeed00..383beac30b 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -222,8 +222,16 @@ final class RoomInfoListViewController: UIViewController { rows: [rowLeave], footer: nil) + let rowReport = Row(type: .destructive, icon: Asset.Images.error.image, text: VectorL10n.roomEventActionReport, accessoryType: .disclosureIndicator) { + self.viewModel.process(viewAction: .report) + } + let sectionReport = Section(header: nil, + rows: [rowReport], + footer: nil) + tmpSections.append(sectionSettings) tmpSections.append(sectionLeave) + tmpSections.append(sectionReport) sections = tmpSections } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift index 572754251a..bf2c82e9b4 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift @@ -79,6 +79,8 @@ final class RoomInfoListViewModel: NSObject, RoomInfoListViewModelType { self.leave() case .cancel: self.coordinatorDelegate?.roomInfoListViewModelDidCancel(self) + case .report: + self.coordinatorDelegate?.roomInfoListViewModelDidRequestReportRoom(self) } } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift index 8a5a1b411a..460c33d511 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift @@ -26,6 +26,7 @@ protocol RoomInfoListViewModelCoordinatorDelegate: AnyObject { func roomInfoListViewModelDidCancel(_ viewModel: RoomInfoListViewModelType) func roomInfoListViewModelDidLeaveRoom(_ viewModel: RoomInfoListViewModelType) func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, wantsToNavigateTo target: RoomInfoListTarget) + func roomInfoListViewModelDidRequestReportRoom(_ viewModel: RoomInfoListViewModelType) } /// Protocol describing the view model used by `RoomInfoListViewController` diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 37cc5a7660..2eec3ea3d7 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -5372,6 +5372,50 @@ - (IBAction)onButtonPressed:(id)sender } } +- (void)handleReportRoom +{ + // Prompt user to enter a description of the problem content. + UIAlertController *reportReasonAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomActionReportPromptReason] + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + [reportReasonAlert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.secureTextEntry = NO; + textField.placeholder = nil; + textField.keyboardType = UIKeyboardTypeDefault; + }]; + + MXWeakify(self); + [reportReasonAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + + NSString *text = [self->currentAlert textFields].firstObject.text; + self->currentAlert = nil; + + [self startActivityIndicator]; + + [self.roomDataSource.mxSession.matrixRestClient reportRoom:self.roomDataSource.roomId reason:text success:^{ + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + + MXLogDebug(@"[RoomVC] Report room (%@) failed", self.roomDataSource.roomId); + //Alert user + [self showError:error]; + }]; + }]]; + + [reportReasonAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + }]]; + + [self presentViewController:reportReasonAlert animated:YES completion:nil]; + self->currentAlert = reportReasonAlert; +} + #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath @@ -5617,6 +5661,10 @@ - (void)roomTitleView:(RoomTitleView*)titleView recognizeTapGesture:(UITapGestur { [self presentDeclineOptionsFromView:tappedView]; } + else if (tappedView == previewHeader.reportButton) + { + [self handleReportRoom]; + } } - (void)presentDeclineOptionsFromView:(UIView *)view @@ -7984,6 +8032,11 @@ - (void)roomInfoCoordinatorBridgePresenter:(RoomInfoCoordinatorBridgePresenter * [self reloadRoomWihtEventId:event.eventId threadId:event.threadId forceUpdateRoomMarker:NO]; } +- (void)roomInfoCoordinatorBridgePresenterDidRequestReportRoom:(RoomInfoCoordinatorBridgePresenter *)coordinatorBridgePresenter +{ + [self handleReportRoom]; +} + -(void)reloadRoomWihtEventId:(NSString *)eventId threadId:(NSString *)threadId forceUpdateRoomMarker:(BOOL)forceUpdateRoomMarker diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h index 79fdde1bb1..d8bcfb086c 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h @@ -32,6 +32,7 @@ @property (weak, nonatomic) IBOutlet UIView *buttonsContainer; @property (weak, nonatomic) IBOutlet UIButton *leftButton; @property (weak, nonatomic) IBOutlet UIButton *rightButton; +@property (weak, nonatomic) IBOutlet UIButton *reportButton; @property (weak, nonatomic) IBOutlet UILabel *subNoticeLabel; @property (weak, nonatomic) IBOutlet UIView *bottomBorderView; diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m index 7e8456a5b9..35fdbab129 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m @@ -51,12 +51,22 @@ - (void)awakeFromNib [self.rightButton setTitle:[VectorL10n join] forState:UIControlStateNormal]; [self.rightButton setTitle:[VectorL10n join] forState:UIControlStateHighlighted]; + [self.reportButton setTitle:[VectorL10n roomActionReport] forState:UIControlStateNormal]; + [self.reportButton setTitle:[VectorL10n roomActionReport] forState:UIControlStateHighlighted]; + tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; [tap setNumberOfTouchesRequired:1]; [tap setNumberOfTapsRequired:1]; [tap setDelegate:self]; [self.rightButton addGestureRecognizer:tap]; self.rightButton.userInteractionEnabled = YES; + + tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; + [tap setNumberOfTouchesRequired:1]; + [tap setNumberOfTapsRequired:1]; + [tap setDelegate:self]; + [self.reportButton addGestureRecognizer:tap]; + self.reportButton.userInteractionEnabled = YES; } -(void)customizeViewRendering @@ -86,6 +96,8 @@ -(void)customizeViewRendering [self.rightButton.layer setCornerRadius:5]; self.rightButton.clipsToBounds = YES; self.rightButton.backgroundColor = ThemeService.shared.theme.tintColor; + + [self.reportButton setTitleColor:ThemeService.shared.theme.warningColor forState:UIControlStateNormal]; } - (void)refreshDisplay diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib index 31fcca2736..873ff88e21 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib @@ -1,25 +1,21 @@ - - - - + + - - - + - + - + @@ -38,7 +34,7 @@ - + @@ -48,9 +44,9 @@ - + - + @@ -58,11 +54,11 @@ - + - - - + @@ -154,15 +158,17 @@ - + + + @@ -187,6 +193,7 @@ + @@ -194,9 +201,16 @@ + - + + + + + + + diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift index d445f29afc..86e1cd5ee1 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift @@ -520,8 +520,12 @@ extension ExploreRoomCoordinator: RoomInfoCoordinatorDelegate { self.remove(childCoordinator: coordinator) } } + func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, viewEventInTimeline event: MXEvent) { } + func roomInfoCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoCoordinatorType) { + + } } diff --git a/matrix-ios-sdk b/matrix-ios-sdk index f03778fddb..3052a396b8 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit f03778fddbaf682173706649ee1412b0143f0449 +Subproject commit 3052a396b88095cbcfe1b4f488127f69e3280cda