From 3788c5e9c7b7949dbc5bd26fd7ae433c24298ea4 Mon Sep 17 00:00:00 2001 From: giomfo Date: Fri, 6 Jan 2017 15:09:18 +0100 Subject: [PATCH] Enhancement - Improve the people invite screens. #904 - MXKContactManager: List the local contacts with methods (instead of handling only the emails). - ContactTableViewCell: Highlight the Matrix-enabled contacts in local contacts section. --- Vector.xcodeproj/project.pbxproj | 17 +- Vector/Assets/Images/riot_icon.png | Bin 0 -> 795 bytes Vector/Assets/Images/riot_icon@2x.png | Bin 0 -> 1850 bytes Vector/Assets/Images/riot_icon@3x.png | Bin 0 -> 2790 bytes .../ContactDetailsViewController.m | 19 +- .../ContactPickerViewController.m | 23 +- .../RoomParticipantsViewController.h | 2 - .../RoomParticipantsViewController.m | 232 ++++++++++-------- .../ViewController/StartChatViewController.m | 38 +-- Vector/Views/Contact/ContactTableViewCell.h | 20 +- Vector/Views/Contact/ContactTableViewCell.m | 125 +++++++--- Vector/Views/Contact/ContactTableViewCell.xib | 24 +- 12 files changed, 309 insertions(+), 191 deletions(-) create mode 100755 Vector/Assets/Images/riot_icon.png create mode 100755 Vector/Assets/Images/riot_icon@2x.png create mode 100755 Vector/Assets/Images/riot_icon@3x.png diff --git a/Vector.xcodeproj/project.pbxproj b/Vector.xcodeproj/project.pbxproj index 5a6ffd236..53a337150 100644 --- a/Vector.xcodeproj/project.pbxproj +++ b/Vector.xcodeproj/project.pbxproj @@ -210,6 +210,9 @@ F047DBB51C576F2200952DA2 /* AuthenticationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F047DBB41C576F2200952DA2 /* AuthenticationViewController.xib */; }; F047DBB91C576F6600952DA2 /* AuthInputsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F047DBB71C576F6600952DA2 /* AuthInputsView.m */; }; F047DBBA1C576F6600952DA2 /* AuthInputsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F047DBB81C576F6600952DA2 /* AuthInputsView.xib */; }; + F04ACE031E154C540000B970 /* riot_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = F04ACE001E154C540000B970 /* riot_icon.png */; }; + F04ACE041E154C540000B970 /* riot_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F04ACE011E154C540000B970 /* riot_icon@2x.png */; }; + F04ACE051E154C540000B970 /* riot_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F04ACE021E154C540000B970 /* riot_icon@3x.png */; }; F056417B1C7C9FD7002276ED /* TableViewCellWithButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F05641791C7C9FD7002276ED /* TableViewCellWithButton.m */; }; F056417C1C7C9FD7002276ED /* TableViewCellWithButton.xib in Resources */ = {isa = PBXBuildFile; fileRef = F056417A1C7C9FD7002276ED /* TableViewCellWithButton.xib */; }; F05895001B8B7E6600B73E85 /* RoomBubbleCellData.m in Sources */ = {isa = PBXBuildFile; fileRef = F05894FF1B8B7E6600B73E85 /* RoomBubbleCellData.m */; }; @@ -642,6 +645,9 @@ F047DBB61C576F6600952DA2 /* AuthInputsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthInputsView.h; sourceTree = ""; }; F047DBB71C576F6600952DA2 /* AuthInputsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AuthInputsView.m; sourceTree = ""; }; F047DBB81C576F6600952DA2 /* AuthInputsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AuthInputsView.xib; sourceTree = ""; }; + F04ACE001E154C540000B970 /* riot_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = riot_icon.png; sourceTree = ""; }; + F04ACE011E154C540000B970 /* riot_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "riot_icon@2x.png"; sourceTree = ""; }; + F04ACE021E154C540000B970 /* riot_icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "riot_icon@3x.png"; sourceTree = ""; }; F05641781C7C9FD7002276ED /* TableViewCellWithButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithButton.h; path = TableViewCell/TableViewCellWithButton.h; sourceTree = ""; }; F05641791C7C9FD7002276ED /* TableViewCellWithButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithButton.m; path = TableViewCell/TableViewCellWithButton.m; sourceTree = ""; }; F056417A1C7C9FD7002276ED /* TableViewCellWithButton.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithButton.xib; path = TableViewCell/TableViewCellWithButton.xib; sourceTree = ""; }; @@ -1138,6 +1144,9 @@ F03BF5B41D8BF5B1002EF6A7 /* Images */ = { isa = PBXGroup; children = ( + F04ACE001E154C540000B970 /* riot_icon.png */, + F04ACE011E154C540000B970 /* riot_icon@2x.png */, + F04ACE021E154C540000B970 /* riot_icon@3x.png */, F0A4B2EB1E0073A30072D355 /* animatedLogo-0.png */, F0A4B2EC1E0073A30072D355 /* animatedLogo-1.png */, F0A4B2ED1E0073A30072D355 /* animatedLogo-2.png */, @@ -1747,7 +1756,6 @@ }; F094A9BD1B78D8F000B1FBBF = { CreatedOnToolsVersion = 6.2; - DevelopmentTeam = 884E442RN2; TestTargetID = F094A9A11B78D8F000B1FBBF; }; }; @@ -1815,6 +1823,7 @@ F0A4B2F11E0073A30072D355 /* animatedLogo-1.png in Resources */, F03BF6B41D8BF5B1002EF6A7 /* priorityLow@2x.png in Resources */, F08294691DB503FE00CEAB63 /* direct_icon@2x.png in Resources */, + F04ACE041E154C540000B970 /* riot_icon@2x.png in Resources */, F09EAFA01DD2109B009C7EFB /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.xib in Resources */, F09EAF0B1DCCEE1D009C7EFB /* e2e_verified@3x.png in Resources */, F03BF6971D8BF5B1002EF6A7 /* leave@3x.png in Resources */, @@ -1942,6 +1951,7 @@ F09EAFA61DD2109B009C7EFB /* RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib in Resources */, 325F6A431C21D20F00C12F51 /* DirectoryRecentTableViewCell.xib in Resources */, F03BF68C1D8BF5B1002EF6A7 /* favouriteOff.png in Resources */, + F04ACE031E154C540000B970 /* riot_icon.png in Resources */, F003AA7C1C68A1F6008B430C /* ExpandedRoomTitleView.xib in Resources */, F03BF6751D8BF5B1002EF6A7 /* camera_switch@3x.png in Resources */, F03BF6D01D8BF5B1002EF6A7 /* shrink_icon@3x.png in Resources */, @@ -2006,6 +2016,7 @@ F0CC4DCB1C4E594C003BBE45 /* MediaAlbumContentViewController.xib in Resources */, F0C34B721C15CA2E00C36F09 /* RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib in Resources */, F022285E1C64E356000AF23C /* RoomViewController.xib in Resources */, + F04ACE051E154C540000B970 /* riot_icon@3x.png in Resources */, F03BF6BF1D8BF5B1002EF6A7 /* search_bg.png in Resources */, F03BF69B1D8BF5B1002EF6A7 /* main_alias_icon.png in Resources */, F0A4B2F31E0073A30072D355 /* animatedLogo-3.png in Resources */, @@ -2400,7 +2411,7 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - DEVELOPMENT_TEAM = 884E442RN2; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -2421,7 +2432,7 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - DEVELOPMENT_TEAM = 884E442RN2; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", diff --git a/Vector/Assets/Images/riot_icon.png b/Vector/Assets/Images/riot_icon.png new file mode 100755 index 0000000000000000000000000000000000000000..373a12638a5dfe3163f8b55f26dbaf8a1b4a8613 GIT binary patch literal 795 zcmV+$1LXXPP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2jC1H z4>v7imuMXT000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0007ZNkl1v9*|#2bY3o|on3y3##6%b{5FwG6xc&g9n2;tyf|waFlco|9F;JI( zAQ6{=NDN4&sM`s3s@?nSz1PKnLmfTZA#1YMx8C(VdGqDXf`5I9=8L0yPOb2T?Zx^v za(*mlZd*vQpwf`Nac(#>`Gee*myz=N$#r|p_mgGhEqcu4aBu zR;{FZYmm@ss`%_%Lf$c#;pfsXQq8289==sZ0UiUwLmD_UH=?(kFCY>RGb(R@n z1-Yr4_is|nhx#wkdCG^iP9D~l0WYRBLx53JAFW1XJDl`;fZ-;&0$e(>y=V56fdU*b zWZ#$9fb)QDda@Ka)B1Dx4rrVkn?HB+gas}Dwe`-d9(+5Vnqz(L>AY<~a%002ovPDHLkV1n6qW3>PP literal 0 HcmV?d00001 diff --git a/Vector/Assets/Images/riot_icon@2x.png b/Vector/Assets/Images/riot_icon@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..84691d7b42b9aec460da5a51b7618199a80c3123 GIT binary patch literal 1850 zcmV-A2gUe_P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2jC1H z4>ue#NoXek000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000J+NklG2+)c)O#vYR52T_ff)=TYd4Lyq00dGC zg%C`l6q=O6161l8Y7weLd1z25qJ2puP|8OIqNzei>U=qly_;RH@9zD+GdwtH2yyJq z)&U;!mqxnM+%xl=Idje&4cyW#{ck0f`{A*#J=K>r!!HQ*m*`}-V+bk6@|c@TnCo4T zi<)VT4wcsDfxm({1o}{Bn8zOfz{By10Y3J{eI+#)@6=)Tbuw-Kd!H2bUA?4$H?%q*b5x_?u-t!fF^%R*l7V9_rZH7O)9&5C)$iM%jq}^D*?K$Do)XTsRR~*L<6=`9xMq$a zr$nX|=luqTG#DuiaNcjwiaY;A$*p^~?x^?VV!1X~UvhP(WaRcWY#JKn-Tha$jeR3j zbN$3w!U=C0KaCkHtwLP_9VrY@Fr5t;YS*{__%o*`7t77Xnx2V9bSGOJaKOa7O%wXp z2Bj$^C9A+_u}UNIm#NRR**1Ybru_!fL6h6uA?D%^ zji}9FuEfR2Bh`w6=}0dL?gM^u6&HhdI@rrBWEAodg6~OrlcGwrfZs zF~k*zBr2usxQw`iobqPz(};@g(u~^-QNj?CD2;JV2QLZk>TL(Rlp!Rm3l)lH?sE3Q zO9EzsIR>3Ra)w2aMYv{;G*T$7v7||&GfZg$4Bu2hguoOAmb@~YV^|0v(+VjhN^1lH ztu>k}-(ulx8!HC5SmMl7#!NUzBlbXn4l_cTVp%4Rw1~2Vvf~n~6hj(FAxSUoUZyjE zxfKBvivSwJpkf#CYi;U(m?b&tp@R%zO8Pcbn7S_^TO;W!7C76flQ(Q6f>uQ>Tj7v5Q=I;UuN=f*_3u(ulI{(oRDxX<`Y3 zP8uQL)fERcr9q-HCg*4P$AP1GC!1)cuf48YDN`?;;LPc1`t1UF!=@It7_f^3Swy1J zDd2Z24p^~^tS_x%Br7A&EnS1AUW`66&!8?c8@AAB`s@OYs15KcS{z-`C_dY%zm@Zn zDW5dXSgz{v|JGn~=uO1EeT=%pT#P)tBxouvzPI<@@z#m}n!;dJzCxm|07V6XF9gdV zqLrq7WR|f_RgywVJ)BQLJ$?La{_k(6VEvC8Pg1sB@`i;eC8m_*M~cX@-IcxaQqH}2 zg45@x<4mh3w2(jeQE4qw~IK@5v8+`4bc3rU3%@X~blE zhBHZ>_^v#ZyLO19;hTArv6~8*X@#FgXZ$pNFfNOa%eA>jfM%DM(g%UPk8GQ;ZW`bv zbwD59vt|4h^}6>o@N*#T(ssKrc;IFOzNIG)O!!*J-N4~4O>)5AM<1AY|9=G#VE=(# zbzpCot_IkE=Kh`mwZ3skr8o@i2K;X7UEpKA0>&DR!9x888ht4^7OpxC5MKVctS1jn zq*}>mfkWL!b+3SbnU8()ri~*lj?YhVymbzVpk(ElPXd595ZCV1{)4+3z*m72T?F-? zdIdb_r9myoV%E7sRO}M{w#zzqm{eu7;!X?rt&xe~IulO4kZF^iT)u$199M}S6m(J&N oMryzK{g=L#+<{907*qoM6N<$f*-GHkpKVy literal 0 HcmV?d00001 diff --git a/Vector/Assets/Images/riot_icon@3x.png b/Vector/Assets/Images/riot_icon@3x.png new file mode 100755 index 0000000000000000000000000000000000000000..d84b0b5f2c6cbc82638dbf51147a45db71eb090a GIT binary patch literal 2790 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2jC1H z4>tq9L1oea000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000U>Nkl-@UMiMJ!?wi&(f2om_NrcC)d{-Te(&2ri}^^b?_qgo;>UqrRaBk$if(0-qN`=yf$g7A%>{pLAQuJ(v52llH@Pz2W7GuY=2v?V>15upqT zqUhkiBj8U$h;QHW<|`gX2zgux-}v#{-xlq2AD3RF9BuB<*(b2_qEp+J9mojBcd7Vw z3SI?23Y!CxXHk{wHof_ZXJ1po*Is+4-doL0%SzbO?lq&AuBPYA%u(m5Ld8^d3`J{l zlu-1lOw|jxp$8BN#H}xlnP0y5l1swZgz)v(-g*;L{#WKCyidpY#L~9so2pLQh|_B% zh-oGg$hk!(ojei=f=BBX7k&NAE1j+r{`|*ods*)DR?qbYqt~s$7>WJQaVaHU6yQZZ zRo`tA15!qu(O3pc)v5Y*{$1HiC_{wcDMhWnCwtb$S|^0Hb|=b8u(XpK*agABs&rd( zLm5%>9dh*&CC{PkIgG?I4B2T;NsY3-GDRcw&kh6YR~K*IyuK6jZkwj0Al~l0G9rzENe|nP#FkgByA*OAN3oIn2wY2|^jIJ9(*l18{5i zeE9NBRmx#}t~byx8bUd_y~~7vl-@LDQ`KpNK07LVsD~aIGs*JAAVsgn&dL-L0wU#& zo6f%Cg|28=9k%je*_jhzAz;nvtI-q25zIKC5e8KJ8hNiu(Q_zyHAZ6@2JIB9Q=@Dx zO)%4_U~49WR*C^TMXp}bP^0ex=gwtKO52M+D>*jTG9`Wbz!Av;=!#B{5o0vo&zkgd zM(jR>fbrTiS84A8 zL*Ts4;`zePHq%jpAv?`*te1ptv!k+yoLj_Hbq1^+mc}#es^*xijhpc?56D1Naz+TlEVmK zd{(P{W&%q!D0G@QKf9|rrW<93tTZV-PTs3f z@*Of}4++hp64VKzkeFuduf5lF$E4?hv=OJzO#GKA3*69SuUlkSHOFabi#{{Sgfm02 zQDw+VlQb;yUWHoFAY+1|Y7l@I1(-@J1Dv?v2%D-w+DN?0NE}5`m~f^kc@6_sikNOv z3*1?gZ!XcF-7gSQ3nf3A%Gw<6J` z%dFL+CUwN?m(X};nsH?sfPS;-mZjO0)}zM&i4(Y}LP1xw)|e#Px?qAI?u2Fix>S5SUGi;|BRC zYc=bK$BpowdVy*8(EYMAKHagrSAMgNaH&Dgs$wV_D-%NmQN%0G^#0QH=IlE!sUA1N zRo^|_m)&~D^1?>Q_~xzHS1n~#atW%Uu)REq9|Z{H)Bk$K`a##amPbOrm7>>7zUo+h z)M6)vj%CYNTzdZ=VZF;>+}TH^`A`drj4thJoAzkiJ5{`T{L8HFXQvRfs*DaW`RGm> z%T+490YD8QF3hgIdRJE)@$F!Hd8(Cr4|yP`#t8rEbgtzvB7fg5^pBlT6{=W&%Ud=) z(Ro$a1=yNFOfy?Y;=M}{#{6y-gtPZ%t5PUe0^vMG zec*HJzI^q9Ck$}MgEv2k5t7@o7iSX-o-jbnCX3)7^WBZs>f*xx3&PoZvtAUk z0dVJ+o#i=QBYf~4K>pVUa-xF|8NdF!>=q%pXlTqnM&lXMMjR(-FjX($1P#(g zf{}PX5=qW20Yqvje%+4zuRW9<1M%rj%63BKfjL-1`}pEt?*4_4T%IwLEQ=2!MDsmR zBlIve154475_UT|@{J0>U7OZkIj1~%{krVENG@vM)wt)5hq9Mq94-2eap07*qoM6N<$f=0$tXaE2J literal 0 HcmV?d00001 diff --git a/Vector/ViewController/ContactDetailsViewController.m b/Vector/ViewController/ContactDetailsViewController.m index 96ffa13dd..2e6b3a5ae 100644 --- a/Vector/ViewController/ContactDetailsViewController.m +++ b/Vector/ViewController/ContactDetailsViewController.m @@ -562,7 +562,7 @@ directChatsIndex = sectionCount++; } // Else check whether the contact has been instantiated with an email or a matrix id - else if ([MXTools isEmailAddress:_contact.displayName]) + else if ((!_contact.isMatrixContact && _contact.emailAddresses.count) || [MXTools isEmailAddress:_contact.displayName]) { directChatsIndex = sectionCount++; } @@ -878,7 +878,20 @@ // Prepare the invited participant data NSArray *inviteArray; NSArray *invite3PIDArray; - NSString *participantId = _contact.displayName; + NSString *participantId; + + if (_contact.emailAddresses.count) + { + // This is a local contact, consider the first email by default. + // TODO: Prompt the user to select the right email. + MXKEmail *email = _contact.emailAddresses.firstObject; + participantId = email.emailAddress; + } + else + { + // This is the text filled by the user. + participantId = _contact.displayName; + } // Is it an email or a Matrix user ID? if ([MXTools isEmailAddress:participantId]) @@ -908,7 +921,7 @@ invite3PIDArray = @[invite3PID]; } - else + else //if ([MXTools isMatrixUserIdentifier:participantId]) { inviteArray = @[participantId]; } diff --git a/Vector/ViewController/ContactPickerViewController.m b/Vector/ViewController/ContactPickerViewController.m index 987ca922b..e9c54a2eb 100644 --- a/Vector/ViewController/ContactPickerViewController.m +++ b/Vector/ViewController/ContactPickerViewController.m @@ -152,18 +152,18 @@ - (void)refreshContactsList { - // Retrieve all known matrix users + // Retrieve all the known matrix users NSArray *contacts = [NSArray arrayWithArray:[MXKContactManager sharedManager].matrixContacts]; - // Retrieve all known email addresses from local contacts - NSArray *localEmailContacts = [MXKContactManager sharedManager].localEmailContacts; + // Retrieve all the local contacts with methods + NSArray *localContactsWithMethods = [MXKContactManager sharedManager].localContactsWithMethods; - matrixContacts = [NSMutableArray arrayWithCapacity:(contacts.count + localEmailContacts.count)]; + matrixContacts = [NSMutableArray arrayWithCapacity:(contacts.count + localContactsWithMethods.count)]; // Add first email contacts - if (localEmailContacts.count) + if (localContactsWithMethods.count) { - [matrixContacts addObjectsFromArray:localEmailContacts]; + [matrixContacts addObjectsFromArray:localContactsWithMethods]; } if (contacts.count) @@ -330,16 +330,9 @@ } // Disambiguate the display name when it appears several times. - if (contact.displayName && [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)]) + if (contact.displayName) { - NSArray *identifiers = contact.matrixIdentifiers; - if (identifiers.count) - { - NSString *participantId = identifiers.firstObject; - NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, participantId]; - - contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId]; - } + participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)]; } [participantCell render:contact]; diff --git a/Vector/ViewController/RoomParticipantsViewController.h b/Vector/ViewController/RoomParticipantsViewController.h index 775dad6d3..b7775c055 100644 --- a/Vector/ViewController/RoomParticipantsViewController.h +++ b/Vector/ViewController/RoomParticipantsViewController.h @@ -16,8 +16,6 @@ #import -#import "ContactTableViewCell.h" - #import "SegmentedViewController.h" @class Contact; diff --git a/Vector/ViewController/RoomParticipantsViewController.m b/Vector/ViewController/RoomParticipantsViewController.m index 438e452fe..ec4428971 100644 --- a/Vector/ViewController/RoomParticipantsViewController.m +++ b/Vector/ViewController/RoomParticipantsViewController.m @@ -30,6 +30,8 @@ #import "MXCallManager.h" +#import "ContactTableViewCell.h" + @interface RoomParticipantsViewController () { // Search session @@ -67,6 +69,9 @@ // Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar. id kAppDelegateDidTapStatusBarNotificationObserver; + + // Observe kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification to refresh the search result on new matrix enabled contact. + id kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver; } @end @@ -418,6 +423,21 @@ { _isAddParticipantSearchBarEditing = isAddParticipantsSearchBarEditing; + if (isAddParticipantsSearchBarEditing) + { + kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + + // Refresh search result display. + [self.tableView reloadData]; + + }]; + } + else if (kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver]; + kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver = nil; + } + // Switch the display between search result and participants list [self.tableView reloadData]; } @@ -925,6 +945,8 @@ participantCell.userInteractionEnabled = YES; participantCell.thumbnailBadgeView.hidden = YES; + + participantCell.showMatrixIdInDisplayName = NO; } participantCell.mxRoom = self.mxRoom; @@ -932,7 +954,7 @@ MXKContact *mxkContact; Contact* contact; - // oneself dedicated cell + // Oneself dedicated cell if ((indexPath.section == participantsSection && userContact && indexPath.row == 0) && !_isAddParticipantSearchBarEditing) { contact = userContact; @@ -954,6 +976,7 @@ mxkContact = invitableAddressBookContacts[indexPath.row]; participantCell.selectionStyle = UITableViewCellSelectionStyleDefault; + participantCell.showMatrixIdInDisplayName = YES; } } else if (indexPath.section == invitableSectionMatrixContacts) @@ -963,21 +986,7 @@ mxkContact = invitableMatrixContacts[indexPath.row]; participantCell.selectionStyle = UITableViewCellSelectionStyleDefault; - - // Append the matrix identifier (if any) to the display name. - NSArray *identifiers = mxkContact.matrixIdentifiers; - if (identifiers.count) - { - NSString *participantId = identifiers.firstObject; - - // Check whether the display name is not already the matrix id - if (![mxkContact.displayName isEqualToString:participantId]) - { - NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", mxkContact.displayName, participantId]; - - mxkContact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId]; - } - } + participantCell.showMatrixIdInDisplayName = YES; } } else @@ -1016,40 +1025,14 @@ if (index < participants.count) { contact = participants[index]; - - // Sanity check - if (contact && contact.mxMember.userId) - { - // Disambiguate the display name when it appears several times. - NSString *disambiguatedDisplayName; - - if (self.isAddParticipantSearchBarEditing) - { - // Consider here the dictionary which lists all the display names of the search result. - if ([isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)]) - { - disambiguatedDisplayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, contact.mxMember.userId]; - } - } - else - { - // Update the display name by considering the current room state. - disambiguatedDisplayName = [self.mxRoom.state memberName:contact.mxMember.userId]; - if ([disambiguatedDisplayName isEqualToString:contact.displayName]) - { - disambiguatedDisplayName = nil; - } - } - - if (disambiguatedDisplayName) - { - MXRoomMember* mxMember = contact.mxMember; - contact = [[Contact alloc] initMatrixContactWithDisplayName:disambiguatedDisplayName andMatrixID:mxMember.userId]; - contact.mxMember = mxMember; - } - } - mxkContact = contact; + + // Disambiguate the display name when it appears several times in the search result. + if (self.isAddParticipantSearchBarEditing && contact.mxMember.userId) + { + // Consider here the dictionary which lists all the display names of the search result. + participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)]; + } } participantCell.selectionStyle = UITableViewCellSelectionStyleNone; @@ -1094,6 +1077,12 @@ participantCell.thumbnailBadgeView.image = [UIImage imageNamed:@"mod_icon"]; participantCell.thumbnailBadgeView.hidden = NO; } + + // When no search is in progress, update the contact display name by considering the current room state. + if (!self.isAddParticipantSearchBarEditing && contact.mxMember.userId) + { + participantCell.contactDisplayNameLabel.text = [self.mxRoom.state memberName:contact.mxMember.userId]; + } } } @@ -1484,9 +1473,11 @@ strongSelf->currentAlert = nil; NSArray *identifiers = contact.matrixIdentifiers; + NSString *participantId; + if (identifiers.count) { - NSString *participantId = identifiers.firstObject; + participantId = identifiers.firstObject; // Invite this user if a room is defined [strongSelf addPendingActionMask]; @@ -1510,8 +1501,18 @@ } else { - // This is the text entered by the user, or a local email contact - NSString *participantId = contact.displayName; + if (contact.emailAddresses.count) + { + // This is a local contact, consider the first email by default. + // TODO: Prompt the user to select the right email. + MXKEmail *email = contact.emailAddresses.firstObject; + participantId = email.emailAddress; + } + else + { + // This is the text filled by the user. + participantId = contact.displayName; + } // Is it an email or a Matrix user ID? if ([MXTools isEmailAddress:participantId]) @@ -1535,7 +1536,7 @@ [[AppDelegate theDelegate] showErrorAsAlert:error]; }]; } - else + else //if ([MXTools isMatrixUserIdentifier:participantId]) { [strongSelf addPendingActionMask]; [strongSelf.mxRoom inviteUser:participantId success:^{ @@ -1646,31 +1647,22 @@ - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { // Update search results. - NSMutableArray *addressBookContacts; - NSMutableArray *matrixContacts; - NSMutableArray *participantsArray; - NSMutableArray *invitedParticipantsArray; + NSUInteger index; + MXKContact *contact; searchText = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - if (currentSearchText.length && [searchText hasPrefix:currentSearchText]) + if (!currentSearchText.length || [searchText hasPrefix:currentSearchText] == NO) { - addressBookContacts = invitableAddressBookContacts; - matrixContacts = invitableMatrixContacts; - participantsArray = filteredActualParticipants; - invitedParticipantsArray = filteredInvitedParticipants; - } - else - { - // Retrieve all known email addresses from local contacts - addressBookContacts = [NSMutableArray arrayWithArray:[MXKContactManager sharedManager].localEmailContacts]; + // Retrieve all the local contacts with emails + invitableAddressBookContacts = [NSMutableArray arrayWithArray:[MXKContactManager sharedManager].localContactsWithMethods]; // Retrieve all known matrix users NSArray *allMatrixContacts = [MXKContactManager sharedManager].matrixContacts; - matrixContacts = [NSMutableArray arrayWithCapacity:allMatrixContacts.count]; + invitableMatrixContacts = [NSMutableArray arrayWithCapacity:allMatrixContacts.count]; // Matrix ids: split contacts with several ids, and remove the current participants. - for (MXKContact* contact in allMatrixContacts) + for (contact in allMatrixContacts) { NSArray *identifiers = contact.matrixIdentifiers; if (identifiers.count > 1) @@ -1680,7 +1672,7 @@ if ([contactsById objectForKey:userId] == nil) { MXKContact *splitContact = [[MXKContact alloc] initMatrixContactWithDisplayName:contact.displayName andMatrixID:userId]; - [matrixContacts addObject:splitContact]; + [invitableMatrixContacts addObject:splitContact]; } } } @@ -1689,14 +1681,14 @@ NSString *userId = identifiers.firstObject; if ([contactsById objectForKey:userId] == nil) { - [matrixContacts addObject:contact]; + [invitableMatrixContacts addObject:contact]; } } } // Copy participants and invited participants - participantsArray = [actualParticipants copy]; - invitedParticipantsArray = [invitedParticipants copy]; + filteredActualParticipants = [NSMutableArray arrayWithArray:actualParticipants]; + filteredInvitedParticipants = [NSMutableArray arrayWithArray:invitedParticipants]; } currentSearchText = searchText; @@ -1707,64 +1699,94 @@ isMultiUseNameByDisplayName = [NSMutableDictionary dictionary]; // Update invitable contacts list: - invitableAddressBookContacts = [NSMutableArray array]; - invitableMatrixContacts = [NSMutableArray array]; - if (currentSearchText.length) { - for (MXKContact* contact in addressBookContacts) + for (index = 0; index < invitableAddressBookContacts.count;) { - if ([contact hasPrefix:currentSearchText]) + contact = invitableAddressBookContacts[index]; + + if (![contact hasPrefix:currentSearchText]) + { + [invitableAddressBookContacts removeObjectAtIndex:index]; + } + else { // Ignore the contact if it corresponds to the search input - if (!isValidInput || [contact.displayName isEqualToString:currentSearchText] == NO) + if (isValidInput && [contact.displayName isEqualToString:currentSearchText]) { - [invitableAddressBookContacts addObject:contact]; + [invitableAddressBookContacts removeObjectAtIndex:index]; + } + else + { + index++; } } } - for (MXKContact* contact in matrixContacts) + for (index = 0; index < invitableMatrixContacts.count;) { - if ([contact hasPrefix:currentSearchText]) + contact = invitableMatrixContacts[index]; + + if (![contact hasPrefix:currentSearchText]) + { + [invitableMatrixContacts removeObjectAtIndex:index]; + } + else { // Ignore the contact if it corresponds to the search input - if (!isValidInput || [contact.displayName isEqualToString:currentSearchText] == NO) + if (isValidInput && [contact.displayName isEqualToString:currentSearchText]) + { + [invitableMatrixContacts removeObjectAtIndex:index]; + } + else { - [invitableMatrixContacts addObject:contact]; - isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO)); + index++; } } } + // Sort the refreshed lists of the invitable contacts [self sortAlphabeticallyInvitableContacts:invitableAddressBookContacts]; [self sortInvitableMatrixContacts]; - } - - // Update filtered participants list - filteredActualParticipants = [NSMutableArray array]; - for (Contact *contact in participantsArray) - { - if ([contact matchedWithPatterns:@[currentSearchText]]) + + // Update filtered participants list + for (index = 0; index < filteredActualParticipants.count;) { - [filteredActualParticipants addObject:contact]; - - isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO)); + contact = filteredActualParticipants[index]; + if (![contact matchedWithPatterns:@[currentSearchText]]) + { + [filteredActualParticipants removeObjectAtIndex:index]; + } + else + { + isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO)); + index++; + } + } + + // Update filtered invited participants list + for (index = 0; index < filteredInvitedParticipants.count;) + { + contact = filteredInvitedParticipants[index]; + if (![contact matchedWithPatterns:@[currentSearchText]]) + { + [filteredInvitedParticipants removeObjectAtIndex:index]; + } + else + { + isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO)); + index++; + } } } - - // Update filtered invited participants list - filteredInvitedParticipants = [NSMutableArray array]; - for (Contact *contact in invitedParticipantsArray) + else { - if ([contact matchedWithPatterns:@[currentSearchText]]) - { - [filteredInvitedParticipants addObject:contact]; - - isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO)); - } + invitableAddressBookContacts = nil; + invitableMatrixContacts = nil; + filteredActualParticipants = nil; + filteredInvitedParticipants = nil; } // Refresh display diff --git a/Vector/ViewController/StartChatViewController.m b/Vector/ViewController/StartChatViewController.m index da4fc3711..3e99995cd 100644 --- a/Vector/ViewController/StartChatViewController.m +++ b/Vector/ViewController/StartChatViewController.m @@ -421,16 +421,9 @@ contact = participants[index]; // Disambiguate the display name when it appears several times. - if (contact.displayName && [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)]) + if (contact.displayName) { - NSArray *identifiers = contact.matrixIdentifiers; - if (identifiers.count) - { - NSString *participantId = identifiers.firstObject; - NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, participantId]; - - contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId]; - } + participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)]; } } } @@ -454,9 +447,7 @@ // Check whether the display name is not already the matrix id if (![contact.displayName isEqualToString:participantId]) { - NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, participantId]; - - contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId]; + participantCell.showMatrixIdInDisplayName = YES; } } } @@ -600,8 +591,21 @@ } else { - // This is a text entered by the user, or a local email contact - NSString *participantId = contact.displayName; + // This is a text entered by the user, or a local contact + NSString *participantId; + + if (contact.emailAddresses.count) + { + // This is a local contact, consider the first email by default. + // TODO: Prompt the user to select the right email. + MXKEmail *email = contact.emailAddresses.firstObject; + participantId = email.emailAddress; + } + else + { + // This is the text filled by the user. + participantId = contact.displayName; + } // Is it an email or a Matrix user ID? if ([MXTools isEmailAddress:participantId]) @@ -756,12 +760,12 @@ NSArray *matrixContacts = [NSMutableArray arrayWithArray:[MXKContactManager sharedManager].matrixContacts]; // Retrieve all known email addresses from local contacts - NSArray *localEmailContacts = [MXKContactManager sharedManager].localEmailContacts; + NSArray *localContactsWithMethods = [MXKContactManager sharedManager].localContactsWithMethods; - searchProcessingContacts = [NSMutableArray arrayWithCapacity:(matrixContacts.count + localEmailContacts.count)]; + searchProcessingContacts = [NSMutableArray arrayWithCapacity:(matrixContacts.count + localContactsWithMethods.count)]; // Add first email contacts - for (MXKContact* contact in localEmailContacts) + for (MXKContact* contact in localContactsWithMethods) { // Remove the current emails listed in participants. if ([participantsById objectForKey:contact.displayName] == nil) diff --git a/Vector/Views/Contact/ContactTableViewCell.h b/Vector/Views/Contact/ContactTableViewCell.h index 7f5281098..32a7ff69c 100644 --- a/Vector/Views/Contact/ContactTableViewCell.h +++ b/Vector/Views/Contact/ContactTableViewCell.h @@ -14,21 +14,24 @@ limitations under the License. */ -#import - -#import "MXKTableViewCell.h" -#import "MXKCellRendering.h" -#import "MXKImageView.h" +#import /** 'ContactTableCell' extends MXKTableViewCell. */ @interface ContactTableViewCell : MXKTableViewCell +{ +@protected + /** + The current displayed contact. + */ + MXKContact *contact; +} @property (nonatomic) IBOutlet MXKImageView *thumbnailView; @property (nonatomic) IBOutlet UIImageView *thumbnailBadgeView; @property (nonatomic) IBOutlet UILabel *contactDisplayNameLabel; -@property (nonatomic) IBOutlet UILabel *lastPresenceLabel; +@property (nonatomic) IBOutlet UILabel *contactInformationLabel; @property (nonatomic) IBOutlet UIView *customAccessoryView; @property (nonatomic) BOOL showCustomAccessoryView; @@ -36,6 +39,11 @@ @property (weak, nonatomic) IBOutlet NSLayoutConstraint *customAccessViewWidthConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *customAccessoryViewLeadingConstraint; +/** + Tell whether the matrix id should be added in the contact display name (NO by default) + */ +@property (nonatomic) BOOL showMatrixIdInDisplayName; + // The room where the contact is. // It is used to display the member information (like invitation) // This property is OPTIONAL. diff --git a/Vector/Views/Contact/ContactTableViewCell.m b/Vector/Views/Contact/ContactTableViewCell.m index 8d1dac972..760dcd4b7 100644 --- a/Vector/Views/Contact/ContactTableViewCell.m +++ b/Vector/Views/Contact/ContactTableViewCell.m @@ -23,13 +23,8 @@ #import "AvatarGenerator.h" #import "Tools.h" -#import "MXKContactManager.h" - @interface ContactTableViewCell() { - // The current displayed contact. - MXKContact *contact; - /** The observer of the presence for matrix user. */ @@ -45,7 +40,10 @@ [super awakeFromNib]; // apply the vector colours - self.lastPresenceLabel.textColor = kVectorTextColorGray; + self.contactInformationLabel.textColor = kVectorTextColorGray; + + // Clear the default background color of a MXKImageView instance + self.thumbnailView.backgroundColor = [UIColor clearColor]; } - (void)layoutSubviews @@ -73,6 +71,16 @@ } } +- (void)setShowMatrixIdInDisplayName:(BOOL)showMatrixIdInDisplayName +{ + _showMatrixIdInDisplayName = showMatrixIdInDisplayName; + + if (contact) + { + [self refreshContactDisplayName]; + } +} + #pragma mark - MXKCellRendering // returns the first matrix id of the contact @@ -100,9 +108,6 @@ mxPresenceObserver = nil; } - // Clear the default background color of a MXKImageView instance - self.thumbnailView.backgroundColor = [UIColor clearColor]; - // Sanity check: accept only object of MXKContact classes or sub-classes NSParameterAssert([cellData isKindOfClass:[MXKContact class]]); contact = (MXKContact*)cellData; @@ -113,7 +118,7 @@ { self.thumbnailView.image = nil; self.contactDisplayNameLabel.text = nil; - self.lastPresenceLabel.text = nil; + self.contactInformationLabel.text = nil; return; } @@ -121,26 +126,32 @@ // Be warned when the thumbnail is updated [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onThumbnailUpdate:) name:kMXKContactThumbnailUpdateNotification object:nil]; - // Observe contact presence change - mxPresenceObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKContactManagerMatrixUserPresenceChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { - - NSString* matrixId = self.firstMatrixId; - - if (matrixId && [matrixId isEqualToString:notif.object]) - { - [self refreshContactPresence]; - } - }]; + [self refreshContactThumbnail]; - if (!contact.isMatrixContact) + [self refreshContactDisplayName]; + + if (contact.isMatrixContact) + { + // Observe contact presence change + mxPresenceObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKContactManagerMatrixUserPresenceChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + + NSString* matrixId = self.firstMatrixId; + + if (matrixId && [matrixId isEqualToString:notif.object]) + { + [self refreshContactPresence]; + } + }]; + + [self refreshContactPresence]; + } + else { // Refresh matrix info of the contact [[MXKContactManager sharedManager] updateMatrixIDsForLocalContact:contact]; + + [self refreshLocalContactInformation]; } - - [self refreshContactDisplayName]; - [self refreshContactPresence]; - [self refreshContactThumbnail]; } + (CGFloat)heightForCellData:(MXKCellData*)cellData withMaximumWidth:(CGFloat)maxWidth @@ -176,16 +187,20 @@ if (!image) { - NSString* matrixId = self.firstMatrixId; + NSArray *identifiers = contact.matrixIdentifiers; - if (matrixId) + if (identifiers.count) { - image = [AvatarGenerator generateAvatarForMatrixItem:matrixId withDisplayName:contact.displayName]; + image = [AvatarGenerator generateAvatarForMatrixItem:identifiers.firstObject withDisplayName:contact.displayName]; } else if (contact.isThirdPartyInvite) { image = [AvatarGenerator generateAvatarForText:contact.displayName]; } + else if ((!contact.isMatrixContact && contact.phoneNumbers.count && !contact.emailAddresses.count)) + { + image = [AvatarGenerator imageFromText:@"#" withBackgroundColor:kVectorColorGreen]; + } else { image = [AvatarGenerator imageFromText:@"@" withBackgroundColor:kVectorColorGreen]; @@ -198,6 +213,56 @@ - (void)refreshContactDisplayName { self.contactDisplayNameLabel.text = contact.displayName; + + // Check whether the matrix identifier must be displayed. + if (_showMatrixIdInDisplayName) + { + // Append the matrix identifier to the display name. + NSArray *identifiers = contact.matrixIdentifiers; + if (identifiers.count) + { + NSString *userId = identifiers.firstObject; + + // Check whether the display name is not already the matrix id + if (![contact.displayName isEqualToString:userId]) + { + // Update the display name by adding the matrix id + NSMutableAttributedString *displayNameLabelText = [[NSMutableAttributedString alloc] initWithString:contact.displayName]; + NSRange strRange = NSMakeRange(0, displayNameLabelText.length); + [displayNameLabelText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17 weight:UIFontWeightMedium] range:strRange]; + + NSMutableAttributedString *userIdStr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%@)", userId]]; + strRange = NSMakeRange(0, userIdStr.length); + [userIdStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17] range:strRange]; + + [displayNameLabelText appendAttributedString:userIdStr]; + self.contactDisplayNameLabel.attributedText = displayNameLabelText; + } + } + } +} + +- (void)refreshLocalContactInformation +{ + NSArray *identifiers = contact.matrixIdentifiers; + if (identifiers.count) + { + self.thumbnailBadgeView.image = [UIImage imageNamed:@"riot_icon"]; + self.thumbnailBadgeView.hidden = NO; + } + else + { + self.thumbnailBadgeView.hidden = YES; + } + + // Display the first contact method in sub label. + NSString *subLabelText = nil; + if (contact.emailAddresses.count) + { + MXKEmail* email = contact.emailAddresses.firstObject; + subLabelText = email.emailAddress; + } + self.contactInformationLabel.text = subLabelText; } - (void)refreshContactPresence @@ -227,7 +292,7 @@ presenceText = NSLocalizedStringFromTable(@"room_participants_offline", @"Vector", nil); } - self.lastPresenceLabel.text = presenceText; + self.contactInformationLabel.text = presenceText; } #pragma mark - events @@ -246,4 +311,4 @@ } } -@end \ No newline at end of file +@end diff --git a/Vector/Views/Contact/ContactTableViewCell.xib b/Vector/Views/Contact/ContactTableViewCell.xib index 01e8229e9..3cb9acae1 100644 --- a/Vector/Views/Contact/ContactTableViewCell.xib +++ b/Vector/Views/Contact/ContactTableViewCell.xib @@ -1,8 +1,12 @@ - - + + + + + - + + @@ -16,7 +20,7 @@ - + @@ -35,21 +39,21 @@ - + -