diff --git a/matrixConsole/matrixConsole.xcodeproj/project.pbxproj b/matrixConsole/matrixConsole.xcodeproj/project.pbxproj index 69806c4dd..1209b8b70 100644 --- a/matrixConsole/matrixConsole.xcodeproj/project.pbxproj +++ b/matrixConsole/matrixConsole.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 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 */; }; + F04A8AD81A3B3DF4008AC915 /* RoomTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = F04A8AD71A3B3DF4008AC915 /* RoomTitleView.m */; }; F04EE51F1A3A01D500C64930 /* APNSHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = F04EE51E1A3A01D500C64930 /* APNSHandler.m */; }; F05B955F19DEED8A008761B0 /* MatrixHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = F05B955E19DEED8A008761B0 /* MatrixHandler.m */; }; F07A80D819DD9DE700B621A1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A80D719DD9DE700B621A1 /* main.m */; }; @@ -90,6 +91,8 @@ F03EF60119F19E7C00A0EE52 /* MediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaManager.m; sourceTree = ""; }; F0465AF81A251F85003639F9 /* RoomMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMessage.h; sourceTree = ""; }; F0465AF91A251F85003639F9 /* RoomMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMessage.m; sourceTree = ""; }; + F04A8AD61A3B3DF4008AC915 /* RoomTitleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomTitleView.h; sourceTree = ""; }; + F04A8AD71A3B3DF4008AC915 /* RoomTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomTitleView.m; sourceTree = ""; }; F04EE51D1A3A01D500C64930 /* APNSHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APNSHandler.h; sourceTree = ""; }; F04EE51E1A3A01D500C64930 /* APNSHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APNSHandler.m; sourceTree = ""; }; F05B955D19DEED8A008761B0 /* MatrixHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatrixHandler.h; sourceTree = ""; }; @@ -207,6 +210,8 @@ F02D707519F1DC9E007B47D3 /* RoomMemberTableCell.m */, F03EF5FD19F1762000A0EE52 /* RoomMessageTableCell.h */, F03EF5FE19F1762000A0EE52 /* RoomMessageTableCell.m */, + F04A8AD61A3B3DF4008AC915 /* RoomTitleView.h */, + F04A8AD71A3B3DF4008AC915 /* RoomTitleView.m */, F0D3C30D1A01330F0000D49E /* SettingsTableViewCell.h */, F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */, ); @@ -444,6 +449,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F04A8AD81A3B3DF4008AC915 /* RoomTitleView.m in Sources */, F07A80DB19DD9DE700B621A1 /* AppDelegate.m in Sources */, F03EF5FF19F1762000A0EE52 /* RoomMessageTableCell.m in Sources */, F07A80D819DD9DE700B621A1 /* main.m in Sources */, diff --git a/matrixConsole/matrixConsole/Base.lproj/Main.storyboard b/matrixConsole/matrixConsole/Base.lproj/Main.storyboard index fb0b0fb45..44c3dbb24 100644 --- a/matrixConsole/matrixConsole/Base.lproj/Main.storyboard +++ b/matrixConsole/matrixConsole/Base.lproj/Main.storyboard @@ -383,16 +383,44 @@ - - + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + - + + + - + @@ -403,14 +431,14 @@ - + - + diff --git a/matrixConsole/matrixConsole/View/RoomTitleView.h b/matrixConsole/matrixConsole/View/RoomTitleView.h new file mode 100644 index 000000000..e362b73e9 --- /dev/null +++ b/matrixConsole/matrixConsole/View/RoomTitleView.h @@ -0,0 +1,33 @@ +/* + 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 + +@class MXRoom; + +@interface RoomTitleView : UIView { +} + +@property (weak, nonatomic) IBOutlet UITextField *displayNameTextField; +@property (weak, nonatomic) IBOutlet UITextField *topicTextField; + +@property (strong, nonatomic) MXRoom *mxRoom; +@property (nonatomic) BOOL editable; +@property (nonatomic) BOOL hiddenTopic; + +- (void)dismissKeyboard; + +@end \ No newline at end of file diff --git a/matrixConsole/matrixConsole/View/RoomTitleView.m b/matrixConsole/matrixConsole/View/RoomTitleView.m new file mode 100644 index 000000000..62bb28a6a --- /dev/null +++ b/matrixConsole/matrixConsole/View/RoomTitleView.m @@ -0,0 +1,94 @@ +/* + 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 "RoomTitleView.h" +#import "MatrixHandler.h" + +@interface RoomTitleView () { + id messagesListener; +} +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *displayNameTextFieldTopConstraint; +@end + +@implementation RoomTitleView + +- (void)dealloc { + if (messagesListener && _mxRoom) { + [_mxRoom removeListener:messagesListener]; + messagesListener = nil; + } + _mxRoom = nil; +} + +- (void)refreshDisplay { + if (_mxRoom) { + _displayNameTextField.text = _mxRoom.state.displayname; + _topicTextField.text = _mxRoom.state.topic; + } else { + _displayNameTextField.text = nil; + _topicTextField.text = nil; + } + + self.hiddenTopic = (!_topicTextField.text.length); +} + +- (void)setMxRoom:(MXRoom *)mxRoom { + // Check whether the room is actually changed + if (_mxRoom != mxRoom) { + // Remove potential listener + if (messagesListener && _mxRoom) { + [_mxRoom removeListener:messagesListener]; + messagesListener = nil; + } + + if (mxRoom) { + // Register a listener to handle messages related to room name + messagesListener = [mxRoom listenToEventsOfTypes:@[kMXEventTypeStringRoomName, kMXEventTypeStringRoomTopic, kMXEventTypeStringRoomAliases] + onEvent:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) { + // Consider only live events + if (direction == MXEventDirectionForwards) { + [self refreshDisplay]; + } + }]; + } + _mxRoom = mxRoom; + } + // Force refresh + [self refreshDisplay]; +} + +- (void)setEditable:(BOOL)editable { + self.displayNameTextField.enabled = editable; + self.topicTextField.enabled = editable; +} + +- (void)setHiddenTopic:(BOOL)hiddenTopic { + if (hiddenTopic) { + _topicTextField.hidden = YES; + _displayNameTextFieldTopConstraint.constant = 10; + } else { + _topicTextField.hidden = NO; + _displayNameTextFieldTopConstraint.constant = 2; + } +} + +- (void)dismissKeyboard { + // Hide the keyboard + [_displayNameTextField resignFirstResponder]; + [_topicTextField resignFirstResponder]; +} + +@end diff --git a/matrixConsole/matrixConsole/ViewController/RecentsViewController.m b/matrixConsole/matrixConsole/ViewController/RecentsViewController.m index fb64c9f45..ad6c73039 100644 --- a/matrixConsole/matrixConsole/ViewController/RecentsViewController.m +++ b/matrixConsole/matrixConsole/ViewController/RecentsViewController.m @@ -365,6 +365,9 @@ controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem; controller.navigationItem.leftItemsSupplementBackButton = YES; } + + // Hide back button title + self.navigationItem.backBarButtonItem=[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; } } diff --git a/matrixConsole/matrixConsole/ViewController/RoomViewController.m b/matrixConsole/matrixConsole/ViewController/RoomViewController.m index 791355aaf..ce6d87589 100644 --- a/matrixConsole/matrixConsole/ViewController/RoomViewController.m +++ b/matrixConsole/matrixConsole/ViewController/RoomViewController.m @@ -21,6 +21,7 @@ #import "RoomMessage.h" #import "RoomMessageTableCell.h" #import "RoomMemberTableCell.h" +#import "RoomTitleView.h" #import "MatrixHandler.h" #import "AppDelegate.h" @@ -78,7 +79,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; } @property (weak, nonatomic) IBOutlet UINavigationItem *roomNavItem; -@property (weak, nonatomic) IBOutlet UITextField *roomNameTextField; +@property (weak, nonatomic) IBOutlet RoomTitleView *roomTitleView; @property (weak, nonatomic) IBOutlet UITableView *messagesTableView; @property (weak, nonatomic) IBOutlet UIView *controlView; @property (weak, nonatomic) IBOutlet UIButton *optionBtn; @@ -258,7 +259,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; // The whole room history is flushed here to rebuild it from the current instant (live) messages = nil; // Disable room title edition - self.roomNameTextField.enabled = NO; + self.roomTitleView.editable = NO; // Update room data MatrixHandler *mxHandler = [MatrixHandler sharedHandler]; @@ -267,9 +268,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; self.mxRoom = [mxHandler.mxSession roomWithRoomId:self.roomId]; } if (self.mxRoom) { - // Update room title - self.roomNameTextField.text = self.mxRoom.state.displayname; - // Check first whether we have to join the room if (self.mxRoom.state.membership == MXMembershipInvite) { isJoinRequestInProgress = YES; @@ -291,7 +289,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; } // Enable room title edition - self.roomNameTextField.enabled = YES; + self.roomTitleView.editable = YES; messages = [NSMutableArray array]; [[AppSettings sharedSettings] addObserver:self forKeyPath:@"hideUnsupportedMessages" options:0 context:nil]; @@ -409,11 +407,10 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; // Trigger a back pagination by reseting first backState to get room history from live [self.mxRoom resetBackState]; [self triggerBackPagination]; - } else { - // Update room title - self.roomNameTextField.text = nil; } + self.roomTitleView.mxRoom = self.mxRoom; + [self.messagesTableView reloadData]; } @@ -914,7 +911,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; - (void)dismissKeyboard { // Hide the keyboard [_messageTextField resignFirstResponder]; - [_roomNameTextField resignFirstResponder]; + [_roomTitleView dismissKeyboard]; } #pragma mark - UITableView data source @@ -1387,79 +1384,134 @@ NSString *const kCmdResetUserPowerLevel = @"/deop"; #pragma mark - UITextField delegate -- (void)onTextFieldChange:(NSNotification *)notif { - NSString *msg = _messageTextField.text; - - if (msg.length) { - _sendBtn.enabled = YES; - _sendBtn.alpha = 1; - // Reset potential placeholder (used in case of wrong command usage) - _messageTextField.placeholder = nil; - } else { - _sendBtn.enabled = NO; - _sendBtn.alpha = 0.5; +- (void)onTextFieldChange:(NSNotification *)notification { + if (notification.object == _messageTextField) { + NSString *msg = _messageTextField.text; + if (msg.length) { + _sendBtn.enabled = YES; + _sendBtn.alpha = 1; + // Reset potential placeholder (used in case of wrong command usage) + _messageTextField.placeholder = nil; + } else { + _sendBtn.enabled = NO; + _sendBtn.alpha = 0.5; + } } } - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { - if (textField == self.roomNameTextField) { + NSString *alertMsg = nil; + + if (textField == _roomTitleView.displayNameTextField) { // Check whether the user has enough power to rename the room MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels]; NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:[MatrixHandler sharedHandler].userId]; if (userPowerLevel >= [powerLevels minimumPowerLevelForPostingEventAsStateEvent:kMXEventTypeStringRoomName]) { // Only the room name is edited here, update the text field with the room name - self.roomNameTextField.text = self.mxRoom.state.name; - self.roomNameTextField.borderStyle = UITextBorderStyleRoundedRect; - self.roomNameTextField.backgroundColor = [UIColor whiteColor]; - return YES; + textField.text = self.mxRoom.state.name; + textField.backgroundColor = [UIColor whiteColor]; } else { - // Alert user - __weak typeof(self) weakSelf = self; - if (self.actionMenu) { - [self.actionMenu dismiss:NO]; - } - self.actionMenu = [[CustomAlert alloc] initWithTitle:nil message:@"You are not authorized to edit this room name" style:CustomAlertStyleAlert]; - self.actionMenu.cancelButtonIndex = [self.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { - weakSelf.actionMenu = nil; - }]; - [self.actionMenu showInViewController:self]; + alertMsg = @"You are not authorized to edit this room name"; } + + // Check whether the user is allowed to change room topic + if (userPowerLevel >= [powerLevels minimumPowerLevelForPostingEventAsStateEvent:kMXEventTypeStringRoomTopic]) { + // Show topic text field even if the current value is nil + _roomTitleView.hiddenTopic = NO; + if (alertMsg) { + // Here the user can only update the room topic, switch on room topic field (without displaying alert) + alertMsg = nil; + [_roomTitleView.topicTextField becomeFirstResponder]; + return NO; + } + } + } else if (textField == _roomTitleView.topicTextField) { + // Check whether the user has enough power to edit room topic + MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels]; + NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:[MatrixHandler sharedHandler].userId]; + if (userPowerLevel >= [powerLevels minimumPowerLevelForPostingEventAsStateEvent:kMXEventTypeStringRoomTopic]) { + textField.backgroundColor = [UIColor whiteColor]; + } else { + alertMsg = @"You are not authorized to edit this room topic"; + } + } + + if (alertMsg) { + // Alert user + __weak typeof(self) weakSelf = self; + if (self.actionMenu) { + [self.actionMenu dismiss:NO]; + } + self.actionMenu = [[CustomAlert alloc] initWithTitle:nil message:alertMsg style:CustomAlertStyleAlert]; + self.actionMenu.cancelButtonIndex = [self.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) { + weakSelf.actionMenu = nil; + }]; + [self.actionMenu showInViewController:self]; return NO; } return YES; } - (void)textFieldDidEndEditing:(UITextField *)textField { - if (textField == self.roomNameTextField) { - self.roomNameTextField.borderStyle = UITextBorderStyleNone; - self.roomNameTextField.backgroundColor = [UIColor clearColor]; + if (textField == _roomTitleView.displayNameTextField) { + textField.backgroundColor = [UIColor clearColor]; - NSString *roomName = self.roomNameTextField.text; - if ([roomName isEqualToString:self.mxRoom.state.name] == NO) { + NSString *roomName = textField.text; + if ((roomName.length || self.mxRoom.state.name.length) && [roomName isEqualToString:self.mxRoom.state.name] == NO) { [self startActivityIndicator]; __weak typeof(self) weakSelf = self; [self.mxRoom setName:roomName success:^{ [weakSelf stopActivityIndicator]; - // Refresh title with room displayName - weakSelf.roomNameTextField.text = weakSelf.mxRoom.state.displayname; + // Refresh title display + textField.text = weakSelf.mxRoom.state.displayname; } failure:^(NSError *error) { [weakSelf stopActivityIndicator]; // Revert change - weakSelf.roomNameTextField.text = weakSelf.mxRoom.state.displayname; + textField.text = weakSelf.mxRoom.state.displayname; NSLog(@"Rename room failed: %@", error); //Alert user [[AppDelegate theDelegate] showErrorAsAlert:error]; }]; } else { // No change on room name, restore title with room displayName - self.roomNameTextField.text = self.mxRoom.state.displayname; + textField.text = self.mxRoom.state.displayname; + } + } else if (textField == _roomTitleView.topicTextField) { + textField.backgroundColor = [UIColor clearColor]; + + NSString *topic = textField.text; + if ((topic.length || self.mxRoom.state.topic.length) && [topic isEqualToString:self.mxRoom.state.topic] == NO) { + [self startActivityIndicator]; + __weak typeof(self) weakSelf = self; + [self.mxRoom setTopic:topic success:^{ + [weakSelf stopActivityIndicator]; + // Hide topic field if empty + weakSelf.roomTitleView.hiddenTopic = !textField.text.length; + } failure:^(NSError *error) { + [weakSelf stopActivityIndicator]; + // Revert change + textField.text = weakSelf.mxRoom.state.topic; + // Hide topic field if empty + weakSelf.roomTitleView.hiddenTopic = !textField.text.length; + NSLog(@"Topic room change failed: %@", error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } else { + // Hide topic field if empty + _roomTitleView.hiddenTopic = !topic.length; } } } - (BOOL)textFieldShouldReturn:(UITextField*) textField { - // "Done" key has been pressed - [textField resignFirstResponder]; + if (textField == _roomTitleView.displayNameTextField) { + // "Next" key has been pressed + [_roomTitleView.topicTextField becomeFirstResponder]; + } else { + // "Done" key has been pressed + [textField resignFirstResponder]; + } return YES; }