mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-16 04:40:01 +02:00
Merge remote-tracking branch 'origin/develop' into room_photo_selection
This commit is contained in:
@@ -21,4 +21,17 @@
|
||||
*/
|
||||
@interface RoomBubbleCellData : MXKRoomBubbleCellDataWithAppendingMode
|
||||
|
||||
/**
|
||||
A Boolean value that determines whether this bubble is the current last one.
|
||||
Used to keep displaying the timestamp of the last message.
|
||||
|
||||
CAUTION: This property is presently set during bubble rendering in order to be used during bubble cell life.
|
||||
*/
|
||||
@property(nonatomic) BOOL isLastBubble;
|
||||
|
||||
/**
|
||||
A Boolean value that determines whether some read receipts are currently displayed in this bubble.
|
||||
*/
|
||||
@property(nonatomic) BOOL hasReadReceipts;
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,9 +20,13 @@
|
||||
|
||||
#import "AvatarGenerator.h"
|
||||
|
||||
#define VECTOR_ROOM_BUBBLE_CELL_DATA_TEXTVIEW_MARGIN 10
|
||||
|
||||
static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
||||
|
||||
@implementation RoomBubbleCellData
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark - Override MXKRoomBubbleCellData
|
||||
|
||||
- (instancetype)initWithEvent:(MXEvent *)event andRoomState:(MXRoomState *)roomState andRoomDataSource:(MXKRoomDataSource *)roomDataSource2
|
||||
{
|
||||
@@ -30,8 +34,22 @@
|
||||
|
||||
if (self)
|
||||
{
|
||||
// use the vector style placeholder
|
||||
// Use the vector style placeholder
|
||||
self.senderAvatarPlaceholder = [AvatarGenerator generateRoomMemberAvatar:self.senderId displayName:self.senderDisplayName];
|
||||
|
||||
// Check whether some read receipts are linked to this event
|
||||
_hasReadReceipts = NO;
|
||||
if ([roomDataSource.room getEventReceipts:event.eventId sorted:NO])
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
|
||||
// Update attributed string by inserting vertical whitespace at the end to display read receipts
|
||||
NSMutableAttributedString *updatedAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:attributedTextMessage];
|
||||
[updatedAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
|
||||
// Update the current text message by reseting content size
|
||||
self.attributedTextMessage = updatedAttributedTextMsg;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -71,10 +89,137 @@
|
||||
[customAttributedTextMsg appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
[customAttributedTextMsg appendAttributedString:componentString];
|
||||
}
|
||||
|
||||
// Add vertical whitespace in case of read receipts
|
||||
if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO])
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
[customAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return customAttributedTextMsg;
|
||||
}
|
||||
|
||||
- (void)prepareBubbleComponentsPosition
|
||||
{
|
||||
if (shouldUpdateComponentsPosition)
|
||||
{
|
||||
_hasReadReceipts = NO;
|
||||
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
// Check whether there is at least one component.
|
||||
if (bubbleComponents.count)
|
||||
{
|
||||
// Set position of the first component
|
||||
MXKRoomBubbleComponent *firstComponent = [bubbleComponents firstObject];
|
||||
|
||||
CGFloat positionY = (self.attachment == nil || self.attachment.type == MXKAttachmentTypeFile) ? VECTOR_ROOM_BUBBLE_CELL_DATA_TEXTVIEW_MARGIN : 0;
|
||||
firstComponent.position = CGPointMake(0, positionY);
|
||||
|
||||
_hasReadReceipts = ([roomDataSource.room getEventReceipts:firstComponent.event.eventId sorted:NO] != nil);
|
||||
|
||||
// Check whether the position of other components need to be refreshed
|
||||
if (!self.attachment && bubbleComponents.count > 1)
|
||||
{
|
||||
// Compute height of the first text component
|
||||
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:firstComponent.attributedTextMessage];
|
||||
|
||||
// Vertical whitescape is added in case of read receipts
|
||||
if (_hasReadReceipts)
|
||||
{
|
||||
[attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
|
||||
|
||||
CGFloat componentHeight = [self rawTextHeight:attributedString];
|
||||
|
||||
// Set position for each other component
|
||||
CGFloat positionY = firstComponent.position.y;
|
||||
CGFloat cumulatedHeight = 0;
|
||||
|
||||
for (NSUInteger index = 1; index < bubbleComponents.count; index++)
|
||||
{
|
||||
cumulatedHeight += componentHeight;
|
||||
positionY += componentHeight;
|
||||
|
||||
MXKRoomBubbleComponent *component = [bubbleComponents objectAtIndex:index];
|
||||
component.position = CGPointMake(0, positionY);
|
||||
|
||||
// Compute height of the current component
|
||||
[attributedString appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
[attributedString appendAttributedString:component.attributedTextMessage];
|
||||
|
||||
// Add vertical whitespace in case of read receipts
|
||||
if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO])
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
[attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
|
||||
componentHeight = [self rawTextHeight:attributedString] - cumulatedHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldUpdateComponentsPosition = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSAttributedString*)attributedTextMessage
|
||||
{
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
if (!attributedTextMessage.length && bubbleComponents.count)
|
||||
{
|
||||
_hasReadReceipts = NO;
|
||||
|
||||
// Create attributed string
|
||||
NSMutableAttributedString *currentAttributedTextMsg;
|
||||
|
||||
for (MXKRoomBubbleComponent* component in bubbleComponents)
|
||||
{
|
||||
if (!currentAttributedTextMsg)
|
||||
{
|
||||
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:component.attributedTextMessage];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append attributed text
|
||||
[currentAttributedTextMsg appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
[currentAttributedTextMsg appendAttributedString:component.attributedTextMessage];
|
||||
}
|
||||
|
||||
// Add vertical whitespace in case of read receipts
|
||||
if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO])
|
||||
{
|
||||
_hasReadReceipts = YES;
|
||||
[currentAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]];
|
||||
}
|
||||
}
|
||||
attributedTextMessage = currentAttributedTextMsg;
|
||||
}
|
||||
}
|
||||
|
||||
return attributedTextMessage;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
+ (NSAttributedString *)readReceiptVerticalWhitespace
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (readReceiptVerticalWhitespace == nil)
|
||||
{
|
||||
readReceiptVerticalWhitespace = [[NSAttributedString alloc] initWithString:@"\n\n" attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
|
||||
NSFontAttributeName: [UIFont systemFontOfSize:4]}];
|
||||
}
|
||||
}
|
||||
return readReceiptVerticalWhitespace;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#import "RoomBubbleCellData.h"
|
||||
|
||||
#import "MXKRoomBubbleTableViewCell+Vector.h"
|
||||
#import "AvatarGenerator.h"
|
||||
|
||||
@implementation RoomDataSource
|
||||
|
||||
@@ -36,8 +37,7 @@
|
||||
|
||||
// Handle timestamp and read receips display at Vector app level (see [tableView: cellForRowAtIndexPath:])
|
||||
self.useCustomDateTimeLabel = YES;
|
||||
//FIXME GFO: disable default receipts display
|
||||
//self.useCustomReceipts = YES;
|
||||
self.useCustomReceipts = YES;
|
||||
|
||||
// TODO custom here self.eventsFilterForMessages according to Vector requirements
|
||||
|
||||
@@ -47,6 +47,34 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveReceiptEvent:(MXEvent *)receiptEvent roomState:(MXRoomState *)roomState
|
||||
{
|
||||
// Override this callback to force rendering of each cell with read receipts information.
|
||||
@synchronized(bubbles)
|
||||
{
|
||||
for (RoomBubbleCellData *cellData in bubbles)
|
||||
{
|
||||
if (cellData.hasReadReceipts)
|
||||
{
|
||||
// Recompute the text message layout
|
||||
cellData.attributedTextMessage = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *readEventIds = receiptEvent.readReceiptEventIds;
|
||||
for (NSString* eventId in readEventIds)
|
||||
{
|
||||
id<MXKRoomBubbleCellDataStoring> bubbleData = [self cellDataOfEventWithEventId:eventId];
|
||||
// Recompute the text message layout
|
||||
bubbleData.attributedTextMessage = nil;
|
||||
}
|
||||
|
||||
|
||||
// Let super handle this receipt
|
||||
[super didReceiveReceiptEvent:receiptEvent roomState:roomState];
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
@@ -55,13 +83,127 @@
|
||||
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
|
||||
{
|
||||
MXKRoomBubbleTableViewCell *bubbleCell = (MXKRoomBubbleTableViewCell*)cell;
|
||||
RoomBubbleCellData *cellData = (RoomBubbleCellData*)bubbleCell.bubbleData;
|
||||
|
||||
// Check whether this bubble is the last one
|
||||
cellData.isLastBubble = (indexPath.row == [tableView numberOfRowsInSection:0] - 1);
|
||||
|
||||
// Display timestamp for the last message.
|
||||
if (indexPath.row == [tableView numberOfRowsInSection:0] - 1)
|
||||
if (cellData.isLastBubble)
|
||||
{
|
||||
if (bubbleCell.bubbleData.bubbleComponents.count)
|
||||
if (cellData.bubbleComponents.count)
|
||||
{
|
||||
[bubbleCell addTimestampLabelForComponent:bubbleCell.bubbleData.bubbleComponents.count - 1];
|
||||
[bubbleCell addTimestampLabelForComponent:cellData.bubbleComponents.count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Handle read receipts display.
|
||||
if (cellData.hasReadReceipts && self.showBubbleReceipts)
|
||||
{
|
||||
// Read receipts container are inserted here on the right side into the overlay container.
|
||||
// Some vertical whitespaces are added in message text view (see RoomBubbleCellData class) to insert correctly multiple receipts.
|
||||
bubbleCell.bubbleOverlayContainer.backgroundColor = [UIColor clearColor];
|
||||
bubbleCell.bubbleOverlayContainer.alpha = 1;
|
||||
bubbleCell.bubbleOverlayContainer.userInteractionEnabled = NO;
|
||||
bubbleCell.bubbleOverlayContainer.hidden = NO;
|
||||
|
||||
NSInteger index = cellData.bubbleComponents.count;
|
||||
CGFloat bottomPositionY = bubbleCell.frame.size.height;
|
||||
while (index--)
|
||||
{
|
||||
MXKRoomBubbleComponent *component = cellData.bubbleComponents[index];
|
||||
|
||||
if (component.event.mxkState != MXKEventStateSendingFailed)
|
||||
{
|
||||
// Get the events receipts by ignoring the current user receipt.
|
||||
NSArray* receipts = [self.room getEventReceipts:component.event.eventId sorted:YES];
|
||||
NSMutableArray *roomMembers;
|
||||
NSMutableArray *placeholders;
|
||||
|
||||
// Check whether some receipts are found
|
||||
if (receipts.count)
|
||||
{
|
||||
// Retrieve the corresponding room members
|
||||
roomMembers = [[NSMutableArray alloc] initWithCapacity:receipts.count];
|
||||
placeholders = [[NSMutableArray alloc] initWithCapacity:receipts.count];
|
||||
|
||||
for (MXReceiptData* data in receipts)
|
||||
{
|
||||
MXRoomMember * roomMember = [self.room.state memberWithUserId:data.userId];
|
||||
if (roomMember)
|
||||
{
|
||||
[roomMembers addObject:roomMember];
|
||||
[placeholders addObject:[AvatarGenerator generateRoomMemberAvatar:roomMember.userId displayName:roomMember.displayname]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether some receipts are found
|
||||
if (roomMembers.count)
|
||||
{
|
||||
// Define the read receipts container, positioned on the right border of the bubble cell (Note the right margin 6 pts).
|
||||
MXKReceiptSendersContainer* avatarsContainer = [[MXKReceiptSendersContainer alloc] initWithFrame:CGRectMake(bubbleCell.frame.size.width - 156, bottomPositionY - 12, 150, 12) andRestClient:self.mxSession.matrixRestClient];
|
||||
|
||||
// Custom avatar display
|
||||
avatarsContainer.maxDisplayedAvatars = 5;
|
||||
avatarsContainer.avatarMargin = 6;
|
||||
|
||||
// Set the container tag to be able to retrieve read receipts container from component index (see component selection in MXKRoomBubbleTableViewCell (Vector) category).
|
||||
avatarsContainer.tag = index;
|
||||
|
||||
[avatarsContainer refreshReceiptSenders:roomMembers withPlaceHolders:placeholders andAlignment:ReadReceiptAlignmentRight];
|
||||
|
||||
avatarsContainer.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[bubbleCell.bubbleOverlayContainer addSubview:avatarsContainer];
|
||||
|
||||
// Force receipts container size
|
||||
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
|
||||
attribute:NSLayoutAttributeWidth
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:nil
|
||||
attribute:NSLayoutAttributeNotAnAttribute
|
||||
multiplier:1.0
|
||||
constant:150];
|
||||
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
|
||||
attribute:NSLayoutAttributeHeight
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:nil
|
||||
attribute:NSLayoutAttributeNotAnAttribute
|
||||
multiplier:1.0
|
||||
constant:12];
|
||||
|
||||
// Force receipts container position
|
||||
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
|
||||
attribute:NSLayoutAttributeTrailing
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:bubbleCell.bubbleOverlayContainer
|
||||
attribute:NSLayoutAttributeTrailing
|
||||
multiplier:1.0
|
||||
constant:-6];
|
||||
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
|
||||
attribute:NSLayoutAttributeTop
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:bubbleCell.bubbleOverlayContainer
|
||||
attribute:NSLayoutAttributeTop
|
||||
multiplier:1.0
|
||||
constant:bottomPositionY - 12];
|
||||
|
||||
if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)])
|
||||
{
|
||||
[NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, rightConstraint]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[avatarsContainer addConstraint:heightConstraint];
|
||||
[avatarsContainer addConstraint:widthConstraint];
|
||||
[bubbleCell.bubbleOverlayContainer addConstraint:topConstraint];
|
||||
[bubbleCell.bubbleOverlayContainer addConstraint:rightConstraint];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the bottom position for the next read receipt container (if any)
|
||||
bottomPositionY = bubbleCell.msgTextViewTopConstraint.constant + component.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +220,6 @@
|
||||
else
|
||||
{
|
||||
// Highlight the selected event in the displayed message
|
||||
MXKRoomBubbleCellData *cellData = (MXKRoomBubbleCellData*)bubbleCell.bubbleData;
|
||||
|
||||
for (NSUInteger index = 0; index < cellData.bubbleComponents.count; index ++)
|
||||
{
|
||||
MXKRoomBubbleComponent *component = cellData.bubbleComponents[index];
|
||||
|
||||
@@ -31,9 +31,42 @@
|
||||
*/
|
||||
@property (nonatomic, copy) void (^onRoomInvitationAccept)(MXRoom*);
|
||||
|
||||
/**
|
||||
There is a pending drag and drop cell.
|
||||
It defines its path of the source cell.
|
||||
*/
|
||||
@property (nonatomic, copy) NSIndexPath* hiddenCellIndexPath;
|
||||
|
||||
/**
|
||||
There is a pending drag and drop cell.
|
||||
It defines its path of the destination cell.
|
||||
*/
|
||||
@property (nonatomic, copy) NSIndexPath* droppingCellIndexPath;
|
||||
|
||||
/**
|
||||
The movingCellBackgroundImage;
|
||||
*/
|
||||
@property (nonatomic) UIImageView* droppingCellBackGroundView;
|
||||
|
||||
/**
|
||||
Return the header height from the section.
|
||||
*/
|
||||
- (CGFloat)heightForHeaderInSection:(NSInteger)section;
|
||||
|
||||
/**
|
||||
Return true of the cell can be moved from a section to another one.
|
||||
*/
|
||||
- (BOOL)isDraggableCellAt:(NSIndexPath*)path;
|
||||
|
||||
/**
|
||||
Return true of the cell can be moved from a section to another one.
|
||||
*/
|
||||
- (BOOL)canCellMoveFrom:(NSIndexPath*)oldPath to:(NSIndexPath*)newPath;
|
||||
|
||||
/**
|
||||
Move a cell from a path to another one.
|
||||
It is based on room Tag.
|
||||
*/
|
||||
- (void)moveRoomCell:(MXRoom*)room from:(NSIndexPath*)oldPath to:(NSIndexPath*)newPath success:(void (^)())moveSuccess failure:(void (^)(NSError *error))moveFailure;
|
||||
|
||||
@end
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
@implementation RecentsDataSource
|
||||
@synthesize onRoomInvitationReject, onRoomInvitationAccept;
|
||||
@synthesize hiddenCellIndexPath, droppingCellIndexPath, droppingCellBackGroundView;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
@@ -106,11 +107,8 @@
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// refresh the sections
|
||||
[self refreshRoomsSections];
|
||||
|
||||
// And inform the delegate about the update
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
[self refreshRoomsSectionsAndReload];
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,16 +141,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)refreshRoomsSectionsAndReload
|
||||
{
|
||||
// Refresh is disabled during drag&drop animation"
|
||||
if (!self.droppingCellIndexPath)
|
||||
{
|
||||
[self refreshRoomsSections];
|
||||
|
||||
// And inform the delegate about the update
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didMXSessionInviteRoomUpdate:(NSNotification *)notif
|
||||
{
|
||||
MXSession *mxSession = notif.object;
|
||||
if (mxSession == self.mxSession)
|
||||
{
|
||||
// refresh the sections
|
||||
[self refreshRoomsSections];
|
||||
|
||||
// And inform the delegate about the update
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
[self refreshRoomsSectionsAndReload];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +188,16 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (BOOL)isMovingCellSection:(NSInteger)section
|
||||
{
|
||||
return self.droppingCellIndexPath && (self.droppingCellIndexPath.section == section);
|
||||
}
|
||||
|
||||
- (BOOL)isHiddenCellSection:(NSInteger)section
|
||||
{
|
||||
return self.hiddenCellIndexPath && (self.hiddenCellIndexPath.section == section);
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
NSUInteger count = 0;
|
||||
@@ -203,7 +219,16 @@
|
||||
count = invitesCellDataArray.count;
|
||||
}
|
||||
|
||||
|
||||
if ([self isMovingCellSection:section])
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if ([self isHiddenCellSection:section])
|
||||
{
|
||||
count--;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -244,10 +269,52 @@
|
||||
return [super viewForHeaderInSection:section withFrame:frame];
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)anIndexPath
|
||||
{
|
||||
UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
NSIndexPath* indexPath = anIndexPath;
|
||||
|
||||
if (self.droppingCellIndexPath && (self.droppingCellIndexPath.section == indexPath.section))
|
||||
{
|
||||
if ([anIndexPath isEqual:self.droppingCellIndexPath])
|
||||
{
|
||||
static NSString* cellIdentifier = @"VectorRecentsMovingCell";
|
||||
|
||||
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"VectorRecentsMovingCell"];
|
||||
|
||||
// add an imageview of the cell.
|
||||
// The image is a shot of the genuine cell.
|
||||
// Thus, this cell has the same look as the genuine cell withourt computing it.
|
||||
UIImageView* imageView = [cell viewWithTag:[cellIdentifier hash]];
|
||||
|
||||
if (!imageView || (imageView != self.droppingCellBackGroundView))
|
||||
{
|
||||
if (imageView)
|
||||
{
|
||||
[imageView removeFromSuperview];
|
||||
}
|
||||
self.droppingCellBackGroundView.tag = [cellIdentifier hash];
|
||||
[cell.contentView addSubview:self.droppingCellBackGroundView];
|
||||
}
|
||||
|
||||
self.droppingCellBackGroundView.frame = self.droppingCellBackGroundView.frame;
|
||||
cell.contentView.backgroundColor = [UIColor clearColor];
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
if (anIndexPath.row > self.droppingCellIndexPath.row)
|
||||
{
|
||||
indexPath = [NSIndexPath indexPathForRow:anIndexPath.row-1 inSection:anIndexPath.section];
|
||||
}
|
||||
}
|
||||
|
||||
if (self.hiddenCellIndexPath && [anIndexPath isEqual:self.hiddenCellIndexPath])
|
||||
{
|
||||
indexPath = [NSIndexPath indexPathForRow:anIndexPath.row-1 inSection:anIndexPath.section];
|
||||
}
|
||||
|
||||
UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
|
||||
// on invite cell, add listeners on accept / reject buttons
|
||||
if (cell && [cell isKindOfClass:[InviteRecentTableViewCell class]])
|
||||
@@ -273,25 +340,35 @@
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (id<MXKRecentCellDataStoring>)cellDataAtIndexPath:(NSIndexPath *)indexPath
|
||||
- (id<MXKRecentCellDataStoring>)cellDataAtIndexPath:(NSIndexPath *)anIndexPath
|
||||
{
|
||||
id<MXKRecentCellDataStoring> cellData = nil;
|
||||
NSInteger row = anIndexPath.row;
|
||||
NSInteger section = anIndexPath.section;
|
||||
|
||||
if (indexPath.section == favoritesSection)
|
||||
if (self.droppingCellIndexPath && (self.droppingCellIndexPath.section == section))
|
||||
{
|
||||
cellData = [favoriteCellDataArray objectAtIndex:indexPath.row];
|
||||
if (anIndexPath.row > self.droppingCellIndexPath.row)
|
||||
{
|
||||
row = anIndexPath.row - 1;
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == conversationSection)
|
||||
|
||||
if (section == favoritesSection)
|
||||
{
|
||||
cellData = [conversationCellDataArray objectAtIndex:indexPath.row];
|
||||
cellData = [favoriteCellDataArray objectAtIndex:row];
|
||||
}
|
||||
else if (indexPath.section == lowPrioritySection)
|
||||
else if (section== conversationSection)
|
||||
{
|
||||
cellData = [lowPriorityCellDataArray objectAtIndex:indexPath.row];
|
||||
cellData = [conversationCellDataArray objectAtIndex:row];
|
||||
}
|
||||
else if (indexPath.section == invitesSection)
|
||||
else if (section == lowPrioritySection)
|
||||
{
|
||||
cellData = [invitesCellDataArray objectAtIndex:indexPath.row];
|
||||
cellData = [lowPriorityCellDataArray objectAtIndex:row];
|
||||
}
|
||||
else if (section == invitesSection)
|
||||
{
|
||||
cellData = [invitesCellDataArray objectAtIndex:row];
|
||||
}
|
||||
|
||||
return cellData;
|
||||
@@ -299,6 +376,11 @@
|
||||
|
||||
- (CGFloat)cellHeightAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (self.droppingCellIndexPath && [indexPath isEqual:self.droppingCellIndexPath])
|
||||
{
|
||||
return self.droppingCellBackGroundView.frame.size.height;
|
||||
}
|
||||
|
||||
// Override this method here to use our own cellDataAtIndexPath
|
||||
id<MXKRecentCellDataStoring> cellData = [self cellDataAtIndexPath:indexPath];
|
||||
|
||||
@@ -494,6 +576,12 @@
|
||||
|
||||
- (void)dataSource:(MXKDataSource*)dataSource didCellChange:(id)changes
|
||||
{
|
||||
// Refresh is disabled during drag&drop animation
|
||||
if (self.droppingCellIndexPath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME : manage multi accounts
|
||||
// to manage multi accounts
|
||||
// this method in MXKInterleavedRecentsDataSource must be split in two parts
|
||||
@@ -519,4 +607,98 @@
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - drag and drop managemenent
|
||||
|
||||
- (BOOL)isDraggableCellAt:(NSIndexPath*)path
|
||||
{
|
||||
return (path && ((path.section == favoritesSection) || (path.section == lowPrioritySection) || (path.section == conversationSection)));
|
||||
}
|
||||
|
||||
- (BOOL)canCellMoveFrom:(NSIndexPath*)oldPath to:(NSIndexPath*)newPath
|
||||
{
|
||||
BOOL res = [self isDraggableCellAt:oldPath] && [self isDraggableCellAt:newPath];
|
||||
|
||||
// the both index pathes are movable
|
||||
if (res)
|
||||
{
|
||||
// only the favorites cell can be moved within the same section
|
||||
res &= (oldPath.section == favoritesSection) || (newPath.section != oldPath.section);
|
||||
|
||||
// other cases ?
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
- (NSString*)roomTagAt:(NSIndexPath*)path
|
||||
{
|
||||
if (path.section == favoritesSection)
|
||||
{
|
||||
return kMXRoomTagFavourite;
|
||||
}
|
||||
else if (path.section == lowPrioritySection)
|
||||
{
|
||||
return kMXRoomTagLowPriority;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)moveRoomCell:(MXRoom*)room from:(NSIndexPath*)oldPath to:(NSIndexPath*)newPath success:(void (^)())moveSuccess failure:(void (^)(NSError *error))moveFailure;
|
||||
{
|
||||
NSLog(@"[RecentsDataSource] moveCellFrom (%d, %d) to (%d, %d)", oldPath.section, oldPath.row, newPath.section, newPath.row);
|
||||
|
||||
if ([self canCellMoveFrom:oldPath to:newPath] && ![newPath isEqual:oldPath])
|
||||
{
|
||||
NSString* oldRoomTag = [self roomTagAt:oldPath];
|
||||
NSString* dstRoomTag = [self roomTagAt:newPath];
|
||||
NSUInteger oldPos = (oldPath.section == newPath.section) ? oldPath.row : NSNotFound;
|
||||
|
||||
NSString* tagOrder = [room.mxSession tagOrderToBeAtIndex:newPath.row from:oldPos withTag:dstRoomTag];
|
||||
|
||||
NSLog(@"[RecentsDataSource] Update the room %@ [%@] tag from %@ to %@ with tag order %@", room.state.roomId, room.state.displayname, oldRoomTag, dstRoomTag, tagOrder);
|
||||
|
||||
[room replaceTag:oldRoomTag
|
||||
byTag:dstRoomTag
|
||||
withOrder:tagOrder
|
||||
success: ^{
|
||||
|
||||
NSLog(@"[RecentsDataSource] move is done");
|
||||
|
||||
if (moveSuccess)
|
||||
{
|
||||
moveSuccess();
|
||||
}
|
||||
|
||||
// wait the server echo to reload the tableview.
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
NSLog(@"[RecentsDataSource] Failed to update the tag %@ of room (%@) failed: %@", dstRoomTag, room.state.roomId, error);
|
||||
|
||||
if (moveFailure)
|
||||
{
|
||||
moveFailure(error);
|
||||
}
|
||||
|
||||
[self refreshRoomsSectionsAndReload];
|
||||
|
||||
// Notify MatrixKit user
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[RecentsDataSource] cannot move this cell");
|
||||
|
||||
if (moveFailure)
|
||||
{
|
||||
moveFailure(nil);
|
||||
}
|
||||
|
||||
[self refreshRoomsSectionsAndReload];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user