diff --git a/Btchap/Config/BuildSettings.swift b/Btchap/Config/BuildSettings.swift index 7862accd68..d3d18241ba 100644 --- a/Btchap/Config/BuildSettings.swift +++ b/Btchap/Config/BuildSettings.swift @@ -229,6 +229,33 @@ final class BuildSettings: NSObject { static let allowBackgroundAudioMessagePlayback: Bool = true + // Tchap: Feature activation by Instance + static let tchapFeatureAnyFeature = "*" // To allow any feature for some instances + static let tchapFeatureAnyHomeServer = "*" // To allow a feature for any instance + // tchapFeatureAnyFeature : [ ] to allow any feature for an instance + // "" : [ tchapFeatureAnyHomeServer ] to allow a feature to any instance + static let tchapFeatureNotificationByEmail = "tchapFeatureNotificationByEmail" + static let tchapFeatureVoiceOverIP = "tchapFeatureVoiceOverIP" + static let tchapFeatureVideoOverIP = "tchapFeatureVideoOverIP" // Tchap: in pre-prod, allow any feature to any instance. + static let tchapFeatureThreads = "tchapFeatureThreads" + static var tchapFeaturesAllowedHomeServersForFeature: [String: [String]] = [ + tchapFeatureNotificationByEmail: [ + "agent.dinum.tchap.gouv.fr" + ], + // No activation of VoIP calls actually in Tchap Production. +// tchapFeatureVoiceOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of video calls actually in Tchap Production. +// tchapFeatureVideoOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of Threads actually in Tchap Production. +// tchapFeatureThreads: [ +// "agent.dinum.tchap.gouv.fr" +// ] + ] + // MARK: - Side Menu static let enableSideMenu: Bool = true && !newAppLayoutEnabled static let sideMenuShowInviteFriends: Bool = true diff --git a/DevTchap/Config/BuildSettings.swift b/DevTchap/Config/BuildSettings.swift index 5db170d892..fac3b0a29f 100644 --- a/DevTchap/Config/BuildSettings.swift +++ b/DevTchap/Config/BuildSettings.swift @@ -230,6 +230,22 @@ final class BuildSettings: NSObject { static let allowBackgroundAudioMessagePlayback: Bool = true + // Tchap: Feature activation by Instance + static let tchapFeatureAnyFeature = "*" // To allow any feature for some instances + static let tchapFeatureAnyHomeServer = "*" // To allow a feature for any instance + // tchapFeatureAnyFeature : [ ] to allow any feature for an instance + // "" : [ tchapFeatureAnyHomeServer ] to allow a feature to any instance + static let tchapFeatureNotificationByEmail = "tchapFeatureNotificationByEmail" + static let tchapFeatureVoiceOverIP = "tchapFeatureVoiceOverIP" + static let tchapFeatureVideoOverIP = "tchapFeatureVideoOverIP" // Tchap: in Dev, allow any feature to any instance. + static let tchapFeatureThreads = "tchapFeatureThreads" + static var tchapFeaturesAllowedHomeServersForFeature: [String: [String]] = [ + tchapFeatureNotificationByEmail: [ tchapFeatureAnyHomeServer ], + tchapFeatureVoiceOverIP: [ tchapFeatureAnyHomeServer ], + tchapFeatureVideoOverIP: [ tchapFeatureAnyHomeServer ], + tchapFeatureThreads: [ tchapFeatureAnyHomeServer ] + ] + // MARK: - Side Menu static let enableSideMenu: Bool = true && !newAppLayoutEnabled static let sideMenuShowInviteFriends: Bool = true diff --git a/Podfile.lock b/Podfile.lock index 05352ad188..89f82a8b84 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -210,4 +210,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: bdd98ddb1a6b2f5d45b1fc00ccfbf2dbaeeb0ff0 -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m index efaed822fe..932559ab92 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.m +++ b/Riot/Managers/PushNotification/PushNotificationService.m @@ -487,28 +487,27 @@ - (void)handleNotificationInlineReplyForRoomId:(NSString*)roomId // initialize data source for a thread or a room __block MXKRoomDataSource *dataSource; dispatch_group_t dispatchGroupDataSource = dispatch_group_create(); - // Tchap: Disable Threads -// if (RiotSettings.shared.enableThreads && threadId) -// { -// dispatch_group_enter(dispatchGroupDataSource); -// [ThreadDataSource loadRoomDataSourceWithRoomId:roomId -// initialEventId:nil -// threadId:threadId -// andMatrixSession:mxSession -// onComplete:^(MXKRoomDataSource *threadDataSource) { -// dataSource = threadDataSource; -// dispatch_group_leave(dispatchGroupDataSource); -// }]; -// } -// else -// { + if (RiotSettings.shared.enableThreads && threadId) + { + dispatch_group_enter(dispatchGroupDataSource); + [ThreadDataSource loadRoomDataSourceWithRoomId:roomId + initialEventId:nil + threadId:threadId + andMatrixSession:mxSession + onComplete:^(MXKRoomDataSource *threadDataSource) { + dataSource = threadDataSource; + dispatch_group_leave(dispatchGroupDataSource); + }]; + } + else + { dispatch_group_enter(dispatchGroupDataSource); MXKRoomDataSourceManager *manager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession]; [manager roomDataSourceForRoom:roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) { dataSource = roomDataSource; dispatch_group_leave(dispatchGroupDataSource); }]; -// } + } dispatch_group_notify(dispatchGroupDataSource, dispatch_get_main_queue(), ^{ if (responseText != nil && responseText.length != 0) diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 0c951b1544..bd7bdbce8e 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -167,8 +167,21 @@ final class RiotSettings: NSObject { var enableRingingForGroupCalls /// Indicates if threads enabled in the timeline. + // Tchap: hijack property to allow thread only for DINUM agents +// @UserDefault(key: "enableThreads", defaultValue: false, storage: defaults) +// var enableThreads @UserDefault(key: "enableThreads", defaultValue: false, storage: defaults) - var enableThreads + var _enableThreads + var enableThreads: Bool { + get { + // only allow true for DINUM agent + let account = MXKAccountManager.shared().activeAccounts.first + return (account?.isFeatureActivated(BuildSettings.tchapFeatureThreads) ?? false) && _enableThreads + } + set { + _enableThreads = newValue + } + } /// Indicates if threads should be forced enabled in the timeline. @UserDefault(key: "forceThreadsEnabled", defaultValue: true, storage: defaults) diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h index ecd5b3aada..a156370a83 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.h @@ -100,7 +100,7 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer /** The account user's presence (`MXPresenceUnknown` by default, available if matrix session `mxSession` is opened). - The notification `kMXKAccountUserInfoDidChangeNotification` is posted in case of change of this property. + The notification `kMXKAccountUserInfoDidChangeNotification` is posted in case of change of this property. */ @property (nonatomic, readonly) MXPresence userPresence; @@ -364,4 +364,11 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer Handle unauthenticated errors from the server triggering hard/soft logouts as appropriate. */ - (void)handleUnauthenticatedWithError:(MXError *)error isSoftLogout:(BOOL)isSoftLogout isRefreshTokenAuth:(BOOL)isRefreshTokenAuth andCompletion:(void (^)(void))completion; + + +// Tchap: helpers +#pragma mark - Tchap Helpers + +- (BOOL)belongsToHomeServer:(nonnull NSString *)homeServer; + @end diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index 8d03739af4..9df52ba338 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -2295,4 +2295,11 @@ - (void)setPreferredSyncPresence:(MXPresence)preferredSyncPresence [[MXKAccountManager sharedManager] saveAccounts]; } +// Tchap: helpers +#pragma mark - Tchap Helpers + +- (BOOL)belongsToHomeServer:(nonnull NSString *)homeServer { + return [self.identityServerURL isEqualToString:[BuildSettings.serverUrlPrefix stringByAppendingString:homeServer]]; +} + @end diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index 8ff04f89c0..ce56b84b73 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -838,9 +838,8 @@ - (CGFloat)threadSummaryViewHeightForEventId:(NSString*)eventId // component is not a thread root return 0; } - return 0; // Threads are disabled in Tchap -// return PlainRoomCellLayoutConstants.threadSummaryViewTopMargin + -// [ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth]; + return PlainRoomCellLayoutConstants.threadSummaryViewTopMargin + + [ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth]; } - (CGFloat)fromAThreadViewHeightForEventId:(NSString*)eventId @@ -866,9 +865,9 @@ - (CGFloat)fromAThreadViewHeightForEventId:(NSString*)eventId // event is not in a thread return 0; } - return 0; // Threads are disabled in Tchap -// return PlainRoomCellLayoutConstants.fromAThreadViewTopMargin + -// [FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth]; +// return 0; // Threads are disabled in Tchap + return PlainRoomCellLayoutConstants.fromAThreadViewTopMargin + + [FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth]; } - (CGFloat)urlPreviewHeightForEventId:(NSString*)eventId diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 4fac685701..b5f193f8f7 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -266,47 +266,46 @@ - (void)fetchEncryptionTrustedLevel - (BOOL)shouldQueueEventForProcessing:(MXEvent *)event roomState:(MXRoomState *)roomState direction:(MXTimelineDirection)direction { - // Tchap: Disable Threads -// if (self.threadId) -// { -// // if in a thread, ignore non-root event or events from other threads -// if (![event.eventId isEqualToString:self.threadId] && ![event.threadId isEqualToString:self.threadId]) -// { -// // Ignore the event -// return NO; -// } -// // also ignore events related to un-threaded or events from other threads -// if (!event.isInThread && event.relatesTo.eventId) -// { -// MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId -// inRoom:event.roomId]; -// if (![relatedEvent.threadId isEqualToString:self.threadId]) -// { -// // ignore the event -// return NO; -// } -// } -// } -// else if (RiotSettings.shared.enableThreads) -// { -// // if not in a thread, ignore all threaded events -// if (event.isInThread) -// { -// // ignore the event -// return NO; -// } -// // also ignore events related to threaded events -// if (event.relatesTo.eventId) -// { -// MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId -// inRoom:event.roomId]; -// if (relatedEvent.isInThread) -// { -// // ignore the event -// return NO; -// } -// } -// } + if (self.threadId) + { + // if in a thread, ignore non-root event or events from other threads + if (![event.eventId isEqualToString:self.threadId] && ![event.threadId isEqualToString:self.threadId]) + { + // Ignore the event + return NO; + } + // also ignore events related to un-threaded or events from other threads + if (!event.isInThread && event.relatesTo.eventId) + { + MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId + inRoom:event.roomId]; + if (![relatedEvent.threadId isEqualToString:self.threadId]) + { + // ignore the event + return NO; + } + } + } + else if (RiotSettings.shared.enableThreads) + { + // if not in a thread, ignore all threaded events + if (event.isInThread) + { + // ignore the event + return NO; + } + // also ignore events related to threaded events + if (event.relatesTo.eventId) + { + MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId + inRoom:event.roomId]; + if (relatedEvent.isInThread) + { + // ignore the event + return NO; + } + } + } return [super shouldQueueEventForProcessing:event roomState:roomState direction:direction]; } @@ -478,26 +477,25 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cellData:cellData contentViewPositionY:bottomPositionY upperDecorationView:urlPreviewView]; } - // Tchap: Disable Threads -// ThreadSummaryView *threadSummaryView; -// -// // display thread summary view if the component has a thread in the room timeline -// if (RiotSettings.shared.enableThreads && component.thread && !self.threadId) -// { -// threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread -// session:self.mxSession]; -// threadSummaryView.delegate = self; -// threadSummaryView.tag = index; -// -// [temporaryViews addObject:threadSummaryView]; -// UIView *upperDecorationView = reactionsView ?: urlPreviewView; -// -// [cellDecorator addThreadSummaryView:threadSummaryView -// toCell:bubbleCell -// cellData:cellData -// contentViewPositionY:bottomPositionY -// upperDecorationView:upperDecorationView]; -// } + ThreadSummaryView *threadSummaryView; + + // display thread summary view if the component has a thread in the room timeline + if (RiotSettings.shared.enableThreads && component.thread && !self.threadId) + { + threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread + session:self.mxSession]; + threadSummaryView.delegate = self; + threadSummaryView.tag = index; + + [temporaryViews addObject:threadSummaryView]; + UIView *upperDecorationView = reactionsView ?: urlPreviewView; + + [cellDecorator addThreadSummaryView:threadSummaryView + toCell:bubbleCell + cellData:cellData + contentViewPositionY:bottomPositionY + upperDecorationView:upperDecorationView]; + } MXKReceiptSendersContainer* avatarsContainer; @@ -1213,12 +1211,11 @@ - (void)didCloseURLPreviewView:(URLPreviewView *)previewView for:(NSString *)eve #pragma mark - ThreadSummaryViewDelegate -// Tchap: Disable Threads -//- (void)threadSummaryViewTapped:(ThreadSummaryView *)summaryView -//{ -// [self.roomDataSourceDelegate roomDataSource:self -// didTapThread:summaryView.thread]; -//} +- (void)threadSummaryViewTapped:(ThreadSummaryView *)summaryView +{ + [self.roomDataSourceDelegate roomDataSource:self + didTapThread:summaryView.thread]; +} #pragma mark - Location sharing diff --git a/Riot/Modules/Room/RoomCoordinator.swift b/Riot/Modules/Room/RoomCoordinator.swift index 254b3a1659..d543db3ccc 100644 --- a/Riot/Modules/Room/RoomCoordinator.swift +++ b/Riot/Modules/Room/RoomCoordinator.swift @@ -80,13 +80,12 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol { self.selectedEventId = parameters.eventId self.userIndicatorStore = UserIndicatorStore(presenter: parameters.userIndicatorPresenter) - // Tchap: Disable Threads -// if let threadId = parameters.threadId { -// self.roomViewController = ThreadViewController.instantiate(withThreadId: threadId, -// configuration: parameters.displayConfiguration) -// } else { + if let threadId = parameters.threadId { + self.roomViewController = ThreadViewController.instantiate(withThreadId: threadId, + configuration: parameters.displayConfiguration) + } else { self.roomViewController = RoomViewController.instantiate(with: parameters.displayConfiguration) -// } + } self.roomViewController.userIndicatorStore = userIndicatorStore self.roomViewController.showSettingsInitially = parameters.showSettingsInitially diff --git a/Riot/Modules/Room/RoomViewController.h b/Riot/Modules/Room/RoomViewController.h index 9029e33e72..10073039e7 100644 --- a/Riot/Modules/Room/RoomViewController.h +++ b/Riot/Modules/Room/RoomViewController.h @@ -31,9 +31,8 @@ @class UniversalLinkParameters; @protocol RoomViewControllerDelegate; @class RoomDisplayConfiguration; -// Tchap: Disable Threads +@class ThreadsCoordinatorBridgePresenter; // Tchap: Disable Live location sharing -//@class ThreadsCoordinatorBridgePresenter; //@class LiveLocationSharingBannerView; @class VoiceBroadcastService; @class ComposerLinkActionBridgePresenter; @@ -355,8 +354,7 @@ didRequestEditForPollWithStartEvent:(MXEvent *)startEvent; - (void)roomViewControllerDidTapLiveLocationSharingBanner:(RoomViewController *)roomViewController; /// Request a threads coordinator for a given threadId, used to open a thread from within a room. -// Tchap: Disable Threads -//- (nullable ThreadsCoordinatorBridgePresenter *)threadsCoordinatorForRoomViewController:(RoomViewController *)roomViewController threadId:(nullable NSString *)threadId; +- (nullable ThreadsCoordinatorBridgePresenter *)threadsCoordinatorForRoomViewController:(RoomViewController *)roomViewController threadId:(nullable NSString *)threadId; @end diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 47ca17f555..803166ed4d 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -208,9 +208,9 @@ @interface RoomViewController () thread = cellData.bubbleComponents.firstObject.thread; -// ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread -// session:self.mxSession]; -// [bubbleCell.tmpSubviews addObject:threadSummaryView]; -// -// threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO; -// [bubbleCell.contentView addSubview:threadSummaryView]; -// -// CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; -// CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]; -// -// CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; -// CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height; -// -// // Set constraints for the summary view -// [NSLayoutConstraint activateConstraints: @[ -// [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor -// constant:leftMargin], -// [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor -// constant:bottomPositionY + PlainRoomCellLayoutConstants.threadSummaryViewTopMargin], -// [threadSummaryView.heightAnchor constraintEqualToConstant:height], -// [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] -// ]]; -// } -// else if (event.isInThread) -// { -// FromAThreadView *fromAThreadView = [FromAThreadView instantiate]; -// [bubbleCell.tmpSubviews addObject:fromAThreadView]; -// -// fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO; -// [bubbleCell.contentView addSubview:fromAThreadView]; -// -// CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; -// CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]; -// -// CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; -// CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height; -// -// // Set constraints for the summary view -// [NSLayoutConstraint activateConstraints: @[ -// [fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor -// constant:leftMargin], -// [fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor -// constant:bottomPositionY + PlainRoomCellLayoutConstants.fromAThreadViewTopMargin], -// [fromAThreadView.heightAnchor constraintEqualToConstant:height], -// [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] -// ]]; -// } -// } -// } + if (RiotSettings.shared.enableThreads) + { + RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row]; + MXEvent *event = cellData.events.firstObject; + + if (event) + { + if (cellData.hasThreadRoot) + { + id thread = cellData.bubbleComponents.firstObject.thread; + ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread + session:self.mxSession]; + [bubbleCell.tmpSubviews addObject:threadSummaryView]; + + threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO; + [bubbleCell.contentView addSubview:threadSummaryView]; + + CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; + CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]; + + CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; + CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height; + + // Set constraints for the summary view + [NSLayoutConstraint activateConstraints: @[ + [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor + constant:leftMargin], + [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor + constant:bottomPositionY + PlainRoomCellLayoutConstants.threadSummaryViewTopMargin], + [threadSummaryView.heightAnchor constraintEqualToConstant:height], + [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] + ]]; + } + else if (event.isInThread) + { + FromAThreadView *fromAThreadView = [FromAThreadView instantiate]; + [bubbleCell.tmpSubviews addObject:fromAThreadView]; + + fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO; + [bubbleCell.contentView addSubview:fromAThreadView]; + + CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; + CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]; + + CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; + CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height; + + // Set constraints for the summary view + [NSLayoutConstraint activateConstraints: @[ + [fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor + constant:leftMargin], + [fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor + constant:bottomPositionY + PlainRoomCellLayoutConstants.fromAThreadViewTopMargin], + [fromAThreadView.heightAnchor constraintEqualToConstant:height], + [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] + ]]; + } + } + } } return cell; diff --git a/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift b/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift index c3cf0b5a0f..a37bf69379 100644 --- a/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift +++ b/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift @@ -359,16 +359,16 @@ class BaseRoomCell: MXKRoomBubbleTableViewCell, BaseRoomCellProtocol { // MARK: - RoomCellThreadSummaryDisplayable -// func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) { -// self.roomCellContentView?.addThreadSummaryView(threadSummaryView) -// -// // tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell -// self.addTemporarySubview(threadSummaryView) -// } -// -// func removeThreadSummaryView() { -// self.roomCellContentView?.removeThreadSummaryView() -// } + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) { + self.roomCellContentView?.addThreadSummaryView(threadSummaryView) + + // tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell + self.addTemporarySubview(threadSummaryView) + } + + func removeThreadSummaryView() { + self.roomCellContentView?.removeThreadSummaryView() + } // MARK: - RoomCellReadMarkerDisplayable diff --git a/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift index e188ac257f..4f89967251 100644 --- a/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift +++ b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift @@ -240,43 +240,43 @@ extension RoomCellContentView: RoomCellReactionsDisplayable { // MARK: - RoomCellThreadSummaryDisplayable extension RoomCellContentView: RoomCellThreadSummaryDisplayable { -// func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) { -// -// guard let containerView = self.threadSummaryContentView else { -// return -// } -// -// containerView.vc_removeAllSubviews() -// -// containerView.translatesAutoresizingMaskIntoConstraints = false -// containerView.addSubview(threadSummaryView) -// -// let leadingConstraint: NSLayoutConstraint -// let trailingConstraint: NSLayoutConstraint -// -// if self.decorationViewsAlignment == .right { -// leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor) -// trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor) -// } else { -// leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor) -// trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor) -// } -// -// NSLayoutConstraint.activate([ -// leadingConstraint, -// threadSummaryView.topAnchor.constraint(equalTo: containerView.topAnchor), -// threadSummaryView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.threadSummaryViewHeight), -// threadSummaryView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), -// trailingConstraint -// ]) -// -// self.showThreadSummary = true -// } -// -// func removeThreadSummaryView() { -// self.showThreadSummary = false -// self.threadSummaryContentView.vc_removeAllSubviews() -// } + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) { + + guard let containerView = self.threadSummaryContentView else { + return + } + + containerView.vc_removeAllSubviews() + + containerView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(threadSummaryView) + + let leadingConstraint: NSLayoutConstraint + let trailingConstraint: NSLayoutConstraint + + if self.decorationViewsAlignment == .right { + leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor) + trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor) + } else { + leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor) + trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor) + } + + NSLayoutConstraint.activate([ + leadingConstraint, + threadSummaryView.topAnchor.constraint(equalTo: containerView.topAnchor), + threadSummaryView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.threadSummaryViewHeight), + threadSummaryView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + trailingConstraint + ]) + + self.showThreadSummary = true + } + + func removeThreadSummaryView() { + self.showThreadSummary = false + self.threadSummaryContentView.vc_removeAllSubviews() + } } // MARK: - RoomCellURLPreviewDisplayable diff --git a/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellThreadSummaryDisplayable.swift b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellThreadSummaryDisplayable.swift index 9c7b1fca96..c84416050c 100644 --- a/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellThreadSummaryDisplayable.swift +++ b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellThreadSummaryDisplayable.swift @@ -18,6 +18,6 @@ import Foundation /// `RoomCellThreadSummaryDisplayable` is a protocol indicating that a cell support displaying a thread summary. @objc protocol RoomCellThreadSummaryDisplayable { -// func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) -// func removeThreadSummaryView() + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) + func removeThreadSummaryView() } diff --git a/Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift b/Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift index 4f2ac729fb..df25796d11 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift +++ b/Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift @@ -204,78 +204,78 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator { } } -// override func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView, -// toCell cell: MXKRoomBubbleTableViewCell, -// cellData: RoomBubbleCellData, -// contentViewPositionY: CGFloat, -// upperDecorationView: UIView?) { -// -// if let threadSummaryDisplayable = cell as? RoomCellThreadSummaryDisplayable { -// threadSummaryDisplayable.addThreadSummaryView(threadSummaryView) -// } else { -// -// cell.addTemporarySubview(threadSummaryView) -// threadSummaryView.translatesAutoresizingMaskIntoConstraints = false -// -// let cellContentView = cell.contentView -// -// cellContentView.addSubview(threadSummaryView) -// -// var rightMargin: CGFloat -// var leftMargin: CGFloat -// -// let leadingConstraint: NSLayoutConstraint -// let trailingConstraint: NSLayoutConstraint -// -// // Incoming message -// if cellData.isIncoming { -// -// leftMargin = BubbleRoomCellLayoutConstants.incomingBubbleBackgroundMargins.left -// if cellData.containsBubbleComponentWithEncryptionBadge { -// leftMargin += PlainRoomCellLayoutConstants.encryptedContentLeftMargin -// } -// -// rightMargin = BubbleRoomCellLayoutConstants.incomingBubbleBackgroundMargins.right -// -// leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, -// constant: leftMargin) -// trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: cellContentView.trailingAnchor, -// constant: -rightMargin) -// } else { -// // Outgoing message -// -// leftMargin = BubbleRoomCellLayoutConstants.outgoingBubbleBackgroundMargins.left -// rightMargin = BubbleRoomCellLayoutConstants.outgoingBubbleBackgroundMargins.right -// -// leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: cellContentView.leadingAnchor, -// constant: leftMargin) -// trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, -// constant: -rightMargin) -// } -// -// let topMargin = PlainRoomCellLayoutConstants.threadSummaryViewTopMargin -// -// let height = ThreadSummaryView.contentViewHeight(forThread: threadSummaryView.thread, -// fitting: cellData.maxTextViewWidth) -// -// // The top constraint may need to include the URL preview view -// let topConstraint: NSLayoutConstraint -// if let upperDecorationView = upperDecorationView { -// topConstraint = threadSummaryView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, -// constant: topMargin) -// } else { -// topConstraint = threadSummaryView.topAnchor.constraint(equalTo: cellContentView.topAnchor, -// constant: contentViewPositionY + topMargin) -// } -// -// NSLayoutConstraint.activate([ -// leadingConstraint, -// trailingConstraint, -// threadSummaryView.heightAnchor.constraint(equalToConstant: height), -// topConstraint -// ]) -// } -// } + override func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView, + toCell cell: MXKRoomBubbleTableViewCell, + cellData: RoomBubbleCellData, + contentViewPositionY: CGFloat, + upperDecorationView: UIView?) { + + if let threadSummaryDisplayable = cell as? RoomCellThreadSummaryDisplayable { + threadSummaryDisplayable.addThreadSummaryView(threadSummaryView) + } else { + + cell.addTemporarySubview(threadSummaryView) + threadSummaryView.translatesAutoresizingMaskIntoConstraints = false + + let cellContentView = cell.contentView + + cellContentView.addSubview(threadSummaryView) + + var rightMargin: CGFloat + var leftMargin: CGFloat + + let leadingConstraint: NSLayoutConstraint + let trailingConstraint: NSLayoutConstraint + + // Incoming message + if cellData.isIncoming { + + leftMargin = BubbleRoomCellLayoutConstants.incomingBubbleBackgroundMargins.left + if cellData.containsBubbleComponentWithEncryptionBadge { + leftMargin += PlainRoomCellLayoutConstants.encryptedContentLeftMargin + } + + rightMargin = BubbleRoomCellLayoutConstants.incomingBubbleBackgroundMargins.right + + leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, + constant: leftMargin) + trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: cellContentView.trailingAnchor, + constant: -rightMargin) + } else { + // Outgoing message + + leftMargin = BubbleRoomCellLayoutConstants.outgoingBubbleBackgroundMargins.left + rightMargin = BubbleRoomCellLayoutConstants.outgoingBubbleBackgroundMargins.right + + leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: cellContentView.leadingAnchor, + constant: leftMargin) + trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, + constant: -rightMargin) + } + + let topMargin = PlainRoomCellLayoutConstants.threadSummaryViewTopMargin + + let height = ThreadSummaryView.contentViewHeight(forThread: threadSummaryView.thread, + fitting: cellData.maxTextViewWidth) + + // The top constraint may need to include the URL preview view + let topConstraint: NSLayoutConstraint + if let upperDecorationView = upperDecorationView { + topConstraint = threadSummaryView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, + constant: topMargin) + } else { + topConstraint = threadSummaryView.topAnchor.constraint(equalTo: cellContentView.topAnchor, + constant: contentViewPositionY + topMargin) + } + + NSLayoutConstraint.activate([ + leadingConstraint, + trailingConstraint, + threadSummaryView.heightAnchor.constraint(equalToConstant: height), + topConstraint + ]) + } + } // MARK: - Private diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift b/Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift index 05ed2b309d..0dd54623a1 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift @@ -152,54 +152,54 @@ class PlainRoomTimelineCellDecorator: RoomTimelineCellDecorator { } } -// func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView, -// toCell cell: MXKRoomBubbleTableViewCell, -// cellData: RoomBubbleCellData, -// contentViewPositionY: CGFloat, -// upperDecorationView: UIView?) { -// -// cell.addTemporarySubview(threadSummaryView) -// -// if let threadSummaryDisplayable = cell as? RoomCellThreadSummaryDisplayable { -// threadSummaryDisplayable.addThreadSummaryView(threadSummaryView) -// } else { -// threadSummaryView.translatesAutoresizingMaskIntoConstraints = false -// -// let cellContentView = cell.contentView -// -// cellContentView.addSubview(threadSummaryView) -// -// var leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin -// -// if cellData.containsBubbleComponentWithEncryptionBadge { -// leftMargin += PlainRoomCellLayoutConstants.encryptedContentLeftMargin -// } -// -// let rightMargin = PlainRoomCellLayoutConstants.reactionsViewRightMargin -// let topMargin = PlainRoomCellLayoutConstants.threadSummaryViewTopMargin -// let height = ThreadSummaryView.contentViewHeight(forThread: threadSummaryView.thread, -// fitting: cellData.maxTextViewWidth) -// -// // The top constraint may need to include the URL preview view -// let topConstraint: NSLayoutConstraint -// if let upperDecorationView = upperDecorationView { -// topConstraint = threadSummaryView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, -// constant: topMargin) -// } else { -// topConstraint = threadSummaryView.topAnchor.constraint(equalTo: cellContentView.topAnchor, -// constant: contentViewPositionY + topMargin) -// } -// -// NSLayoutConstraint.activate([ -// threadSummaryView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, -// constant: leftMargin), -// threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: cellContentView.trailingAnchor, -// constant: -rightMargin), -// threadSummaryView.heightAnchor.constraint(equalToConstant: height), -// topConstraint -// ]) -// } -// } + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView, + toCell cell: MXKRoomBubbleTableViewCell, + cellData: RoomBubbleCellData, + contentViewPositionY: CGFloat, + upperDecorationView: UIView?) { + + cell.addTemporarySubview(threadSummaryView) + + if let threadSummaryDisplayable = cell as? RoomCellThreadSummaryDisplayable { + threadSummaryDisplayable.addThreadSummaryView(threadSummaryView) + } else { + threadSummaryView.translatesAutoresizingMaskIntoConstraints = false + + let cellContentView = cell.contentView + + cellContentView.addSubview(threadSummaryView) + + var leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin + + if cellData.containsBubbleComponentWithEncryptionBadge { + leftMargin += PlainRoomCellLayoutConstants.encryptedContentLeftMargin + } + + let rightMargin = PlainRoomCellLayoutConstants.reactionsViewRightMargin + let topMargin = PlainRoomCellLayoutConstants.threadSummaryViewTopMargin + let height = ThreadSummaryView.contentViewHeight(forThread: threadSummaryView.thread, + fitting: cellData.maxTextViewWidth) + + // The top constraint may need to include the URL preview view + let topConstraint: NSLayoutConstraint + if let upperDecorationView = upperDecorationView { + topConstraint = threadSummaryView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, + constant: topMargin) + } else { + topConstraint = threadSummaryView.topAnchor.constraint(equalTo: cellContentView.topAnchor, + constant: contentViewPositionY + topMargin) + } + + NSLayoutConstraint.activate([ + threadSummaryView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, + constant: leftMargin), + threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: cellContentView.trailingAnchor, + constant: -rightMargin), + threadSummaryView.heightAnchor.constraint(equalToConstant: height), + topConstraint + ]) + } + } func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell, withFailedEventIds failedEventIds: Set) { cell.updateTickView(withFailedEventIds: failedEventIds) diff --git a/Riot/Modules/Room/TimelineCells/Styles/RoomTimelineCellDecorator.swift b/Riot/Modules/Room/TimelineCells/Styles/RoomTimelineCellDecorator.swift index 5f4e881dc2..fd488294ca 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/RoomTimelineCellDecorator.swift +++ b/Riot/Modules/Room/TimelineCells/Styles/RoomTimelineCellDecorator.swift @@ -42,11 +42,11 @@ protocol RoomTimelineCellDecorator { contentViewPositionY: CGFloat, upperDecorationView: UIView?) -// func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView, -// toCell cell: MXKRoomBubbleTableViewCell, -// cellData: RoomBubbleCellData, -// contentViewPositionY: CGFloat, -// upperDecorationView: UIView?) + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView, + toCell cell: MXKRoomBubbleTableViewCell, + cellData: RoomBubbleCellData, + contentViewPositionY: CGFloat, + upperDecorationView: UIView?) func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell, withFailedEventIds failedEventIds: Set) diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index 16c9d8893a..bf2c751282 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -322,8 +322,7 @@ @interface SettingsViewController () ] to allow any feature for an instance + // "" : [ tchapFeatureAnyHomeServer ] to allow a feature to any instance + static let tchapFeatureNotificationByEmail = "tchapFeatureNotificationByEmail" + static let tchapFeatureVoiceOverIP = "tchapFeatureVoiceOverIP" + static let tchapFeatureVideoOverIP = "tchapFeatureVideoOverIP" + static let tchapFeatureThreads = "tchapFeatureThreads" + static var tchapFeaturesAllowedHomeServersForFeature: [String: [String]] = [ + tchapFeatureNotificationByEmail: [ + "agent.dinum.tchap.gouv.fr" + ], + // No activation of VoIP calls actually in Tchap Production. +// tchapFeatureVoiceOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of video calls actually in Tchap Production. +// tchapFeatureVideoOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of Threads actually in Tchap Production. +// tchapFeatureThreads: [ +// "agent.dinum.tchap.gouv.fr" +// ] + ] + // MARK: - Side Menu static let enableSideMenu: Bool = true && !newAppLayoutEnabled static let sideMenuShowInviteFriends: Bool = true diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index 70394a3ff2..e3833a3237 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -83,3 +83,6 @@ targets: - path: ../Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/MatrixSDK - path: ../Riot/Managers/Theme - path: ../Riot/Categories/UIColor.swift + + # Tchap + - path: ../Tchap/Extensions/Account+Tchap.swift diff --git a/RiotShareExtension/BuildSettings.swift b/RiotShareExtension/BuildSettings.swift index 35f1c53888..9ce79284fb 100644 --- a/RiotShareExtension/BuildSettings.swift +++ b/RiotShareExtension/BuildSettings.swift @@ -259,6 +259,33 @@ final class BuildSettings: NSObject { static let allowBackgroundAudioMessagePlayback: Bool = true + // Tchap: Feature activation by Instance + static let tchapFeatureAnyFeature = "*" // To allow any feature for some instances + static let tchapFeatureAnyHomeServer = "*" // To allow a feature for any instance + // tchapFeatureAnyFeature : [ ] to allow any feature for an instance + // "" : [ tchapFeatureAnyHomeServer ] to allow a feature to any instance + static let tchapFeatureNotificationByEmail = "tchapFeatureNotificationByEmail" + static let tchapFeatureVoiceOverIP = "tchapFeatureVoiceOverIP" + static let tchapFeatureVideoOverIP = "tchapFeatureVideoOverIP" + static let tchapFeatureThreads = "tchapFeatureThreads" + static var tchapFeaturesAllowedHomeServersForFeature: [String: [String]] = [ + tchapFeatureNotificationByEmail: [ + "agent.dinum.tchap.gouv.fr" + ], + // No activation of VoIP calls actually in Tchap Production. +// tchapFeatureVoiceOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of video calls actually in Tchap Production. +// tchapFeatureVideoOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of Threads actually in Tchap Production. +// tchapFeatureThreads: [ +// "agent.dinum.tchap.gouv.fr" +// ] + ] + // MARK: - Side Menu static let enableSideMenu: Bool = true && !newAppLayoutEnabled static let sideMenuShowInviteFriends: Bool = true diff --git a/Tchap/Config/BuildSettings.swift b/Tchap/Config/BuildSettings.swift index 35f1c53888..9ce79284fb 100644 --- a/Tchap/Config/BuildSettings.swift +++ b/Tchap/Config/BuildSettings.swift @@ -259,6 +259,33 @@ final class BuildSettings: NSObject { static let allowBackgroundAudioMessagePlayback: Bool = true + // Tchap: Feature activation by Instance + static let tchapFeatureAnyFeature = "*" // To allow any feature for some instances + static let tchapFeatureAnyHomeServer = "*" // To allow a feature for any instance + // tchapFeatureAnyFeature : [ ] to allow any feature for an instance + // "" : [ tchapFeatureAnyHomeServer ] to allow a feature to any instance + static let tchapFeatureNotificationByEmail = "tchapFeatureNotificationByEmail" + static let tchapFeatureVoiceOverIP = "tchapFeatureVoiceOverIP" + static let tchapFeatureVideoOverIP = "tchapFeatureVideoOverIP" + static let tchapFeatureThreads = "tchapFeatureThreads" + static var tchapFeaturesAllowedHomeServersForFeature: [String: [String]] = [ + tchapFeatureNotificationByEmail: [ + "agent.dinum.tchap.gouv.fr" + ], + // No activation of VoIP calls actually in Tchap Production. +// tchapFeatureVoiceOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of video calls actually in Tchap Production. +// tchapFeatureVideoOverIP: [ +// "agent.dinum.tchap.gouv.fr" +// ], + // No activation of Threads actually in Tchap Production. +// tchapFeatureThreads: [ +// "agent.dinum.tchap.gouv.fr" +// ] + ] + // MARK: - Side Menu static let enableSideMenu: Bool = true && !newAppLayoutEnabled static let sideMenuShowInviteFriends: Bool = true diff --git a/Tchap/Extensions/Account+Tchap.swift b/Tchap/Extensions/Account+Tchap.swift new file mode 100644 index 0000000000..ef21323c99 --- /dev/null +++ b/Tchap/Extensions/Account+Tchap.swift @@ -0,0 +1,38 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +@objc extension MXKAccount { + + func isFeatureActivated(_ featureId: String) -> Bool { + guard let allowedHomeServers = BuildSettings.tchapFeaturesAllowedHomeServersForFeature[featureId] ?? BuildSettings.tchapFeaturesAllowedHomeServersForFeature[BuildSettings.tchapFeatureAnyFeature] else { + return false + } + + if allowedHomeServers.contains(BuildSettings.tchapFeatureAnyHomeServer) { + return true + } + + guard let homeServerURL = self.mxCredentials.homeServer else { + return false + } + + let homeServerDomain = homeServerURL.replacingOccurrences(of: BuildSettings.serverUrlPrefix, with: "") + + return allowedHomeServers.contains(homeServerDomain) + } +} diff --git a/Tchap/Modules/RoomPreview/RoomPreviewCoordinator.swift b/Tchap/Modules/RoomPreview/RoomPreviewCoordinator.swift index c0103af40e..4556c1a28f 100644 --- a/Tchap/Modules/RoomPreview/RoomPreviewCoordinator.swift +++ b/Tchap/Modules/RoomPreview/RoomPreviewCoordinator.swift @@ -305,8 +305,7 @@ extension RoomPreviewCoordinator: RoomViewControllerDelegate { // } - // Tchap: Disable Threads -// func threadsCoordinator(for roomViewController: RoomViewController, threadId: String?) -> ThreadsCoordinatorBridgePresenter? { -// return nil -// } + func threadsCoordinator(for roomViewController: RoomViewController, threadId: String?) -> ThreadsCoordinatorBridgePresenter? { + return nil + } } diff --git a/TchapTests/target.yml b/TchapTests/target.yml index c10ba193b3..03599ca31c 100644 --- a/TchapTests/target.yml +++ b/TchapTests/target.yml @@ -61,6 +61,7 @@ targets: # Tchap - path: ../Tchap/Config/BuildSettings.swift + - path: ../Tchap/Extensions/Account+Tchap.swift # Riot - path: ../Riot/Categories/Bundle.swift diff --git a/changelog.d/878.feature b/changelog.d/878.feature new file mode 100644 index 0000000000..111252a527 --- /dev/null +++ b/changelog.d/878.feature @@ -0,0 +1 @@ +Activer l'affichage en thread \ No newline at end of file diff --git a/changelog.d/912.feature b/changelog.d/912.feature new file mode 100644 index 0000000000..f22d9eae7c --- /dev/null +++ b/changelog.d/912.feature @@ -0,0 +1 @@ +N’activer l'affichage en thread que pour un agent DINUM \ No newline at end of file