mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-20 14:42:09 +02:00
Chat screen: Customize bubble cells
This commit is contained in:
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "RoomDataSource.h"
|
||||
#import "EventFormatter.h"
|
||||
|
||||
#import "RoomViewController.h"
|
||||
#import "SettingsViewController.h"
|
||||
#import "MXKContactManager.h"
|
||||
#import "RageShakeManager.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
@@ -435,6 +438,9 @@
|
||||
|
||||
- (void)initMatrixSessions
|
||||
{
|
||||
// Set first RoomDataSource class used in Vector
|
||||
[MXKRoomDataSourceManager registerRoomDataSourceClass:RoomDataSource.class];
|
||||
|
||||
// Register matrix session state observer in order to handle multi-sessions.
|
||||
matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif)
|
||||
{
|
||||
@@ -684,7 +690,7 @@
|
||||
if (account.enableInAppNotifications)
|
||||
{
|
||||
// Build MXEvent -> NSString formatter
|
||||
MXKEventFormatter *eventFormatter = [[MXKEventFormatter alloc] initWithMatrixSession:account.mxSession];
|
||||
EventFormatter *eventFormatter = [[EventFormatter alloc] initWithMatrixSession:account.mxSession];
|
||||
eventFormatter.isForSubtitle = YES;
|
||||
|
||||
[account listenToNotifications:^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "EventFormatter.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
@interface RecentListDataSource ()
|
||||
@@ -54,6 +56,9 @@
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
self.eventFormatter = [[EventFormatter alloc] initWithMatrixSession:self.mxSession];
|
||||
self.eventFormatter.isForSubtitle = YES;
|
||||
|
||||
highlightedPublicRooms = @[@"#matrix:matrix.org", @"#matrix-dev:matrix.org", @"#matrix-fr:matrix.org"]; // Add here a room name to highlight its display in public room list
|
||||
}
|
||||
return self;
|
||||
|
||||
@@ -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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
/**
|
||||
The data source for `RoomViewController` in Vector.
|
||||
*/
|
||||
@interface RoomDataSource : MXKRoomDataSource
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 "RoomDataSource.h"
|
||||
|
||||
#import "EventFormatter.h"
|
||||
#import "RoomIncomingBubbleTableViewCell.h"
|
||||
#import "RoomOutgoingBubbleTableViewCell.h"
|
||||
|
||||
@implementation RoomDataSource
|
||||
|
||||
- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession
|
||||
{
|
||||
self = [super initWithRoomId:roomId andMatrixSession:matrixSession];
|
||||
if (self)
|
||||
{
|
||||
// Keep default Cell data class (MXKRoomBubbleCellDataWithAppendingMode)
|
||||
// [self registerCellDataClass:MXKRoomBubbleCellDataWithAppendingMode.class forCellIdentifier:kMXKRoomBubbleCellDataIdentifier];
|
||||
|
||||
// Replace cell view classes
|
||||
[self registerCellViewClass:RoomIncomingBubbleTableViewCell.class forCellIdentifier:kMXKRoomIncomingTextMsgBubbleTableViewCellIdentifier];
|
||||
[self registerCellViewClass:RoomIncomingBubbleTableViewCell.class forCellIdentifier:kMXKRoomIncomingAttachmentBubbleTableViewCellIdentifier];
|
||||
[self registerCellViewClass:RoomOutgoingBubbleTableViewCell.class forCellIdentifier:kMXKRoomOutgoingTextMsgBubbleTableViewCellIdentifier];
|
||||
[self registerCellViewClass:RoomOutgoingBubbleTableViewCell.class forCellIdentifier:kMXKRoomOutgoingAttachmentBubbleTableViewCellIdentifier];
|
||||
|
||||
// Replace event formatter
|
||||
self.eventFormatter = [[EventFormatter alloc] initWithMatrixSession:self.mxSession];
|
||||
|
||||
// TODO custom here self.eventsFilterForMessages according to Vector requirements
|
||||
|
||||
// Set bubble pagination
|
||||
self.bubblesPagination = MXKRoomDataSourceBubblesPaginationPerDay;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -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 <MatrixKit/MatrixKit.h>
|
||||
|
||||
/**
|
||||
`EventFormatter` class inherits from `MXKEventFormatter` to define Vector formatting
|
||||
*/
|
||||
@interface EventFormatter : MXKEventFormatter
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 "EventFormatter.h"
|
||||
|
||||
@interface EventFormatter ()
|
||||
{
|
||||
/**
|
||||
The calendar used to retrieve the today date.
|
||||
*/
|
||||
NSCalendar *calendar;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation EventFormatter
|
||||
|
||||
- (instancetype)initWithMatrixSession:(MXSession *)matrixSession
|
||||
{
|
||||
self = [super initWithMatrixSession:matrixSession];
|
||||
if (self)
|
||||
{
|
||||
calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
|
||||
// Note: NSDate object always shows time according to GMT, so the calendar should be in GMT too.
|
||||
calendar.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Timestamp formatting
|
||||
|
||||
- (NSString*)dateStringFromDate:(NSDate *)date withTime:(BOOL)time
|
||||
{
|
||||
// Retrieve today date at midnight
|
||||
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];
|
||||
NSDate *today = [calendar dateFromComponents:components];
|
||||
|
||||
NSTimeInterval interval = -[date timeIntervalSinceDate:today];
|
||||
if (interval > 60*60*24*6)
|
||||
{
|
||||
dateFormat = @"EEE MMM dd yyyy";
|
||||
return [super dateStringFromDate:date withTime:time];
|
||||
}
|
||||
else if (interval > 60*60*24)
|
||||
{
|
||||
dateFormat = @"EEEE";
|
||||
return [super dateStringFromDate:date withTime:time];
|
||||
}
|
||||
else if (interval > 0)
|
||||
{
|
||||
if (time)
|
||||
{
|
||||
dateFormat = nil;
|
||||
return [NSString stringWithFormat:@"yesterday %@", [super dateStringFromDate:date withTime:YES]];
|
||||
}
|
||||
return @"yesterday";
|
||||
}
|
||||
else if (interval > - 60*60*24)
|
||||
{
|
||||
if (time)
|
||||
{
|
||||
dateFormat = nil;
|
||||
return [NSString stringWithFormat:@"today %@", [super dateStringFromDate:date withTime:YES]];
|
||||
}
|
||||
return @"today";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Date in future
|
||||
dateFormat = @"EEE MMM dd yyyy";
|
||||
return [super dateStringFromDate:date withTime:time];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -222,6 +222,8 @@
|
||||
[self dismissKeyboard];
|
||||
|
||||
MXKRoomMemberListDataSource *membersDataSource = [[MXKRoomMemberListDataSource alloc] initWithRoomId:self.roomDataSource.roomId andMatrixSession:self.mainSession];
|
||||
[membersDataSource finalizeInitialization];
|
||||
|
||||
[membersController displayList:membersDataSource];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,16 @@
|
||||
|
||||
#import "RoomIncomingBubbleTableViewCell.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
#pragma mark - UI Constant definitions
|
||||
#define MXKROOMBUBBLETABLEVIEWCELL_INCOMING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN -10
|
||||
|
||||
@implementation RoomIncomingBubbleTableViewCell
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
||||
self.typingBadge.image = [NSBundle mxk_imageFromMXKAssetsBundleWithName:@"icon_keyboard"];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// [self stopTypingIndicatorAnimating];
|
||||
}
|
||||
|
||||
- (void)render:(MXKCellData *)cellData
|
||||
@@ -36,56 +34,20 @@
|
||||
|
||||
if (self.bubbleData)
|
||||
{
|
||||
// Check whether the previous message has been sent by the same user.
|
||||
// The user's picture and name are displayed only for the first message.
|
||||
// Handle sender's picture and adjust view's constraints
|
||||
if (self.bubbleData.isSameSenderAsPreviousBubble)
|
||||
{
|
||||
self.pictureView.hidden = YES;
|
||||
self.msgTextViewTopConstraint.constant = self.class.cellWithOriginalXib.msgTextViewTopConstraint.constant + MXKROOMBUBBLETABLEVIEWCELL_INCOMING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
self.attachViewTopConstraint.constant = self.class.cellWithOriginalXib.attachViewTopConstraint.constant + MXKROOMBUBBLETABLEVIEWCELL_INCOMING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
|
||||
if (!self.dateTimeLabelContainer.hidden)
|
||||
{
|
||||
self.dateTimeLabelContainerTopConstraint.constant += MXKROOMBUBBLETABLEVIEWCELL_INCOMING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
}
|
||||
}
|
||||
// TODO handle here pagination display per day
|
||||
|
||||
// Display user's display name except if the name appears in the displayed text (see emote and membership event)
|
||||
self.userNameLabel.hidden = (self.bubbleData.isSameSenderAsPreviousBubble || self.bubbleData.startsWithSenderName);
|
||||
self.userNameLabel.text = self.bubbleData.senderDisplayName;
|
||||
// Set typing badge visibility
|
||||
self.typingBadge.hidden = (self.pictureView.hidden || !self.bubbleData.isTyping);
|
||||
if (!self.typingBadge.hidden)
|
||||
{
|
||||
[self.typingBadge.superview bringSubviewToFront:self.typingBadge];
|
||||
}
|
||||
// TODO handle here timestamp display
|
||||
|
||||
// TODO handle here typing indicator
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
|
||||
- (void)didEndDisplay
|
||||
{
|
||||
CGFloat rowHeight = [super heightForCellData:cellData withMaximumWidth:maxWidth];
|
||||
[super didEndDisplay];
|
||||
|
||||
MXKRoomBubbleCellData *bubbleData = (MXKRoomBubbleCellData*)cellData;
|
||||
|
||||
// Check whether the previous message has been sent by the same user.
|
||||
// The user's picture and name are displayed only for the first message.
|
||||
if (bubbleData.isSameSenderAsPreviousBubble)
|
||||
{
|
||||
// Reduce top margin -> row height reduction
|
||||
rowHeight += MXKROOMBUBBLETABLEVIEWCELL_INCOMING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We consider a minimun cell height in order to display correctly user's picture
|
||||
if (rowHeight < self.cellWithOriginalXib.frame.size.height)
|
||||
{
|
||||
rowHeight = self.cellWithOriginalXib.frame.size.height;
|
||||
}
|
||||
}
|
||||
|
||||
return rowHeight;
|
||||
// Stop potential typing indicator
|
||||
// [self stopTypingIndicatorAnimating];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6751" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
@@ -21,15 +21,15 @@
|
||||
<constraint firstAttribute="height" constant="40" id="dNT-QU-CUG"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zwq-eh-8Fb" userLabel="typingBadge">
|
||||
<rect key="frame" x="5" y="0.0" width="20" height="20"/>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="typing.png" translatesAutoresizingMaskIntoConstraints="NO" id="zwq-eh-8Fb" userLabel="typingBadge">
|
||||
<rect key="frame" x="18" y="45" width="20" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="20" id="7ni-rb-ovL"/>
|
||||
<constraint firstAttribute="height" constant="20" id="mcu-rQ-hnj"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="User name:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" translatesAutoresizingMaskIntoConstraints="NO" id="q9c-0p-QyP">
|
||||
<rect key="frame" x="51" y="3" width="480" height="20"/>
|
||||
<rect key="frame" x="51" y="3" width="541" height="20"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" placeholder="YES" id="5ZO-W1-tS2"/>
|
||||
@@ -59,25 +59,6 @@
|
||||
<constraint firstAttribute="width" constant="32" id="aeJ-j3-rfX"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kwd-hP-feC" userLabel="showHideDateTime">
|
||||
<rect key="frame" x="531" y="0.0" width="69" height="49"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="69" id="9vA-4g-EE5"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="showHideDateTime:" destination="WmY-Jw-mqv" eventType="touchUpInside" id="jYV-nj-p60"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW" userLabel="DateTimeLabelContainer">
|
||||
<rect key="frame" x="531" y="10" width="61" height="39"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="61" 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="-1" width="100" height="70"/>
|
||||
<subviews>
|
||||
@@ -111,25 +92,19 @@
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="hgp-Z5-rAj" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="5" id="2Ih-ga-N9s"/>
|
||||
<constraint firstItem="kwd-hP-feC" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="5bB-HV-WAA"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="3" id="6mM-Ag-m0K"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="18" id="96U-67-5TP"/>
|
||||
<constraint firstAttribute="trailing" secondItem="q9c-0p-QyP" secondAttribute="trailing" constant="69" id="Bkh-h2-JOQ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="q9c-0p-QyP" secondAttribute="trailing" constant="8" id="Bkh-h2-JOQ"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="Cot-3X-2cU" secondAttribute="centerY" id="H5t-l6-fL1"/>
|
||||
<constraint firstItem="q9c-0p-QyP" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="3" id="Ixr-7h-f8j"/>
|
||||
<constraint firstAttribute="bottom" secondItem="kwd-hP-feC" secondAttribute="bottom" id="LQg-cI-Nkn"/>
|
||||
<constraint firstItem="zwq-eh-8Fb" firstAttribute="centerX" secondItem="hgp-Z5-rAj" secondAttribute="centerX" id="Jse-fI-be0"/>
|
||||
<constraint firstItem="zwq-eh-8Fb" firstAttribute="top" secondItem="hgp-Z5-rAj" secondAttribute="bottom" id="L78-IF-L1h"/>
|
||||
<constraint firstAttribute="bottom" secondItem="5IE-JS-uf3" secondAttribute="bottom" id="SHN-tC-zsJ"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="HTH-5n-MSU" secondAttribute="trailing" constant="69" id="Shz-6S-kGd"/>
|
||||
<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="10" id="XSL-TG-m62"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="HTH-5n-MSU" secondAttribute="trailing" constant="8" id="Shz-6S-kGd"/>
|
||||
<constraint firstItem="q9c-0p-QyP" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="3" id="YWK-C2-15w"/>
|
||||
<constraint firstItem="zwq-eh-8Fb" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="5" id="dgK-4e-UuE"/>
|
||||
<constraint firstAttribute="trailing" secondItem="kwd-hP-feC" secondAttribute="trailing" id="f2V-Ka-kU3"/>
|
||||
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="8" id="hQV-lO-7aQ"/>
|
||||
<constraint firstItem="HTH-5n-MSU" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="10" id="mkw-3s-H8B"/>
|
||||
<constraint firstAttribute="bottom" secondItem="HTH-5n-MSU" secondAttribute="bottom" id="oTk-3F-SEC"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerX" secondItem="Cot-3X-2cU" secondAttribute="centerX" id="sF7-QL-vdj"/>
|
||||
<constraint firstItem="zwq-eh-8Fb" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="tUd-UR-lzA"/>
|
||||
<constraint firstItem="hgp-Z5-rAj" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="8" id="tuw-aU-ncu"/>
|
||||
<constraint firstItem="HTH-5n-MSU" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="51" id="uig-Xh-7m6"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="fdx-qs-8en" secondAttribute="centerY" id="v0F-Ts-14P"/>
|
||||
@@ -141,8 +116,6 @@
|
||||
<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="dateTimeLabelContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
|
||||
<outlet property="dateTimeLabelContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
|
||||
<outlet property="messageTextView" destination="HTH-5n-MSU" id="YN4-iK-gNc"/>
|
||||
<outlet property="msgTextViewLeadingConstraint" destination="uig-Xh-7m6" id="kgj-3v-ECW"/>
|
||||
<outlet property="msgTextViewTopConstraint" destination="mkw-3s-H8B" id="lON-oG-Xx9"/>
|
||||
@@ -157,4 +130,7 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="typing.png" width="20" height="20"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -21,200 +21,43 @@
|
||||
|
||||
@implementation RoomOutgoingBubbleTableViewCell
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self stopAnimating];
|
||||
}
|
||||
|
||||
- (void)render:(MXKCellData *)cellData
|
||||
{
|
||||
[super render:cellData];
|
||||
|
||||
if (self.bubbleData)
|
||||
{
|
||||
// Check whether the previous message has been sent by the same user.
|
||||
// The user's picture and name are displayed only for the first message.
|
||||
// Handle sender's picture and adjust view's constraints
|
||||
if (self.bubbleData.isSameSenderAsPreviousBubble)
|
||||
{
|
||||
self.pictureView.hidden = YES;
|
||||
self.msgTextViewTopConstraint.constant = self.class.cellWithOriginalXib.msgTextViewTopConstraint.constant + MXKROOMBUBBLETABLEVIEWCELL_OUTGOING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
self.attachViewTopConstraint.constant = self.class.cellWithOriginalXib.attachViewTopConstraint.constant + MXKROOMBUBBLETABLEVIEWCELL_OUTGOING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
|
||||
if (!self.dateTimeLabelContainer.hidden)
|
||||
{
|
||||
self.dateTimeLabelContainerTopConstraint.constant += MXKROOMBUBBLETABLEVIEWCELL_OUTGOING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
}
|
||||
}
|
||||
// TODO handle here pagination display per day
|
||||
|
||||
// TODO handle here timestamp display
|
||||
|
||||
// TODO handle here unsent
|
||||
|
||||
// Add unsent label for failed components
|
||||
for (MXKRoomBubbleComponent *component in self.bubbleData.bubbleComponents)
|
||||
{
|
||||
if (component.event.mxkState == MXKEventStateSendingFailed)
|
||||
{
|
||||
UIButton *unsentButton = [[UIButton alloc] initWithFrame:CGRectMake(0, component.position.y, 58 , 20)];
|
||||
|
||||
[unsentButton setTitle:[NSBundle mxk_localizedStringForKey:@"unsent"] forState:UIControlStateNormal];
|
||||
[unsentButton setTitle:[NSBundle mxk_localizedStringForKey:@"unsent"] forState:UIControlStateSelected];
|
||||
[unsentButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
|
||||
[unsentButton setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
|
||||
|
||||
unsentButton.backgroundColor = [UIColor whiteColor];
|
||||
unsentButton.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
|
||||
[unsentButton addTarget:self action:@selector(onResendToggle:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[self.dateTimeLabelContainer addSubview:unsentButton];
|
||||
self.dateTimeLabelContainer.hidden = NO;
|
||||
self.dateTimeLabelContainer.userInteractionEnabled = YES;
|
||||
|
||||
// ensure that dateTimeLabelContainer is at front to catch the tap event
|
||||
[self.dateTimeLabelContainer.superview bringSubviewToFront:self.dateTimeLabelContainer];
|
||||
}
|
||||
}
|
||||
|
||||
if (self.attachmentView)
|
||||
{
|
||||
// Check if the image is uploading
|
||||
MXKRoomBubbleComponent *component = self.bubbleData.bubbleComponents.firstObject;
|
||||
if (MXKEventStateUploading == component.event.mxkState)
|
||||
{
|
||||
// Retrieve the uploadId embedded in the fake url
|
||||
self.bubbleData.uploadId = component.event.content[@"url"];
|
||||
|
||||
// And start showing upload progress
|
||||
[self startUploadAnimating];
|
||||
self.attachmentView.hideActivityIndicator = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.attachmentView.hideActivityIndicator = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
|
||||
{
|
||||
CGFloat rowHeight = [super heightForCellData:cellData withMaximumWidth:maxWidth];
|
||||
|
||||
MXKRoomBubbleCellData *bubbleData = (MXKRoomBubbleCellData*)cellData;
|
||||
|
||||
// Check whether the previous message has been sent by the same user.
|
||||
// The user's picture and name are displayed only for the first message.
|
||||
if (bubbleData.isSameSenderAsPreviousBubble)
|
||||
{
|
||||
// Reduce top margin -> row height reduction
|
||||
rowHeight += MXKROOMBUBBLETABLEVIEWCELL_OUTGOING_HEIGHT_REDUCTION_WHEN_SENDER_INFO_IS_HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We consider a minimun cell height in order to display correctly user's picture
|
||||
if (rowHeight < self.cellWithOriginalXib.frame.size.height)
|
||||
{
|
||||
rowHeight = self.cellWithOriginalXib.frame.size.height;
|
||||
}
|
||||
}
|
||||
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
|
||||
- (void)didEndDisplay
|
||||
{
|
||||
[super didEndDisplay];
|
||||
|
||||
// Hide potential loading wheel
|
||||
[self stopAnimating];
|
||||
|
||||
self.dateTimeLabelContainer.userInteractionEnabled = NO;
|
||||
}
|
||||
|
||||
-(void)startUploadAnimating
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXKMediaUploadProgressNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUploadProgress:) name:kMXKMediaUploadProgressNotification object:nil];
|
||||
|
||||
self.activityIndicator.hidden = NO;
|
||||
[self.activityIndicator startAnimating];
|
||||
|
||||
MXKMediaLoader *uploader = [MXKMediaManager existingUploaderWithId:self.bubbleData.uploadId];
|
||||
if (uploader && uploader.statisticsDict)
|
||||
{
|
||||
[self.activityIndicator stopAnimating];
|
||||
[self updateProgressUI:uploader.statisticsDict];
|
||||
|
||||
// Check whether the upload is ended
|
||||
if (self.progressChartView.progress == 1.0)
|
||||
{
|
||||
self.progressView.hidden = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.progressView.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(void)stopAnimating
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXKMediaUploadProgressNotification object:nil];
|
||||
[self.activityIndicator stopAnimating];
|
||||
}
|
||||
|
||||
- (void)onUploadProgress:(NSNotification *)notif
|
||||
{
|
||||
// sanity check
|
||||
if ([notif.object isKindOfClass:[NSString class]])
|
||||
{
|
||||
NSString *uploadId = notif.object;
|
||||
if ([uploadId isEqualToString:self.bubbleData.uploadId])
|
||||
{
|
||||
[self.activityIndicator stopAnimating];
|
||||
[self updateProgressUI:notif.userInfo];
|
||||
|
||||
// the upload is ended
|
||||
if (self.progressChartView.progress == 1.0)
|
||||
{
|
||||
self.progressView.hidden = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - User actions
|
||||
|
||||
- (IBAction)onResendToggle:(id)sender
|
||||
{
|
||||
if ([sender isKindOfClass:[UIButton class]] && self.delegate)
|
||||
{
|
||||
MXEvent *selectedEvent = nil;
|
||||
if (self.bubbleData.bubbleComponents.count == 1)
|
||||
{
|
||||
MXKRoomBubbleComponent *component = [self.bubbleData.bubbleComponents firstObject];
|
||||
selectedEvent = component.event;
|
||||
}
|
||||
else if (self.bubbleData.bubbleComponents.count)
|
||||
{
|
||||
// Here the selected view is a textView (attachment has no more than one component)
|
||||
|
||||
// Look for the selected component
|
||||
UIButton *unsentButton = (UIButton *)sender;
|
||||
for (MXKRoomBubbleComponent *component in self.bubbleData.bubbleComponents)
|
||||
{
|
||||
if (unsentButton.frame.origin.y == component.position.y)
|
||||
{
|
||||
selectedEvent = component.event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedEvent)
|
||||
{
|
||||
[self.delegate cell:self didRecognizeAction:kMXKRoomBubbleCellUnsentButtonPressed userInfo:@{kMXKRoomBubbleCellEventKey:selectedEvent}];
|
||||
}
|
||||
// for (MXKRoomBubbleComponent *component in self.bubbleData.bubbleComponents)
|
||||
// {
|
||||
// if (component.event.mxkState == MXKEventStateSendingFailed)
|
||||
// {
|
||||
// UIButton *unsentButton = [[UIButton alloc] initWithFrame:CGRectMake(0, component.position.y, 58 , 20)];
|
||||
//
|
||||
// [unsentButton setTitle:[NSBundle mxk_localizedStringForKey:@"unsent"] forState:UIControlStateNormal];
|
||||
// [unsentButton setTitle:[NSBundle mxk_localizedStringForKey:@"unsent"] forState:UIControlStateSelected];
|
||||
// [unsentButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
|
||||
// [unsentButton setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
|
||||
//
|
||||
// unsentButton.backgroundColor = [UIColor whiteColor];
|
||||
// unsentButton.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
//
|
||||
// [unsentButton addTarget:self action:@selector(onResendToggle:) forControlEvents:UIControlEventTouchUpInside];
|
||||
//
|
||||
// [self.dateTimeLabelContainer addSubview:unsentButton];
|
||||
// self.dateTimeLabelContainer.hidden = NO;
|
||||
// self.dateTimeLabelContainer.userInteractionEnabled = YES;
|
||||
//
|
||||
// // ensure that dateTimeLabelContainer is at front to catch the tap event
|
||||
// [self.dateTimeLabelContainer.superview bringSubviewToFront:self.dateTimeLabelContainer];
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -44,25 +45,6 @@
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Mqf-7a-bsm">
|
||||
<rect key="frame" x="443" y="24" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LVJ-Av-zVs" userLabel="showHideDateTime">
|
||||
<rect key="frame" x="0.0" y="0.0" width="69" height="49"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="69" id="ghQ-Qb-BBg"/>
|
||||
</constraints>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="showHideDateTime:" destination="pad-g3-2YJ" eventType="touchUpInside" id="Ztw-z5-zlU"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a51-cR-7FE" userLabel="DateTimeLabelContainer">
|
||||
<rect key="frame" x="8" y="10" width="61" height="39"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="61" id="fDy-iL-hrD"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="apW-hM-veR" userLabel="ProgressView">
|
||||
<rect key="frame" x="18" y="-1" width="100" height="70"/>
|
||||
<subviews>
|
||||
@@ -100,20 +82,14 @@
|
||||
<constraint firstAttribute="bottom" secondItem="tgO-Rv-C7R" secondAttribute="bottom" id="7C3-Tl-mMq"/>
|
||||
<constraint firstItem="tgO-Rv-C7R" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="10" id="8Sy-eu-tYs"/>
|
||||
<constraint firstItem="ezT-Dl-ESR" firstAttribute="leading" secondItem="SIW-l4-PfI" secondAttribute="trailing" constant="3" id="9z3-D2-2SS"/>
|
||||
<constraint firstItem="a51-cR-7FE" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="E3x-h8-GPF"/>
|
||||
<constraint firstItem="LVJ-Av-zVs" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" id="Hve-E3-z5N"/>
|
||||
<constraint firstAttribute="bottom" secondItem="LVJ-Av-zVs" secondAttribute="bottom" id="IKr-Dc-HKz"/>
|
||||
<constraint firstItem="apW-hM-veR" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="18" id="LFn-vp-m0v"/>
|
||||
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="18" id="QDm-tP-KWa"/>
|
||||
<constraint firstItem="ezT-Dl-ESR" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="5" id="aHl-KA-68x"/>
|
||||
<constraint firstAttribute="bottom" secondItem="SIW-l4-PfI" secondAttribute="bottom" id="fMN-Th-SOT"/>
|
||||
<constraint firstItem="a51-cR-7FE" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="10" id="fQv-07-Pgx"/>
|
||||
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="ZC1-hT-7fs" secondAttribute="centerY" id="ffI-vh-SW3"/>
|
||||
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="69" id="hwr-aa-TB4"/>
|
||||
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="hwr-aa-TB4"/>
|
||||
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="ZC1-hT-7fs" secondAttribute="centerX" id="jah-TA-P0P"/>
|
||||
<constraint firstItem="LVJ-Av-zVs" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="pYO-hi-P72"/>
|
||||
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="Mqf-7a-bsm" secondAttribute="centerY" id="sKJ-ny-LjM"/>
|
||||
<constraint firstAttribute="bottom" secondItem="a51-cR-7FE" secondAttribute="bottom" id="viZ-Sx-3RW"/>
|
||||
<constraint firstItem="apW-hM-veR" firstAttribute="centerY" secondItem="SIW-l4-PfI" secondAttribute="centerY" id="wmh-x1-U32"/>
|
||||
<constraint firstAttribute="trailing" secondItem="tgO-Rv-C7R" secondAttribute="trailing" constant="51" id="xYz-lp-c7K"/>
|
||||
</constraints>
|
||||
@@ -124,8 +100,6 @@
|
||||
<outlet property="attachViewTopConstraint" destination="QDm-tP-KWa" id="Ku6-FC-jqo"/>
|
||||
<outlet property="attachViewWidthConstraint" destination="iGr-e7-bde" id="uD4-aU-1Ru"/>
|
||||
<outlet property="attachmentView" destination="SIW-l4-PfI" id="L4H-ub-pPI"/>
|
||||
<outlet property="dateTimeLabelContainer" destination="a51-cR-7FE" id="wrR-cU-DVm"/>
|
||||
<outlet property="dateTimeLabelContainerTopConstraint" destination="fQv-07-Pgx" id="82c-KH-Wop"/>
|
||||
<outlet property="messageTextView" destination="tgO-Rv-C7R" id="LZ5-hQ-AbQ"/>
|
||||
<outlet property="msgTextViewLeadingConstraint" destination="hwr-aa-TB4" id="c9j-8p-cpx"/>
|
||||
<outlet property="msgTextViewTopConstraint" destination="8Sy-eu-tYs" id="7yx-oJ-KBP"/>
|
||||
|
||||
Reference in New Issue
Block a user