mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 15:52:40 +00:00
Merge remote-tracking branch 'origin/develop' into mxfilestore
This commit is contained in:
commit
fdfce7b5db
14 changed files with 410 additions and 106 deletions
|
@ -21,6 +21,7 @@
|
|||
@property (nonatomic) BOOL displayAllEvents;
|
||||
@property (nonatomic) BOOL hideUnsupportedMessages;
|
||||
@property (nonatomic) BOOL sortMembersUsingLastSeenTime;
|
||||
@property (nonatomic) BOOL displayLeftUsers;
|
||||
|
||||
+ (AppSettings *)sharedSettings;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ static AppSettings *sharedSettings = nil;
|
|||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"displayAllEvents"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"hideUnsupportedMessages"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"sortMembersUsingLastSeenTime"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"displayLeftUsers"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
|
@ -87,4 +88,12 @@ static AppSettings *sharedSettings = nil;
|
|||
[[NSUserDefaults standardUserDefaults] setBool:sortMembersUsingLastSeen forKey:@"sortMembersUsingLastSeenTime"];
|
||||
}
|
||||
|
||||
- (BOOL)displayLeftUsers {
|
||||
return [[NSUserDefaults standardUserDefaults] boolForKey:@"displayLeftUsers"];
|
||||
}
|
||||
|
||||
- (void)setDisplayLeftUsers:(BOOL)displayLeftUsers {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:displayLeftUsers forKey:@"displayLeftUsers"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Recents-->
|
||||
|
@ -307,45 +308,43 @@
|
|||
<constraint firstAttribute="width" constant="40" id="pLY-G3-fxB"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="userLabel" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="uVK-4R-arl" userLabel="userLabel">
|
||||
<rect key="frame" x="56" y="5" width="464" height="34"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="userLabel" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uVK-4R-arl" userLabel="userLabel">
|
||||
<rect key="frame" x="56" y="5" width="520" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="lastActiveLabel" textAlignment="center" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="R86-SF-Vqh">
|
||||
<rect key="frame" x="528" y="5" width="64" height="39"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="UDn-QR-f6Q">
|
||||
<rect key="frame" x="56" y="42" width="464" height="2"/>
|
||||
</progressView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wDo-tA-Ar7" userLabel="PowerContainer">
|
||||
<rect key="frame" x="578" y="18" width="14" height="14"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="14" id="12z-f1-s6Z"/>
|
||||
<constraint firstAttribute="width" constant="14" id="pnc-pv-ZIj"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="UDn-QR-f6Q" firstAttribute="leading" secondItem="prD-ap-cDD" secondAttribute="leading" constant="56" id="2HY-kb-aUu"/>
|
||||
<constraint firstAttribute="bottom" secondItem="R86-SF-Vqh" secondAttribute="bottom" constant="5" id="3dt-Qu-01M"/>
|
||||
<constraint firstAttribute="bottom" secondItem="UDn-QR-f6Q" secondAttribute="bottom" constant="5" id="49f-EW-vEr"/>
|
||||
<constraint firstItem="RW8-nh-DTj" firstAttribute="top" secondItem="prD-ap-cDD" secondAttribute="top" constant="5" id="6La-Gc-4B8"/>
|
||||
<constraint firstItem="UDn-QR-f6Q" firstAttribute="top" secondItem="uVK-4R-arl" secondAttribute="bottom" constant="3" id="81T-EM-1pe"/>
|
||||
<constraint firstAttribute="trailing" secondItem="R86-SF-Vqh" secondAttribute="trailing" constant="8" id="BvW-r7-R0r"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UDn-QR-f6Q" secondAttribute="trailing" constant="80" id="Nrk-rv-6eb"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="wDo-tA-Ar7" secondAttribute="trailing" id="GKG-lb-3k0"/>
|
||||
<constraint firstItem="uVK-4R-arl" firstAttribute="leading" secondItem="RW8-nh-DTj" secondAttribute="trailing" constant="8" id="O2H-DM-jOU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="uVK-4R-arl" secondAttribute="trailing" constant="80" id="RSx-Sk-WrV"/>
|
||||
<constraint firstAttribute="trailing" secondItem="uVK-4R-arl" secondAttribute="trailing" constant="24" id="RSx-Sk-WrV"/>
|
||||
<constraint firstAttribute="centerY" secondItem="wDo-tA-Ar7" secondAttribute="centerY" id="a3l-Wn-dkq"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wDo-tA-Ar7" secondAttribute="trailing" constant="21" id="cAm-Af-t17"/>
|
||||
<constraint firstItem="uVK-4R-arl" firstAttribute="top" secondItem="prD-ap-cDD" secondAttribute="top" constant="5" id="cFa-Qa-p2W"/>
|
||||
<constraint firstItem="RW8-nh-DTj" firstAttribute="leading" secondItem="prD-ap-cDD" secondAttribute="leading" constant="8" id="hXV-sM-uhV"/>
|
||||
<constraint firstAttribute="bottom" secondItem="uVK-4R-arl" secondAttribute="bottom" constant="10" id="l5F-M4-LOB"/>
|
||||
<constraint firstItem="R86-SF-Vqh" firstAttribute="top" secondItem="prD-ap-cDD" secondAttribute="top" constant="5" id="mNu-kF-Hb7"/>
|
||||
<constraint firstItem="R86-SF-Vqh" firstAttribute="leading" secondItem="uVK-4R-arl" secondAttribute="trailing" constant="8" id="tz0-aZ-yaX"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="cAm-Af-t17"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<outlet property="lastActiveAgoLabel" destination="R86-SF-Vqh" id="AIr-OL-gqM"/>
|
||||
<outlet property="pictureView" destination="RW8-nh-DTj" id="1Lk-bd-tKv"/>
|
||||
<outlet property="powerContainer" destination="wDo-tA-Ar7" id="sub-O0-L9d"/>
|
||||
<outlet property="userLabel" destination="uVK-4R-arl" id="OhP-VD-vj0"/>
|
||||
<outlet property="userPowerLevel" destination="UDn-QR-f6Q" id="Ts8-l1-Lyv"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
|
@ -450,7 +449,7 @@
|
|||
<scene sceneID="3rt-8o-eGh">
|
||||
<objects>
|
||||
<tableViewController title="Home" id="ldZ-75-BUU" customClass="HomeViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="40" sectionFooterHeight="22" id="LbI-fz-LaI">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="40" sectionFooterHeight="22" id="LbI-fz-LaI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
|
@ -59,4 +59,6 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
|
|||
- (NSString*)senderAvatarUrlForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
|
||||
- (NSString*)displayTextForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState inSubtitleMode:(BOOL)isSubtitle;
|
||||
|
||||
// search if a 1:1 conversation has been started with this member
|
||||
- (NSString*) getRoomStartedWithMember:(MXRoomMember*)roomMember;
|
||||
@end
|
||||
|
|
|
@ -543,7 +543,13 @@ static MatrixHandler *sharedHandler = nil;
|
|||
prevDisplayname = nil;
|
||||
}
|
||||
if ((displayname || prevDisplayname) && ([displayname isEqualToString:prevDisplayname] == NO)) {
|
||||
displayText = [NSString stringWithFormat:@"%@ changed their display name from %@ to %@", event.userId, prevDisplayname, displayname];
|
||||
if (!prevDisplayname) {
|
||||
displayText = [NSString stringWithFormat:@"%@ set their display name to %@", event.userId, displayname];
|
||||
} else if (!displayname) {
|
||||
displayText = [NSString stringWithFormat:@"%@ removed their display name (previouly named %@)", event.userId, prevDisplayname];
|
||||
} else {
|
||||
displayText = [NSString stringWithFormat:@"%@ changed their display name from %@ to %@", event.userId, prevDisplayname, displayname];
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the avatar has been changed
|
||||
|
@ -731,4 +737,37 @@ static MatrixHandler *sharedHandler = nil;
|
|||
return displayText;
|
||||
}
|
||||
|
||||
|
||||
// search if a conversation has been started with this user
|
||||
- (NSString*) getRoomStartedWithMember:(MXRoomMember*)roomMember {
|
||||
//
|
||||
if (self.mxSession) {
|
||||
// list the last messages of each room to get the rooms list
|
||||
NSArray *recentEvents = [NSMutableArray arrayWithArray:[self.mxSession recentsWithTypeIn:self.eventsFilterForMessages]];
|
||||
|
||||
// loops
|
||||
for (MXEvent *mxEvent in recentEvents) {
|
||||
// get the dedicated mxRooms
|
||||
MXRoom *mxRoom = [self.mxSession roomWithRoomId:mxEvent.roomId];
|
||||
|
||||
// accept only room with 2 users
|
||||
if (mxRoom.state.members.count == 2) {
|
||||
NSArray* roomMembers = mxRoom.state.members;
|
||||
|
||||
MXRoomMember* member1 = [roomMembers objectAtIndex:0];
|
||||
MXRoomMember* member2 = [roomMembers objectAtIndex:1];
|
||||
|
||||
// check if they are the dedicated users
|
||||
if (
|
||||
([member1.userId isEqualToString:self.mxSession.myUser.userId] || [member1.userId isEqualToString:roomMember.userId]) &&
|
||||
([member2.userId isEqualToString:self.mxSession.myUser.userId] || [member2.userId isEqualToString:roomMember.userId])) {
|
||||
return mxRoom.state.roomId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -22,10 +22,13 @@
|
|||
|
||||
// Room Member Table View Cell
|
||||
@interface RoomMemberTableCell : UITableViewCell
|
||||
{
|
||||
//
|
||||
CAShapeLayer* powerContainerLayer;
|
||||
}
|
||||
@property (strong, nonatomic) IBOutlet CustomImageView *pictureView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *userLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIProgressView *userPowerLevel;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *lastActiveAgoLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIView *powerContainer;
|
||||
|
||||
- (void)setRoomMember:(MXRoomMember *)roomMember withRoom:(MXRoom *)room;
|
||||
@end
|
||||
|
|
|
@ -19,11 +19,125 @@
|
|||
|
||||
@implementation RoomMemberTableCell
|
||||
|
||||
// returns the presence color
|
||||
// nil if there is no valid one
|
||||
- (UIColor*) getUserPresenceColor:(MXUser*) user
|
||||
{
|
||||
if (user) {
|
||||
switch (user.presence) {
|
||||
case MXPresenceOnline:
|
||||
return [UIColor colorWithRed:0.2 green:0.9 blue:0.2 alpha:1.0];
|
||||
case MXPresenceUnavailable:
|
||||
return [UIColor colorWithRed:0.9 green:0.9 blue:0.0 alpha:1.0];
|
||||
case MXPresenceOffline:
|
||||
return [UIColor colorWithRed:0.9 green:0.2 blue:0.2 alpha:1.0];
|
||||
case MXPresenceUnknown:
|
||||
case MXPresenceFreeForChat:
|
||||
case MXPresenceHidden:
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)getLastPresenceText:(MXUser*)user {
|
||||
|
||||
NSString* presenceText = nil;
|
||||
|
||||
// Prepare last active ago string
|
||||
NSUInteger lastActiveAgoInSec = user.lastActiveAgo / 1000;
|
||||
if (lastActiveAgoInSec < 60) {
|
||||
presenceText = [NSString stringWithFormat:@"%lus", (unsigned long)lastActiveAgoInSec];
|
||||
} else if (lastActiveAgoInSec < 3600) {
|
||||
presenceText = [NSString stringWithFormat:@"%lum", (unsigned long)(lastActiveAgoInSec / 60)];
|
||||
} else if (lastActiveAgoInSec < 86400) {
|
||||
presenceText = [NSString stringWithFormat:@"%luh", (unsigned long)(lastActiveAgoInSec / 3600)];
|
||||
} else {
|
||||
presenceText = [NSString stringWithFormat:@"%lud", (unsigned long)(lastActiveAgoInSec / 86400)];
|
||||
}
|
||||
|
||||
// Check presence
|
||||
switch (user.presence) {
|
||||
case MXPresenceOffline: {
|
||||
presenceText = @"offline";
|
||||
break;
|
||||
}
|
||||
case MXPresenceHidden:
|
||||
case MXPresenceUnknown:
|
||||
case MXPresenceFreeForChat: {
|
||||
presenceText = nil;
|
||||
break;
|
||||
}
|
||||
case MXPresenceOnline:
|
||||
case MXPresenceUnavailable:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return presenceText;
|
||||
}
|
||||
|
||||
- (void) setPowerContainerValue:(CGFloat)progress
|
||||
{
|
||||
// no power level -> hide the pie
|
||||
if (0 == progress) {
|
||||
self.powerContainer.hidden = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
// display it
|
||||
self.powerContainer.hidden = NO;
|
||||
|
||||
// defines the view settings
|
||||
CGFloat radius = self.powerContainer.frame.size.width / 2;
|
||||
|
||||
// draw a rounded view
|
||||
[self.powerContainer.layer setCornerRadius:radius];
|
||||
|
||||
// the default body color is gray
|
||||
self.powerContainer.backgroundColor = [UIColor lightGrayColor];
|
||||
|
||||
// draw the pie
|
||||
CALayer* layer = [self.powerContainer layer];
|
||||
|
||||
// remove any previous drawn layer
|
||||
if (powerContainerLayer) {
|
||||
[powerContainerLayer removeFromSuperlayer];
|
||||
}
|
||||
|
||||
// create the red layer
|
||||
powerContainerLayer = [CAShapeLayer layer];
|
||||
[powerContainerLayer setZPosition:0];
|
||||
[powerContainerLayer setStrokeColor:NULL];
|
||||
|
||||
// power level is drawn in red
|
||||
powerContainerLayer.fillColor = [UIColor redColor].CGColor;
|
||||
|
||||
// build the path
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathMoveToPoint(path, NULL, radius, radius);
|
||||
|
||||
CGPathAddArc(path, NULL, radius, radius, radius, -M_PI / 2, (progress * 2 * M_PI) - (M_PI / 2), 0);
|
||||
CGPathCloseSubpath(path);
|
||||
|
||||
[powerContainerLayer setPath:path];
|
||||
CFRelease(path);
|
||||
|
||||
// add the sub layer
|
||||
[layer addSublayer:powerContainerLayer];
|
||||
}
|
||||
|
||||
- (void)setRoomMember:(MXRoomMember *)roomMember withRoom:(MXRoom *)room {
|
||||
if (room && roomMember) {
|
||||
// set the user info
|
||||
self.userLabel.text = [room.state memberName:roomMember.userId];
|
||||
|
||||
// user
|
||||
self.pictureView.placeholder = @"default-profile";
|
||||
self.pictureView.imageURL = roomMember.avatarUrl;
|
||||
|
||||
// Round image view
|
||||
[self.pictureView.layer setCornerRadius:self.pictureView.frame.size.width / 2];
|
||||
self.pictureView.clipsToBounds = YES;
|
||||
|
@ -38,20 +152,21 @@
|
|||
view.alpha = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// user info
|
||||
CGFloat powerLevel = 0;
|
||||
NSString* presenceText = nil;
|
||||
UIColor* thumbnailBorderColor = nil;
|
||||
|
||||
// Customize banned and left (kicked) members
|
||||
if (roomMember.membership == MXMembershipLeave || roomMember.membership == MXMembershipBan) {
|
||||
self.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0];
|
||||
|
||||
self.userPowerLevel.hidden = YES;
|
||||
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor lightGrayColor];
|
||||
self.lastActiveAgoLabel.text = (roomMember.membership == MXMembershipLeave) ? @"left" : @"banned";
|
||||
presenceText = (roomMember.membership == MXMembershipLeave) ? @"left" : @"banned";
|
||||
} else {
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
// Handle power level display
|
||||
self.userPowerLevel.hidden = NO;
|
||||
//self.userPowerLevel.hidden = NO;
|
||||
MXRoomPowerLevels *roomPowerLevels = room.state.powerLevels;
|
||||
|
||||
int maxLevel = 0;
|
||||
|
@ -66,68 +181,63 @@
|
|||
if (userPowerLevel) {
|
||||
userPowerLevelFloat = userPowerLevel;
|
||||
}
|
||||
self.userPowerLevel.progress = maxLevel ? userPowerLevelFloat / maxLevel : 1;
|
||||
|
||||
powerLevel = maxLevel ? userPowerLevelFloat / maxLevel : 1;
|
||||
|
||||
// get the user presence and his thumbnail border color
|
||||
if (roomMember.membership == MXMembershipInvite) {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor lightGrayColor];
|
||||
self.lastActiveAgoLabel.text = @"invited";
|
||||
thumbnailBorderColor = [UIColor lightGrayColor];
|
||||
presenceText = @"invited";
|
||||
} else {
|
||||
// Get the user that corresponds to this member
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
MXUser *user = [mxHandler.mxSession userWithUserId:roomMember.userId];
|
||||
|
||||
// Prepare last active ago string
|
||||
NSUInteger lastActiveAgoInSec = user.lastActiveAgo / 1000;
|
||||
NSString *lastActive;
|
||||
if (lastActiveAgoInSec < 60) {
|
||||
lastActive = [NSString stringWithFormat:@"%lus ago", (unsigned long)lastActiveAgoInSec];
|
||||
} else if (lastActiveAgoInSec < 3600) {
|
||||
lastActive = [NSString stringWithFormat:@"%lum ago", (unsigned long)(lastActiveAgoInSec / 60)];
|
||||
} else if (lastActiveAgoInSec < 86400) {
|
||||
lastActive = [NSString stringWithFormat:@"%luh ago", (unsigned long)(lastActiveAgoInSec / 3600)];
|
||||
} else {
|
||||
lastActive = [NSString stringWithFormat:@"%lud ago", (unsigned long)(lastActiveAgoInSec / 86400)];
|
||||
}
|
||||
|
||||
// Check presence
|
||||
switch (user.presence) {
|
||||
case MXPresenceUnknown: {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor clearColor];
|
||||
self.lastActiveAgoLabel.text = nil;//@"unknown";
|
||||
break;
|
||||
}
|
||||
case MXPresenceOnline: {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor colorWithRed:0.2 green:0.9 blue:0.2 alpha:1.0];
|
||||
self.lastActiveAgoLabel.text = lastActive;
|
||||
self.lastActiveAgoLabel.numberOfLines = 0;
|
||||
break;
|
||||
}
|
||||
case MXPresenceUnavailable: {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.0 alpha:1.0];
|
||||
self.lastActiveAgoLabel.text = lastActive;
|
||||
self.lastActiveAgoLabel.numberOfLines = 0;
|
||||
break;
|
||||
}
|
||||
case MXPresenceOffline: {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.2 blue:0.2 alpha:1.0];
|
||||
self.lastActiveAgoLabel.text = @"offline";
|
||||
break;
|
||||
}
|
||||
case MXPresenceFreeForChat: {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor clearColor];
|
||||
self.lastActiveAgoLabel.text = nil;//@"free for chat";
|
||||
break;
|
||||
}
|
||||
case MXPresenceHidden: {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor clearColor];
|
||||
self.lastActiveAgoLabel.text = nil;//@"hidden";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
// existing user ?
|
||||
if (user) {
|
||||
thumbnailBorderColor = [self getUserPresenceColor:user];
|
||||
presenceText = [self getLastPresenceText:user];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display the power level pie
|
||||
[self setPowerContainerValue:powerLevel];
|
||||
|
||||
// if the thumbnail is defined
|
||||
if (thumbnailBorderColor) {
|
||||
self.pictureView.layer.borderWidth = 2;
|
||||
self.pictureView.layer.borderColor = thumbnailBorderColor.CGColor;
|
||||
} else {
|
||||
// remove the border
|
||||
// else it draws black border
|
||||
self.pictureView.layer.borderWidth = 0;
|
||||
}
|
||||
|
||||
// and the presence text (if any)
|
||||
if (presenceText) {
|
||||
NSString* extraText = [NSString stringWithFormat:@"(%@)", presenceText];
|
||||
self.userLabel.text = [NSString stringWithFormat:@"%@ %@", self.userLabel.text, extraText];
|
||||
|
||||
NSRange range = [self.userLabel.text rangeOfString:extraText];
|
||||
UIFont* font = self.userLabel.font;
|
||||
|
||||
// Create the attributes
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
font, NSFontAttributeName,
|
||||
self.userLabel.textColor, NSForegroundColorAttributeName, nil];
|
||||
|
||||
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
font, NSFontAttributeName,
|
||||
[UIColor lightGrayColor], NSForegroundColorAttributeName, nil];
|
||||
|
||||
// Create the attributed string (text + attributes)
|
||||
NSMutableAttributedString *attributedText =[[NSMutableAttributedString alloc] initWithString:self.userLabel.text attributes:attrs];
|
||||
[attributedText setAttributes:subAttrs range:range];
|
||||
|
||||
// Set it in our UILabel and we are done!
|
||||
[self.userLabel setAttributedText:attributedText];
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "CustomImageView.h"
|
||||
#import "RoomMessage.h"
|
||||
|
||||
// Room Message Table View Cell
|
||||
@interface RoomMessageTableCell : UITableViewCell
|
||||
|
@ -28,6 +29,9 @@
|
|||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewWidthConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewTopConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *dateTimeLabelContainerTopConstraint;
|
||||
|
||||
// reference to the linked message
|
||||
@property (strong, nonatomic) RoomMessage *message;
|
||||
@end
|
||||
|
||||
@interface IncomingMessageTableCell : RoomMessageTableCell
|
||||
|
|
|
@ -26,4 +26,12 @@
|
|||
|
||||
|
||||
@implementation OutgoingMessageTableCell
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
// ensure that the text is still aligned to the left side of the screen
|
||||
// even during animation while enlarging/reducing the viewcontroller (with UISplitViewController)
|
||||
CGFloat leftInset = self.message.maxTextViewWidth - self.message.contentSize.width;
|
||||
self.messageTextView.contentInset = UIEdgeInsetsMake(0, leftInset, 0, -leftInset);
|
||||
}
|
||||
@end
|
|
@ -318,6 +318,29 @@
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - scrollView delegate
|
||||
|
||||
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
|
||||
// hide the keyboard if the user scrolls the public rooms list
|
||||
if (!filteredPublicRooms) {
|
||||
if ([self.roomNameTextField isFirstResponder]) {
|
||||
[self.roomNameTextField resignFirstResponder];
|
||||
[self.tableView becomeFirstResponder];
|
||||
}
|
||||
|
||||
if ([self.roomAliasTextField isFirstResponder]) {
|
||||
[self.roomNameTextField resignFirstResponder];
|
||||
[self.tableView becomeFirstResponder];
|
||||
}
|
||||
|
||||
if ([self.participantsTextField isFirstResponder]) {
|
||||
[self.participantsTextField resignFirstResponder];
|
||||
[self.tableView becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#import "CustomAlert.h"
|
||||
|
||||
@interface LoginViewController ()
|
||||
{
|
||||
// reference to any opened alert view
|
||||
CustomAlert *alert;
|
||||
}
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewBottomConstraint;
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
|
||||
|
@ -90,6 +94,12 @@
|
|||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// close any opened alert
|
||||
if (alert) {
|
||||
[alert dismiss:NO];
|
||||
alert = nil;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
|
||||
|
@ -211,8 +221,41 @@
|
|||
_loginBtn.enabled = YES;
|
||||
|
||||
NSLog(@"Login failed: %@", error);
|
||||
|
||||
// translate the error code to a human message
|
||||
NSString* message = error.localizedDescription;
|
||||
NSDictionary* dict = error.userInfo;
|
||||
|
||||
// detect if it is a Matrix SDK issue
|
||||
if (dict) {
|
||||
NSString* localizedError = [dict valueForKey:@"error"];
|
||||
NSString* errCode = [dict valueForKey:@"errcode"];
|
||||
|
||||
if (errCode) {
|
||||
if ([errCode isEqualToString:@"M_FORBIDDEN"]) {
|
||||
message = @"Invalid username/password";
|
||||
} else if (localizedError .length > 0) {
|
||||
message = localizedError;
|
||||
} else if ([errCode isEqualToString:@"M_UNKNOWN_TOKEN"]) {
|
||||
message = @"The access token specified was not recognised";
|
||||
} else if ([errCode isEqualToString:@"M_BAD_JSON"]) {
|
||||
message = @"Malformed JSON";
|
||||
} else if ([errCode isEqualToString:@"M_NOT_JSON"]) {
|
||||
message = @"Did not contain valid JSON";
|
||||
} else if ([errCode isEqualToString:@"M_LIMIT_EXCEEDED"]) {
|
||||
message = @"Too many requests have been sent";
|
||||
} else if ([errCode isEqualToString:@"M_USER_IN_USE"]) {
|
||||
message = @"This user name is already used";
|
||||
} else if ([errCode isEqualToString:@"M_LOGIN_EMAIL_URL_NOT_YET"]) {
|
||||
message = @"The email link which has not been clicked yet";
|
||||
} else {
|
||||
message = errCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Alert user
|
||||
CustomAlert *alert = [[CustomAlert alloc] initWithTitle:@"Login Failed" message:@"Invalid username/password" style:CustomAlertStyleAlert];
|
||||
alert = [[CustomAlert alloc] initWithTitle:@"Login Failed" message:message style:CustomAlertStyleAlert];
|
||||
[alert addActionWithTitle:@"Dismiss" style:CustomAlertActionStyleCancel handler:^(CustomAlert *alert) {}];
|
||||
[alert showInViewController:self];
|
||||
}];
|
||||
|
|
|
@ -647,7 +647,21 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
# pragma mark - Room members
|
||||
|
||||
- (void)updateRoomMembers {
|
||||
members = [[self.mxRoom.state members] sortedArrayUsingComparator:^NSComparisonResult(MXRoomMember *member1, MXRoomMember *member2) {
|
||||
NSArray* membersList = [self.mxRoom.state members];
|
||||
|
||||
if (![[AppSettings sharedSettings] displayLeftUsers]) {
|
||||
NSMutableArray* filteredMembers = [[NSMutableArray alloc] init];
|
||||
|
||||
for (MXRoomMember* member in membersList) {
|
||||
if (member.membership != MXMembershipLeave) {
|
||||
[filteredMembers addObject:member];
|
||||
}
|
||||
}
|
||||
|
||||
membersList = filteredMembers;
|
||||
}
|
||||
|
||||
members = [membersList sortedArrayUsingComparator:^NSComparisonResult(MXRoomMember *member1, MXRoomMember *member2) {
|
||||
// Move banned and left members at the end of the list
|
||||
if (member1.membership == MXMembershipLeave || member1.membership == MXMembershipBan) {
|
||||
if (member2.membership != MXMembershipLeave && member2.membership != MXMembershipBan) {
|
||||
|
@ -665,7 +679,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
} else if (member2.membership == MXMembershipInvite) {
|
||||
return NSOrderedAscending;
|
||||
}
|
||||
|
||||
|
||||
if ([[AppSettings sharedSettings] sortMembersUsingLastSeenTime]) {
|
||||
// Get the users that correspond to these members
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
|
@ -1188,6 +1202,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
|
||||
// Restore initial settings
|
||||
cell.message = message;
|
||||
cell.attachmentView.imageURL = nil; // Cancel potential attachment loading
|
||||
cell.attachmentView.hidden = YES;
|
||||
cell.playIconView.hidden = YES;
|
||||
|
@ -1417,13 +1432,15 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:mxHandler.userId];
|
||||
NSUInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:roomMember.userId];
|
||||
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
|
||||
// Consider membership of the selected member
|
||||
switch (roomMember.membership) {
|
||||
case MXMembershipInvite:
|
||||
case MXMembershipJoin: {
|
||||
// Check conditions to be able to kick someone
|
||||
if (userPowerLevel >= [powerLevels kick] && userPowerLevel >= memberPowerLevel) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Kick" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
|
@ -1441,9 +1458,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
// Check conditions to be able to ban someone
|
||||
if (userPowerLevel >= [powerLevels ban] && userPowerLevel >= memberPowerLevel) {
|
||||
if (!self.actionMenu) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
}
|
||||
[self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
|
@ -1464,7 +1478,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
case MXMembershipLeave: {
|
||||
// Check conditions to be able to invite someone
|
||||
if (userPowerLevel >= [powerLevels invite]) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Invite" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
|
@ -1481,9 +1494,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
// Check conditions to be able to ban someone
|
||||
if (userPowerLevel >= [powerLevels ban] && userPowerLevel >= memberPowerLevel) {
|
||||
if (!self.actionMenu) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
}
|
||||
[self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
|
@ -1504,7 +1514,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
case MXMembershipBan: {
|
||||
// Check conditions to be able to unban someone
|
||||
if (userPowerLevel >= [powerLevels ban] && userPowerLevel >= memberPowerLevel) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Unban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
|
@ -1525,6 +1534,45 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the current web interface always creates a new room
|
||||
// uncoment this line opens any existing room with the same uers
|
||||
__block NSString* startedRoomID = nil; // [mxHandler getRoomStartedWithMember:roomMember];
|
||||
|
||||
//, offer to chat with this user only
|
||||
if (startedRoomID) {
|
||||
[self.actionMenu addActionWithTitle:@"Open chat" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
// Open created room
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoom:startedRoomID];
|
||||
}];
|
||||
} else {
|
||||
[self.actionMenu addActionWithTitle:@"Start chat" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
// Create new room
|
||||
[mxHandler.mxRestClient createRoom:(roomMember.displayname) ? roomMember.displayname : roomMember.userId
|
||||
visibility:kMXRoomVisibilityPrivate
|
||||
roomAlias:nil
|
||||
topic:nil
|
||||
success:^(MXCreateRoomResponse *response) {
|
||||
// add the user
|
||||
[mxHandler.mxRestClient inviteUser:roomMember.userId toRoom:response.roomId success:^{
|
||||
//NSLog(@"%@ has been invited (roomId: %@)", roomMember.userId, response.roomId);
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"%@ invitation failed (roomId: %@): %@", roomMember.userId, response.roomId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
|
||||
// Open created room
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoom:response.roomId];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"Create room failed: %@", error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
// Notify user when his power is too weak
|
||||
|
@ -2156,10 +2204,13 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
// Set power level
|
||||
if (userId && powerLevel) {
|
||||
// FIXME
|
||||
NSLog(@"Set user power level (/op) is not supported yet (%@)", userId);
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"/op is not supported yet" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
|
||||
[alert show];
|
||||
// Set user power level
|
||||
[self.mxRoom setPowerLevelOfUserWithUserID:userId powerLevel:[powerLevel integerValue] success:^{
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"Set user power (%@) failed: %@", userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
} else {
|
||||
// Display cmd usage in text input as placeholder
|
||||
self.messageTextField.placeholder = @"Usage: /op <userId> <power level>";
|
||||
|
@ -2167,10 +2218,12 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
} else if ([cmd isEqualToString:kCmdResetUserPowerLevel]) {
|
||||
if (userId) {
|
||||
// Reset user power level
|
||||
// FIXME
|
||||
NSLog(@"Reset user power level (/deop) is not supported yet (%@)", userId);
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"/deop is not supported yet" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
|
||||
[alert show];
|
||||
[self.mxRoom setPowerLevelOfUserWithUserID:userId powerLevel:0 success:^{
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"Reset user power (%@) failed: %@", userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
} else {
|
||||
// Display cmd usage in text input as placeholder
|
||||
self.messageTextField.placeholder = @"Usage: /deop <userId>";
|
||||
|
|
|
@ -50,6 +50,7 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
|
|||
UISwitch *allEventsSwitch;
|
||||
UISwitch *unsupportedMsgSwitch;
|
||||
UISwitch *sortMembersSwitch;
|
||||
UISwitch *displayLeftMembersSwitch;
|
||||
}
|
||||
@property (strong, nonatomic) IBOutlet UITableView *tableView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *tableHeader;
|
||||
|
@ -105,6 +106,7 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
|
|||
allEventsSwitch = nil;
|
||||
unsupportedMsgSwitch = nil;
|
||||
sortMembersSwitch = nil;
|
||||
displayLeftMembersSwitch = nil;
|
||||
[[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"isInitialSyncDone"];
|
||||
}
|
||||
|
||||
|
@ -371,6 +373,8 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
|
|||
[AppSettings sharedSettings].hideUnsupportedMessages = unsupportedMsgSwitch.on;
|
||||
} else if (sender == sortMembersSwitch) {
|
||||
[AppSettings sharedSettings].sortMembersUsingLastSeenTime = sortMembersSwitch.on;
|
||||
} else if (sender == displayLeftMembersSwitch) {
|
||||
[AppSettings sharedSettings].displayLeftUsers = displayLeftMembersSwitch.on;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +408,7 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
|
|||
}
|
||||
return 1;
|
||||
} else if (section == SETTINGS_SECTION_ROOMS_INDEX) {
|
||||
return 3;
|
||||
return 4;
|
||||
} else if (section == SETTINGS_SECTION_CONFIGURATION_INDEX) {
|
||||
return 1;
|
||||
} else if (section == SETTINGS_SECTION_COMMANDS_INDEX) {
|
||||
|
@ -488,10 +492,14 @@ NSString* const kCommandsDescriptionText = @"The following commands are availabl
|
|||
roomsSettingCell.settingLabel.text = @"Hide unsupported messages";
|
||||
roomsSettingCell.settingSwitch.on = [[AppSettings sharedSettings] hideUnsupportedMessages];
|
||||
unsupportedMsgSwitch = roomsSettingCell.settingSwitch;
|
||||
} else {
|
||||
} else if (indexPath.row == 2) {
|
||||
roomsSettingCell.settingLabel.text = @"Sort members by last seen time";
|
||||
roomsSettingCell.settingSwitch.on = [[AppSettings sharedSettings] sortMembersUsingLastSeenTime];
|
||||
sortMembersSwitch = roomsSettingCell.settingSwitch;
|
||||
} else {
|
||||
roomsSettingCell.settingLabel.text = @"Display left members";
|
||||
roomsSettingCell.settingSwitch.on = [[AppSettings sharedSettings] displayLeftUsers];
|
||||
displayLeftMembersSwitch = roomsSettingCell.settingSwitch;
|
||||
}
|
||||
cell = roomsSettingCell;
|
||||
} else if (indexPath.section == SETTINGS_SECTION_CONFIGURATION_INDEX) {
|
||||
|
|
|
@ -18,5 +18,7 @@
|
|||
<true/>
|
||||
<key>sortMembersUsingLastSeenTime</key>
|
||||
<true/>
|
||||
<key>displayLeftUsers</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
Loading…
Reference in a new issue