Merge branch 'develop' into ismail/5068_start_thread

This commit is contained in:
ismailgulek 2022-01-25 14:30:52 +03:00
commit 8cc82cf7e1
No known key found for this signature in database
GPG key ID: E96336D42D9470A9
114 changed files with 2639 additions and 548 deletions

View file

@ -57,8 +57,9 @@ body:
id: homeserver
attributes:
label: Homeserver
description: Which server is your account registered on?
placeholder: e.g. matrix.org
description: |
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
validations:
required: false
- type: dropdown

View file

@ -11,7 +11,6 @@ on:
env:
# Make the git branch for a PR available to our Fastfile
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
MapTilerAPIKey: ${{ secrets.MAPTILER_API_KEY }}
jobs:
build:

View file

@ -12,7 +12,6 @@ on:
env:
# Make the git branch for a PR available to our Fastfile
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
MapTilerAPIKey: ${{ secrets.MAPTILER_API_KEY }}
jobs:
tests:

View file

@ -11,7 +11,6 @@ on:
env:
# Make the git branch for a PR available to our Fastfile
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
MapTilerAPIKey: ${{ secrets.MAPTILER_API_KEY }}
jobs:
build:

View file

@ -15,7 +15,6 @@
//
import Foundation
import Keys
/// BuildSettings provides settings computed at build time.
/// In future, it may be automatically generated from xcconfig files
@ -213,7 +212,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
@ -261,7 +262,6 @@ final class BuildSettings: NSObject {
static let settingsScreenAllowBugReportingManually: Bool = true
static let settingsScreenAllowDeactivatingAccount: Bool = true
static let settingsScreenShowChangePassword:Bool = true
static let settingsScreenShowInviteFriends:Bool = true
static let settingsScreenShowEnableStunServerFallback: Bool = true
static let settingsScreenShowNotificationDecodedContentOption: Bool = true
static let settingsScreenShowNsfwRoomsOption: Bool = true
@ -349,6 +349,7 @@ final class BuildSettings: NSObject {
static let authScreenShowPhoneNumber = true
static let authScreenShowForgotPassword = true
static let authScreenShowCustomServerOptions = true
static let authScreenShowSocialLoginSection = true
// MARK: - Unified Search
static let unifiedSearchScreenShowPublicDirectory = true
@ -368,7 +369,7 @@ final class BuildSettings: NSObject {
// MARK: - Location Sharing
static let tileServerMapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)!
static let tileServerMapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx")!
static var locationSharingEnabled: Bool {
guard #available(iOS 14, *) else {

View file

@ -3,7 +3,6 @@ source "https://rubygems.org"
gem "xcode-install"
gem "fastlane"
gem "cocoapods", '~>1.11.2'
gem "cocoapods-keys"
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

View file

@ -3,9 +3,6 @@ GEM
specs:
CFPropertyList (3.0.5)
rexml
RubyInline (3.12.5)
ZenTest (~> 4.3)
ZenTest (4.12.0)
activesupport (6.1.4.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
@ -67,9 +64,6 @@ GEM
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.5.1)
cocoapods-keys (2.2.1)
dotenv
osx_keychain
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
@ -231,8 +225,6 @@ GEM
netrc (0.11.0)
optparse (0.1.1)
os (1.1.4)
osx_keychain (1.0.2)
RubyInline (~> 3)
plist (3.6.0)
public_suffix (4.0.6)
rake (13.0.6)
@ -300,7 +292,6 @@ PLATFORMS
DEPENDENCIES
cocoapods (~> 1.11.2)
cocoapods-keys
fastlane
fastlane-plugin-diawi
fastlane-plugin-versioning
@ -308,4 +299,4 @@ DEPENDENCIES
xcode-install
BUNDLED WITH
2.2.28
2.2.32

View file

@ -129,11 +129,6 @@ abstract_target 'RiotPods' do
end
plugin 'cocoapods-keys', {
:project => "Riot",
:keys => ["MapTilerAPIKey"]
}
post_install do |installer|
installer.pods_project.targets.each do |target|

View file

@ -49,7 +49,6 @@ PODS:
- Introspect (0.1.3)
- JitsiMeetSDK (3.10.2)
- KeychainAccess (4.2.2)
- Keys (1.0.1)
- KituraContracts (1.2.1):
- LoggerAPI (~> 1.7)
- KTCenterFlowLayout (1.3.1)
@ -115,7 +114,6 @@ DEPENDENCIES:
- HPGrowingTextView (~> 1.1)
- Introspect (~> 0.1)
- KeychainAccess (~> 4.2.2)
- Keys (from `Pods/CocoaPodsKeys`)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.20.16)
@ -179,12 +177,10 @@ EXTERNAL SOURCES:
AnalyticsEvents:
:branch: release/swift
:git: https://github.com/matrix-org/matrix-analytics-events.git
Keys:
:path: Pods/CocoaPodsKeys
CHECKOUT OPTIONS:
AnalyticsEvents:
:commit: f1805ad7c3fafa7fd9c6e2eaa9e0165f8142ecd2
:commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c
:git: https://github.com/matrix-org/matrix-analytics-events.git
SPEC CHECKSUMS:
@ -207,7 +203,6 @@ SPEC CHECKSUMS:
Introspect: 2be020f30f084ada52bb4387fff83fa52c5c400e
JitsiMeetSDK: 2f118fa770f23e518f3560fc224fae3ac7062223
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9
KituraContracts: e845e60dc8627ad0a76fa55ef20a45451d8f830b
KTCenterFlowLayout: 6e02b50ab2bd865025ae82fe266ed13b6d9eaf97
libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd
@ -230,6 +225,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: 2493587902f8f28bb2638303dd583c47e9f24d8b
PODFILE CHECKSUM: c9a50c445e32b40b22fadd0f54b376f1bd624ebb
COCOAPODS: 1.11.2

View file

@ -19,5 +19,8 @@
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,33 @@
//
// Copyright 2021 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
extension MXKRoomBubbleCellData {
/// Indicate true if the sender is the session user
var isSenderCurrentUser: Bool {
if let senderId = self.senderId, let currentUserId = self.mxSession.myUserId, senderId == currentUserId {
return true
}
return false
}
// Indicate true if the cell data is collapsable and collapsed
var isCollapsableAndCollapsed: Bool {
return self.collapsable && self.collapsed
}
}

View file

@ -198,6 +198,10 @@ final class RiotSettings: NSObject {
@UserDefault(key: "roomScreenEnableMessageBubbles", defaultValue: BuildSettings.roomScreenEnableMessageBubblesByDefault, storage: defaults)
var roomScreenEnableMessageBubbles
var roomTimelineStyleIdentifier: RoomTimelineStyleIdentifier {
return self.roomScreenEnableMessageBubbles ? .bubble : .plain
}
// MARK: - Room Contextual Menu
@UserDefault(key: "roomContextualMenuShowMoreOptionForMessages", defaultValue: BuildSettings.roomContextualMenuShowMoreOptionForMessages, storage: defaults)

View file

@ -52,7 +52,7 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan
[self updateAppearance];
[[NSNotificationCenter defaultCenter] postNotificationName:kThemeServiceDidChangeThemeNotification object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:kThemeServiceDidChangeThemeNotification object:self];
}
}

View file

@ -1391,9 +1391,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
else
{
void(^findRoom)(void) = ^{
if ([_masterTabBarController.selectedViewController isKindOfClass:MXKActivityHandlingViewController.class])
if ([_masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)])
{
MXKActivityHandlingViewController *homeViewController = (MXKActivityHandlingViewController*)_masterTabBarController.selectedViewController;
UIViewController<MXKViewControllerActivityHandling> *homeViewController = (UIViewController<MXKViewControllerActivityHandling>*)_masterTabBarController.selectedViewController;
[homeViewController startActivityIndicator];
@ -1670,11 +1670,13 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Try to get more information about the room before opening its preview
[roomPreviewData peekInRoom:^(BOOL succeeded) {
MXStrongifyAndReturnIfNil(self);
MXKViewController *homeViewController = (MXKViewController*)self.masterTabBarController.selectedViewController;
if ([self.masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)])
{
UIViewController<MXKViewControllerActivityHandling> *homeViewController = (UIViewController<MXKViewControllerActivityHandling>*)self.masterTabBarController.selectedViewController;
// Note: the activity indicator will not disappear if the session is not ready
[homeViewController stopActivityIndicator];
}
// If no data is available for this room, we name it with the known room alias (if any).
if (!succeeded && self->universalLinkFragmentPendingRoomAlias[roomIdOrAlias])

View file

@ -482,7 +482,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0;
// Hide input view when there is only social login actions to present
if ((self.authType == MXKAuthenticationTypeLogin || self.authType == MXKAuthenticationTypeRegister)
&& self.currentLoginSSOFlow
&& !self.isAuthSessionContainsPasswordFlow)
&& !self.isAuthSessionContainsPasswordFlow
&& BuildSettings.authScreenShowSocialLoginSection)
{
hideAuthInputView = YES;
}
@ -1736,7 +1737,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0;
{
SocialLoginButtonMode socialLoginButtonMode = SocialLoginButtonModeContinue;
BOOL showSocialLoginView = self.currentLoginSSOFlow ? YES : NO;
BOOL showSocialLoginView = BuildSettings.authScreenShowSocialLoginSection && (self.currentLoginSSOFlow ? YES : NO);
switch (self.authType)
{

View file

@ -0,0 +1,29 @@
//
// Copyright 2021 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 UIKit
/// UICollectionViewFlowLayout with right align behavior
class CollectionViewRightAlignFlowLayout: UICollectionViewFlowLayout {
override var flipsHorizontallyInOppositeLayoutDirection: Bool {
return true
}
override var developmentLayoutDirection: UIUserInterfaceLayoutDirection {
return UIUserInterfaceLayoutDirection.rightToLeft
}
}

View file

@ -1026,6 +1026,12 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
{
[super dataSource:dataSource didCellChange:changes];
}
else
{
// Since we've enabled room list pagination, `refreshRecentsTable` not called in this case.
// Refresh tab bar badges separately.
[[AppDelegate theDelegate].masterTabBarController refreshTabBarBadges];
}
if (changes == nil)
{

View file

@ -16,7 +16,7 @@
import Foundation
class HomeViewControllerWithBannerWrapperViewController: MXKActivityHandlingViewController, BannerPresentationProtocol {
class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKViewControllerActivityHandling, BannerPresentationProtocol {
@objc let homeViewController: HomeViewController
private var bannerContainerView: UIView!
@ -85,4 +85,22 @@ class HomeViewControllerWithBannerWrapperViewController: MXKActivityHandlingView
bannerView.removeFromSuperview()
}
}
// MARK: - MXKViewControllerActivityHandling
var activityIndicator: UIActivityIndicatorView! {
get {
return homeViewController.activityIndicator
}
set {
homeViewController.activityIndicator = newValue
}
}
func startActivityIndicator() {
homeViewController.startActivityIndicator()
}
func stopActivityIndicator() {
homeViewController.stopActivityIndicator()
}
}

View file

@ -14,3 +14,4 @@
#import "MXKRoomInputToolbarView.h"
#import "MXKImageView.h"
#import "MXKRoomBubbleCellData.h"

View file

@ -168,4 +168,11 @@
*/
- (MXKRoomBubbleComponent*)getFirstBubbleComponentWithDisplay;
/**
Get the last visible component.
@return Last visible component or nil.
*/
- (MXKRoomBubbleComponent*)getLastBubbleComponentWithDisplay;
@end

View file

@ -313,9 +313,8 @@
@synchronized(bubbleComponents)
{
for (NSInteger index = 0; index < bubbleComponents.count; index++)
for (MXKRoomBubbleComponent *component in bubbleComponents)
{
MXKRoomBubbleComponent *component = bubbleComponents[index];
if (component.attributedTextMessage)
{
first = component;
@ -327,6 +326,26 @@
return first;
}
- (MXKRoomBubbleComponent*)getLastBubbleComponentWithDisplay
{
// Look for the first component which is actually displayed (some event are ignored in room history display).
MXKRoomBubbleComponent* lastVisibleComponent = nil;
@synchronized(bubbleComponents)
{
for (MXKRoomBubbleComponent *component in bubbleComponents.reverseObjectEnumerator)
{
if (component.attributedTextMessage)
{
lastVisibleComponent = component;
break;
}
}
}
return lastVisibleComponent;
}
- (NSAttributedString*)attributedTextMessageWithHighlightedEvent:(NSString*)eventId tintColor:(UIColor*)tintColor
{
NSAttributedString *customAttributedTextMsg;

View file

@ -18,6 +18,13 @@ import Foundation
import MatrixSDK
import Reusable
import DGCollectionViewLeftAlignFlowLayout
import UIKit
/// BubbleReactionsView items alignment
enum BubbleReactionsViewAlignment {
case left
case right
}
@objcMembers
final class BubbleReactionsView: UIView, NibOwnerLoadable {
@ -51,6 +58,12 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
}
}
var alignment: BubbleReactionsViewAlignment = .left {
didSet {
self.updateCollectionViewLayout(for: alignment)
}
}
// MARK: - Setup
private func commonInit() {
@ -87,7 +100,18 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
self.collectionView.isScrollEnabled = false
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
self.alignment = .left
self.collectionView.register(cellType: BubbleReactionViewCell.self)
self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
self.collectionView.reloadData()
}
private func updateCollectionViewLayout(for alignment: BubbleReactionsViewAlignment) {
let collectionViewLayout = self.collectionViewLayout(for: alignment)
self.collectionView.collectionViewLayout = collectionViewLayout
if let collectionViewFlowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
collectionViewFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
@ -95,9 +119,22 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
collectionViewFlowLayout.minimumLineSpacing = Constants.minimumLineSpacing
}
self.collectionView.register(cellType: BubbleReactionViewCell.self)
self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
self.collectionView.reloadData()
self.collectionView.collectionViewLayout.invalidateLayout()
}
private func collectionViewLayout(for alignment: BubbleReactionsViewAlignment) -> UICollectionViewLayout {
let collectionViewLayout: UICollectionViewLayout
switch alignment {
case .left:
collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
case .right:
collectionViewLayout = CollectionViewRightAlignFlowLayout()
}
return collectionViewLayout
}
private func setupLongPressGestureRecognizer() {

View file

@ -870,6 +870,12 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
- (BOOL)addEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState
{
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
if (NO == [timelineConfiguration.currentStyle canAddEvent:event and:roomState to:self]) {
return NO;
}
BOOL shouldAddEvent = YES;
switch (self.tag)

View file

@ -372,6 +372,8 @@ const CGFloat kTypingCellHeight = 24;
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
id<RoomTimelineCellDecorator> cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator;
// Finalize cell view customization here
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
{
@ -383,11 +385,8 @@ const CGFloat kTypingCellHeight = 24;
BOOL isCollapsableCellCollapsed = cellData.collapsable && cellData.collapsed;
// Display timestamp of the last message
if (cellData.containsLastMessage && !isCollapsableCellCollapsed)
{
[bubbleCell addTimestampLabelForComponent:cellData.mostRecentComponentIndex];
}
// Display timestamp of the message if needed
[cellDecorator addTimestampLabelIfNeededToCell:bubbleCell cellData:cellData];
NSMutableArray *temporaryViews = [NSMutableArray new];
@ -431,23 +430,8 @@ const CGFloat kTypingCellHeight = 24;
urlPreviewView.tag = index;
[temporaryViews addObject:urlPreviewView];
[bubbleCell.tmpSubviews addObject:urlPreviewView];
urlPreviewView.translatesAutoresizingMaskIntoConstraints = NO;
urlPreviewView.availableWidth = cellData.maxTextViewWidth;
[bubbleCell.contentView addSubview:urlPreviewView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
{
leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
}
// Set the preview view's origin
[NSLayoutConstraint activateConstraints: @[
[urlPreviewView.leadingAnchor constraintEqualToAnchor:urlPreviewView.superview.leadingAnchor constant:leftMargin],
[urlPreviewView.topAnchor constraintEqualToAnchor:urlPreviewView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin],
]];
[cellDecorator addURLPreviewView:urlPreviewView
toCell:bubbleCell cellData:cellData contentViewPositionY:bottomPositionY];
}
MXAggregatedReactions* reactions = cellData.reactions[componentEventId].aggregatedReactionsWithNonZeroCount;
@ -469,44 +453,8 @@ const CGFloat kTypingCellHeight = 24;
bubbleReactionsViewModel.viewModelDelegate = self;
[temporaryViews addObject:reactionsView];
[bubbleCell.tmpSubviews addObject:reactionsView];
if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReactionsDisplayable)])
{
id<BubbleCellReactionsDisplayable> reactionsDisplayable = (id<BubbleCellReactionsDisplayable>)bubbleCell;
[reactionsDisplayable addReactionsView:reactionsView];
}
else
{
reactionsView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:reactionsView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
{
leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
}
// The top constraint may need to include the URL preview view
NSLayoutConstraint *topConstraint;
if (urlPreviewView)
{
topConstraint = [reactionsView.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor constant:RoomBubbleCellLayout.reactionsViewTopMargin];
}
else
{
topConstraint = [reactionsView.topAnchor constraintEqualToAnchor:reactionsView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.reactionsViewTopMargin];
}
// Force receipts container size
[NSLayoutConstraint activateConstraints:
@[
[reactionsView.leadingAnchor constraintEqualToAnchor:reactionsView.superview.leadingAnchor constant:leftMargin],
[reactionsView.trailingAnchor constraintEqualToAnchor:reactionsView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin],
topConstraint
]];
}
[cellDecorator addReactionView:reactionsView toCell:bubbleCell
cellData:cellData contentViewPositionY:bottomPositionY upperDecorationView:urlPreviewView];
}
ThreadSummaryView *threadSummaryView;
@ -518,43 +466,13 @@ const CGFloat kTypingCellHeight = 24;
threadSummaryView.delegate = self;
[temporaryViews addObject:threadSummaryView];
[bubbleCell.tmpSubviews addObject:threadSummaryView];
UIView *upperDecorationView = reactionsView ?: urlPreviewView;
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:threadSummaryView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
{
leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
}
// The top constraint may need to include the URL preview view or reactions view
NSLayoutConstraint *topConstraint;
if (reactionsView)
{
topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor
constant:RoomBubbleCellLayout.threadSummaryViewTopMargin];
}
else if (urlPreviewView)
{
topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor
constant:RoomBubbleCellLayout.threadSummaryViewTopMargin];
}
else
{
topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin];
}
// Set constraints for the summary view
[NSLayoutConstraint activateConstraints: @[
[threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
constant:leftMargin],
topConstraint,
[threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:component.thread fitting:cellData.maxTextViewWidth]],
[threadSummaryView.trailingAnchor constraintEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
]];
[cellDecorator addThreadSummaryView:threadSummaryView
toCell:bubbleCell
cellData:cellData
contentViewPositionY:bottomPositionY
upperDecorationView:upperDecorationView];
}
MXKReceiptSendersContainer* avatarsContainer;
@ -612,67 +530,13 @@ const CGFloat kTypingCellHeight = 24;
avatarsContainer.accessibilityIdentifier = @"readReceiptsContainer";
[temporaryViews addObject:avatarsContainer];
// Add this read receipts container in the content view
[bubbleCell.tmpSubviews addObject:avatarsContainer];
UIView *upperDecorationView = threadSummaryView ?: (reactionsView ?: urlPreviewView);
if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReadReceiptsDisplayable)])
{
id<BubbleCellReadReceiptsDisplayable> readReceiptsDisplayable = (id<BubbleCellReadReceiptsDisplayable>)bubbleCell;
[readReceiptsDisplayable addReadReceiptsView:avatarsContainer];
}
else
{
[bubbleCell.contentView addSubview:avatarsContainer];
// Force receipts container size
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:RoomBubbleCellLayout.readReceiptsViewWidth];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:RoomBubbleCellLayout.readReceiptsViewHeight];
// Force receipts container position
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:avatarsContainer.superview
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-RoomBubbleCellLayout.readReceiptsViewRightMargin];
// At the bottom, we either have a thread summary, a reactions, a URL preview or nothing
NSLayoutConstraint *topConstraint;
if (threadSummaryView)
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:threadSummaryView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
else if (reactionsView)
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
else if (urlPreviewView)
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
else
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:avatarsContainer.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
// Available on iOS 8 and later
[NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]];
}
[cellDecorator addReadReceiptsView:avatarsContainer
toCell:bubbleCell
cellData:cellData
contentViewPositionY:bottomPositionY
upperDecorationView:upperDecorationView];
}
}
@ -755,16 +619,7 @@ const CGFloat kTypingCellHeight = 24;
// Check whether an event is currently selected: the other messages are then blurred
if (_selectedEventId)
{
// Check whether the selected event belongs to this bubble
NSInteger selectedComponentIndex = cellData.selectedComponentIndex;
if (selectedComponentIndex != NSNotFound)
{
[bubbleCell selectComponent:cellData.selectedComponentIndex showEditButton:NO showTimestamp:cellData.showTimestampForSelectedComponent];
}
else
{
bubbleCell.blurred = YES;
}
[[RoomTimelineConfiguration shared].currentStyle applySelectedStyleIfNeededToCell:bubbleCell cellData:cellData];
}
// Reset the marker if any
@ -801,13 +656,24 @@ const CGFloat kTypingCellHeight = 24;
// We are interested only by outgoing messages
if ([cellData.senderId isEqualToString: self.mxSession.credentials.userId])
{
[bubbleCell updateTickViewWithFailedEventIds:self.failedEventIds];
[cellDecorator addSendStatusViewToCell:bubbleCell
withFailedEventIds:self.failedEventIds];
}
// Make extra cell layout updates if needed
[self updateCellLayoutIfNeeded:bubbleCell withCellData:cellData];
}
return cell;
}
- (void)updateCellLayoutIfNeeded:(MXKRoomBubbleTableViewCell*)cell withCellData:(MXKRoomBubbleCellData*)cellData {
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater updateLayoutIfNeededFor:cell andCellData:cellData];
}
- (RoomBubbleCellData*)roomBubbleCellDataForEventId:(NSString*)eventId
{
id<MXKRoomBubbleCellDataStoring> cellData = [self cellDataOfEventWithEventId:eventId];

View file

@ -18,7 +18,7 @@ import UIKit
import Reusable
import Mapbox
class LocationUserMarkerView: MGLAnnotationView, NibLoadable {
class LocationMarkerView: MGLAnnotationView, NibLoadable {
@IBOutlet private var avatarView: UserAvatarView!

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="iN0-l3-epB" customClass="LocationMarkerView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="108"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GS1-Cw-Ezx">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="41S-fj-tn4"/>
<constraint firstAttribute="height" constant="54" id="MAX-5E-xvS"/>
</constraints>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_marker_icon" translatesAutoresizingMaskIntoConstraints="NO" id="gQe-Hv-22e">
<rect key="frame" x="13" y="15" width="24" height="24"/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="XuF-VU-qG2"/>
<constraint firstAttribute="height" constant="24" id="ejE-pC-umv"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qut-wn-BX3" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="2" y="2" width="46" height="46"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="BjG-I5-n8f"/>
<constraint firstAttribute="width" constant="46" id="W3F-Aw-FO3"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="ldO-kc-R5W" firstAttribute="top" secondItem="GS1-Cw-Ezx" secondAttribute="top" id="1cb-YG-bcI"/>
<constraint firstItem="ldO-kc-R5W" firstAttribute="leading" secondItem="GS1-Cw-Ezx" secondAttribute="leading" id="8I8-Zn-R5S"/>
<constraint firstItem="gQe-Hv-22e" firstAttribute="centerY" secondItem="GS1-Cw-Ezx" secondAttribute="centerY" id="EE9-rM-y0V"/>
<constraint firstItem="qut-wn-BX3" firstAttribute="centerY" secondItem="GS1-Cw-Ezx" secondAttribute="centerY" constant="-2" id="EQM-Hr-37h"/>
<constraint firstAttribute="trailing" secondItem="ldO-kc-R5W" secondAttribute="trailing" id="QUB-rY-t4j"/>
<constraint firstItem="qut-wn-BX3" firstAttribute="centerX" secondItem="GS1-Cw-Ezx" secondAttribute="centerX" id="XLg-Qs-yTR"/>
<constraint firstAttribute="bottom" secondItem="ldO-kc-R5W" secondAttribute="bottom" id="l4H-nN-44g"/>
<constraint firstItem="gQe-Hv-22e" firstAttribute="centerX" secondItem="GS1-Cw-Ezx" secondAttribute="centerX" id="syG-Kp-4F9"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="GS1-Cw-Ezx" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="61F-Ve-exC"/>
<constraint firstAttribute="trailing" secondItem="GS1-Cw-Ezx" secondAttribute="trailing" id="H8I-4T-A0M"/>
<constraint firstItem="GS1-Cw-Ezx" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hhI-gR-E5z"/>
<constraint firstAttribute="bottom" secondItem="GS1-Cw-Ezx" secondAttribute="bottom" constant="54" id="mvD-6W-gMh"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
</connections>
<point key="canvasLocation" x="58.695652173913047" y="4.6875"/>
</view>
</objects>
<resources>
<image name="location_marker_icon" width="24" height="24"/>
<image name="location_user_marker" width="51" height="54.5"/>
</resources>
</document>

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="LocationUserMarkerView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
</imageView>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qut-wn-BX3" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="2" y="2" width="46" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="ldO-kc-R5W" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="VF5-CP-8eH"/>
<constraint firstItem="ldO-kc-R5W" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Voc-LH-fTw"/>
<constraint firstAttribute="trailing" secondItem="ldO-kc-R5W" secondAttribute="trailing" id="Vt0-UN-s20"/>
<constraint firstAttribute="bottom" secondItem="ldO-kc-R5W" secondAttribute="bottom" id="Ybf-8x-UaG"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
</connections>
<point key="canvasLocation" x="-84.057971014492765" y="-80.357142857142847"/>
</view>
</objects>
<resources>
<image name="location_user_marker" width="51" height="54.5"/>
</resources>
</document>

View file

@ -17,7 +17,6 @@
import UIKit
import Reusable
import Mapbox
import Keys
class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegate {
@ -25,7 +24,6 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
private struct Constants {
static let mapHeight: CGFloat = 300.0
static let mapTilerKey = RiotKeys().mapTilerAPIKey
static let mapZoomLevel = 15.0
static let cellBorderRadius: CGFloat = 1.0
static let cellCornerRadius: CGFloat = 8.0
@ -36,9 +34,10 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
@IBOutlet private var descriptionContainerView: UIView!
@IBOutlet private var descriptionLabel: UILabel!
@IBOutlet private var descriptionIcon: UIImageView!
private var mapView: MGLMapView!
private var annotationView: LocationUserMarkerView?
private var annotationView: LocationMarkerView?
// MARK: Public
@ -73,19 +72,13 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
// MARK: - Public
public func displayLocation(_ location: CLLocationCoordinate2D,
userIdentifier: String,
userDisplayName: String,
userAvatarURLString: String?,
mediaManager: MXMediaManager) {
public func displayLocation(_ location: CLLocationCoordinate2D, userAvatarData: AvatarViewData? = nil) {
annotationView = LocationUserMarkerView.loadFromNib()
annotationView = LocationMarkerView.loadFromNib()
annotationView?.setAvatarData(AvatarViewData(matrixItemId: userIdentifier,
displayName: userDisplayName,
avatarUrl: userAvatarURLString,
mediaManager: mediaManager,
fallbackImage: .matrixItem(userIdentifier, userDisplayName)))
if let userAvatarData = userAvatarData {
annotationView?.setAvatarData(userAvatarData)
}
if let annotations = mapView.annotations {
mapView.removeAnnotations(annotations)
@ -103,6 +96,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
func update(theme: Theme) {
descriptionLabel.textColor = theme.colors.primaryContent
descriptionLabel.font = theme.fonts.footnote
descriptionIcon.tintColor = theme.colors.accent
layer.borderColor = theme.colors.quinaryContent.cgColor
}

View file

@ -58,6 +58,7 @@
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="descriptionContainerView" destination="oVd-gS-Rmb" id="Npu-jp-oYo"/>
<outlet property="descriptionIcon" destination="GP2-dA-giJ" id="7YL-UU-ClT"/>
<outlet property="descriptionLabel" destination="c68-l7-McA" id="HiH-8Q-yTp"/>
</connections>
<point key="canvasLocation" x="165.94202898550725" y="-100.78125"/>

View file

@ -36,16 +36,6 @@
#import "MXKRoomBubbleCellData.h"
#import "MXKRoomIncomingTextMsgBubbleCell.h"
#import "MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
#import "MXKRoomIncomingAttachmentBubbleCell.h"
#import "MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
#import "MXKRoomOutgoingTextMsgBubbleCell.h"
#import "MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "MXKRoomOutgoingAttachmentBubbleCell.h"
#import "MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "MXKEncryptionKeysImportView.h"
#import "NSBundle+MatrixKit.h"
@ -616,17 +606,6 @@
_bubblesTableView.delegate = self;
_bubblesTableView.dataSource = roomDataSource; // Note: data source may be nil here, it will be set during [displayRoom:] call.
// Set up default classes to use for cells
[_bubblesTableView registerClass:MXKRoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
[_bubblesTableView registerClass:MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
// Observe kMXSessionWillLeaveRoomNotification to be notified if the user leaves the current room.
MXWeakify(self);
_mxSessionWillLeaveRoomNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionWillLeaveRoomNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
@ -2477,64 +2456,7 @@
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
{
Class cellViewClass = nil;
// Sanity check
if ([cellData conformsToProtocol:@protocol(MXKRoomBubbleCellDataStoring)])
{
id<MXKRoomBubbleCellDataStoring> bubbleData = (id<MXKRoomBubbleCellDataStoring>)cellData;
// Select the suitable table view cell class
if (bubbleData.isIncoming)
{
if (bubbleData.isAttachmentWithThumbnail)
{
if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
}
else
{
cellViewClass = MXKRoomIncomingAttachmentBubbleCell.class;
}
}
else
{
if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.class;
}
else
{
cellViewClass = MXKRoomIncomingTextMsgBubbleCell.class;
}
}
}
else if (bubbleData.isAttachmentWithThumbnail)
{
if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class;
}
else
{
cellViewClass = MXKRoomOutgoingAttachmentBubbleCell.class;
}
}
else
{
if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class;
}
else
{
cellViewClass = MXKRoomOutgoingTextMsgBubbleCell.class;
}
}
}
return cellViewClass;
return nil;
}
- (NSString *)cellReuseIdentifierForCellData:(MXKCellData*)cellData

View file

@ -54,55 +54,7 @@
#import "JitsiViewController.h"
#import "RoomEmptyBubbleCell.h"
#import "RoomIncomingTextMsgBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingAttachmentBubbleCell.h"
#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingAttachmentBubbleCell.h"
#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomMembershipBubbleCell.h"
#import "RoomMembershipWithPaginationTitleBubbleCell.h"
#import "RoomMembershipCollapsedBubbleCell.h"
#import "RoomMembershipCollapsedWithPaginationTitleBubbleCell.h"
#import "RoomMembershipExpandedBubbleCell.h"
#import "RoomMembershipExpandedWithPaginationTitleBubbleCell.h"
#import "RoomCreationWithPaginationCollapsedBubbleCell.h"
#import "RoomCreationCollapsedBubbleCell.h"
#import "RoomSelectedStickerBubbleCell.h"
#import "RoomPredecessorBubbleCell.h"
#import "MXKRoomBubbleTableViewCell+Riot.h"
#import "AvatarGenerator.h"
@ -130,6 +82,8 @@
#import "MXSDKOptions.h"
#import "RoomTimelineCellProvider.h"
#import "GeneratedInterface-Swift.h"
NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNotification";
@ -367,83 +321,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[super viewDidLoad];
// Register first customized cell view classes used to render bubbles
[self.bubblesTableView registerClass:RoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomEmptyBubbleCell.class forCellReuseIdentifier:RoomEmptyBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipBubbleCell.class forCellReuseIdentifier:RoomMembershipBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipCollapsedBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipCollapsedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipExpandedBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipExpandedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
// call cells
[self.bubblesTableView registerClass:RoomDirectCallStatusBubbleCell.class forCellReuseIdentifier:RoomDirectCallStatusBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomGroupCallStatusBubbleCell.class forCellReuseIdentifier:RoomGroupCallStatusBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationIntroCell.class forCellReuseIdentifier:RoomCreationIntroCell.defaultReuseIdentifier];
[self.bubblesTableView registerNib:RoomTypingBubbleCell.nib forCellReuseIdentifier:RoomTypingBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:VoiceMessageBubbleCell.class forCellReuseIdentifier:VoiceMessageBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:VoiceMessageWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:VoiceMessageWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:PollBubbleCell.class forCellReuseIdentifier:PollBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:PollWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:PollWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:PollWithPaginationTitleBubbleCell.class forCellReuseIdentifier:PollWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:LocationBubbleCell.class forCellReuseIdentifier:LocationBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:LocationWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:LocationWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[[RoomTimelineConfiguration shared].currentStyle.cellProvider registerCellsForTableView:self.bubblesTableView];
[self vc_removeBackTitle];
@ -2236,6 +2114,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[MXSDKOptions sharedInstance].videoConversionPresetName = presetName;
[roomInputToolbarView sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
}];
compressionPrompt.popoverPresentationController.sourceView = roomInputToolbarView.attachMediaButton;
compressionPrompt.popoverPresentationController.sourceRect = roomInputToolbarView.attachMediaButton.bounds;
[self presentViewController:compressionPrompt animated:YES completion:nil];
}
@ -2698,15 +2578,24 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
{
Class cellViewClass = nil;
BOOL showEncryptionBadge = NO;
RoomTimelineCellIdentifier cellIdentifier = [self cellIdentifierForCellData:cellData andRoomDataSource:customizedRoomDataSource];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
return [timelineConfiguration.currentStyle.cellProvider cellViewClassForCellIdentifier:cellIdentifier];;
}
- (RoomTimelineCellIdentifier)cellIdentifierForCellData:(MXKCellData*)cellData andRoomDataSource:(RoomDataSource *)customizedRoomDataSource;
{
// Sanity check
if (![cellData conformsToProtocol:@protocol(MXKRoomBubbleCellDataStoring)])
{
return nil;
return RoomTimelineCellIdentifierUnknown;
}
BOOL showEncryptionBadge = NO;
RoomTimelineCellIdentifier cellIdentifier;
id<MXKRoomBubbleCellDataStoring> bubbleData = (id<MXKRoomBubbleCellDataStoring>)cellData;
MXKRoomBubbleCellData *roomBubbleCellData;
@ -2720,27 +2609,27 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Select the suitable table view cell class, by considering first the empty bubble cell.
if (bubbleData.hasNoDisplay)
{
cellViewClass = RoomEmptyBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierEmpty;
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreationIntro)
{
cellViewClass = RoomCreationIntroCell.class;
cellIdentifier = RoomTimelineCellIdentifierRoomCreationIntro;
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor)
{
cellViewClass = RoomPredecessorBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierRoomPredecessor;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class : KeyVerificationIncomingRequestApprovalBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequest)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class : KeyVerificationRequestStatusBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationRequestStatus;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationConclusion)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationConclusionWithPaginationTitleBubbleCell.class : KeyVerificationConclusionBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationConclusion;
}
else if (bubbleData.tag == RoomBubbleCellDataTagMembership)
{
@ -2748,80 +2637,80 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.nextCollapsableCellData)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipCollapsedWithPaginationTitleBubbleCell.class : RoomMembershipCollapsedBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle : RoomTimelineCellIdentifierMembershipCollapsed;
}
else
{
// Use a normal membership cell for a single membership event
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipWithPaginationTitleBubbleCell.class : RoomMembershipBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipWithPaginationTitle : RoomTimelineCellIdentifierMembership;
}
}
else if (bubbleData.collapsedAttributedTextMessage)
{
// The cell (and its series) is not collapsed but this cell is the first
// of the series. So, use the cell with the "collapse" button.
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipExpandedWithPaginationTitleBubbleCell.class : RoomMembershipExpandedBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle : RoomTimelineCellIdentifierMembershipExpanded;
}
else
{
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipWithPaginationTitleBubbleCell.class : RoomMembershipBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipWithPaginationTitle : RoomTimelineCellIdentifierMembership;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreateConfiguration)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomCreationWithPaginationCollapsedBubbleCell.class : RoomCreationCollapsedBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle : RoomTimelineCellIdentifierRoomCreationCollapsed;
}
else if (bubbleData.tag == RoomBubbleCellDataTagCall)
{
cellViewClass = RoomDirectCallStatusBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierDirectCallStatus;
}
else if (bubbleData.tag == RoomBubbleCellDataTagGroupCall)
{
cellViewClass = RoomGroupCallStatusBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierGroupCallStatus;
}
else if (bubbleData.attachment.type == MXKAttachmentTypeVoiceMessage || bubbleData.attachment.type == MXKAttachmentTypeAudio)
{
if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = VoiceMessageWithPaginationTitleBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = VoiceMessageWithoutSenderInfoBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo;
}
else
{
cellViewClass = VoiceMessageBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierVoiceMessage;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagPoll)
{
if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = PollWithPaginationTitleBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierPollWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = PollWithoutSenderInfoBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierPollWithoutSenderInfo;
}
else
{
cellViewClass = PollBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierPoll;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagLocation)
{
if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = LocationWithPaginationTitleBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierLocationWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = LocationWithoutSenderInfoBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierLocationWithoutSenderInfo;
}
else
{
cellViewClass = LocationBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierLocation;
}
}
else if (bubbleData.isIncoming)
@ -2831,19 +2720,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Check whether the provided celldata corresponds to a selected sticker
if (customizedRoomDataSource.selectedEventId && (bubbleData.attachment.type == MXKAttachmentTypeSticker) && [bubbleData.attachment.eventId isEqualToString:customizedRoomDataSource.selectedEventId])
{
cellViewClass = RoomSelectedStickerBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierSelectedSticker;
}
else if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo;
}
else
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentBubbleCell.class : RoomIncomingAttachmentBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncrypted : RoomTimelineCellIdentifierIncomingAttachment;
}
}
else
@ -2852,24 +2741,24 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class : RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class : RoomIncomingTextMsgWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName : RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgBubbleCell.class : RoomIncomingTextMsgBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncrypted : RoomTimelineCellIdentifierIncomingTextMessage;
}
}
}
@ -2881,19 +2770,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Check whether the provided celldata corresponds to a selected sticker
if (customizedRoomDataSource.selectedEventId && (bubbleData.attachment.type == MXKAttachmentTypeSticker) && [bubbleData.attachment.eventId isEqualToString:customizedRoomDataSource.selectedEventId])
{
cellViewClass = RoomSelectedStickerBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierSelectedSticker;
}
else if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class :RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo;
}
else
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentBubbleCell.class : RoomOutgoingAttachmentBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncrypted : RoomTimelineCellIdentifierOutgoingAttachment;
}
}
else
@ -2902,29 +2791,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class :RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName : RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgBubbleCell.class : RoomOutgoingTextMsgBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncrypted : RoomTimelineCellIdentifierOutgoingTextMessage;
}
}
}
return cellViewClass;
return cellIdentifier;
}
#pragma mark - MXKDataSource delegate

View file

@ -216,6 +216,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewMinHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewBottomConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
/**
The constraints which defines the relationship between bubbleInfoContainer and its superview
@ -325,4 +326,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
*/
- (void)setupViews;
/// Add temporary subview to `tmpSubviews` property.
- (void)addTemporarySubview:(UIView*)subview;
@end

View file

@ -1128,6 +1128,16 @@ static BOOL _disableLongPressGestureOnEvent;
[self resetAttachmentViewBottomConstraintConstant];
}
- (void)addTemporarySubview:(UIView*)subview
{
if (!self.tmpSubviews)
{
self.tmpSubviews = [NSMutableArray new];
}
[self.tmpSubviews addObject:subview];
}
#pragma mark - Attachment progress handling
- (void)updateProgressUI:(NSDictionary*)statisticsDict

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -128,6 +128,7 @@
<connections>
<outlet property="activityIndicator" destination="OrM-nA-kyg" id="Frc-ED-PlH"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="p93-5h-lvW" id="WRx-S5-r3M"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -161,6 +161,7 @@
<connections>
<outlet property="activityIndicator" destination="jmK-pe-WZd" id="F7y-hE-pcg"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="6mM-Ag-m0K" id="lG4-bl-Kio"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>

View file

@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
/**
`RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell` displays outgoing attachment bubbles and pagination title but no sender name.
*/
@interface RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell : RoomOutgoingAttachmentWithPaginationTitleBubbleCell
@end

View file

@ -0,0 +1,32 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations 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 "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "ThemeService.h"
#import "GeneratedInterface-Swift.h"
@implementation RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell
- (void)customizeTableViewCellRendering
{
[super customizeTableViewCellRendering];
self.messageTextView.tintColor = ThemeService.shared.theme.tintColor;
}
@end

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
<rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SFg-55-RF4" userLabel="Pagination Title View">
<rect key="frame" x="56" y="10" width="534" height="24"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wkY-7Y-sGw" userLabel="Pagination Label">
<rect key="frame" x="0.0" y="0.0" width="524" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="PiZ-Ag-oxc"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0kR-4b-Wav" userLabel="Pagination Separator View">
<rect key="frame" x="0.0" y="23" width="534" height="1"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<accessibility key="accessibilityConfiguration" identifier="PaginationTitleView"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="wkY-7Y-sGw" secondAttribute="trailing" constant="10" id="4DU-xA-diS"/>
<constraint firstItem="wkY-7Y-sGw" firstAttribute="top" secondItem="SFg-55-RF4" secondAttribute="top" id="6Cz-bj-kUg"/>
<constraint firstItem="0kR-4b-Wav" firstAttribute="top" secondItem="wkY-7Y-sGw" secondAttribute="bottom" constant="5" id="K4B-zf-5x2"/>
<constraint firstAttribute="height" constant="24" id="Qo9-cw-LCa"/>
<constraint firstAttribute="trailing" secondItem="0kR-4b-Wav" secondAttribute="trailing" id="fnd-bR-QmB"/>
<constraint firstAttribute="bottom" secondItem="0kR-4b-Wav" secondAttribute="bottom" id="pBK-pC-oCA"/>
<constraint firstItem="0kR-4b-Wav" firstAttribute="leading" secondItem="SFg-55-RF4" secondAttribute="leading" id="rhH-Hz-w9J"/>
<constraint firstItem="wkY-7Y-sGw" firstAttribute="leading" secondItem="SFg-55-RF4" secondAttribute="leading" id="uq9-MP-Dmm"/>
</constraints>
</view>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="hgp-Z5-rAj" userLabel="Picture View" customClass="MXKImageView">
<rect key="frame" x="13" y="54" width="30" height="30"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="PictureView"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="NQk-ck-Lo8"/>
<constraint firstAttribute="height" constant="30" id="dNT-QU-CUG"/>
</constraints>
</view>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="5IE-JS-uf3" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="56" y="45" width="192" height="65"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AttachmentView"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="9zO-jU-qTb"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="34" id="C5F-6D-LZx"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="K9X-gn-noF" userLabel="File Type Image View">
<rect key="frame" x="56" y="45" width="32" height="32"/>
<accessibility key="accessibilityConfiguration" identifier="FileTypeImageView"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="OE8-oh-B7Q"/>
<constraint firstAttribute="height" constant="32" id="jJB-zj-fbT"/>
</constraints>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Cot-3X-2cU" userLabel="Play Icon Image View">
<rect key="frame" x="136" y="61.5" width="32" height="32"/>
<accessibility key="accessibilityConfiguration" identifier="PlayIconImageView"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="8io-Wk-GzF"/>
<constraint firstAttribute="width" constant="32" id="aeJ-j3-rfX"/>
</constraints>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="jmK-pe-WZd">
<rect key="frame" x="142" y="67.5" width="20" height="20"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="ActivityIndicator"/>
</userDefinedRuntimeAttributes>
</activityIndicatorView>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW">
<rect key="frame" x="515" y="54" width="70" height="66"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="BubbleInfoContainer"/>
<constraints>
<constraint firstAttribute="width" constant="70" id="tLr-6k-ArA"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fdx-qs-8en" userLabel="ProgressView">
<rect key="frame" x="487" y="50" width="100" height="70"/>
<gestureRecognizers/>
<constraints>
<constraint firstAttribute="height" constant="70" id="5w2-Hm-hZx"/>
<constraint firstAttribute="width" constant="100" id="ryE-fW-SgG"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3b7-4a-YL0">
<rect key="frame" x="8" y="3" width="584" height="114"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="3b7-4a-YL0" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="topMargin" constant="-8" id="10i-70-PDz"/>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="54" id="2Ih-ga-N9s"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="13" id="6mM-Ag-m0K"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="45" id="96U-67-5TP"/>
<constraint firstAttribute="bottom" secondItem="fdx-qs-8en" secondAttribute="bottom" id="AeT-4F-mKp"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="Cot-3X-2cU" secondAttribute="centerY" id="H5t-l6-fL1"/>
<constraint firstItem="SFg-55-RF4" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="56" id="I4N-5Q-LFe"/>
<constraint firstItem="jmK-pe-WZd" firstAttribute="centerX" secondItem="5IE-JS-uf3" secondAttribute="centerX" id="IoK-NR-EyQ"/>
<constraint firstAttribute="bottom" secondItem="5IE-JS-uf3" secondAttribute="bottom" constant="10" id="SHN-tC-zsJ"/>
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="54" id="XSL-TG-m62"/>
<constraint firstItem="3b7-4a-YL0" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leadingMargin" constant="-8" id="aGh-ad-trR"/>
<constraint firstAttribute="trailingMargin" secondItem="3b7-4a-YL0" secondAttribute="trailing" constant="-8" id="abE-n9-N8T"/>
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="15" id="hQV-lO-7aQ"/>
<constraint firstAttribute="trailing" secondItem="SFg-55-RF4" secondAttribute="trailing" constant="10" id="jvR-oT-EQF"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="K9X-gn-noF" secondAttribute="leading" id="p93-5h-lvW"/>
<constraint firstItem="jmK-pe-WZd" firstAttribute="centerY" secondItem="5IE-JS-uf3" secondAttribute="centerY" id="qqJ-jh-rGK"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerX" secondItem="Cot-3X-2cU" secondAttribute="centerX" id="sF7-QL-vdj"/>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="13" id="tuw-aU-ncu"/>
<constraint firstItem="SFg-55-RF4" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="10" id="wJX-7V-bJB"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="K9X-gn-noF" secondAttribute="top" id="wkX-zQ-iQS"/>
<constraint firstAttribute="bottomMargin" secondItem="3b7-4a-YL0" secondAttribute="bottom" constant="-8" id="wpa-8Z-Gy3"/>
<constraint firstAttribute="trailing" secondItem="fdx-qs-8en" secondAttribute="trailing" constant="13" id="xKk-Gz-moE"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomBubbleCell"/>
<connections>
<outlet property="activityIndicator" destination="jmK-pe-WZd" id="F7y-hE-pcg"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="6mM-Ag-m0K" id="lG4-bl-Kio"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
<outlet property="attachmentView" destination="5IE-JS-uf3" id="imT-1z-hR1"/>
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
<outlet property="bubbleOverlayContainer" destination="3b7-4a-YL0" id="KNb-h4-YHD"/>
<outlet property="fileTypeIconView" destination="K9X-gn-noF" id="4Pj-bc-3gk"/>
<outlet property="paginationLabel" destination="wkY-7Y-sGw" id="9Uh-tX-t0I"/>
<outlet property="paginationSeparatorView" destination="0kR-4b-Wav" id="c7x-Sh-aj6"/>
<outlet property="paginationTitleView" destination="SFg-55-RF4" id="mbP-6I-gOn"/>
<outlet property="pictureView" destination="hgp-Z5-rAj" id="rKM-QG-RJN"/>
<outlet property="playIconView" destination="Cot-3X-2cU" id="KEF-KK-Og1"/>
<outlet property="progressView" destination="fdx-qs-8en" id="V7E-pn-Xze"/>
</connections>
<point key="canvasLocation" x="-26" y="113"/>
</tableViewCell>
</objects>
</document>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -95,6 +95,7 @@
<connections>
<outlet property="activityIndicator" destination="8Bq-Mk-bN8" id="cbT-lK-yjP"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="bSL-lG-ued" id="M5E-Ot-73d"/>
<outlet property="attachViewMinHeightConstraint" destination="Uqr-7d-0dv" id="UIs-4K-np5"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>

View file

@ -23,6 +23,8 @@
#import "MXKImageView.h"
#import "MXKPieChartView.h"
#import "GeneratedInterface-Swift.h"
@implementation MXKRoomOutgoingAttachmentBubbleCell
- (void)dealloc
@ -30,6 +32,15 @@
[self stopAnimating];
}
- (void)setupViews
{
[super setupViews];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForOutgoingFileAttachmentCell:self];
}
- (void)render:(MXKCellData *)cellData
{
[super render:cellData];

View file

@ -37,11 +37,17 @@ class LocationBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable
let location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
locationView.displayLocation(location,
userIdentifier: bubbleData.senderId,
userDisplayName: bubbleData.senderDisplayName,
userAvatarURLString: bubbleData.senderAvatarUrl,
mediaManager: bubbleData.mxSession.mediaManager)
if locationContent.assetType == .user {
let avatarViewData = AvatarViewData(matrixItemId: bubbleData.senderId,
displayName: bubbleData.senderDisplayName,
avatarUrl: bubbleData.senderAvatarUrl,
mediaManager: bubbleData.mxSession.mediaManager,
fallbackImage: .matrixItem(bubbleData.senderId, bubbleData.senderDisplayName))
locationView.displayLocation(location, userAvatarData: avatarViewData)
} else {
locationView.displayLocation(location)
}
}
override func setupViews() {

View file

@ -0,0 +1,115 @@
//
// Copyright 2021 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.
//
/// RoomTimelineCellIdentifier represents room timeline cell identifiers.
typedef NS_ENUM(NSUInteger, RoomTimelineCellIdentifier) {
RoomTimelineCellIdentifierUnknown,
// - Text message
// -- Incoming
// --- Clear
RoomTimelineCellIdentifierIncomingTextMessage,
RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle,
RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName,
RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName,
// --- Encrypted
RoomTimelineCellIdentifierIncomingTextMessageEncrypted,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName,
// -- Outgoing
// --- Clear
RoomTimelineCellIdentifierOutgoingTextMessage,
RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle,
RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName,
RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName,
// --- Encrypted
RoomTimelineCellIdentifierOutgoingTextMessageEncrypted,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName,
// - Attachment
// -- Incoming
// --- Clear
RoomTimelineCellIdentifierIncomingAttachment,
RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle,
// --- Encrypted
RoomTimelineCellIdentifierIncomingAttachmentEncrypted,
RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle,
// -- Outgoing
// --- Clear
RoomTimelineCellIdentifierOutgoingAttachment,
RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle,
// --- Encrypted
RoomTimelineCellIdentifierOutgoingAttachmentEncrypted,
RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle,
// - Room membership
RoomTimelineCellIdentifierMembership,
RoomTimelineCellIdentifierMembershipWithPaginationTitle,
RoomTimelineCellIdentifierMembershipCollapsed,
RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle,
RoomTimelineCellIdentifierMembershipExpanded,
RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle,
// - Key verification
RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval,
RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle,
RoomTimelineCellIdentifierKeyVerificationRequestStatus,
RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle,
RoomTimelineCellIdentifierKeyVerificationConclusion,
RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle,
// - Room creation
RoomTimelineCellIdentifierRoomCreationCollapsed,
RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle,
// - Call
RoomTimelineCellIdentifierDirectCallStatus,
RoomTimelineCellIdentifierGroupCallStatus,
// - Voice message
RoomTimelineCellIdentifierVoiceMessage,
RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo,
RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle,
// - Poll
RoomTimelineCellIdentifierPoll,
RoomTimelineCellIdentifierPollWithoutSenderInfo,
RoomTimelineCellIdentifierPollWithPaginationTitle,
// - Location sharing
RoomTimelineCellIdentifierLocation,
RoomTimelineCellIdentifierLocationWithoutSenderInfo,
RoomTimelineCellIdentifierLocationWithPaginationTitle,
// - Others
RoomTimelineCellIdentifierEmpty,
RoomTimelineCellIdentifierSelectedSticker,
RoomTimelineCellIdentifierRoomPredecessor,
RoomTimelineCellIdentifierRoomCreationIntro,
RoomTimelineCellIdentifierTyping
};

View file

@ -0,0 +1,96 @@
//
// Copyright 2021 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
/// RoomTimelineConfiguration enables to manage room timeline appearance configuration
@objcMembers
class RoomTimelineConfiguration: NSObject {
// MARK: - Constants
static let shared = RoomTimelineConfiguration()
// MARK: - Properties
private(set) var currentStyle: RoomTimelineStyle
// MARK: - Setup
init(style: RoomTimelineStyle) {
self.currentStyle = style
super.init()
self.registerThemeDidChange()
}
convenience init(styleIdentifier: RoomTimelineStyleIdentifier) {
let style = type(of: self).style(for: styleIdentifier)
self.init(style: style)
}
convenience override init() {
let styleIdentifier = RiotSettings.shared.roomTimelineStyleIdentifier
self.init(styleIdentifier: styleIdentifier)
}
// MARK: - Public
func updateStyle(_ roomTimelineStyle: RoomTimelineStyle) {
self.currentStyle = roomTimelineStyle
}
func updateStyle(withIdentifier identifier: RoomTimelineStyleIdentifier) {
let style = type(of: self).style(for: identifier)
self.updateStyle(style)
}
// MARK: - Private
private func registerThemeDidChange() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange(notification:)), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange(notification: Notification) {
guard let themeService = notification.object as? ThemeService else {
return
}
self.currentStyle.update(theme: themeService.theme)
}
private class func style(for identifier: RoomTimelineStyleIdentifier) -> RoomTimelineStyle {
let roomTimelineStyle: RoomTimelineStyle
let theme = ThemeService.shared().theme
switch identifier {
case .plain:
roomTimelineStyle = PlainRoomTimelineStyle(theme: theme)
case .bubble:
roomTimelineStyle = BubbleRoomTimelineStyle(theme: theme)
}
return roomTimelineStyle
}
}

View file

@ -27,7 +27,6 @@
@property (weak, nonatomic) IBOutlet UILabel *descriptionLabel;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *userNameLabelTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *descriptionContainerViewBottomConstraint;
@end

View file

@ -0,0 +1,345 @@
//
// Copyright 2021 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 UIKit
@objcMembers
class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
// MARK: - Properties
private var theme: Theme
private var incomingColor: UIColor {
return self.theme.colors.system
}
private var outgoingColor: UIColor {
return self.theme.colors.accent.withAlphaComponent(0.10)
}
// MARK: - Setup
init(theme: Theme) {
self.theme = theme
}
// MARK: - Public
func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if cellData.isSenderCurrentUser {
self.updateLayout(forOutgoingTextMessageCell: cell, andCellData: cellData)
} else {
self.updateLayout(forIncomingTextMessageCell: cell, andCellData: cellData)
}
}
func updateLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if let messageBubbleBackgroundView = cell.messageBubbleBackgroundView {
if self.canUseBubbleBackground(forCell: cell, withCellData: cellData) {
messageBubbleBackgroundView.isHidden = false
self.updateMessageBubbleBackgroundView(messageBubbleBackgroundView, withCell: cell, andCellData: cellData)
} else {
messageBubbleBackgroundView.isHidden = true
}
}
}
func updateLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if let messageBubbleBackgroundView = cell.messageBubbleBackgroundView {
if self.canUseBubbleBackground(forCell: cell, withCellData: cellData) {
messageBubbleBackgroundView.isHidden = false
self.updateMessageBubbleBackgroundView(messageBubbleBackgroundView, withCell: cell, andCellData: cellData)
} else {
messageBubbleBackgroundView.isHidden = true
}
}
}
func setupLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell) {
self.setupIncomingMessageTextViewMargins(for: cell)
self.addBubbleBackgroundViewToCell(cell, backgroundColor: self.incomingColor)
cell.setNeedsUpdateConstraints()
}
func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell) {
self.setupOutgoingMessageTextViewMargins(for: cell)
// Hide avatar view
cell.pictureView?.isHidden = true
self.addBubbleBackgroundViewToCell(cell, backgroundColor: self.outgoingColor)
cell.setNeedsUpdateConstraints()
}
func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell) {
// Hide avatar view
cell.pictureView?.isHidden = true
self.setupOutgoingFileAttachViewMargins(for: cell)
}
// MARK: Themable
func update(theme: Theme) {
self.theme = theme
}
// MARK: - Private
// MARK: Bubble background view
private func createBubbleBackgroundView(with backgroundColor: UIColor) -> RoomMessageBubbleBackgroundView {
let bubbleBackgroundView = RoomMessageBubbleBackgroundView()
bubbleBackgroundView.backgroundColor = backgroundColor
return bubbleBackgroundView
}
private func addBubbleBackgroundViewToCell(_ bubbleCell: MXKRoomBubbleTableViewCell, backgroundColor: UIColor) {
guard let messageTextView = bubbleCell.messageTextView else {
return
}
let topMargin: CGFloat = 0.0
let leftMargin: CGFloat = 5.0
let rightMargin: CGFloat = 45.0 // Add extra space for timestamp
let bubbleBackgroundView = self.createBubbleBackgroundView(with: backgroundColor)
bubbleCell.contentView.insertSubview(bubbleBackgroundView, at: 0)
let topAnchor = messageTextView.topAnchor
let leadingAnchor = messageTextView.leadingAnchor
let trailingAnchor = messageTextView.trailingAnchor
bubbleBackgroundView.updateHeight(messageTextView.frame.height)
NSLayoutConstraint.activate([
bubbleBackgroundView.topAnchor.constraint(equalTo: topAnchor, constant: topMargin),
bubbleBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: -leftMargin),
bubbleBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: rightMargin)
])
}
private func canUseBubbleBackground(forCell cell: MXKRoomBubbleTableViewCell, withCellData cellData: MXKRoomBubbleCellData) -> Bool {
guard let firstComponent = cellData.getFirstBubbleComponentWithDisplay(), let firstEvent = firstComponent.event else {
return false
}
switch firstEvent.eventType {
case .roomMessage:
if let messageTypeString = firstEvent.content["msgtype"] as? String {
let messageType = MXMessageType(identifier: messageTypeString)
switch messageType {
case .text, .emote, .file:
return true
default:
break
}
}
default:
break
}
return false
}
private func getTextMessageHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
guard let roomBubbleCellData = cellData as? RoomBubbleCellData,
let lastBubbleComponent = cellData.getLastBubbleComponentWithDisplay(),
let firstComponent = roomBubbleCellData.getFirstBubbleComponentWithDisplay() else {
return nil
}
let bubbleHeight: CGFloat
let lastEventId = lastBubbleComponent.event.eventId
let lastMessageBottomPosition = cell.bottomPosition(ofEvent: lastEventId)
let firstEventId = firstComponent.event.eventId
let firstMessageTopPosition = cell.topPosition(ofEvent: firstEventId)
let additionalContentHeight = roomBubbleCellData.additionalContentHeight
bubbleHeight = lastMessageBottomPosition - firstMessageTopPosition - additionalContentHeight
guard bubbleHeight >= 0 else {
return nil
}
return bubbleHeight
}
// TODO: Improve text message height calculation
// This method is closer to final result but lack of stability because of extra vertical space not handled here.
// private func getTextMessageHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
//
// guard let roomBubbleCellData = cellData as? RoomBubbleCellData,
// let firstComponent = roomBubbleCellData.getFirstBubbleComponentWithDisplay() else {
// return nil
// }
//
// let bubbleHeight: CGFloat
//
// let componentIndex = cellData.bubbleComponentIndex(forEventId: firstComponent.event.eventId)
//
// let componentFrame = cell.componentFrameInContentView(for: componentIndex)
//
// bubbleHeight = componentFrame.height
//
// guard bubbleHeight >= 0 else {
// return nil
// }
//
// return bubbleHeight
// }
private func getMessageBubbleBackgroundHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
var finalBubbleHeight: CGFloat?
let extraMargin: CGFloat = 4.0
if let bubbleHeight = self.getTextMessageHeight(for: cell, andCellData: cellData) {
finalBubbleHeight = bubbleHeight + extraMargin
} else if let messageTextViewHeight = cell.messageTextView?.frame.height {
finalBubbleHeight = messageTextViewHeight + extraMargin
}
return finalBubbleHeight
}
@discardableResult
private func updateMessageBubbleBackgroundView(_ roomMessageBubbleBackgroundView: RoomMessageBubbleBackgroundView, withCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> Bool {
if let bubbleHeight = self.getMessageBubbleBackgroundHeight(for: cell, andCellData: cellData) {
return roomMessageBubbleBackgroundView.updateHeight(bubbleHeight)
} else {
return false
}
}
private func getIncomingMessageTextViewInsets(from bubbleCell: MXKRoomBubbleTableViewCell) -> UIEdgeInsets {
let messageViewMarginTop: CGFloat
let messageViewMarginBottom: CGFloat = -2.0
let messageViewMarginLeft: CGFloat = 3.0
let messageViewMarginRight: CGFloat = 80
if bubbleCell.userNameLabel != nil {
messageViewMarginTop = 10.0
} else {
messageViewMarginTop = 0.0
}
let messageViewInsets = UIEdgeInsets(top: messageViewMarginTop, left: messageViewMarginLeft, bottom: messageViewMarginBottom, right: messageViewMarginRight)
return messageViewInsets
}
// MARK: Text message
private func setupIncomingMessageTextViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard cell.messageTextView != nil else {
return
}
let messageViewInsets = self.getIncomingMessageTextViewInsets(from: cell)
cell.msgTextViewBottomConstraint.constant += messageViewInsets.bottom
cell.msgTextViewTopConstraint.constant += messageViewInsets.top
cell.msgTextViewLeadingConstraint.constant += messageViewInsets.left
cell.msgTextViewTrailingConstraint.constant += messageViewInsets.right
}
private func setupOutgoingMessageTextViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard let messageTextView = cell.messageTextView else {
return
}
let contentView = cell.contentView
let leftMargin: CGFloat = 80.0
let rightMargin: CGFloat = 78.0
let bottomMargin: CGFloat = -2.0
cell.msgTextViewLeadingConstraint.isActive = false
cell.msgTextViewTrailingConstraint.isActive = false
let leftConstraint = messageTextView.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: leftMargin)
let rightConstraint = messageTextView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -rightMargin)
NSLayoutConstraint.activate([
leftConstraint,
rightConstraint
])
cell.msgTextViewLeadingConstraint = leftConstraint
cell.msgTextViewTrailingConstraint = rightConstraint
cell.msgTextViewBottomConstraint.constant += bottomMargin
}
private func setupOutgoingFileAttachViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard let attachmentView = cell.attachmentView else {
return
}
let contentView = cell.contentView
// TODO: Use constants
// Same as URL preview
let rightMargin: CGFloat = 34.0
if let attachViewLeadingConstraint = cell.attachViewLeadingConstraint {
attachViewLeadingConstraint.isActive = false
cell.attachViewLeadingConstraint = nil
}
let rightConstraint = attachmentView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -rightMargin)
NSLayoutConstraint.activate([
rightConstraint
])
}
}

View file

@ -0,0 +1,230 @@
//
// Copyright 2021 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 UIKit
class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
override func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
guard self.canShowTimestamp(forCellData: cellData) else {
return
}
self.addTimestampLabel(toCell: cell, cellData: cellData)
}
override func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
// If cell contains a bubble background, add the timestamp inside of it
if let bubbleBackgroundView = cell.messageBubbleBackgroundView, bubbleBackgroundView.isHidden == false {
let componentIndex = cellData.mostRecentComponentIndex
guard let bubbleComponents = cellData.bubbleComponents,
componentIndex < bubbleComponents.count else {
return
}
let component = bubbleComponents[componentIndex]
let timestampLabel = self.createTimestampLabel(cellData: cellData,
bubbleComponent: component,
viewTag: componentIndex)
timestampLabel.translatesAutoresizingMaskIntoConstraints = false
cell.addTemporarySubview(timestampLabel)
bubbleBackgroundView.addSubview(timestampLabel)
let rightMargin: CGFloat = 8.0
let bottomMargin: CGFloat = 4.0
let trailingConstraint = timestampLabel.trailingAnchor.constraint(equalTo: bubbleBackgroundView.trailingAnchor, constant: -rightMargin)
let bottomConstraint = timestampLabel.bottomAnchor.constraint(equalTo: bubbleBackgroundView.bottomAnchor, constant: -bottomMargin)
NSLayoutConstraint.activate([
trailingConstraint,
bottomConstraint
])
} else {
super.addTimestampLabel(toCell: cell, cellData: cellData)
}
}
override func addReactionView(_ reactionsView: BubbleReactionsView,
toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData, contentViewPositionY: CGFloat, upperDecorationView: UIView?) {
cell.addTemporarySubview(reactionsView)
if let reactionsDisplayable = cell as? BubbleCellReactionsDisplayable {
reactionsDisplayable.addReactionsView(reactionsView)
return
}
reactionsView.translatesAutoresizingMaskIntoConstraints = false
let cellContentView = cell.contentView
cellContentView.addSubview(reactionsView)
// TODO: Use constants
let topMargin: CGFloat = 4.0
let leftMargin: CGFloat
let rightMargin: CGFloat
// Outgoing message
if cellData.isSenderCurrentUser {
reactionsView.alignment = .right
// TODO: Use constants
var outgointLeftMargin: CGFloat = 80.0
if cellData.containsBubbleComponentWithEncryptionBadge {
outgointLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin = outgointLeftMargin
// TODO: Use constants
rightMargin = 33
} else {
// Incoming message
var incomingLeftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
incomingLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin = incomingLeftMargin - 6.0
// TODO: Use constants
let messageViewMarginRight: CGFloat = 42.0
rightMargin = messageViewMarginRight
}
let leadingConstraint = reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
let trailingConstraint = reactionsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = reactionsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
} else {
topConstraint = reactionsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
leadingConstraint,
trailingConstraint,
topConstraint
])
}
override func addURLPreviewView(_ urlPreviewView: URLPreviewView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat) {
cell.addTemporarySubview(urlPreviewView)
let cellContentView = cell.contentView
urlPreviewView.translatesAutoresizingMaskIntoConstraints = false
urlPreviewView.availableWidth = cellData.maxTextViewWidth
cellContentView.addSubview(urlPreviewView)
let leadingOrTrailingConstraint: NSLayoutConstraint
// Outgoing message
if cellData.isSenderCurrentUser {
// TODO: Use constants
let rightMargin: CGFloat = 34.0
leadingOrTrailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
} else {
// Incoming message
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin-=5.0
leadingOrTrailingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
}
let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
// Set the preview view's origin
NSLayoutConstraint.activate([
leadingOrTrailingConstraint,
urlPreviewView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: topMargin)
])
}
// MARK: - Private
private func createTimestampLabel(cellData: MXKRoomBubbleCellData, bubbleComponent: MXKRoomBubbleComponent, viewTag: Int) -> UILabel {
let timeLabel = UILabel()
timeLabel.text = cellData.eventFormatter.timeString(from: bubbleComponent.date)
timeLabel.textAlignment = .right
timeLabel.textColor = ThemeService.shared().theme.textSecondaryColor
timeLabel.font = UIFont.systemFont(ofSize: 11, weight: .light)
timeLabel.adjustsFontSizeToFitWidth = true
timeLabel.tag = viewTag
timeLabel.accessibilityIdentifier = "timestampLabel"
return timeLabel
}
private func canShowTimestamp(forCellData cellData: MXKRoomBubbleCellData) -> Bool {
guard cellData.isCollapsableAndCollapsed == false else {
return false
}
guard let firstComponent = cellData.getFirstBubbleComponentWithDisplay(), let firstEvent = firstComponent.event else {
return false
}
switch firstEvent.eventType {
case .roomMessage:
if let messageTypeString = firstEvent.content["msgtype"] as? String {
let messageType = MXMessageType(identifier: messageTypeString)
switch messageType {
case .text, .emote, .file:
return true
default:
break
}
}
default:
break
}
return false
}
}

View file

@ -0,0 +1,25 @@
//
// Copyright 2021 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 "PlainRoomTimelineCellProvider.h"
NS_ASSUME_NONNULL_BEGIN
@interface BubbleRoomTimelineCellProvider : PlainRoomTimelineCellProvider
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,90 @@
//
// Copyright 2021 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 "BubbleRoomTimelineCellProvider.h"
#pragma mark - Imports
#pragma mark Text message
// Outgoing
// Clear
#import "RoomOutgoingTextMsgBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
// Encrypted
#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#pragma mark Attachment
// Outgoing
// Clear
#import "RoomOutgoingAttachmentBubbleCell.h"
#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
// Encrypted
#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
@implementation BubbleRoomTimelineCellProvider
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping
{
// Hide sender info and avatar for bubble outgoing messages
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingTextMessage) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName) : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingTextMessageEncrypted) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping
{
// Hide sender info and avatar for bubble outgoing file attachment
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
};
}
@end

View file

@ -0,0 +1,76 @@
//
// Copyright 2021 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 UIKit
class BubbleRoomTimelineStyle: RoomTimelineStyle {
// MARK: - Properties
// MARK: Private
private var theme: Theme
// MARK: Public
let identifier: RoomTimelineStyleIdentifier
let cellLayoutUpdater: RoomCellLayoutUpdating?
let cellProvider: RoomTimelineCellProvider
let cellDecorator: RoomTimelineCellDecorator
// MARK: - Setup
init(theme: Theme) {
self.theme = theme
self.identifier = .bubble
self.cellLayoutUpdater = BubbleRoomCellLayoutUpdater(theme: theme)
self.cellProvider = BubbleRoomTimelineCellProvider()
self.cellDecorator = BubbleRoomTimelineCellDecorator()
}
// MARK: - Public
func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool {
return false
}
func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
// Check whether the selected event belongs to this bubble
let selectedComponentIndex = cellData.selectedComponentIndex
if selectedComponentIndex != NSNotFound {
cell.selectComponent(UInt(selectedComponentIndex),
showEditButton: false,
showTimestamp: false)
self.cellDecorator.addTimestampLabel(toCell: cell, cellData: cellData)
} else {
cell.blurred = true
}
}
// MARK: Themable
func update(theme: Theme) {
self.theme = theme
self.cellLayoutUpdater?.update(theme: theme)
}
}

View file

@ -0,0 +1,30 @@
//
// Copyright 2021 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
extension MXKRoomBubbleTableViewCell {
// Enables to get existing bubble background view
// This used while there is no dedicated cell classes for bubble style
var messageBubbleBackgroundView: RoomMessageBubbleBackgroundView? {
let foundView = self.contentView.subviews.first { view in
return view is RoomMessageBubbleBackgroundView
}
return foundView as? RoomMessageBubbleBackgroundView
}
}

View file

@ -0,0 +1,74 @@
//
// Copyright 2021 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
class RoomMessageBubbleBackgroundView: UIView {
// MARK: - Constant
private enum Constants {
static let cornerRadius: CGFloat = 12.0
}
// MARK: - Properties
private var heightConstraint: NSLayoutConstraint?
// MARK: - Setup
convenience init() {
self.init(frame: CGRect.zero)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self.commonInit()
}
private func commonInit() {
self.translatesAutoresizingMaskIntoConstraints = false
self.layer.masksToBounds = true
self.layer.cornerRadius = Constants.cornerRadius
}
// MARK: - Public
@discardableResult
func updateHeight(_ height: CGFloat) -> Bool {
if let heightConstraint = self.heightConstraint {
guard heightConstraint.constant != height else {
return false
}
heightConstraint.constant = height
return true
} else {
let heightConstraint = self.heightAnchor.constraint(equalToConstant: height)
heightConstraint.isActive = true
self.heightConstraint = heightConstraint
return true
}
}
}

View file

@ -0,0 +1,148 @@
//
// Copyright 2021 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 UIKit
@objcMembers
class PlainRoomTimelineCellDecorator: RoomTimelineCellDecorator {
func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
guard cellData.containsLastMessage && cellData.isCollapsableAndCollapsed == false else {
return
}
// Display timestamp of the last message
self.addTimestampLabel(toCell: cell, cellData: cellData)
}
func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
cell.addTimestampLabel(forComponent: UInt(cellData.mostRecentComponentIndex))
}
func addURLPreviewView(_ urlPreviewView: URLPreviewView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat) {
cell.addTemporarySubview(urlPreviewView)
let cellContentView = cell.contentView
urlPreviewView.translatesAutoresizingMaskIntoConstraints = false
urlPreviewView.availableWidth = cellData.maxTextViewWidth
cellContentView.addSubview(urlPreviewView)
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
// Set the preview view's origin
NSLayoutConstraint.activate([
urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin),
urlPreviewView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: topMargin)
])
}
func addReactionView(_ reactionsView: BubbleReactionsView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?) {
cell.addTemporarySubview(reactionsView)
if let reactionsDisplayable = cell as? BubbleCellReactionsDisplayable {
reactionsDisplayable.addReactionsView(reactionsView)
} else {
reactionsView.translatesAutoresizingMaskIntoConstraints = false
let cellContentView = cell.contentView
cellContentView.addSubview(reactionsView)
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
let rightMargin = RoomBubbleCellLayout.reactionsViewRightMargin
let topMargin = RoomBubbleCellLayout.reactionsViewTopMargin
// The top constraint may need to include the URL preview view
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = reactionsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
} else {
topConstraint = reactionsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin),
reactionsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin),
topConstraint
])
}
}
func addReadReceiptsView(_ readReceiptsView: MXKReceiptSendersContainer,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?) {
cell.addTemporarySubview(readReceiptsView)
if let readReceiptsDisplayable = cell as? BubbleCellReadReceiptsDisplayable {
readReceiptsDisplayable.addReadReceiptsView(readReceiptsView)
} else {
let cellContentView = cell.contentView
cellContentView.addSubview(readReceiptsView)
// Force receipts container size
let widthConstraint = readReceiptsView.widthAnchor.constraint(equalToConstant: RoomBubbleCellLayout.readReceiptsViewWidth)
let heightConstraint = readReceiptsView.heightAnchor.constraint(equalToConstant: RoomBubbleCellLayout.readReceiptsViewHeight)
// Force receipts container position
let trailingConstraint = readReceiptsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -RoomBubbleCellLayout.readReceiptsViewRightMargin)
let topMargin = RoomBubbleCellLayout.readReceiptsViewTopMargin
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = readReceiptsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
} else {
topConstraint = readReceiptsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
widthConstraint,
heightConstraint,
trailingConstraint,
topConstraint
])
}
}
func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell, withFailedEventIds failedEventIds: Set<AnyHashable>) {
cell.updateTickView(withFailedEventIds: failedEventIds)
}
}

View file

@ -0,0 +1,29 @@
//
// Copyright 2021 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 "RoomTimelineCellProvider.h"
NS_ASSUME_NONNULL_BEGIN
@interface PlainRoomTimelineCellProvider: NSObject<RoomTimelineCellProvider>
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping;
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,453 @@
//
// Copyright 2021 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 "PlainRoomTimelineCellProvider.h"
#import "MXKRoomBubbleTableViewCell+Riot.h"
#import "RoomEmptyBubbleCell.h"
#import "RoomIncomingTextMsgBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingAttachmentBubbleCell.h"
#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingAttachmentBubbleCell.h"
#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomMembershipBubbleCell.h"
#import "RoomMembershipWithPaginationTitleBubbleCell.h"
#import "RoomMembershipCollapsedBubbleCell.h"
#import "RoomMembershipCollapsedWithPaginationTitleBubbleCell.h"
#import "RoomMembershipExpandedBubbleCell.h"
#import "RoomMembershipExpandedWithPaginationTitleBubbleCell.h"
#import "RoomCreationWithPaginationCollapsedBubbleCell.h"
#import "RoomCreationCollapsedBubbleCell.h"
#import "RoomSelectedStickerBubbleCell.h"
#import "RoomPredecessorBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@interface PlainRoomTimelineCellProvider()
@property (nonatomic, strong) NSDictionary<NSNumber*, Class>* cellClasses;
@end
@implementation PlainRoomTimelineCellProvider
#pragma mark - Public
- (void)registerCellsForTableView:(UITableView*)tableView
{
// Text message
[self registerIncomingTextMessageCellsForTableView:tableView];
[self registerOutgoingTextMessageCellsForTableView:tableView];
// Attachment cells
[self registerIncomingAttachmentCellsForTableView:tableView];
[self registerOutgoingAttachmentCellsForTableView:tableView];
// Other cells
[self registerMembershipCellsForTableView:tableView];
[self registerKeyVerificationCellsForTableView:tableView];
[self registerRoomCreationCellsForTableView:tableView];
[self registerCallCellsForTableView:tableView];
[self registerVoiceMessageCellsForTableView:tableView];
[self registerPollCellsForTableView:tableView];
[self registerLocationCellsForTableView:tableView];
[tableView registerClass:RoomEmptyBubbleCell.class forCellReuseIdentifier:RoomEmptyBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomCreationIntroCell.class forCellReuseIdentifier:RoomCreationIntroCell.defaultReuseIdentifier];
[tableView registerNib:RoomTypingBubbleCell.nib forCellReuseIdentifier:RoomTypingBubbleCell.defaultReuseIdentifier];
}
- (Class<MXKCellRendering>)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier
{
if (self.cellClasses == nil)
{
self.cellClasses = [self buildCellClasses];
}
Class cellViewClass = self.cellClasses[@(identifier)];
return cellViewClass;
}
#pragma mark - Private
#pragma mark Cell registration
- (void)registerIncomingTextMessageCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomIncomingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
}
- (void)registerOutgoingTextMessageCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
}
- (void)registerIncomingAttachmentCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomIncomingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerOutgoingAttachmentCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomOutgoingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
}
- (void)registerMembershipCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:RoomMembershipBubbleCell.class forCellReuseIdentifier:RoomMembershipBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipCollapsedBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipCollapsedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipExpandedBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipExpandedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerKeyVerificationCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerRoomCreationCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
}
- (void)registerCallCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:RoomDirectCallStatusBubbleCell.class forCellReuseIdentifier:RoomDirectCallStatusBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomGroupCallStatusBubbleCell.class forCellReuseIdentifier:RoomGroupCallStatusBubbleCell.defaultReuseIdentifier];
}
- (void)registerVoiceMessageCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:VoiceMessageBubbleCell.class forCellReuseIdentifier:VoiceMessageBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerPollCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:PollBubbleCell.class forCellReuseIdentifier:PollBubbleCell.defaultReuseIdentifier];
[tableView registerClass:PollWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:PollWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:PollWithPaginationTitleBubbleCell.class forCellReuseIdentifier:PollWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerLocationCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:LocationBubbleCell.class forCellReuseIdentifier:LocationBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
#pragma mark Cell class association
- (NSDictionary<NSNumber*, Class>*)buildCellClasses
{
NSMutableDictionary<NSNumber*, Class>* cellClasses = [NSMutableDictionary dictionary];
// Text message
NSDictionary *incomingTextMessageCellsMapping = [self incomingTextMessageCellsMapping];
[cellClasses addEntriesFromDictionary:incomingTextMessageCellsMapping];
NSDictionary *outgoingTextMessageCellsMapping = [self outgoingTextMessageCellsMapping];
[cellClasses addEntriesFromDictionary:outgoingTextMessageCellsMapping];
// Attachment
NSDictionary *incomingAttachmentCellsMapping = [self incomingAttachmentCellsMapping];
[cellClasses addEntriesFromDictionary:incomingAttachmentCellsMapping];
NSDictionary *outgoingAttachmentCellsMapping = [self outgoingAttachmentCellsMapping];
[cellClasses addEntriesFromDictionary:outgoingAttachmentCellsMapping];
// Other cells
NSDictionary *roomMembershipCellsMapping = [self membershipCellsMapping];
[cellClasses addEntriesFromDictionary:roomMembershipCellsMapping];
NSDictionary *keyVerificationCellsMapping = [self keyVerificationCellsMapping];
[cellClasses addEntriesFromDictionary:keyVerificationCellsMapping];
NSDictionary *roomCreationCellsMapping = [self roomCreationCellsMapping];
[cellClasses addEntriesFromDictionary:roomCreationCellsMapping];
NSDictionary *callCellsMapping = [self callCellsMapping];
[cellClasses addEntriesFromDictionary:callCellsMapping];
NSDictionary *voiceMessageCellsMapping = [self voiceMessageCellsMapping];
[cellClasses addEntriesFromDictionary:voiceMessageCellsMapping];
NSDictionary *pollCellsMapping = [self pollCellsMapping];
[cellClasses addEntriesFromDictionary:pollCellsMapping];
NSDictionary *locationCellsMapping = [self locationCellsMapping];
[cellClasses addEntriesFromDictionary:locationCellsMapping];
NSDictionary *othersCells = @{
@(RoomTimelineCellIdentifierEmpty) : RoomEmptyBubbleCell.class,
@(RoomTimelineCellIdentifierSelectedSticker) : RoomSelectedStickerBubbleCell.class,
@(RoomTimelineCellIdentifierRoomPredecessor) : RoomPredecessorBubbleCell.class,
@(RoomTimelineCellIdentifierRoomCreationIntro) : RoomCreationIntroCell.class,
@(RoomTimelineCellIdentifierTyping) : RoomTypingBubbleCell.class,
};
[cellClasses addEntriesFromDictionary:othersCells];
return [cellClasses copy];
}
- (NSDictionary<NSNumber*, Class>*)incomingTextMessageCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierIncomingTextMessage) : RoomIncomingTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo) : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle) : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName) : RoomIncomingTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName) : RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierIncomingTextMessageEncrypted) : RoomIncomingEncryptedTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo) : RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle) : RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName) : RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingTextMessage) : RoomOutgoingTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName) : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingTextMessageEncrypted) : RoomOutgoingEncryptedTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)incomingAttachmentCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierIncomingAttachment) : RoomIncomingAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo) : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle) : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierIncomingAttachmentEncrypted) : RoomIncomingEncryptedAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo) : RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle) : RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)membershipCellsMapping
{
return @{
@(RoomTimelineCellIdentifierMembership) : RoomMembershipBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipWithPaginationTitle) : RoomMembershipWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipCollapsed) : RoomMembershipCollapsedBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle) : RoomMembershipCollapsedWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipExpanded) : RoomMembershipExpandedBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle) : RoomMembershipExpandedWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)keyVerificationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval) : KeyVerificationIncomingRequestApprovalBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle) : KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationRequestStatus) : KeyVerificationRequestStatusBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle) : KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationConclusion) : KeyVerificationConclusionBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle) : KeyVerificationConclusionWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)roomCreationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierRoomCreationCollapsed) : RoomCreationCollapsedBubbleCell.class,
@(RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle) : RoomCreationWithPaginationCollapsedBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)callCellsMapping
{
return @{
@(RoomTimelineCellIdentifierDirectCallStatus) : RoomDirectCallStatusBubbleCell.class,
@(RoomTimelineCellIdentifierGroupCallStatus) : RoomGroupCallStatusBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)voiceMessageCellsMapping
{
return @{
@(RoomTimelineCellIdentifierVoiceMessage) : VoiceMessageBubbleCell.class,
@(RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)pollCellsMapping
{
return @{
@(RoomTimelineCellIdentifierPoll) : PollBubbleCell.class,
@(RoomTimelineCellIdentifierPollWithoutSenderInfo) : PollWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierPollWithPaginationTitle) : PollWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)locationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierLocation) : LocationBubbleCell.class,
@(RoomTimelineCellIdentifierLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class
};
}
@end

View file

@ -0,0 +1,74 @@
//
// Copyright 2021 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
class PlainRoomTimelineStyle: RoomTimelineStyle {
// MARK: - Properties
// MARK: Private
private var theme: Theme
// MARK: Public
let identifier: RoomTimelineStyleIdentifier
let cellLayoutUpdater: RoomCellLayoutUpdating?
let cellProvider: RoomTimelineCellProvider
let cellDecorator: RoomTimelineCellDecorator
// MARK: - Setup
init(theme: Theme) {
self.theme = theme
self.identifier = .plain
self.cellLayoutUpdater = nil
self.cellProvider = PlainRoomTimelineCellProvider()
self.cellDecorator = PlainRoomTimelineCellDecorator()
}
// MARK: - Methods
func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool {
return true
}
func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
// Check whether the selected event belongs to this bubble
let selectedComponentIndex = cellData.selectedComponentIndex
if selectedComponentIndex != NSNotFound {
let showTimestamp = cellData.showTimestampForSelectedComponent
cell.selectComponent(UInt(selectedComponentIndex),
showEditButton: false,
showTimestamp: showTimestamp)
} else {
cell.blurred = true
}
}
// MARK: Themable
func update(theme: Theme) {
self.theme = theme
}
}

View file

@ -0,0 +1,30 @@
//
// Copyright 2021 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
/// Enables to setup or update a room timeline cell view
@objc
protocol RoomCellLayoutUpdating: Themable {
func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData)
func setupLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell)
func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell)
func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell)
}

View file

@ -0,0 +1,47 @@
//
// Copyright 2021 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 UIKit
/// RoomTimelineCellDecorator enables to add decoration on a cell (reactions, read receipts, timestamp, URL preview).
@objc
protocol RoomTimelineCellDecorator {
func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData)
func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData)
func addURLPreviewView(_ urlPreviewView: URLPreviewView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat)
func addReactionView(_ reactionsView: BubbleReactionsView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?)
func addReadReceiptsView(_ readReceiptsView: MXKReceiptSendersContainer,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?)
func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell,
withFailedEventIds failedEventIds: Set<AnyHashable>)
}

View file

@ -0,0 +1,36 @@
//
// Copyright 2021 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 <UIKit/UIKit.h>
#import "RoomTimelineCellIdentifier.h"
#import "MXKCellRendering.h"
NS_ASSUME_NONNULL_BEGIN
/// Enables to register and provide room timeline cells
@protocol RoomTimelineCellProvider <NSObject>
/// Register timeline cells for the given table view
- (void)registerCellsForTableView:(UITableView*)tableView;
/// Get timeline cell class from cell identifier
- (Class<MXKCellRendering>)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,45 @@
//
// Copyright 2021 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
import MatrixSDK
/// RoomTimelineStyle describes a room timeline style used to customize timeline appearance
@objc
protocol RoomTimelineStyle: Themable {
// MARK: - Properties
/// Style identifier
var identifier: RoomTimelineStyleIdentifier { get }
/// Update layout if needed for cells provided by the cell provider
var cellLayoutUpdater: RoomCellLayoutUpdating? { get }
/// Register and provide timeline cells
var cellProvider: RoomTimelineCellProvider { get }
/// Handle cell decorations (reactions, read receipts, URL preview, )
var cellDecorator: RoomTimelineCellDecorator { get }
// MARK: - Methods
/// Indicate to merge or not event in timeline
func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool
/// Apply selected or blurred style on cell
func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData)
}

View file

@ -17,7 +17,8 @@
import Foundation
/// Represents the room timeline style identifiers available
enum RoomTimelineStyleIdentifier {
@objc
enum RoomTimelineStyleIdentifier: Int {
case plain
case bubble
}

View file

@ -16,6 +16,17 @@
#import "MXKRoomIncomingTextMsgBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@implementation MXKRoomIncomingTextMsgBubbleCell
- (void)setupViews
{
[super setupViews];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForIncomingTextMessageCell:self];
}
@end

View file

@ -16,6 +16,18 @@
#import "MXKRoomOutgoingTextMsgBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@implementation MXKRoomOutgoingTextMsgBubbleCell
- (void)setupViews
{
[super setupViews];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForOutgoingTextMessageCell:self];
}
@end

View file

@ -3898,6 +3898,13 @@ TableViewSectionsDelegate>
- (void)toggleEnableRoomMessageBubbles:(UISwitch *)sender
{
RiotSettings.shared.roomScreenEnableMessageBubbles = sender.isOn;
[[RoomTimelineConfiguration shared] updateStyleWithIdentifier:RiotSettings.shared.roomTimelineStyleIdentifier];
// Close all room data sources
// Be sure to use new room timeline style configurations
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
[roomDataSourceManager reset];
}
#pragma mark - TextField listener

View file

@ -97,8 +97,13 @@ final class SideMenuViewModel: SideMenuViewModelType {
return
}
let sideMenuItems: [SideMenuItem] = [
.inviteFriends,
var sideMenuItems: [SideMenuItem] = []
if BuildSettings.sideMenuShowInviteFriends {
sideMenuItems += [.inviteFriends]
}
sideMenuItems += [
.settings,
.help,
.feedback

Some files were not shown because too many files have changed in this diff Show more