Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Left panel] add an option "Inviter à rejoindre Tchap" (#449) #506

Merged
merged 4 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Btchap/Config/BuildSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ final class BuildSettings: NSObject {

static let allowInviteExernalUsers: Bool = true

// MARK: - Side Menu
static let enableSideMenu: Bool = true
static let sideMenuShowInviteFriends: Bool = true

/// Whether to read the `io.element.functional_members` state event and exclude any service members when computing a room's name and avatar.
static let supportFunctionalMembers: Bool = true
Expand Down
3 changes: 3 additions & 0 deletions Riot/Modules/Application/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ extension AppCoordinator: SplitViewCoordinatorDelegate {
// MARK: - SideMenuCoordinatorDelegate
extension AppCoordinator: SideMenuCoordinatorDelegate {
func sideMenuCoordinator(_ coordinator: SideMenuCoordinatorType, didTapMenuItem menuItem: SideMenuItem, fromSourceView sourceView: UIView) {
if menuItem == .inviteFriends {
self.splitViewCoordinator?.presentInvitePeople()
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion Riot/Modules/SideMenu/SideMenuCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,11 @@ extension SideMenuCoordinator: SideMenuViewModelCoordinatorDelegate {

switch menuItem {
case .inviteFriends:
self.showInviteFriends(from: sourceView)
// Tchap: Redirect to invite people
self.sideMenuNavigationViewController.dismiss(animated: true) {
self.delegate?.sideMenuCoordinator(self, didTapMenuItem: menuItem, fromSourceView: sourceView)
}
return
case .settings:
self.showSettings()
case .help:
Expand Down
2 changes: 1 addition & 1 deletion Riot/Modules/SideMenu/SideMenuItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ extension SideMenuItem {

switch self {
case .inviteFriends:
title = VectorL10n.sideMenuActionInviteFriends
title = TchapL10n.sideMenuActionInviteFriends
case .settings:
title = VectorL10n.sideMenuActionSettings
case .help:
Expand Down
6 changes: 3 additions & 3 deletions Riot/Modules/SideMenu/SideMenuViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ final class SideMenuViewModel: SideMenuViewModelType {

var sideMenuItems: [SideMenuItem] = []

// if BuildSettings.sideMenuShowInviteFriends {
// sideMenuItems += [.inviteFriends]
// }
if BuildSettings.sideMenuShowInviteFriends {
sideMenuItems += [.inviteFriends]
}

sideMenuItems += [
.settings,
Expand Down
4 changes: 4 additions & 0 deletions Riot/Modules/SplitView/SplitViewCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ final class SplitViewCoordinator: NSObject, SplitViewCoordinatorType {
self.tabBarCoordinator?.popToHome(animated: animated, completion: completion)
}

func presentInvitePeople() {
self.tabBarCoordinator?.presentInvitePeople()
}

// MARK: - Private methods

private func createPlaceholderDetailsViewController() -> UIViewController {
Expand Down
4 changes: 4 additions & 0 deletions Riot/Modules/SplitView/SplitViewCoordinatorType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ protocol SplitViewCoordinatorType: Coordinator, Presentable {
// TODO: Do not expose publicly this method
/// Remove detail screens and display placeholder if needed
func resetDetails(animated: Bool)

// Tchap: redirect to invite people alert
/// Present invite people alert (with textField)
func presentInvitePeople()
}
139 changes: 139 additions & 0 deletions Riot/Modules/TabBar/TabBarCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
return self.navigationRouter.modules.last is MasterTabBarController
}

// Tchap: Add invite service for user invitation
private var inviteService: InviteServiceType?
private var errorPresenter: ErrorPresenter?
private weak var currentAlertController: UIAlertController?

// MARK: Public

// Must be used only internally
Expand Down Expand Up @@ -110,6 +115,8 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
if MXKAccountManager.shared().accounts.isEmpty {
self.showWelcome()
}

self.errorPresenter = AlertErrorPresenter(viewControllerPresenter: masterTabBarController)
}

func toPresentable() -> UIViewController {
Expand Down Expand Up @@ -181,6 +188,12 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
}
}

func presentInvitePeople() {
promptUserToFillAnEmailToInvite { [weak self] email in
self?.sendEmailInvite(to: email)
}
}

// MARK: - SplitViewMasterPresentable

var selectedNavigationRouter: NavigationRouterType? {
Expand Down Expand Up @@ -705,6 +718,132 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
}
}

// Tchap: Manage e-mail invitation
extension TabBarCoordinator {
private func promptUserToFillAnEmailToInvite(completion: @escaping ((String) -> Void)) {
currentAlertController?.dismiss(animated: false)

let alertController = UIAlertController(title: TchapL10n.contactsInviteByEmailTitle,
message: TchapL10n.contactsInviteByEmailMessage,
preferredStyle: .alert)

// Add textField
alertController.addTextField(configurationHandler: { textField in
textField.isSecureTextEntry = false
textField.placeholder = nil
textField.keyboardType = .emailAddress
})

// Cancel action
let cancelAction = UIAlertAction(title: VectorL10n.cancel,
style: .cancel) { [weak self] _ in
self?.currentAlertController = nil
}
alertController.addAction(cancelAction)

// Invite action
let inviteAction = UIAlertAction(title: VectorL10n.invite,
style: .default) { [weak self] _ in
guard let currentAlertController = self?.currentAlertController,
let email = currentAlertController.textFields?.first?.text?.lowercased() else {
return // FIXME: Verify if dismiss should be needed in this case
}

self?.currentAlertController = nil

if MXTools.isEmailAddress(email) {
completion(email)
} else {
self?.currentAlertController?.dismiss(animated: false)
let errorAlertController = UIAlertController(title: TchapL10n.authenticationErrorInvalidEmail,
message: nil,
preferredStyle: .alert)
let okAction = UIAlertAction(title: VectorL10n.ok,
style: .default) { [weak self] _ in
self?.currentAlertController = nil
}
errorAlertController.addAction(okAction)
errorAlertController.mxk_setAccessibilityIdentifier("ContactsVCInviteByEmailError")
self?.currentAlertController = errorAlertController
self?.masterTabBarController.present(errorAlertController, animated: true)
}
}
alertController.addAction(inviteAction)
alertController.mxk_setAccessibilityIdentifier("ContactsVCInviteByEmailDialog")

self.currentAlertController = alertController

masterTabBarController.present(alertController, animated: true)
}

private func sendEmailInvite(to email: String) {
guard let session = self.currentMatrixSession else { return }
if self.inviteService == nil {
self.inviteService = InviteService(session: session)
}
guard let inviteService = self.inviteService else { return }

self.activityIndicatorPresenter.presentActivityIndicator(on: masterTabBarController.view, animated: true)
inviteService.sendEmailInvite(to: email) { [weak self] (response) in
guard let sself = self else {
return
}

sself.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
switch response {
case .success(let result):
var message: String
var discoveredUserID: String?
switch result {
case .inviteHasBeenSent(roomID: _):
message = TchapL10n.inviteSendingSucceeded
case .inviteAlreadySent(roomID: _):
message = TchapL10n.inviteAlreadySentByEmail(email)
case .inviteIgnoredForDiscoveredUser(userID: let userID):
discoveredUserID = userID
message = TchapL10n.inviteNotSentForDiscoveredUser
case .inviteIgnoredForUnauthorizedEmail:
message = TchapL10n.inviteNotSentForUnauthorizedEmail(email)
}

sself.currentAlertController?.dismiss(animated: false)

let alert = UIAlertController(title: TchapL10n.inviteInformationTitle, message: message, preferredStyle: .alert)

let okTitle = Bundle.mxk_localizedString(forKey: "ok")
let okAction = UIAlertAction(title: okTitle, style: .default, handler: { action in
if let userID = discoveredUserID {
// Open the discussion
sself.startDiscussion(with: userID)
}
})
alert.addAction(okAction)
sself.currentAlertController = alert

sself.masterTabBarController.present(alert, animated: true, completion: nil)
case .failure(let error):
let errorPresentable = sself.inviteErrorPresentable(from: error)
sself.errorPresenter?.present(errorPresentable: errorPresentable, animated: true)
}
}
}

private func inviteErrorPresentable(from error: Error) -> ErrorPresentable {
let errorTitle = TchapL10n.inviteSendingFailedTitle
let errorMessage: String

let nsError = error as NSError

if let message = nsError.userInfo[NSLocalizedDescriptionKey] as? String {
errorMessage = message
} else {
errorMessage = TchapL10n.errorMessageDefault
}

return ErrorPresentableImpl(title: errorTitle, message: errorMessage)
}
}

// MARK: - MasterTabBarControllerDelegate
extension TabBarCoordinator: MasterTabBarControllerDelegate {

Expand Down
4 changes: 4 additions & 0 deletions Riot/Modules/TabBar/TabBarCoordinatorType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,8 @@ protocol TabBarCoordinatorType: Coordinator, SplitViewMasterPresentable {
// TODO: Remove this method, this implementation detail should not be exposed
// Release the current selected item (room/contact/group...).
func releaseSelectedItems()

// Tchap: redirect to invite people alert
/// Present invite people alert (with textField)
func presentInvitePeople()
}
2 changes: 2 additions & 0 deletions RiotNSE/BuildSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ final class BuildSettings: NSObject {

static let allowInviteExernalUsers: Bool = true

// MARK: - Side Menu
static let enableSideMenu: Bool = true
static let sideMenuShowInviteFriends: Bool = true

/// Whether to read the `io.element.functional_members` state event and exclude any service members when computing a room's name and avatar.
static let supportFunctionalMembers: Bool = true
Expand Down
2 changes: 2 additions & 0 deletions RiotShareExtension/BuildSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ final class BuildSettings: NSObject {

static let allowInviteExernalUsers: Bool = true

// MARK: - Side Menu
static let enableSideMenu: Bool = true
static let sideMenuShowInviteFriends: Bool = true

/// Whether to read the `io.element.functional_members` state event and exclude any service members when computing a room's name and avatar.
static let supportFunctionalMembers: Bool = true
Expand Down
4 changes: 4 additions & 0 deletions Tchap/Assets/Localizations/fr.lproj/Tchap.strings
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,7 @@
////////////////////////////////////////////////////////////////////////////////
// MARK: Forward
"forward_screen_title" = "Transférer à";

////////////////////////////////////////////////////////////////////////////////
// MARK: Side menu
"side_menu_action_invite_friends" = "Inviter à rejoindre Tchap";
2 changes: 2 additions & 0 deletions Tchap/Config/BuildSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ final class BuildSettings: NSObject {

static let allowInviteExernalUsers: Bool = true

// MARK: - Side Menu
static let enableSideMenu: Bool = true
static let sideMenuShowInviteFriends: Bool = true

/// Whether to read the `io.element.functional_members` state event and exclude any service members when computing a room's name and avatar.
static let supportFunctionalMembers: Bool = true
Expand Down
2 changes: 2 additions & 0 deletions Tchap/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ internal enum TchapL10n {
internal static let settingsShowProfileChangesMessagesTitle = TchapL10n.tr("Tchap", "settings_show_profile_changes_messages_title")
/// Échec d'envoi. Veuillez renouveler cet envoi depuis l'application
internal static let shareExtensionFailedToShareInEmptyDiscussion = TchapL10n.tr("Tchap", "share_extension_failed_to_share_in_empty_discussion")
/// Inviter à rejoindre Tchap
internal static let sideMenuActionInviteFriends = TchapL10n.tr("Tchap", "side_menu_action_invite_friends")
/// Votre correspondant a quitté définitivement cette discussion.
/// Vous devez en créer une nouvelle pour le recontacter, s'il est toujours joignable sur Tchap.
internal static let tchapCannotInviteDeactivatedAccountUser = TchapL10n.tr("Tchap", "tchap_cannot_invite_deactivated_account_user")
Expand Down
19 changes: 0 additions & 19 deletions Tchap/Modules/Contacts/ContactsViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,6 @@ - (void)promptUserToFillAnEmailToInvite:(void (^)(NSString *email))completion
[self presentViewController:self.currentAlert animated:YES completion:nil];
}

- (void)sendInviteToTchapByEmail:(NSString *)email
{
// Sanity check
if ([self.delegate respondsToSelector:@selector(contactsViewController:sendInviteToTchapByEmail:)])
{
[self.delegate contactsViewController:self sendInviteToTchapByEmail:email];
}
}

- (void)selectEmail:(NSString *)email
{
// Check whether the delegate allows this email to be invited
Expand Down Expand Up @@ -463,16 +454,6 @@ - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Check first the potential invite button
if ([self.contactsDataSource isInviteButtonIndexPath:indexPath])
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self promptUserToFillAnEmailToInvite:^(NSString *email) {
[self sendInviteToTchapByEmail:email];
}];
return;
}

// Check whether the user wants to invite people by sharing a link to the room
if ([self.contactsDataSource isInviteByLinkButtonIndexPath:indexPath])
{
Expand Down
8 changes: 0 additions & 8 deletions Tchap/Modules/Contacts/DataSources/ContactsDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,6 @@ typedef enum : NSUInteger
NSMutableArray<MXKContact*> *filteredMatrixContacts;
}

/**
Check whether the invite button is located to the given index path.

@param indexPath the index of the cell
@return YES if the indexPath is the invite button one
*/
-(BOOL)isInviteButtonIndexPath:(NSIndexPath*)indexPath;

/**
Check whether the invite by link button is located to the given index path.

Expand Down
5 changes: 0 additions & 5 deletions Tchap/Modules/Contacts/DataSources/ContactsDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -1216,11 +1216,6 @@ - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)

#pragma mark -

-(BOOL)isInviteButtonIndexPath:(NSIndexPath*)indexPath
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to remove this method in ContactsDataSource.h too

{
return (indexPath.section == inviteToTchapButtonSection);
}

-(BOOL)isInviteByLinkButtonIndexPath:(NSIndexPath*)indexPath
{
return (indexPath.section == inviteByLinkButtonSection);
Expand Down
1 change: 1 addition & 0 deletions changelog.d/449.change
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[Left panel] add an option "Inviter à rejoindre Tchap"