Room details - change messages layout: successive text messages from the same sender are concatenated in only one textView.

This commit is contained in:
giomfo 2014-11-27 10:50:09 +01:00
parent b0cf813e46
commit 7752f0ddd2
9 changed files with 963 additions and 511 deletions

View file

@ -23,6 +23,7 @@
F03EF5FB19F171EB00A0EE52 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5F519F171EB00A0EE52 /* SettingsViewController.m */; };
F03EF5FF19F1762000A0EE52 /* RoomMessageTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */; };
F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F03EF60119F19E7C00A0EE52 /* MediaManager.m */; };
F0465AFA1A251F85003639F9 /* RoomMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = F0465AF91A251F85003639F9 /* RoomMessage.m */; };
F05B955F19DEED8A008761B0 /* MatrixHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = F05B955E19DEED8A008761B0 /* MatrixHandler.m */; };
F07A80D819DD9DE700B621A1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A80D719DD9DE700B621A1 /* main.m */; };
F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A80DA19DD9DE700B621A1 /* AppDelegate.m */; };
@ -80,6 +81,8 @@
F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMessageTableCell.m; sourceTree = "<group>"; };
F03EF60019F19E7C00A0EE52 /* MediaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaManager.h; sourceTree = "<group>"; };
F03EF60119F19E7C00A0EE52 /* MediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaManager.m; sourceTree = "<group>"; };
F0465AF81A251F85003639F9 /* RoomMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMessage.h; sourceTree = "<group>"; };
F0465AF91A251F85003639F9 /* RoomMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMessage.m; sourceTree = "<group>"; };
F05B955D19DEED8A008761B0 /* MatrixHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatrixHandler.h; sourceTree = "<group>"; };
F05B955E19DEED8A008761B0 /* MatrixHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MatrixHandler.m; sourceTree = "<group>"; };
F07A80D219DD9DE700B621A1 /* matrixConsole.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = matrixConsole.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -195,6 +198,15 @@
path = View;
sourceTree = "<group>";
};
F0465AF71A251F85003639F9 /* Model */ = {
isa = PBXGroup;
children = (
F0465AF81A251F85003639F9 /* RoomMessage.h */,
F0465AF91A251F85003639F9 /* RoomMessage.m */,
);
path = Model;
sourceTree = "<group>";
};
F07A80C919DD9DE700B621A1 = {
isa = PBXGroup;
children = (
@ -218,6 +230,7 @@
F07A80D419DD9DE700B621A1 /* matrixConsole */ = {
isa = PBXGroup;
children = (
F0465AF71A251F85003639F9 /* Model */,
F03EF5FC19F1762000A0EE52 /* View */,
F03EF5E919F171EB00A0EE52 /* ViewController */,
F07A80D919DD9DE700B621A1 /* AppDelegate.h */,
@ -418,6 +431,7 @@
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */,
F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */,
F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */,
F0465AFA1A251F85003639F9 /* RoomMessage.m in Sources */,
F03C47111A02952800E445AB /* CustomAlert.m in Sources */,
F0E84D401A1F9AEC005F2E42 /* RecentsTableViewCell.m in Sources */,
F02D707619F1DC9E007B47D3 /* RoomMemberTableCell.m in Sources */,

View file

@ -52,19 +52,20 @@
</constraints>
</imageView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="J5R-Mh-3hV">
<rect key="frame" x="51" y="20" width="200" height="30"/>
<rect key="frame" x="51" y="10" width="200" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="rsq-bW-mGt"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="mvK-ez-meg" userLabel="Attachment View" customClass="CustomImageView">
<rect key="frame" x="59" y="28" width="184" height="14"/>
<rect key="frame" x="59" y="18" width="184" height="24"/>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="play.png" translatesAutoresizingMaskIntoConstraints="NO" id="vF4-rq-4Rn">
<rect key="frame" x="135" y="19" width="32" height="32"/>
<rect key="frame" x="135" y="14" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="JvT-k9-GoK"/>
<constraint firstAttribute="width" constant="32" id="sTU-9e-QiN"/>
@ -119,7 +120,7 @@
<constraint firstAttribute="trailing" secondItem="Ttt-0P-dQW" secondAttribute="trailing" id="mJg-Df-CWQ"/>
<constraint firstItem="uhu-R0-9NH" firstAttribute="top" secondItem="iJp-sA-hG6" secondAttribute="top" constant="5" id="mer-CT-cEg"/>
<constraint firstItem="J5R-Mh-3hV" firstAttribute="leading" secondItem="uhu-R0-9NH" secondAttribute="trailing" constant="3" id="qkW-ys-ckn"/>
<constraint firstItem="J5R-Mh-3hV" firstAttribute="top" secondItem="iJp-sA-hG6" secondAttribute="top" constant="20" id="rJt-w3-D8g"/>
<constraint firstItem="J5R-Mh-3hV" firstAttribute="top" secondItem="iJp-sA-hG6" secondAttribute="top" constant="10" id="rJt-w3-D8g"/>
<constraint firstAttribute="trailing" secondItem="yRH-kt-si3" secondAttribute="trailing" constant="8" id="vh8-ds-cqA"/>
<constraint firstItem="egJ-aY-QVW" firstAttribute="leading" secondItem="uhu-R0-9NH" secondAttribute="trailing" constant="3" id="wym-In-Raa"/>
</constraints>
@ -147,26 +148,27 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="7qn-gi-w7s">
<rect key="frame" x="349" y="20" width="200" height="30"/>
<rect key="frame" x="349" y="10" width="200" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="a6g-WS-jjN"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QZT-V8-yqJ" userLabel="Attachment View" customClass="CustomImageView">
<rect key="frame" x="357" y="28" width="184" height="14"/>
<rect key="frame" x="357" y="18" width="184" height="24"/>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="play.png" translatesAutoresizingMaskIntoConstraints="NO" id="0Bl-Sv-Q2H">
<rect key="frame" x="433" y="19" width="32" height="32"/>
<rect key="frame" x="433" y="14" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="VbS-GC-vtz"/>
<constraint firstAttribute="width" constant="32" id="faJ-bg-xPV"/>
</constraints>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Pq8-lB-cZM">
<rect key="frame" x="439" y="25" width="20" height="20"/>
<rect key="frame" x="439" y="20" width="20" height="20"/>
</activityIndicatorView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="default-profile.png" translatesAutoresizingMaskIntoConstraints="NO" id="mks-jh-AiZ" customClass="CustomImageView">
<rect key="frame" x="552" y="5" width="40" height="40"/>
@ -223,7 +225,7 @@
<constraint firstItem="QZT-V8-yqJ" firstAttribute="centerY" secondItem="0Bl-Sv-Q2H" secondAttribute="centerY" id="aUE-Bv-XF2"/>
<constraint firstItem="mks-jh-AiZ" firstAttribute="leading" secondItem="7qn-gi-w7s" secondAttribute="trailing" constant="3" id="cCA-xk-XBe"/>
<constraint firstItem="QZT-V8-yqJ" firstAttribute="centerY" secondItem="Pq8-lB-cZM" secondAttribute="centerY" id="ej0-OC-3hJ"/>
<constraint firstItem="7qn-gi-w7s" firstAttribute="top" secondItem="5tf-BC-9Ed" secondAttribute="top" constant="20" id="owD-KZ-snG"/>
<constraint firstItem="7qn-gi-w7s" firstAttribute="top" secondItem="5tf-BC-9Ed" secondAttribute="top" constant="10" id="owD-KZ-snG"/>
<constraint firstItem="QZT-V8-yqJ" firstAttribute="bottom" secondItem="7qn-gi-w7s" secondAttribute="bottom" constant="-8" id="q4h-EM-X4Z"/>
<constraint firstItem="7qn-gi-w7s" firstAttribute="leading" secondItem="2lD-F0-Haf" secondAttribute="trailing" id="q5r-bz-qP7"/>
<constraint firstItem="QZT-V8-yqJ" firstAttribute="trailing" secondItem="7qn-gi-w7s" secondAttribute="trailing" constant="-8" id="tgM-eJ-BEk"/>

View file

@ -45,8 +45,8 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
- (void)enableEventsNotifications:(BOOL)isEnabled;
- (BOOL)isAttachment:(MXEvent*)message;
- (BOOL)isNotification:(MXEvent*)message;
- (NSString*)displayTextFor:(MXEvent*)message inSubtitleMode:(BOOL)isSubtitle;
- (BOOL)isSupportedAttachment:(MXEvent*)event;
- (BOOL)isEmote:(MXEvent*)event;
- (NSString*)displayTextForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState inSubtitleMode:(BOOL)isSubtitle;
@end

View file

@ -236,13 +236,14 @@ static MatrixHandler *sharedHandler = nil;
eventsListener = [self.mxSession listenToEventsOfTypes:self.mxSession.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
// Consider only live event (Ignore presence event)
if (direction == MXEventDirectionForwards && (event.eventType != MXEventTypePresence)) {
MXRoomState* roomState = (MXRoomState*)customObject;
// If we are running on background, show a local notif
if (UIApplicationStateBackground == [UIApplication sharedApplication].applicationState)
{
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
localNotification.hasAction = YES;
[localNotification setAlertBody:[self displayTextFor:event inSubtitleMode:YES]];
[localNotification setAlertBody:[self displayTextForEvent:event withRoomState:roomState inSubtitleMode:YES]];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
} else if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId] == NO) {
// The concerned room is not presently visible, we display a notification by removing existing one (if any)
@ -250,8 +251,8 @@ static MatrixHandler *sharedHandler = nil;
[self.mxNotification dismiss:NO];
}
self.mxNotification = [[CustomAlert alloc] initWithTitle:[self.mxSession room:event.roomId].state.displayname
message:[self displayTextFor:event inSubtitleMode:YES]
self.mxNotification = [[CustomAlert alloc] initWithTitle:roomState.displayname
message:[self displayTextForEvent:event withRoomState:roomState inSubtitleMode:YES]
style:CustomAlertStyleAlert];
self.mxNotification.cancelButtonIndex = [self.mxNotification addActionWithTitle:@"OK"
style:CustomAlertActionStyleDefault
@ -383,68 +384,80 @@ static MatrixHandler *sharedHandler = nil;
[[NSUserDefaults standardUserDefaults] synchronize];
}
#pragma mark - messages handler
#pragma mark - events handler
- (BOOL)isAttachment:(MXEvent*)message {
if (message.eventType == MXEventTypeRoomMessage) {
NSString *msgtype = message.content[@"msgtype"];
if ([msgtype isEqualToString:kMXMessageTypeImage]
|| [msgtype isEqualToString:kMXMessageTypeAudio]
|| [msgtype isEqualToString:kMXMessageTypeVideo]
|| [msgtype isEqualToString:kMXMessageTypeLocation]) {
// Checks whether the event is related to an attachment and if it is supported
- (BOOL)isSupportedAttachment:(MXEvent*)event {
BOOL isSupportedAttachment = NO;
if (event.eventType == MXEventTypeRoomMessage) {
NSString *msgtype = event.content[@"msgtype"];
NSString *requiredField;
if ([msgtype isEqualToString:kMXMessageTypeImage]) {
requiredField = event.content[@"url"];
if (requiredField.length) {
isSupportedAttachment = YES;
}
} else if ([msgtype isEqualToString:kMXMessageTypeAudio]) {
// Not supported yet
} else if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
requiredField = event.content[@"url"];
if (requiredField) {
isSupportedAttachment = YES;
}
} else if ([msgtype isEqualToString:kMXMessageTypeLocation]) {
// Not supported yet
}
}
return isSupportedAttachment;
}
// Check whether the event is emote event
- (BOOL)isEmote:(MXEvent*)event {
if (event.eventType == MXEventTypeRoomMessage) {
NSString *msgtype = event.content[@"msgtype"];
if ([msgtype isEqualToString:kMXMessageTypeEmote]) {
return YES;
}
}
return NO;
}
- (BOOL)isNotification:(MXEvent*)message {
// We consider as notification mxEvent which is not a text message or an attachment
if (message.eventType == MXEventTypeRoomMessage) {
NSString *msgtype = message.content[@"msgtype"];
if ([msgtype isEqualToString:kMXMessageTypeEmote]) {
return YES;
}
return NO;
}
return YES;
}
- (NSString*)displayTextFor:(MXEvent*)message inSubtitleMode:(BOOL)isSubtitle {
- (NSString*)displayTextForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState inSubtitleMode:(BOOL)isSubtitle {
NSString *displayText = nil;
// Retrieve roomData related to the message
MXRoom *room = [self.mxSession room:message.roomId];
// Prepare display name for concerned users
NSString *memberDisplayName = [room.state memberName:message.userId];
NSString *memberDisplayName = [roomState memberName:event.userId];
NSString *targetDisplayName = nil;
if (message.stateKey) {
targetDisplayName = [room.state memberName:message.stateKey];
if (event.stateKey) {
targetDisplayName = [roomState memberName:event.stateKey];
}
switch (message.eventType) {
switch (event.eventType) {
case MXEventTypeRoomName: {
displayText = [NSString stringWithFormat:@"%@ changed the room name to: %@", memberDisplayName, message.content[@"name"]];
displayText = [NSString stringWithFormat:@"%@ changed the room name to: %@", memberDisplayName, event.content[@"name"]];
break;
}
case MXEventTypeRoomTopic: {
displayText = [NSString stringWithFormat:@"%@ changed the topic to: %@", memberDisplayName, message.content[@"topic"]];
displayText = [NSString stringWithFormat:@"%@ changed the topic to: %@", memberDisplayName, event.content[@"topic"]];
break;
}
case MXEventTypeRoomMember: {
// Presently only change on membership, display name and avatar are supported
// Retrieve membership
NSString* membership = message.content[@"membership"];
NSString* membership = event.content[@"membership"];
NSString *prevMembership = nil;
if (message.prevContent) {
prevMembership = message.prevContent[@"membership"];
if (event.prevContent) {
prevMembership = event.prevContent[@"membership"];
}
// Check whether the membership is unchanged
if (prevMembership && membership && [membership isEqualToString:prevMembership]) {
// Check whether the display name has been changed
NSString *displayname = message.content[@"displayname"];
NSString *prevDisplayname = message.prevContent[@"displayname"];
NSString *displayname = event.content[@"displayname"];
NSString *prevDisplayname = event.prevContent[@"displayname"];
if (!displayname.length) {
displayname = nil;
}
@ -452,12 +465,12 @@ static MatrixHandler *sharedHandler = nil;
prevDisplayname = nil;
}
if ((displayname || prevDisplayname) && ([displayname isEqualToString:prevDisplayname] == NO)) {
displayText = [NSString stringWithFormat:@"%@ changed their display name from %@ to %@", message.userId, prevDisplayname, displayname];
displayText = [NSString stringWithFormat:@"%@ changed their display name from %@ to %@", event.userId, prevDisplayname, displayname];
}
// Check whether the avatar has been changed
NSString *avatar = message.content[@"avatar_url"];
NSString *prevAvatar = message.prevContent[@"avatar_url"];
NSString *avatar = event.content[@"avatar_url"];
NSString *prevAvatar = event.prevContent[@"avatar_url"];
if (!avatar.length) {
avatar = nil;
}
@ -478,13 +491,13 @@ static MatrixHandler *sharedHandler = nil;
} else if ([membership isEqualToString:@"join"]) {
displayText = [NSString stringWithFormat:@"%@ joined", memberDisplayName];
} else if ([membership isEqualToString:@"leave"]) {
if ([message.userId isEqualToString:message.stateKey]) {
if ([event.userId isEqualToString:event.stateKey]) {
displayText = [NSString stringWithFormat:@"%@ left", memberDisplayName];
} else if (prevMembership) {
if ([prevMembership isEqualToString:@"join"] || [prevMembership isEqualToString:@"invite"]) {
displayText = [NSString stringWithFormat:@"%@ kicked %@", memberDisplayName, targetDisplayName];
if (message.content[@"reason"]) {
displayText = [NSString stringWithFormat:@"%@: %@", displayText, message.content[@"reason"]];
if (event.content[@"reason"]) {
displayText = [NSString stringWithFormat:@"%@: %@", displayText, event.content[@"reason"]];
}
} else if ([prevMembership isEqualToString:@"ban"]) {
displayText = [NSString stringWithFormat:@"%@ unbanned %@", memberDisplayName, targetDisplayName];
@ -492,22 +505,22 @@ static MatrixHandler *sharedHandler = nil;
}
} else if ([membership isEqualToString:@"ban"]) {
displayText = [NSString stringWithFormat:@"%@ banned %@", memberDisplayName, targetDisplayName];
if (message.content[@"reason"]) {
displayText = [NSString stringWithFormat:@"%@: %@", displayText, message.content[@"reason"]];
if (event.content[@"reason"]) {
displayText = [NSString stringWithFormat:@"%@: %@", displayText, event.content[@"reason"]];
}
}
}
break;
}
case MXEventTypeRoomCreate: {
NSString *creatorId = message.content[@"creator"];
NSString *creatorId = event.content[@"creator"];
if (creatorId) {
displayText = [NSString stringWithFormat:@"%@ created the room", [room.state memberName:creatorId]];
displayText = [NSString stringWithFormat:@"%@ created the room", [roomState memberName:creatorId]];
}
break;
}
case MXEventTypeRoomJoinRules: {
NSString *joinRule = message.content[@"join_rule"];
NSString *joinRule = event.content[@"join_rule"];
if (joinRule) {
displayText = [NSString stringWithFormat:@"The join rule is: %@", joinRule];
}
@ -515,47 +528,47 @@ static MatrixHandler *sharedHandler = nil;
}
case MXEventTypeRoomPowerLevels: {
displayText = @"The power level of room members are:";
NSDictionary *users = message.content[@"users"];
NSDictionary *users = event.content[@"users"];
for (NSString *key in users.allKeys) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, key, [users objectForKey:key]];
}
if (message.content[@"users_default"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"default", message.content[@"users_default"]];
if (event.content[@"users_default"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"default", event.content[@"users_default"]];
}
displayText = [NSString stringWithFormat:@"%@\r\nThe minimum power levels that a user must have before acting are:", displayText];
if (message.content[@"ban"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 ban: %@", displayText, message.content[@"ban"]];
if (event.content[@"ban"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 ban: %@", displayText, event.content[@"ban"]];
}
if (message.content[@"kick"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 kick: %@", displayText, message.content[@"kick"]];
if (event.content[@"kick"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 kick: %@", displayText, event.content[@"kick"]];
}
if (message.content[@"redact"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 redact: %@", displayText, message.content[@"redact"]];
if (event.content[@"redact"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 redact: %@", displayText, event.content[@"redact"]];
}
displayText = [NSString stringWithFormat:@"%@\r\nThe minimum power levels related to events are:", displayText];
NSDictionary *events = message.content[@"events"];
NSDictionary *events = event.content[@"events"];
for (NSString *key in events.allKeys) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, key, [events objectForKey:key]];
}
if (message.content[@"events_default"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"events_default", message.content[@"events_default"]];
if (event.content[@"events_default"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"events_default", event.content[@"events_default"]];
}
if (message.content[@"state_default"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"state_default", message.content[@"state_default"]];
if (event.content[@"state_default"]) {
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 %@: %@", displayText, @"state_default", event.content[@"state_default"]];
}
break;
}
// case MXEventTypeRoomAddStateLevel: {
// NSString *minLevel = message.content[@"level"];
// NSString *minLevel = event.content[@"level"];
// if (minLevel) {
// displayText = [NSString stringWithFormat:@"The minimum power level a user needs to add state is: %@", minLevel];
// }
// break;
// }
// case MXEventTypeRoomSendEventLevel: {
// NSString *minLevel = message.content[@"level"];
// NSString *minLevel = event.content[@"level"];
// if (minLevel) {
// displayText = [NSString stringWithFormat:@"The minimum power level a user needs to send an event is: %@", minLevel];
// }
@ -563,32 +576,67 @@ static MatrixHandler *sharedHandler = nil;
// }
// case MXEventTypeRoomOpsLevel: {
// displayText = @"The minimum power levels that a user must have before acting are:";
// for (NSString *key in message.content.allKeys) {
// displayText = [NSString stringWithFormat:@"%@\r\n%@:%@", displayText, key, [message.content objectForKey:key]];
// for (NSString *key in event.content.allKeys) {
// displayText = [NSString stringWithFormat:@"%@\r\n%@:%@", displayText, key, [event.content objectForKey:key]];
// }
// break;
// }
case MXEventTypeRoomAliases: {
NSArray *aliases = message.content[@"aliases"];
NSArray *aliases = event.content[@"aliases"];
if (aliases) {
displayText = [NSString stringWithFormat:@"The room aliases are: %@", aliases];
}
break;
}
case MXEventTypeRoomMessage: {
NSString *msgtype = message.content[@"msgtype"];
if ([msgtype isEqualToString:kMXMessageTypeText]) {
displayText = message.content[@"body"];
} else if ([msgtype isEqualToString:kMXMessageTypeEmote]) {
displayText = [NSString stringWithFormat:@"* %@ %@", memberDisplayName, message.content[@"body"]];
NSString *msgtype = event.content[@"msgtype"];
displayText = [event.content[@"body"] isKindOfClass:[NSString class]] ? event.content[@"body"] : nil;
if ([msgtype isEqualToString:kMXMessageTypeEmote]) {
displayText = [NSString stringWithFormat:@"* %@ %@", memberDisplayName, displayText];
} else if ([msgtype isEqualToString:kMXMessageTypeImage]) {
displayText = @"image attachment";
displayText = displayText? displayText : @"image attachment";
// Check attachment validity
if (![self isSupportedAttachment:event]) {
NSLog(@"ERROR: Unsupported attachment %@", event.description);
// Check whether unsupported/unexpected messages should be exposed
if (isSubtitle || [AppSettings sharedSettings].hideUnsupportedMessages) {
displayText = @"invalid image attachment";
} else {
// Display event content as unsupported message
displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, event.description];
}
}
} else if ([msgtype isEqualToString:kMXMessageTypeAudio]) {
displayText = @"audio attachment";
displayText = displayText? displayText : @"audio attachment";
if (![self isSupportedAttachment:event]) {
NSLog(@"ERROR: Unsupported attachment %@", event.description);
if (isSubtitle || [AppSettings sharedSettings].hideUnsupportedMessages) {
displayText = @"invalid audio attachment";
} else {
displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, event.description];
}
}
} else if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
displayText = @"video attachment";
displayText = displayText? displayText : @"video attachment";
if (![self isSupportedAttachment:event]) {
NSLog(@"ERROR: Unsupported attachment %@", event.description);
if (isSubtitle || [AppSettings sharedSettings].hideUnsupportedMessages) {
displayText = @"invalid video attachment";
} else {
displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, event.description];
}
}
} else if ([msgtype isEqualToString:kMXMessageTypeLocation]) {
displayText = @"location attachment";
displayText = displayText? displayText : @"location attachment";
if (![self isSupportedAttachment:event]) {
NSLog(@"ERROR: Unsupported attachment %@", event.description);
if (isSubtitle || [AppSettings sharedSettings].hideUnsupportedMessages) {
displayText = @"invalid location attachment";
} else {
displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, event.description];
}
}
}
// Check whether the sender name has to be added
@ -599,8 +647,8 @@ static MatrixHandler *sharedHandler = nil;
break;
}
case MXEventTypeRoomMessageFeedback: {
NSString *type = message.content[@"type"];
NSString *eventId = message.content[@"target_event_id"];
NSString *type = event.content[@"type"];
NSString *eventId = event.content[@"target_event_id"];
if (type && eventId) {
displayText = [NSString stringWithFormat:@"Feedback event (id: %@): %@", eventId, type];
}
@ -612,13 +660,11 @@ static MatrixHandler *sharedHandler = nil;
break;
}
if (displayText == nil) {
NSLog(@"ERROR: Unsupported message %@)", message.description);
if (isSubtitle || [AppSettings sharedSettings].hideUnsupportedMessages) {
displayText = @"";
} else {
// Return event content as unsupported message
displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, message.description];
if (!displayText) {
NSLog(@"ERROR: Unsupported event %@)", event.description);
if (!isSubtitle && ![AppSettings sharedSettings].hideUnsupportedMessages) {
// Return event content as unsupported event
displayText = [NSString stringWithFormat:@"%@%@", kMatrixHandlerUnsupportedMessagePrefix, event.description];
}
}

View file

@ -0,0 +1,69 @@
/*
Copyright 2014 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 <MatrixSDK/MatrixSDK.h>
#define ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH 200
#define ROOM_MESSAGE_CELL_IMAGE_MARGIN 8
extern NSString *const kLocalEchoEventIdPrefix;
extern NSString *const kFailedEventId;
typedef enum : NSUInteger {
RoomMessageTypeText,
RoomMessageTypeImage,
RoomMessageTypeAudio,
RoomMessageTypeVideo,
RoomMessageTypeLocation
} RoomMessageType;
// Converts matrix events in room messages
@interface RoomMessage : NSObject
@property (nonatomic) RoomMessageType messageType;
@property (nonatomic) NSString *senderId;
@property (nonatomic) NSString *senderName;
@property (nonatomic) NSString *senderAvatarUrl;
// The message content size depends on its type:
// - RoomMessageTypeText: returns suitable content size of a text view to display the whole text message
// - Others: returns suitable content size for an image view in order to display attachment thumbnail or icon.
@property (nonatomic) CGSize contentSize;
// The body of the message, or kind of content description in case of attachment (e.g. "image attachment")
@property (nonatomic) NSAttributedString *attributedTextMessage;
// True if the sender name appears at the beginning of the message text (available only for messageType is RoomMessageTypeText)
@property (nonatomic) BOOL startsWithSenderName;
// Attachment info (nil when messageType is RoomMessageTypeText)
@property (nonatomic) BOOL isUploadInProgress;
@property (nonatomic) NSString *attachmentURL;
@property (nonatomic) NSDictionary *attachmentInfo;
@property (nonatomic) NSString *thumbnailURL;
@property (nonatomic) NSDictionary *thumbnailInfo;
- (id)initWithEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState;
// Concatenates successive text messages from the same user
// Return false if the provided event could not be added (for example the sender id is not the same, the sender name has been changed, or the messageType is not RoomMessageTypeText)
- (BOOL)addEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
// Remove the item defined with this event id
// Return false if the event id is not found
- (BOOL)removeEvent:(NSString*)eventId;
// Return true if the event id is one of the message items
- (BOOL)containsEventId:(NSString*)eventId;
@end

View file

@ -0,0 +1,397 @@
/*
Copyright 2014 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 "RoomMessage.h"
#import "MatrixHandler.h"
#import "AppSettings.h"
NSString *const kLocalEchoEventIdPrefix = @"localEcho-";
NSString *const kFailedEventId = @"failedEventId";
static NSDateFormatter *dateFormatter = nil;
static NSAttributedString *messageItemsSeparator = nil;
typedef enum : NSUInteger {
RoomMessageItemDisplayModeDefault,
RoomMessageItemDisplayModeHighlighted,
RoomMessageItemDisplayModeLocalEcho,
RoomMessageItemDisplayModeFailure,
RoomMessageItemDisplayModeError
} RoomMessageItemDisplayMode;
@interface RoomMessageItem : NSObject
@property (nonatomic) NSString *textMessage;
@property (nonatomic) NSString *eventId;
@property (nonatomic) NSDate *date;
@property (nonatomic) RoomMessageItemDisplayMode displayMode;
@property (nonatomic) NSUInteger height;
// True if text message starts with the sender name (see membership events, emote ...)
@property (nonatomic) BOOL startsWithSenderName;
- (id)initWithTextMessage:(NSString*)textMessage andEvent:(MXEvent*)event;
@end
#pragma mark -
@interface RoomMessage() {
// Array of RoomMessageItem
NSMutableArray *messageItems;
}
+ (NSDateFormatter *)dateFormatter;
+ (NSAttributedString *)messageItemsSeparator;
+ (NSDictionary*)stringAttributesForDisplayMode:(RoomMessageItemDisplayMode)displayMode;
@end
@implementation RoomMessage
- (id)initWithEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState {
if (self = [super init]) {
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
_senderId = event.userId;
_senderName = [roomState memberName:event.userId];
_senderAvatarUrl = [roomState memberWithUserId:event.userId].avatarUrl;
_contentSize = CGSizeZero;
// Build text message from event
NSString* textMessage = [mxHandler displayTextForEvent:event withRoomState:roomState inSubtitleMode:NO];
// Set the message type (use Text by default), and check attachment if any
_messageType = RoomMessageTypeText;
if ([mxHandler isSupportedAttachment:event]) {
// Note: event.eventType is equal here to MXEventTypeRoomMessage
NSString *msgtype = event.content[@"msgtype"];
if ([msgtype isEqualToString:kMXMessageTypeImage]) {
_messageType = RoomMessageTypeImage;
_attachmentURL = event.content[@"url"];
_attachmentInfo = event.content[@"info"];
_thumbnailURL = event.content[@"thumbnail_url"];
_thumbnailInfo = event.content[@"thumbnail_info"];
} else if ([msgtype isEqualToString:kMXMessageTypeAudio]) {
// Not supported yet
//_messageType = RoomMessageTypeAudio;
} else if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
_messageType = RoomMessageTypeVideo;
_attachmentURL = event.content[@"url"];
_attachmentInfo = event.content[@"info"];
if (_attachmentInfo) {
_thumbnailURL = _attachmentInfo[@"thumbnail_url"];
_thumbnailInfo = _attachmentInfo[@"thumbnail_info"];
}
} else if ([msgtype isEqualToString:kMXMessageTypeLocation]) {
// Not supported yet
// _messageType = RoomMessageTypeLocation;
}
}
if (textMessage) {
// Create first message item
RoomMessageItem *msgItem = [[RoomMessageItem alloc] initWithTextMessage:textMessage andEvent:event];
msgItem.startsWithSenderName = ([textMessage hasPrefix:_senderName] || [mxHandler isEmote:event]);
messageItems = [NSMutableArray array];
[messageItems addObject:msgItem];
msgItem.height = self.contentSize.height;
}
else {
// Ignore this event
self = nil;
}
}
return self;
}
- (void)dealloc {
messageItems = nil;
}
- (BOOL)addEvent:(MXEvent *)event withRoomState:(MXRoomState*)roomState {
// We group together text messages from the same user
if ([event.userId isEqualToString:_senderId] && (_messageType == RoomMessageTypeText)) {
// Attachments (image, video ...) cannot be added here
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
if ([mxHandler isSupportedAttachment:event]) {
return NO;
}
// Check sender information
if ((_senderName || [roomState memberName:event.userId]) &&
([_senderName isEqualToString:[roomState memberName:event.userId]] == NO)) {
return NO;
}
if ((_senderAvatarUrl || [roomState memberWithUserId:event.userId].avatarUrl) &&
([_senderAvatarUrl isEqualToString:[roomState memberWithUserId:event.userId].avatarUrl] == NO)) {
return NO;
}
NSString* textMessage = [mxHandler displayTextForEvent:event withRoomState:roomState inSubtitleMode:NO];
if (textMessage) {
// Create new message item
RoomMessageItem *addedItem = [[RoomMessageItem alloc] initWithTextMessage:textMessage andEvent:event];
addedItem.startsWithSenderName = ([textMessage hasPrefix:_senderName] || [mxHandler isEmote:event]);
// Insert the new item according to its date
NSUInteger index = messageItems.count;
NSMutableArray *savedMessageItems = [NSMutableArray arrayWithCapacity:index];
RoomMessageItem* msgItem;
if (addedItem.date) {
while (index--) {
msgItem = [messageItems lastObject];
if (!msgItem.date || [msgItem.date compare:addedItem.date] == NSOrderedDescending) {
[savedMessageItems insertObject:msgItem atIndex:0];
[messageItems removeLastObject];
} else {
break;
}
}
}
// Force content size refresh
_attributedTextMessage = nil;
_contentSize = CGSizeZero;
CGFloat previousHeight = self.contentSize.height;
[messageItems addObject:addedItem];
// Force content size refresh after adding new item in order to compute its height
_attributedTextMessage = nil;
_contentSize = CGSizeZero;
addedItem.height = self.contentSize.height - previousHeight;
// Re-add existing message items (later in time than the new one)
for (msgItem in savedMessageItems) {
previousHeight = self.contentSize.height;
[messageItems addObject:msgItem];
// Force content size refresh after adding new item in order to compute its height
_attributedTextMessage = nil;
_contentSize = CGSizeZero;
msgItem.height = self.contentSize.height - previousHeight;
}
}
// else the event is ignored, we consider it as handled
return YES;
}
return NO;
}
- (BOOL)removeEvent:(NSString *)eventId {
if (_messageType == RoomMessageTypeText) {
NSUInteger index = messageItems.count;
NSMutableArray *savedMessageItems = [NSMutableArray arrayWithCapacity:index];
RoomMessageItem* msgItem;
while (index--) {
msgItem = [messageItems lastObject];
if ([msgItem.eventId isEqualToString:eventId] == NO) {
[savedMessageItems insertObject:msgItem atIndex:0];
[messageItems removeLastObject];
} else {
[messageItems removeLastObject];
_attributedTextMessage = nil;
_contentSize = CGSizeZero;
for (msgItem in savedMessageItems) {
// Re-add message items
CGFloat previousHeight = self.contentSize.height;
[messageItems addObject:msgItem];
// Force content size refresh after adding new item in order to compute its height
_attributedTextMessage = nil;
_contentSize = CGSizeZero;
msgItem.height = self.contentSize.height - previousHeight;
}
return YES;
}
}
// here the provided eventId has not been found, restore message Items and return
messageItems = savedMessageItems;
}
return NO;
}
- (BOOL)containsEventId:(NSString *)eventId {
for (RoomMessageItem* msgItem in messageItems) {
if ([msgItem.eventId isEqualToString:eventId]) {
return YES;
}
}
return NO;
}
#pragma mark -
- (CGSize)contentSize {
if (CGSizeEqualToSize(_contentSize, CGSizeZero)) {
if (_messageType == RoomMessageTypeText) {
if (self.attributedTextMessage.length) {
// Use a TextView template to compute cell height
UITextView *dummyTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH, MAXFLOAT)];
dummyTextView.attributedText = self.attributedTextMessage;
_contentSize = [dummyTextView sizeThatFits:dummyTextView.frame.size];
}
} else if (_messageType == RoomMessageTypeImage || _messageType == RoomMessageTypeVideo) {
CGFloat width, height;
width = height = 40;
if (_thumbnailInfo) {
width = [_thumbnailInfo[@"w"] integerValue] + 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN;
height = [_thumbnailInfo[@"h"] integerValue] + 2 * ROOM_MESSAGE_CELL_IMAGE_MARGIN;
if (width > ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH || height > ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH) {
if (width > height) {
height = (height * ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH) / width;
height = floorf(height / 2) * 2;
width = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH;
} else {
width = (width * ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH) / height;
width = floorf(width / 2) * 2;
height = ROOM_MESSAGE_CELL_MAX_TEXTVIEW_WIDTH;
}
}
}
_contentSize = CGSizeMake(width, height);
} else {
_contentSize = CGSizeMake(40, 40);
}
}
return _contentSize;
}
- (NSAttributedString*)attributedTextMessage {
if (!_attributedTextMessage && messageItems.count) {
// Create attributed string
NSMutableAttributedString *mutableAttributedString = nil;
for (RoomMessageItem* msgItem in messageItems) {
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:msgItem.textMessage attributes:[RoomMessage stringAttributesForDisplayMode:msgItem.displayMode]];
if (!mutableAttributedString) {
mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
} else {
// Append attributed text
[mutableAttributedString appendAttributedString:[RoomMessage messageItemsSeparator]];
[mutableAttributedString appendAttributedString:attributedString];
}
}
_attributedTextMessage = mutableAttributedString;
}
return _attributedTextMessage;
}
- (BOOL)startsWithSenderName {
if (_messageType == RoomMessageTypeText) {
if (messageItems.count) {
RoomMessageItem *msgItem = [messageItems firstObject];
return msgItem.startsWithSenderName;
}
}
return NO;
}
- (BOOL)isUploadInProgress {
if (_messageType != RoomMessageTypeText) {
if (messageItems.count) {
RoomMessageItem *msgItem = [messageItems firstObject];
return (msgItem.displayMode == RoomMessageItemDisplayModeLocalEcho);
}
}
return NO;
}
#pragma mark -
+ (NSDateFormatter *)dateFormatter {
@synchronized(self) {
if(dateFormatter == nil) {
NSString *dateFormat = @"MMM dd HH:mm";
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
[dateFormatter setDateFormat:dateFormat];
}
}
return dateFormatter;
}
+ (NSAttributedString *)messageItemsSeparator {
@synchronized(self) {
if(messageItemsSeparator == nil) {
messageItemsSeparator = [[NSAttributedString alloc] initWithString:@"\r\n\r\n" attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
NSFontAttributeName: [UIFont systemFontOfSize:4]}];
}
}
return messageItemsSeparator;
}
+ (NSDictionary*)stringAttributesForDisplayMode:(RoomMessageItemDisplayMode)displayMode {
UIColor *textColor;
switch (displayMode) {
case RoomMessageItemDisplayModeDefault:
textColor = [UIColor blackColor];
break;
case RoomMessageItemDisplayModeHighlighted:
textColor = [UIColor blueColor];
break;
case RoomMessageItemDisplayModeLocalEcho:
textColor = [UIColor lightGrayColor];
break;
case RoomMessageItemDisplayModeFailure:
case RoomMessageItemDisplayModeError:
textColor = [UIColor redColor];
break;
default:
textColor = [UIColor blackColor];
break;
}
return @{
NSForegroundColorAttributeName : textColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]
};
}
@end
# pragma mark -
@implementation RoomMessageItem
- (id)initWithTextMessage:(NSString*)textMessage andEvent:(MXEvent*)event {
if (self = [super init]) {
_textMessage = textMessage;
_eventId = event.eventId;
_height = 0;
// Set date time text label
if (event.originServerTs != kMXUndefinedTimestamp) {
_date = [NSDate dateWithTimeIntervalSince1970:event.originServerTs/1000];
// NSString* dateTime = [[RoomMessage dateFormatter] stringFromDate:_date];
} else {
_date = nil;
}
// Set display mode
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
BOOL isIncomingMsg = ([event.userId isEqualToString:mxHandler.userId] == NO);
if ([textMessage hasPrefix:kMatrixHandlerUnsupportedMessagePrefix]) {
_displayMode = RoomMessageItemDisplayModeError;
} else if ([_eventId hasPrefix:kFailedEventId]) {
_displayMode = RoomMessageItemDisplayModeFailure;
} else if (isIncomingMsg && ([textMessage rangeOfString:mxHandler.userDisplayName options:NSCaseInsensitiveSearch].location != NSNotFound || [textMessage rangeOfString:mxHandler.userId options:NSCaseInsensitiveSearch].location != NSNotFound)) {
_displayMode = RoomMessageItemDisplayModeHighlighted;
} else if (!isIncomingMsg && [_eventId hasPrefix:kLocalEchoEventIdPrefix]) {
_displayMode = RoomMessageItemDisplayModeLocalEcho;
} else {
_displayMode = RoomMessageItemDisplayModeDefault;
}
}
return self;
}
@end

View file

@ -95,13 +95,13 @@
NSUInteger lastActiveAgoInSec = user.lastActiveAgo / 1000;
NSString *lastActive;
if (lastActiveAgoInSec < 60) {
lastActive = [NSString stringWithFormat:@"%ds ago", lastActiveAgoInSec];
lastActive = [NSString stringWithFormat:@"%lus ago", (unsigned long)lastActiveAgoInSec];
} else if (lastActiveAgoInSec < 3600) {
lastActive = [NSString stringWithFormat:@"%dm ago", (lastActiveAgoInSec / 60)];
lastActive = [NSString stringWithFormat:@"%lum ago", (unsigned long)(lastActiveAgoInSec / 60)];
} else if (lastActiveAgoInSec < 86400) {
lastActive = [NSString stringWithFormat:@"%dh ago", (lastActiveAgoInSec / 3600)];
lastActive = [NSString stringWithFormat:@"%luh ago", (unsigned long)(lastActiveAgoInSec / 3600)];
} else {
lastActive = [NSString stringWithFormat:@"%dd ago", (lastActiveAgoInSec / 86400)];
lastActive = [NSString stringWithFormat:@"%lud ago", (unsigned long)(lastActiveAgoInSec / 86400)];
}
// Check presence

View file

@ -268,7 +268,7 @@
MXRoom *mxRoom = [mxHandler.mxSession room:mxEvent.roomId];
cell.roomTitle.text = [mxRoom.state displayname];
cell.lastEventDescription.text = [mxHandler displayTextFor:mxEvent inSubtitleMode:YES];
cell.lastEventDescription.text = [mxHandler displayTextForEvent:mxEvent withRoomState:mxRoom.state inSubtitleMode:YES];
// Set in bold public room name
if (mxRoom.state.isPublic) {

File diff suppressed because it is too large Load diff