From 15d4231df6b014a7fcd63fb6af8774187b51ffc4 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:30:59 +0100 Subject: [PATCH 01/26] Key verification: Add encryption images. --- .../Images.xcassets/Encryption/Contents.json | 6 +++++ .../encryption_normal.imageset/Contents.json | 23 ++++++++++++++++++ .../encryption_normal.png | Bin 0 -> 384 bytes .../encryption_normal@2x.png | Bin 0 -> 627 bytes .../encryption_normal@3x.png | Bin 0 -> 913 bytes .../encryption_trusted.imageset/Contents.json | 23 ++++++++++++++++++ .../encryption_trusted.png | Bin 0 -> 476 bytes .../encryption_trusted@2x.png | Bin 0 -> 804 bytes .../encryption_trusted@3x.png | Bin 0 -> 1156 bytes .../encryption_warning.imageset/Contents.json | 23 ++++++++++++++++++ .../encryption_warning.png | Bin 0 -> 423 bytes .../encryption_warning@2x.png | Bin 0 -> 688 bytes .../encryption_warning@3x.png | Bin 0 -> 980 bytes Riot/Generated/Images.swift | 3 +++ 14 files changed, 78 insertions(+) create mode 100644 Riot/Assets/Images.xcassets/Encryption/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal@2x.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal@3x.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/encryption_trusted.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/encryption_trusted@2x.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/encryption_trusted@3x.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_warning.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_warning.imageset/encryption_warning.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_warning.imageset/encryption_warning@2x.png create mode 100644 Riot/Assets/Images.xcassets/Encryption/encryption_warning.imageset/encryption_warning@3x.png diff --git a/Riot/Assets/Images.xcassets/Encryption/Contents.json b/Riot/Assets/Images.xcassets/Encryption/Contents.json new file mode 100644 index 000000000..da4a164c9 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Encryption/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/Contents.json b/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/Contents.json new file mode 100644 index 000000000..91448ccb6 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "encryption_normal.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "encryption_normal@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "encryption_normal@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal.png b/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..c628f322ab8e7df9d1f339202ed5a039f60e8fcc GIT binary patch literal 384 zcmV-`0e}99P)@rma;#oyE0Iw?~V`k~k!?LxdIbIh+j+s3%mx6(W4`mKlHs zT7?8XiPs6(nx=WT>HVNxod=9;>-Vk@XfRU7>=eM`*cyh>Xt$b}bEFxyqXr{fpLc+e zb}IET9uE3+trOg#1`XyP`3jcG^E_Fp*5v2ccgSL?EPda{N=F+nLXylCf?QXqzhF^Z euqpeHF%I@ch?(Ytvo%2g0000@y_6E6U`Y6quiW(Bp7ZN%d+&j$o+X3`z*I}gqzCMj$m^4RQ56^t+ANb^C`pBB zCM_#U$+00^TPnU*EGhql*c0q-_D`U<=sQKDQTDrKsJ*?7Mn;Co@Ap#&w-wz>KWmzn za0TGRlQL<*ejZ5;!(cyCGMOYd>AFtA;2;eJgACNCc1PHk402TrK&VN>;U~&wvs8`% z1Bg*;cJeR`pt%C{4+P3iT1-Blk6vFQ1prM>gS}4f7PE=|Sq*>&Km$MpNaKJN%xl?V zrriKyIAAUJTDGM)<_7S912z(`wY0d9YhIEI06Np49UmVfuY_2--hyVrz7rMza3`M6 z6j{Xcp1cc)fml)-YJb63zz`@N4zYWkpPf_$fosptPOY5~G1a@b@;O~7DSLU|$7!77Iv^hf-ozO0;`ZkHPwxcA;?8CAh>YbZtyC~n!2Gj} zb~yY6Vy<>>I*ttW3>>0LFfPg N002ovPDHLkV1lEn6D9xv literal 0 HcmV?d00001 diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal@3x.png b/Riot/Assets/Images.xcassets/Encryption/encryption_normal.imageset/encryption_normal@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..85e974954d12eefba707fde9226614a6d3feb9d0 GIT binary patch literal 913 zcmV;C18)3@P)wD+q-Vw#3 zo#H5QG_66<_5^)so?t;)A-Zja=a{3)af5UqL_@%7kjigIE$fJ52yKpCd?t-Ss5xLc z`HZKPCnv8LRsH(?KK(rTMUBR1YBmk~8Z0aWGI=u?AHyG-{61|80t|N17ecxlJmrUMIVT#+-iNNNyubw z(em=$VP*h~tjb1I2FiRW$?e_lZx-FK1y3s4514V%EazwD85^j28v+d=B@UZSPLD5a zpi8qPoxWllS}7E~W-4r;?Cp0k=tCgBR(nS}z{5k}1+ZRx?Az}G{o}+2bQ2rUO>96n zu>sx026XdZ8Zh0HWHL#*xtdOUF9#Mifd-cN=d5m|b-@q$?(P& z5#Y6eA@>zZX3k!@Mw%WFCcnrvm*agFgWh{6>?RKwZ){WpTYo)3>yvidnGsc4L?ve48z!a zWMV@CqmgpkApU**qjG{n_zHik7Yg_7a}OptRcC`{jpgi#?a5m%oleJkzEQHSUB77u z&O4p1YImk8(o!!hB5x`7$Y8`rczfI}rAT2>kF4O$KJ2MIrFllARar7}D%z%=E|G0? n1B?hCE^+LS@@kBUi3!givDIR|C@=Uh00000NkvXXu0mjfS}&gF literal 0 HcmV?d00001 diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/Contents.json b/Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/Contents.json new file mode 100644 index 000000000..cfcf9df66 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "encryption_trusted.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "encryption_trusted@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "encryption_trusted@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/encryption_trusted.png b/Riot/Assets/Images.xcassets/Encryption/encryption_trusted.imageset/encryption_trusted.png new file mode 100644 index 0000000000000000000000000000000000000000..748d42a77675cf24b1c85470e4acce44f02ae5d7 GIT binary patch literal 476 zcmV<20VDp2P)D#}xurJ&Ye~zW{Jl-j{r;Zj+yYDxAtXi(LF7Pt=+^sp-ylP^&>}khcR$A< zTtxJy`SV$9YR}NnIw0w)y{WL20zRGtA(@3(IMT*PHMGQWoWcSsQcpQLevv@7-T*^9 zJ1i`w;4o9bHC@GkN{AJto@#p%Ji3o51U`gq!)cy}vt_|m3;Tg@SGOTH8-caEx~uN$ zKuBak-#CE$Lfi$b1JknuGd({XcLOKD$2$m$p!Usw;nZA|F5S@%YJ4JNItAF3n^1q1 zJz*i4qqh>haIAo%+?OrwWc|MGISKYj`Dnr(;aGqZQo|6j^mvJHwZ>rj=Bt%03ZElf z1~1V=rFz0UuIA}s#9K_bittk$5tJ1;EN*$e&ZVu8UyR_Ntpluvl zIuw&Zp@Jr%f)$jWg0*1be4j7hC71h`YfMuLec;Vq?!NDRe&64GAv(^|bv=%tZc3V_ zICk`g${h2D0>epz(sbTps+WK7=;hs}N4hM7vSX;*D!<}p%9k;YBuA8^o~ZDn!cnbX zp-6v-l4l|m8&bu+MT;^DilS6J0oZs#n#Rq~VV2+Cr2Mx{s_ts!CABX|qoENIvB9wQ z^$JIZL9%WDy45tdRU&PFkJ=Gn;)5!UpN%xZFo5C-F!btK+oo;`p6aFVHy_ymdYlS( z+T1H=4;`^O4xsi8(Ce$?^eHhVy1lCaHS?sHaB3jPSG8rGjsY0v;XrN6nESjgmTgx6 ztmaQY7HImzlCQeH0I;d--Hdbuvfzl`jBe6NwCjXyf{%FcshXhxz;cw#}UY z#6GJAntwymJf4+5wJjL$-f)Z2D` z@0Wa;BbS^f74t74WIGSwAim>$&ne`4Pr^ zh9{kD`3lD!2G9-!U;;_;5VzjIF8LyQ+q{a9B;8v-~4sRaq|K i?#Kj!NYaUptNsB_h^_@ISi?*J0000B74<*4+OaKoi>-(m=P1(-uZnrJPq+jwfyVGg=ee>hJnKwjblol0KBfU7m2r{*(ytCv#q+9zw5{QHNZdkG3}MQJhdO}qoX%Cpo{*G%1YEuyr6 z#ui~)78ft3I6qBXO zRshJq{=Q1306GumJ9Cy^T@5MQoudC7WdWr|Nd*L|YiX@*kk;-DIt4f-N+tm0mv8k8 zZxg7gqv=2oc|l18z&(OIJdBAw7ZF^BN;+or*9WqC8U!smNI z-U6`GbORar_+c_H@_=UnAhgppLOb_IY$GLr&t>HA=1Cs#Ea2spPOq~w9@3;{FN4(DF zH|vJKEYX|TCn_W)E+r9h4E^Ca!lmZs2l(WV5G{3-W>=xrC8&#B}nT zb&H8jF&gp1J@Nu<#oyg{BqDbPG;&EE$mxd0m`=!>ru`~1cJNNf-sJ)uE79wgtwMzD zfhv(JgQqJdS^hN4+39f>;xroQ_32=@EW*Rvj8Ts8d`D))35l`jhnq{q%=%VR(-1OD}UKjcHk0Fo|AWaz_Rs z3gR)ZS4u?%lX|S%U-m)Gb2`Z|rq!55$gWXW@aa;ti*5iT!Ugu?^SQXjGRi2!J^lf` WdJ1Pue1g&d0000w3gFyfW6iKf^kW>&7f(L`)M-&tdpeP`@ljIOIVHZ2h z>~>j7KhkSWU-Ir_=gsWwzFlAdh$t^a7POOgnRWV7pJY*ImYH+^^?^&`SDCpEt&6yO z1RD21^TnzPOTfx9u*wX>8y>k}-UdOCxB?N2E4aD_-V#86+r$N)P-!6j@KY8RfsK+B zt#W}V_Zw)wTDoMx7B_Vqb@uFZZR9W}CZ|9PvoqaM*^e~s9=F<99^OW!W9%H{J9fMm zB>Ai+cFv29rUU+HVLGhhaGwKHUc9%>E>!%##Ed2s3zNS~kRqq-`=znXEl2EXJouR< z#v1XzZ-;WI=shJmIVV~xSsvAhlp=HBhJl=UW^4*QJ-fS5L{@Op=17TI@B=duqbk0L R0I>i7002ovPDHLkV1hxqrb+++ literal 0 HcmV?d00001 diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_warning.imageset/encryption_warning@2x.png b/Riot/Assets/Images.xcassets/Encryption/encryption_warning.imageset/encryption_warning@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..15bd69270b338ecdee0bdd7bc1ae973c4cd1e16f GIT binary patch literal 688 zcmV;h0#E&kP)3NklqJNtG0Fq&y@y5T#6{Bwad8MTblQ9l|t7hyq+d1;SJy zXe=S<0GHSlxPf+=e|JxJx97XFEQ3JuFOBcDH}mb|X2-xomQpH5!(GY-Es0&KKxbkL zw*n(hpW2`cPEe)Jn_>;+=+d^$^W7}}UQ$pw?S<%TNKZjMyc5O% z$q?KL*(+M%OLB1fpfB<1 z_P#AZh_t4iCqbOngLA(!3X7w{cg@h(B=}#nQQMM?vSryeSdww2bJe>G(=Rey0M0pw z-SoUF_SsHv=Kvv)k{tf%3sy%2Nh&_LMgRK+{S_I_B=x*w01H7U6JT-LxG)e~)o7z= zui4v430^|4BoM=5tC5m?dRD3bMWs&8!e#k3+v2vw%Gv%Aam9Oi+?7Hgv@!JcP;~<* WG(<$;lpd-80000<2$D&FM6orW(n5ab4p$iM`z)}X1feoq2KY+r(0z;Ao39(Qln1bp~ zAV30v%Gj8VrbD}w^>|-`zW(-+M$Ul0}AMf)HYc4|my) z*>*FTj7`%HCY@v3V%rg3pzQ(r&@_Pw6%^^V2#&98HMUEX1QclyI5N`wz9-F$Hd`I{ zqzDMK288ryj8>7PU(aYeo}3Wv{~~Jb5Pkg2zyHYg>=~l`6{4$4d|Wa;%4W0Jwt3CG zrf~!)(ja_I9sNmv_(JraN$=YO(kA4Uki`X}xmmwnSo{_ngh0?S1reYYS)JsF`;%_% z@+f~I`tg&-0z}*>j1mJt$c9^pPC$hZTb|1g4tbOmei!~e7(7@u zJGhSqrzj50o+rAuE+5__06&ib@d#MFsA*fEI1rD32_hAcG*SUcBNdP|QUOWhzZ78i z&+tu?H1JhAfG4Oi3($Sj1cC0;J8BH!9K>(#zjXr8Nh+P=i{~#;Xdvjp=kq~FMsGMr zFccObKQsdz%vkO&o_GKu8%JdjQRp@xLPDS(79brpmgvD52Q+kD{1$Pwe}=#$iM4=d z-Yg8aG+T#%8-7q^1zKz@Zg^ z)Z(*d^rRP(zK)&XpiS!atT z4Iyh{4NuMGcSnfFPlZ@slZJD&c~MhtnJkz@QRr%9Agw3fj#^TR6-;Vfn2UX=sg-D& zq1>wC5^|*4{<*uvR_F#WBYZf=)(rD%Opzi*aQp=`a8$Ga!S&Ao0000 Date: Fri, 20 Dec 2019 10:32:09 +0100 Subject: [PATCH 02/26] UIStackView: Refactor extension method vc_removeAllSubviews to vc_removeAllArrangedSubviews. --- Riot/Categories/UIStackView.swift | 2 +- .../Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift | 4 ++-- .../Room/ContextualMenu/RoomContextualMenuToolbarView.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Riot/Categories/UIStackView.swift b/Riot/Categories/UIStackView.swift index e1ebb800b..b3040c916 100644 --- a/Riot/Categories/UIStackView.swift +++ b/Riot/Categories/UIStackView.swift @@ -18,7 +18,7 @@ import UIKit extension UIStackView { - func vc_removeAllSubviews() { + func vc_removeAllArrangedSubviews() { let subviews = self.arrangedSubviews for subview in subviews { self.removeArrangedSubview(subview) diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift index 7913799cd..082e368e4 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift @@ -103,13 +103,13 @@ final class ReactionsMenuView: UIView, Themable, NibLoadable { private func fill(reactionsMenuViewDatas: [ReactionMenuItemViewData]) { self.reactionViewDatas = reactionsMenuViewDatas - self.reactionsStackView.vc_removeAllSubviews() + self.reactionsStackView.vc_removeAllArrangedSubviews() let reactionsStackViewCount = self.reactionsStackView.arrangedSubviews.count // Remove all menu buttons if reactions count has changed if reactionsStackViewCount != self.reactionViewDatas.count { - self.reactionsStackView.vc_removeAllSubviews() + self.reactionsStackView.vc_removeAllArrangedSubviews() } var index = 0 diff --git a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuToolbarView.swift b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuToolbarView.swift index 8d695c945..9ef0436e5 100644 --- a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuToolbarView.swift +++ b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuToolbarView.swift @@ -53,7 +53,7 @@ final class RoomContextualMenuToolbarView: MXKRoomInputToolbarView, NibOwnerLoad } @objc func fill(contextualMenuItems: [RoomContextualMenuItem]) { - self.menuItemsStackView.vc_removeAllSubviews() + self.menuItemsStackView.vc_removeAllArrangedSubviews() self.menuItemViews.removeAll() for menuItem in contextualMenuItems { From 25bb439aff3ad6461228f7077bc13d5e74a74113 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:32:33 +0100 Subject: [PATCH 03/26] UIView: Add convenient vc_removeAllSubviews method. --- Riot/Categories/UIView.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Riot/Categories/UIView.swift b/Riot/Categories/UIView.swift index 5a4652104..e455766e1 100644 --- a/Riot/Categories/UIView.swift +++ b/Riot/Categories/UIView.swift @@ -19,7 +19,7 @@ import Foundation extension UIView { /// Add a subview matching parent view using autolayout - func vc_addSubViewMatchingParent(_ subView: UIView) { + @objc func vc_addSubViewMatchingParent(_ subView: UIView) { self.addSubview(subView) subView.translatesAutoresizingMaskIntoConstraints = false let views = ["view": subView] @@ -31,4 +31,10 @@ extension UIView { constraints.forEach { $0.isActive = true } } } + + @objc func vc_removeAllSubviews() { + for subView in self.subviews { + subView.removeFromSuperview() + } + } } From 4dcc6fb861d1473431911cef72537bb293430c15 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:35:04 +0100 Subject: [PATCH 04/26] RoomBubbleCellData: Add new tags in RoomBubbleCellDataTag for key verification cells. --- .../Room/CellData/RoomBubbleCellData.h | 5 +- .../Room/CellData/RoomBubbleCellData.m | 54 +++++++++++++------ 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.h b/Riot/Modules/Room/CellData/RoomBubbleCellData.h index 7c34278ff..7f355f5b1 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.h +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.h @@ -21,7 +21,10 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) { RoomBubbleCellDataTagMessage = 0, // Default value used for messages RoomBubbleCellDataTagMembership, - RoomBubbleCellDataTagRoomCreateWithPredecessor + RoomBubbleCellDataTagRoomCreateWithPredecessor, + RoomBubbleCellDataTagDeviceKeyVerificationRequestIncomingApproval, + RoomBubbleCellDataTagDeviceKeyVerificationRequest, + RoomBubbleCellDataTagDeviceKeyVerificationConclusion }; /** diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index a89214ce4..c433215b8 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -62,26 +62,46 @@ static NSAttributedString *timestampVerticalWhitespace = nil; if (self) { - if (event.eventType == MXEventTypeRoomMember) + switch (event.eventType) { - // Membership events have their own cell type - self.tag = RoomBubbleCellDataTagMembership; - - // Membership events can be collapsed together - self.collapsable = YES; - - // Collapse them by default - self.collapsed = YES; - } - - if (event.eventType == MXEventTypeRoomCreate) - { - MXRoomCreateContent *createContent = [MXRoomCreateContent modelFromJSON:event.content]; - - if (createContent.roomPredecessorInfo) + case MXEventTypeRoomMember: { - self.tag = RoomBubbleCellDataTagRoomCreateWithPredecessor; + // Membership events have their own cell type + self.tag = RoomBubbleCellDataTagMembership; + + // Membership events can be collapsed together + self.collapsable = YES; + + // Collapse them by default + self.collapsed = YES; } + break; + case MXEventTypeRoomCreate: + { + MXRoomCreateContent *createContent = [MXRoomCreateContent modelFromJSON:event.content]; + + if (createContent.roomPredecessorInfo) + { + self.tag = RoomBubbleCellDataTagRoomCreateWithPredecessor; + } + } + break; + case MXEventTypeKeyVerificationCancel: + case MXEventTypeKeyVerificationDone: + self.tag = RoomBubbleCellDataTagDeviceKeyVerificationConclusion; + break; + case MXEventTypeRoomMessage: + { + NSString *msgType = event.content[@"msgtype"]; + + if ([msgType isEqualToString:kMXMessageTypeKeyVerificationRequest]) + { + self.tag = RoomBubbleCellDataTagDeviceKeyVerificationRequest; + } + } + break; + default: + break; } // Increase maximum number of components From fc77865f844adc55837f6365b1f3517f957cc696 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:37:53 +0100 Subject: [PATCH 05/26] Add BubbleCellReadReceiptsDisplayable protocol describing a cell able to manage read receipts display. --- .../BubbleCellReadReceiptsDisplayable.swift | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift new file mode 100644 index 000000000..e9b657a03 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift @@ -0,0 +1,22 @@ +/* + Copyright 2019 New Vector 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 Foundation + +@objc protocol BubbleCellReadReceiptsDisplayable { + func addReadReceiptsView(_ readReceiptsView: UIView) + func removeReadReceiptsView() +} From d4fd68e40551fae87a41b1de7341ed353c4d6ce8 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:39:22 +0100 Subject: [PATCH 06/26] Create BubbleCellWithoutSenderInfoContentView a base room bubble cell content view. --- ...bbleCellWithoutSenderInfoContentView.swift | 74 +++++++++++++++ ...BubbleCellWithoutSenderInfoContentView.xib | 93 +++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift new file mode 100644 index 000000000..e4c7a9bd8 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift @@ -0,0 +1,74 @@ +/* + Copyright 2019 New Vector 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 UIKit +import Reusable + +@objcMembers +final class BubbleCellWithoutSenderInfoContentView: UIView, NibLoadable { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet weak var bubbleInfoContainer: UIView! + @IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint! + + @IBOutlet weak var innerContentView: UIView! + + @IBOutlet weak var readReceiptsContainerView: UIView! + @IBOutlet weak var readReceiptsContentView: UIView! + + @IBOutlet weak var bubbleOverlayContainer: UIView! + + // MARK: Private + + private var showReadReceipts: Bool { + get { + return self.readReceiptsContainerView.isHidden + } + set { + self.readReceiptsContainerView.isHidden = !newValue + } + } + + // MARK: - Setup + + class func instantiate() -> BubbleCellWithoutSenderInfoContentView { + return BubbleCellWithoutSenderInfoContentView.loadFromNib() + } + + // MARK: - Public + + func update(theme: Theme) { + self.backgroundColor = theme.backgroundColor + } +} + +// MARK: - BubbleCellReadReceiptsDisplayable +extension BubbleCellWithoutSenderInfoContentView: BubbleCellReadReceiptsDisplayable { + + func addReadReceiptsView(_ readReceiptsView: UIView) { + self.readReceiptsContentView.vc_removeAllSubviews() + self.readReceiptsContentView.vc_addSubViewMatchingParent(readReceiptsView) + self.showReadReceipts = true + } + + func removeReadReceiptsView() { + self.showReadReceipts = false + self.readReceiptsContentView.vc_removeAllSubviews() + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib new file mode 100644 index 000000000..ac074f0ca --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 48db9c37a4f470d8748c74864bd0a9d0f0b0b9a2 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:42:28 +0100 Subject: [PATCH 07/26] Create DM key verification cells. --- .../KeyVerificationBaseBubbleCell.swift | 223 ++++++++++++++++++ .../KeyVerificationCellInnerContentView.swift | 159 +++++++++++++ .../KeyVerificationCellInnerContentView.xib | 99 ++++++++ .../KeyVerificationConclusionBubbleCell.swift | 103 ++++++++ .../KeyVerificationConclusionViewData.swift | 24 ++ ...ionIncomingRequestApprovalBubbleCell.swift | 99 ++++++++ ...ationIncomingRequestApprovalViewData.swift | 23 ++ ...yVerificationRequestStatusBubbleCell.swift | 91 +++++++ ...KeyVerificationRequestStatusViewData.swift | 24 ++ .../KeyVerification/SizingViewHeight.swift | 43 ++++ 10 files changed, 888 insertions(+) create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionViewData.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalViewData.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusViewData.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift new file mode 100644 index 000000000..a280a979e --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift @@ -0,0 +1,223 @@ +/* + Copyright 2019 New Vector 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 Foundation + +@objcMembers +class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { + + // MARK: - Constants + + private enum Sizing { + static var sizes = Set() + } + + // MARK: - Properties + + // MARK: Public + + weak var keyVerificationCellInnerContentView: KeyVerificationCellInnerContentView? + weak var bubbleCellWithoutSenderInfoContentView: BubbleCellWithoutSenderInfoContentView? + + override var bubbleInfoContainer: UIView! { + get { + guard let infoContainer = self.bubbleCellWithoutSenderInfoContentView?.bubbleInfoContainer else { + fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainer should not be used before set") + } + return infoContainer + } + set { + super.bubbleInfoContainer = newValue + } + } + + override var bubbleOverlayContainer: UIView! { + get { + guard let overlayContainer = self.bubbleCellWithoutSenderInfoContentView?.bubbleOverlayContainer else { + fatalError("[KeyVerificationBaseBubbleCell] bubbleOverlayContainer should not be used before set") + } + return overlayContainer + } + set { + super.bubbleInfoContainer = newValue + } + } + + override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! { + get { + guard let infoContainerTopConstraint = self.bubbleCellWithoutSenderInfoContentView?.bubbleInfoContainerTopConstraint else { + fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainerTopConstraint should not be used before set") + } + return infoContainerTopConstraint + } + set { + super.bubbleInfoContainerTopConstraint = newValue + } + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + + self.selectionStyle = .none + self.setupContentView() + self.update(theme: ThemeService.shared().theme) + + super.setupViews() + } + + // MARK: - Public + + func update(theme: Theme) { + self.bubbleCellWithoutSenderInfoContentView?.update(theme: theme) + self.keyVerificationCellInnerContentView?.update(theme: theme) + } + + func buildUserInfoText(with userId: String, userDisplayName: String?) -> String { + + let userInfoText: String + + if let userDisplayName = userDisplayName { + userInfoText = "\(userId) (\(userDisplayName))" + } else { + userInfoText = userId + } + + return userInfoText + } + + func senderId(from bubbleCellData: MXKRoomBubbleCellData) -> String { + return bubbleCellData.senderId ?? "" + } + + func senderDisplayName(from bubbleCellData: MXKRoomBubbleCellData) -> String? { + let senderId = self.senderId(from: bubbleCellData) + guard let senderDisplayName = bubbleCellData.senderDisplayName, senderId != senderDisplayName else { + return nil + } + return senderDisplayName + } + + class func sizingView() -> MXKRoomBubbleTableViewCell { + fatalError("[KeyVerificationBaseBubbleCell] Subclass should implement this method") + } + + // TODO: Implement thiscmethod in subclasses + class func sizingHeightHashValue(from bubbleData: MXKRoomBubbleCellData) -> Int { + return bubbleData.hashValue + } + + // MARK: - Overrides + + override class func defaultReuseIdentifier() -> String! { + return String(describing: self) + } + + override func didEndDisplay() { + super.didEndDisplay() + self.removeReadReceiptsView() + } + + override class func height(for cellData: MXKCellData!, withMaximumWidth maxWidth: CGFloat) -> CGFloat { + guard let cellData = cellData else { + return 0 + } + + guard let roomBubbleCellData = cellData as? MXKRoomBubbleCellData else { + return 0 + } + + let height: CGFloat + + let sizingViewHeight = self.findOrCreateSizingViewHeight(from: roomBubbleCellData) + + if let cachedHeight = sizingViewHeight.heights[maxWidth] { + height = cachedHeight + } else { + height = self.contentViewHeight(for: roomBubbleCellData, fitting: maxWidth) + sizingViewHeight.heights[maxWidth] = height + } + + return height + } + + // MARK: - Private + + private func setupContentView() { + if self.bubbleCellWithoutSenderInfoContentView == nil { + + let bubbleCellWithoutSenderInfoContentView = BubbleCellWithoutSenderInfoContentView.instantiate() + + let innerContentView = KeyVerificationCellInnerContentView.instantiate() + + bubbleCellWithoutSenderInfoContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView) + + self.contentView.vc_addSubViewMatchingParent(bubbleCellWithoutSenderInfoContentView) + + self.bubbleCellWithoutSenderInfoContentView = bubbleCellWithoutSenderInfoContentView + self.keyVerificationCellInnerContentView = innerContentView + } + } + + private static func findOrCreateSizingViewHeight(from bubbleData: MXKRoomBubbleCellData) -> SizingViewHeight { + + let sizingViewHeight: SizingViewHeight + let bubbleDataHashValue = bubbleData.hashValue + + if let foundSizingViewHeight = self.Sizing.sizes.first(where: { (sizingViewHeight) -> Bool in + return sizingViewHeight.uniqueIdentifier == bubbleDataHashValue + }) { + sizingViewHeight = foundSizingViewHeight + } else { + sizingViewHeight = SizingViewHeight(uniqueIdentifier: bubbleDataHashValue) + } + + return sizingViewHeight + } + + private static func contentViewHeight(for cellData: MXKCellData, fitting width: CGFloat) -> CGFloat { + let sizingView = self.sizingView() + + sizingView.render(cellData) + sizingView.layoutIfNeeded() + + let fittingSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height) + let height = sizingView.systemLayoutSizeFitting(fittingSize).height + + return height + } +} + +// MARK: - BubbleCellReadReceiptsDisplayable +extension KeyVerificationBaseBubbleCell: BubbleCellReadReceiptsDisplayable { + + func addReadReceiptsView(_ readReceiptsView: UIView) { + self.bubbleCellWithoutSenderInfoContentView?.addReadReceiptsView(readReceiptsView) + } + + func removeReadReceiptsView() { + self.bubbleCellWithoutSenderInfoContentView?.removeReadReceiptsView() + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift new file mode 100644 index 000000000..4b859339f --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift @@ -0,0 +1,159 @@ +/* + Copyright 2019 New Vector 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 UIKit +import Reusable + +final class KeyVerificationCellInnerContentView: UIView, NibLoadable { + + // MARK: - Constants + + private enum Constants { + static let cornerRadius: CGFloat = 8.0 + static let buttonBackgroundColorAlpha: CGFloat = 0.8 + static let buttonCornerRadius: CGFloat = 6.0 + } + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var badgeImageView: UIImageView! + @IBOutlet private weak var titleLabel: UILabel! + + @IBOutlet private weak var userInformationsLabel: UILabel! + + @IBOutlet private weak var requestStatusLabel: UILabel! + + @IBOutlet private weak var acceptButton: UIButton! + @IBOutlet private weak var declineButton: UIButton! + + // MARK: Public + + var isButtonsHidden: Bool { + get { + return self.acceptButton.isHidden && self.declineButton.isHidden + } + set { + self.acceptButton.isHidden = newValue + self.declineButton.isHidden = newValue + } + } + + var isRequestStatusHidden: Bool { + get { + return self.requestStatusLabel.isHidden + } + set { + self.requestStatusLabel.isHidden = newValue + } + } + + var badgeImage: UIImage? { + get { + return self.badgeImageView.image + } + set { + self.badgeImageView.image = newValue + } + } + + var title: String? { + get { + return self.titleLabel.text + } + set { + self.titleLabel.text = newValue + } + } + + var requestStatusText: String? { + get { + return self.requestStatusLabel.text + } + set { + self.requestStatusLabel.text = newValue + } + } + + var acceptActionHandler: (() -> Void)? + + var declineActionHandler: (() -> Void)? + + // MARK: - Setup + + static func instantiate() -> KeyVerificationCellInnerContentView { + let view = KeyVerificationCellInnerContentView.loadFromNib() + return view + } + + // MARK: - Life cycle + + override func awakeFromNib() { + super.awakeFromNib() + + self.layer.masksToBounds = true + } + + override func layoutSubviews() { + super.layoutSubviews() + + self.layer.cornerRadius = Constants.cornerRadius + + if self.isButtonsHidden == false { + self.acceptButton.layer.cornerRadius = Constants.buttonCornerRadius + self.declineButton.layer.cornerRadius = Constants.buttonCornerRadius + } + } + + // MARK: - Public + + func update(theme: Theme) { + self.backgroundColor = theme.headerBackgroundColor + self.titleLabel.textColor = theme.textPrimaryColor + self.userInformationsLabel.textColor = theme.textSecondaryColor + + self.acceptButton.vc_setBackgroundColor(theme.tintColor.withAlphaComponent(Constants.buttonBackgroundColorAlpha), for: .normal) + self.declineButton.vc_setBackgroundColor(theme.noticeColor.withAlphaComponent(Constants.buttonBackgroundColorAlpha), for: .normal) + } + + func updateSenderInfo(with userId: String, userDisplayName: String?) { + self.userInformationsLabel.text = self.buildUserInfoText(with: userId, userDisplayName: userDisplayName) + } + + // MARK: - Private + + private func buildUserInfoText(with userId: String, userDisplayName: String?) -> String { + + let userInfoText: String + + if let userDisplayName = userDisplayName { + userInfoText = "\(userId) (\(userDisplayName))" + } else { + userInfoText = userId + } + + return userInfoText + } + + @IBAction private func declineButtonAction(_ sender: Any) { + self.declineActionHandler?() + } + + @IBAction private func acceptButtonAction(_ sender: Any) { + self.acceptActionHandler?() + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib new file mode 100644 index 000000000..ca7a98a8c --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift new file mode 100644 index 000000000..6bf6b0a5d --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift @@ -0,0 +1,103 @@ +/* + Copyright 2019 New Vector 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 UIKit + +@objcMembers +final class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { + + // MARK: - Constants + + private enum Sizing { + static let view = KeyVerificationConclusionBubbleCell(style: .default, reuseIdentifier: nil) + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + self.keyVerificationCellInnerContentView?.isButtonsHidden = true + self.keyVerificationCellInnerContentView?.isRequestStatusHidden = true + } + + // MARK: - Overrides + + override func render(_ cellData: MXKCellData!) { + super.render(cellData) + + guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView, + let bubbleData = self.bubbleData, + let viewData = self.viewData(from: bubbleData) else { + NSLog("[KeyVerificationConclusionBubbleCell] Fail to render \(String(describing: cellData))") + return + } + + keyVerificationCellInnerContentView.badgeImage = viewData.badgeImage + keyVerificationCellInnerContentView.title = viewData.title + keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName) + } + + override class func sizingView() -> MXKRoomBubbleTableViewCell { + return self.Sizing.view + } + + // MARK: - Private + + // TODO: Handle view data filling + private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationConclusionViewData? { + guard let event = bubbleData.bubbleComponents.first?.event else { + return nil + } + + let viewData: KeyVerificationConclusionViewData? + + let senderId = self.senderId(from: bubbleData) + let senderDisplayName = self.senderDisplayName(from: bubbleData) + let title: String? + let badgeImage: UIImage? + + switch event.eventType { + case .keyVerificationDone: + title = "Verified" + badgeImage = Asset.Images.encryptionTrusted.image + case .keyVerificationCancel: + title = "Cancelled" + badgeImage = Asset.Images.encryptionNormal.image + default: + badgeImage = nil + title = nil + } + + if let title = title, let badgeImage = badgeImage { + viewData = KeyVerificationConclusionViewData(badgeImage: badgeImage, + title: title, + senderId: senderId, + senderDisplayName: senderDisplayName) + } else { + viewData = nil + } + + return viewData + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionViewData.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionViewData.swift new file mode 100644 index 000000000..4df053de6 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionViewData.swift @@ -0,0 +1,24 @@ +/* + Copyright 2019 New Vector 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 Foundation + +struct KeyVerificationConclusionViewData { + let badgeImage: UIImage + let title: String + let senderId: String + let senderDisplayName: String? +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift new file mode 100644 index 000000000..9cc1c0136 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift @@ -0,0 +1,99 @@ +/* + Copyright 2019 New Vector 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 UIKit + +@objcMembers +final class KeyVerificationIncomingRequestApprovalBubbleCell: KeyVerificationBaseBubbleCell { + + // MARK: - Constants + + private enum Sizing { + static let view = KeyVerificationConclusionBubbleCell(style: .default, reuseIdentifier: nil) + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView else { + fatalError("[KeyVerificationIncomingRequestApprovalBubbleCell] keyVerificationCellInnerContentView should not be nil") + } + + keyVerificationCellInnerContentView.isButtonsHidden = false + keyVerificationCellInnerContentView.isRequestStatusHidden = true + keyVerificationCellInnerContentView.badgeImage = Asset.Images.encryptionNormal.image + } + + // MARK: - Overrides + + override func prepareForReuse() { + super.prepareForReuse() + + self.keyVerificationCellInnerContentView?.acceptActionHandler = nil + self.keyVerificationCellInnerContentView?.declineActionHandler = nil + } + + override func render(_ cellData: MXKCellData!) { + super.render(cellData) + + guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView, + let bubbleData = self.bubbleData, + let viewData = self.viewData(from: bubbleData) else { + NSLog("[KeyVerificationIncomingRequestApprovalBubbleCell] Fail to render \(String(describing: cellData))") + return + } + + keyVerificationCellInnerContentView.title = viewData.title + keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName) + + keyVerificationCellInnerContentView.acceptActionHandler = { [weak self] in + // TODO: Use correct action identifier + self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellTapOnContentView, userInfo: nil) + } + + keyVerificationCellInnerContentView.declineActionHandler = { [weak self] in + // TODO: Use correct action identifier + self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellTapOnContentView, userInfo: nil) + } + } + + override class func sizingView() -> MXKRoomBubbleTableViewCell { + return self.Sizing.view + } + + // MARK: - Private + + // TODO: Handle view data filling + private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationIncomingRequestApprovalViewData? { + + let senderId = self.senderId(from: bubbleData) + let senderDisplayName = self.senderDisplayName(from: bubbleData) + let title = "Verification request" + + return KeyVerificationIncomingRequestApprovalViewData(title: title, + senderId: senderId, + senderDisplayName: senderDisplayName) + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalViewData.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalViewData.swift new file mode 100644 index 000000000..91824fe16 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalViewData.swift @@ -0,0 +1,23 @@ +/* + Copyright 2019 New Vector 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 Foundation + +struct KeyVerificationIncomingRequestApprovalViewData { + let title: String + let senderId: String + let senderDisplayName: String? +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift new file mode 100644 index 000000000..453407ced --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift @@ -0,0 +1,91 @@ +/* + Copyright 2019 New Vector 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 UIKit + +@objcMembers +final class KeyVerificationRequestStatusBubbleCell: KeyVerificationBaseBubbleCell { + + // MARK: - Constants + + private enum Sizing { + static let view = KeyVerificationRequestStatusBubbleCell(style: .default, reuseIdentifier: nil) + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView else { + fatalError("[KeyVerificationRequestStatusBubbleCell] keyVerificationCellInnerContentView should not be nil") + } + + keyVerificationCellInnerContentView.isButtonsHidden = true + keyVerificationCellInnerContentView.isRequestStatusHidden = false + keyVerificationCellInnerContentView.badgeImage = Asset.Images.encryptionNormal.image + } + + // MARK: - Overrides + + override func render(_ cellData: MXKCellData!) { + super.render(cellData) + + guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView, + let bubbleData = self.bubbleData, + let viewData = self.viewData(from: bubbleData) else { + NSLog("[KeyVerificationRequestStatusBubbleCell] Fail to render \(String(describing: cellData))") + return + } + + keyVerificationCellInnerContentView.title = viewData.title + keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName) + keyVerificationCellInnerContentView.requestStatusText = viewData.statusText + } + + override class func sizingView() -> MXKRoomBubbleTableViewCell { + return self.Sizing.view + } + + // MARK: - Private + + // TODO: Handle view data filling + private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationRequestStatusViewData? { + + let senderId = self.senderId(from: bubbleData) + let senderDisplayName = self.senderDisplayName(from: bubbleData) + let title: String + let statusText: String = "You accepted" + + if senderId.isEmpty == false { + title = "Verification request" + } else { + title = "Verification sent" + } + + return KeyVerificationRequestStatusViewData(title: title, + senderId: senderId, + senderDisplayName: senderDisplayName, + statusText: statusText) + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusViewData.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusViewData.swift new file mode 100644 index 000000000..c411b56ca --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusViewData.swift @@ -0,0 +1,24 @@ +/* + Copyright 2019 New Vector 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 Foundation + +struct KeyVerificationRequestStatusViewData { + let title: String + let senderId: String + let senderDisplayName: String? + let statusText: String +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift new file mode 100644 index 000000000..f1607fb4f --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift @@ -0,0 +1,43 @@ +/* + Copyright 2019 New Vector 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 Foundation + +final class SizingViewHeight: Hashable, Equatable { + + // MARK: - Properties + + let uniqueIdentifier: Int + var heights: [CGFloat /* width */: CGFloat /* height */] = [:] + + // MARK: - Setup + + init(uniqueIdentifier: Int) { + self.uniqueIdentifier = uniqueIdentifier + } + + // MARK: - Hashable + + func hash(into hasher: inout Hasher) { + hasher.combine(self.uniqueIdentifier) + } + + // MARK: - Equatable + + static func == (lhs: SizingViewHeight, rhs: SizingViewHeight) -> Bool { + return lhs.uniqueIdentifier == rhs.uniqueIdentifier + } +} From 2fba33e598d78f6110c3c9f43f6ca8a67ed5409d Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:43:07 +0100 Subject: [PATCH 08/26] RoomVC: Handle DM key verification cells. --- Riot/Modules/Room/RoomViewController.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 2c4fac795..03ccc1656 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -353,6 +353,10 @@ [self.bubblesTableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier]; [self.bubblesTableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier]; + [self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier]; + [self.bubblesTableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier]; + [self.bubblesTableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier]; + // Prepare expanded header expandedHeader = [ExpandedRoomTitleView roomTitleView]; expandedHeader.delegate = self; @@ -2039,6 +2043,18 @@ { cellViewClass = RoomPredecessorBubbleCell.class; } + else if (bubbleData.tag == RoomBubbleCellDataTagDeviceKeyVerificationRequestIncomingApproval) + { + cellViewClass = KeyVerificationIncomingRequestApprovalBubbleCell.class; + } + else if (bubbleData.tag == RoomBubbleCellDataTagDeviceKeyVerificationRequest) + { + cellViewClass = KeyVerificationRequestStatusBubbleCell.class; + } + else if (bubbleData.tag == RoomBubbleCellDataTagDeviceKeyVerificationConclusion) + { + cellViewClass = KeyVerificationConclusionBubbleCell.class; + } else if (bubbleData.tag == RoomBubbleCellDataTagMembership) { if (bubbleData.collapsed) From 5cfe5833ce2b3a8cd33ffc73ab2af1add3a13050 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 20 Dec 2019 10:44:01 +0100 Subject: [PATCH 09/26] RoomDataSource: Handle read receipts display for cells conforming to BubbleCellReadReceiptsDisplayable. --- .../Modules/Room/DataSources/RoomDataSource.m | 82 +++++++++++-------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 103fd0acc..5b82ce4fe 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -284,7 +284,7 @@ ]]; } - MXKReceiptSendersContainer* avatarsContainer; + MXKReceiptSendersContainer* avatarsContainer; // Handle read receipts (if any) if (self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed) @@ -349,47 +349,57 @@ { [bubbleCell.tmpSubviews addObject:avatarsContainer]; } - [bubbleCell.contentView addSubview:avatarsContainer]; - // Force receipts container size - NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer - attribute:NSLayoutAttributeWidth - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:RoomBubbleCellLayout.readReceiptsViewWidth]; - NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer - attribute:NSLayoutAttributeHeight - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:RoomBubbleCellLayout.readReceiptsViewHeight]; - - // Force receipts container position - NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer - attribute:NSLayoutAttributeTrailing - relatedBy:NSLayoutRelationEqual - toItem:avatarsContainer.superview - attribute:NSLayoutAttributeTrailing - multiplier:1.0 - constant:-RoomBubbleCellLayout.readReceiptsViewRightMargin]; - - // At the bottom, we have reactions or nothing - NSLayoutConstraint *topConstraint; - if (reactionsView) + if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReadReceiptsDisplayable)]) { - topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin]; + id readReceiptsDisplayable = (id)bubbleCell; + + [readReceiptsDisplayable addReadReceiptsView:avatarsContainer]; } else { - topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:avatarsContainer.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin]; + [bubbleCell.contentView addSubview:avatarsContainer]; + + // Force receipts container size + NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:RoomBubbleCellLayout.readReceiptsViewWidth]; + NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:RoomBubbleCellLayout.readReceiptsViewHeight]; + + // Force receipts container position + NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:avatarsContainer.superview + attribute:NSLayoutAttributeTrailing + multiplier:1.0 + constant:-RoomBubbleCellLayout.readReceiptsViewRightMargin]; + + // At the bottom, we have reactions or nothing + NSLayoutConstraint *topConstraint; + if (reactionsView) + { + topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin]; + } + else + { + topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:avatarsContainer.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin]; + } + + + // Available on iOS 8 and later + [NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]]; } - - - // Available on iOS 8 and later - [NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]]; } } From c8a68fb2d8710d767b449e26a8ff2d01f603b3de Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 19:21:32 +0100 Subject: [PATCH 10/26] Add key verification tiles strings --- Riot/Assets/en.lproj/Vector.strings | 19 +++++++++++++ Riot/Generated/Strings.swift | 44 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 0117d6693..2b9f1c04d 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1087,3 +1087,22 @@ // Generic errors "error_invite_3pid_with_no_identity_server" = "Add an identity server in your settings to invite by email."; "error_not_supported_on_mobile" = "You can't do this from %@ mobile."; + +// MARK: - Key Verification + +// Tiles + +"key_verification_tile_request_incoming_title" = "Verification request"; +"key_verification_tile_request_outgoing_title" = "Verification sent"; + +"key_verification_tile_request_status_data_loading" = "Data loading …"; +"key_verification_tile_request_status_waiting" = "Waiting …"; +"key_verification_tile_request_status_expired" = "Expired"; +"key_verification_tile_request_status_cancelled_by_me" = "You cancel"; +"key_verification_tile_request_status_cancelled" = "%@ cancelled"; +"key_verification_tile_request_status_accepted" = "You accepted"; + +"key_verification_tile_request_incoming_approval_accept" = "Accept"; +"key_verification_tile_request_incoming_approval_decline" = "Decline"; + +"key_verification_tile_conclusion_done_title" = "Verified"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 305d37a19..6240b5928 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1470,6 +1470,50 @@ internal enum VectorL10n { internal static var keyBackupSetupTitle: String { return VectorL10n.tr("Vector", "key_backup_setup_title") } + /// Verified + internal static var keyVerificationTileConclusionDoneTitle: String { + return VectorL10n.tr("Vector", "key_verification_tile_conclusion_done_title") + } + /// Accept + internal static var keyVerificationTileRequestIncomingApprovalAccept: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_approval_accept") + } + /// Decline + internal static var keyVerificationTileRequestIncomingApprovalDecline: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_approval_decline") + } + /// Verification request + internal static var keyVerificationTileRequestIncomingTitle: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_title") + } + /// Verification sent + internal static var keyVerificationTileRequestOutgoingTitle: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_outgoing_title") + } + /// You accepted + internal static var keyVerificationTileRequestStatusAccepted: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_status_accepted") + } + /// %@ cancelled + internal static func keyVerificationTileRequestStatusCancelled(_ p1: String) -> String { + return VectorL10n.tr("Vector", "key_verification_tile_request_status_cancelled", p1) + } + /// You cancel + internal static var keyVerificationTileRequestStatusCancelledByMe: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_status_cancelled_by_me") + } + /// Data loading … + internal static var keyVerificationTileRequestStatusDataLoading: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_status_data_loading") + } + /// Expired + internal static var keyVerificationTileRequestStatusExpired: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_status_expired") + } + /// Waiting … + internal static var keyVerificationTileRequestStatusWaiting: String { + return VectorL10n.tr("Vector", "key_verification_tile_request_status_waiting") + } /// %.1fK internal static func largeBadgeValueKFormat(_ p1: Float) -> String { return VectorL10n.tr("Vector", "large_badge_value_k_format", p1) From d9408dda330de74c0e133e127b9d709152bd8723 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 19:46:02 +0100 Subject: [PATCH 11/26] RoomBubbleCellData: Handle key verification cells. Add key verification property and add key verification cell data tags. --- .../Room/CellData/RoomBubbleCellData.h | 17 +- .../Room/CellData/RoomBubbleCellData.m | 175 +++++++++++++++--- 2 files changed, 167 insertions(+), 25 deletions(-) diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.h b/Riot/Modules/Room/CellData/RoomBubbleCellData.h index 7f355f5b1..62d27d998 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.h +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.h @@ -22,9 +22,10 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) RoomBubbleCellDataTagMessage = 0, // Default value used for messages RoomBubbleCellDataTagMembership, RoomBubbleCellDataTagRoomCreateWithPredecessor, - RoomBubbleCellDataTagDeviceKeyVerificationRequestIncomingApproval, - RoomBubbleCellDataTagDeviceKeyVerificationRequest, - RoomBubbleCellDataTagDeviceKeyVerificationConclusion + RoomBubbleCellDataTagKeyVerificationNoDisplay, + RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval, + RoomBubbleCellDataTagKeyVerificationRequest, + RoomBubbleCellDataTagKeyVerificationConclusion }; /** @@ -73,6 +74,16 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) */ @property(nonatomic, readonly) CGFloat additionalContentHeight; +/** + MXKeyVerification object associated to key verifcation event when using key verification by direct message. + */ +@property(nonatomic, strong) MXKeyVerification *keyVerification; + +/** + Indicate if there is a pending operation that updates `keyVerification` property. + */ +@property(nonatomic) BOOL isKeyVerificationOperationPending; + /** Indicate to update additional content height. */ diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index c433215b8..af30837de 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -86,23 +86,11 @@ static NSAttributedString *timestampVerticalWhitespace = nil; } } break; - case MXEventTypeKeyVerificationCancel: - case MXEventTypeKeyVerificationDone: - self.tag = RoomBubbleCellDataTagDeviceKeyVerificationConclusion; - break; - case MXEventTypeRoomMessage: - { - NSString *msgType = event.content[@"msgtype"]; - - if ([msgType isEqualToString:kMXMessageTypeKeyVerificationRequest]) - { - self.tag = RoomBubbleCellDataTagDeviceKeyVerificationRequest; - } - } - break; default: break; } + + [self keyVerificationDidUpdate]; // Increase maximum number of components self.maxComponentCount = 20; @@ -167,6 +155,16 @@ static NSAttributedString *timestampVerticalWhitespace = nil; return attributedTextMessage; } +- (BOOL)hasNoDisplay +{ + if (self.tag == RoomBubbleCellDataTagKeyVerificationNoDisplay) + { + return YES; + } + + return [super hasNoDisplay]; +} + #pragma mark - Bubble collapsing - (BOOL)collapseWith:(id)cellData @@ -683,21 +681,154 @@ static NSAttributedString *timestampVerticalWhitespace = nil; - (BOOL)addEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState { - if (self.tag == RoomBubbleCellDataTagMembership || event.eventType == MXEventTypeRoomMember) + BOOL shouldAddEvent = YES; + + switch (self.tag) { - // One single bubble per membership event - return NO; + case RoomBubbleCellDataTagKeyVerificationNoDisplay: + case RoomBubbleCellDataTagKeyVerificationRequest: + case RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval: + case RoomBubbleCellDataTagKeyVerificationConclusion: + shouldAddEvent = NO; + break; + case RoomBubbleCellDataTagRoomCreateWithPredecessor: + // We do not want to merge room create event cells with other cell types + shouldAddEvent = NO; + break; + case RoomBubbleCellDataTagMembership: + // One single bubble per membership event + shouldAddEvent = NO; + break; + default: + break; } - if (self.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor || event.eventType == MXEventTypeRoomCreate) + if (shouldAddEvent) { - // We do not want to merge room create event cells with other cell types - return NO; + switch (event.eventType) + { + case MXEventTypeRoomMessage: + { + NSString *messageType = event.content[@"msgtype"]; + + if ([messageType isEqualToString:kMXMessageTypeKeyVerificationRequest]) + { + shouldAddEvent = NO; + } + } + break; + case MXEventTypeKeyVerificationStart: + case MXEventTypeKeyVerificationAccept: + case MXEventTypeKeyVerificationKey: + case MXEventTypeKeyVerificationMac: + case MXEventTypeKeyVerificationDone: + case MXEventTypeKeyVerificationCancel: + shouldAddEvent = NO; + break; + case MXEventTypeRoomMember: + shouldAddEvent = NO; + break; + case MXEventTypeRoomCreate: + shouldAddEvent = NO; + break; + default: + break; + } } - - return [super addEvent:event andRoomState:roomState]; + + if (shouldAddEvent) + { + shouldAddEvent = [super addEvent:event andRoomState:roomState]; + } + + return shouldAddEvent; } +- (void)setKeyVerification:(MXKeyVerification *)keyVerification +{ + _keyVerification = keyVerification; + + [self keyVerificationDidUpdate]; +} + +- (void)keyVerificationDidUpdate +{ + MXEvent *event = self.getFirstBubbleComponentWithDisplay.event; + MXKeyVerification *keyVerification = _keyVerification; + + if (!event) + { + return; + } + + switch (event.eventType) + { + case MXEventTypeKeyVerificationCancel: + { + RoomBubbleCellDataTag cellDataTag; + + MXTransactionCancelCode *transactionCancelCode = keyVerification.transaction.reasonCancelCode; + + if (transactionCancelCode + && ([transactionCancelCode isEqual:[MXTransactionCancelCode mismatchedSas]] + || [transactionCancelCode isEqual:[MXTransactionCancelCode mismatchedKeys]] + || [transactionCancelCode isEqual:[MXTransactionCancelCode mismatchedCommitment]] + ) + ) + { + cellDataTag = RoomBubbleCellDataTagKeyVerificationConclusion; + } + else + { + cellDataTag = RoomBubbleCellDataTagKeyVerificationNoDisplay; + } + + self.tag = cellDataTag; + } + break; + case MXEventTypeKeyVerificationDone: + { + RoomBubbleCellDataTag cellDataTag; + + // Avoid to display incoming and outgoing done, only display the incoming one. + if (self.isIncoming && keyVerification && (keyVerification.state == MXKeyVerificationStateVerified)) + { + cellDataTag = RoomBubbleCellDataTagKeyVerificationConclusion; + } + else + { + cellDataTag = RoomBubbleCellDataTagKeyVerificationNoDisplay; + } + + self.tag = cellDataTag; + } + break; + case MXEventTypeRoomMessage: + { + NSString *msgType = event.content[@"msgtype"]; + + if ([msgType isEqualToString:kMXMessageTypeKeyVerificationRequest]) + { + RoomBubbleCellDataTag cellDataTag; + + if (self.isIncoming && !self.isKeyVerificationOperationPending && keyVerification && keyVerification.state == MXKeyVerificationRequestStatePending) + { + cellDataTag = RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval; + } + else + { + cellDataTag = RoomBubbleCellDataTagKeyVerificationRequest; + } + + self.tag = cellDataTag; + } + } + break; + default: + break; + } + +} #pragma mark - Show all reactions From a47522b7c51b670883a625d34019019cdf81318d Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 19:55:49 +0100 Subject: [PATCH 12/26] MXKRoomBubbleTableViewCell: Add incoming key verification request action identifiers. --- Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h | 14 ++++++++++++++ Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h b/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h index ca82723c6..ce1282065 100644 --- a/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h +++ b/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h @@ -42,6 +42,20 @@ extern NSString *const kMXKRoomBubbleCellLongPressOnReactionView; */ extern NSString *const kMXKRoomBubbleCellEventIdKey; +/** + Action identifier used when the user pressed accept button for an incoming key verification request. + + The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellEventIdKey` key, representing the event id associated to the key verification request. + */ +extern NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed; + +/** + Action identifier used when the user pressed decline button for an incoming key verification request. + + The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellEventIdKey` key, representing the event id associated to the key verification request. + */ +extern NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed; + /** Define a `MXKRoomBubbleTableViewCell` category at Riot level to handle bubble customisation. */ diff --git a/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m b/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m index 077bfe8b1..6723f2dc0 100644 --- a/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m +++ b/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m @@ -31,6 +31,8 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi NSString *const kMXKRoomBubbleCellTapOnReceiptsContainer = @"kMXKRoomBubbleCellTapOnReceiptsContainer"; NSString *const kMXKRoomBubbleCellLongPressOnReactionView = @"kMXKRoomBubbleCellLongPressOnReactionView"; NSString *const kMXKRoomBubbleCellEventIdKey = @"kMXKRoomBubbleCellEventIdKey"; +NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed = @"kMXKRoomBubbleCellKeyVerificationAcceptPressed"; +NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = @"kMXKRoomBubbleCellKeyVerificationDeclinePressed"; @implementation MXKRoomBubbleTableViewCell (Riot) @@ -76,6 +78,12 @@ NSString *const kMXKRoomBubbleCellEventIdKey = @"kMXKRoomBubbleCellEventIdKey"; viewTag:(NSInteger)viewTag displayOnLeft:(BOOL)displayOnLeft { + if (!self.bubbleInfoContainer) + { + NSLog(@"[MXKRoomBubbleTableViewCell+Riot] bubbleInfoContainer property is missing for cell class: %@", NSStringFromClass(self.class)); + return; + } + NSArray *bubbleComponents = bubbleData.bubbleComponents; MXKRoomBubbleComponent *component = bubbleComponents[componentIndex]; From 194e314afe721d748735114c68b9a723a8f74b05 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 19:56:56 +0100 Subject: [PATCH 13/26] Add RoomBubbleCellData.h and MXKRoomBubbleTableViewCell+Riot.h to Objective-C bridging header. --- Riot/SupportingFiles/Riot-Bridging-Header.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h index be5547efb..c39876075 100644 --- a/Riot/SupportingFiles/Riot-Bridging-Header.h +++ b/Riot/SupportingFiles/Riot-Bridging-Header.h @@ -15,3 +15,5 @@ #import "EventFormatter.h" #import "MediaPickerViewController.h" #import "AppDelegate.h" +#import "RoomBubbleCellData.h" +#import "MXKRoomBubbleTableViewCell+Riot.h" From 05d0ab7ff4077780e8f8098ec41537f02e634e56 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 19:58:16 +0100 Subject: [PATCH 14/26] EventFormatter: Make key verification cancel and done event types visible in timeline. --- Riot/Utils/EventFormatter.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 3ba09e318..f9227d391 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -143,6 +143,13 @@ static NSString *const kEventFormatterTimeFormat = @"HH:mm"; } } + // Make event types MXEventTypeKeyVerificationCancel and MXEventTypeKeyVerificationDone visible in timeline. + // TODO: Find another way to keep them visible and avoid instantiate empty NSMutableAttributedString. + if (event.eventType == MXEventTypeKeyVerificationCancel || event.eventType == MXEventTypeKeyVerificationDone) + { + return [NSMutableAttributedString new]; + } + NSAttributedString *attributedString = [super attributedStringFromEvent:event withRoomState:roomState error:error]; if (event.sentState == MXEventSentStateSent From 6fe6067529c104d6bf7eea780145dbb5af08db4c Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 20:02:34 +0100 Subject: [PATCH 15/26] Refactor BubbleCellWithoutSenderInfoContentView to BubbleCellContentView and handle pagination title. --- ...View.swift => BubbleCellContentView.swift} | 27 +++- .../BubbleCellContentView.xib | 148 ++++++++++++++++++ ...BubbleCellWithoutSenderInfoContentView.xib | 93 ----------- 3 files changed, 170 insertions(+), 98 deletions(-) rename Riot/Modules/Room/Views/BubbleCells/BaseContentViews/{BubbleCellWithoutSenderInfoContentView.swift => BubbleCellContentView.swift} (68%) create mode 100644 Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib delete mode 100644 Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.swift similarity index 68% rename from Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift rename to Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.swift index e4c7a9bd8..158df123c 100644 --- a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.swift +++ b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.swift @@ -18,7 +18,7 @@ import UIKit import Reusable @objcMembers -final class BubbleCellWithoutSenderInfoContentView: UIView, NibLoadable { +final class BubbleCellContentView: UIView, NibLoadable { // MARK: - Properties @@ -34,32 +34,49 @@ final class BubbleCellWithoutSenderInfoContentView: UIView, NibLoadable { @IBOutlet weak var bubbleOverlayContainer: UIView! + @IBOutlet weak var paginationTitleContainerView: UIView! + @IBOutlet weak var paginationLabel: UILabel! + @IBOutlet weak var paginationSeparatorView: UIView! + // MARK: Private private var showReadReceipts: Bool { get { - return self.readReceiptsContainerView.isHidden + return !self.readReceiptsContainerView.isHidden } set { self.readReceiptsContainerView.isHidden = !newValue } } + // MARK: Public + + var showPaginationTitle: Bool { + get { + return !self.paginationTitleContainerView.isHidden + } + set { + self.paginationTitleContainerView.isHidden = !newValue + } + } + // MARK: - Setup - class func instantiate() -> BubbleCellWithoutSenderInfoContentView { - return BubbleCellWithoutSenderInfoContentView.loadFromNib() + class func instantiate() -> BubbleCellContentView { + return BubbleCellContentView.loadFromNib() } // MARK: - Public func update(theme: Theme) { self.backgroundColor = theme.backgroundColor + self.paginationLabel.textColor = theme.tintColor + self.paginationSeparatorView.backgroundColor = theme.tintColor } } // MARK: - BubbleCellReadReceiptsDisplayable -extension BubbleCellWithoutSenderInfoContentView: BubbleCellReadReceiptsDisplayable { +extension BubbleCellContentView: BubbleCellReadReceiptsDisplayable { func addReadReceiptsView(_ readReceiptsView: UIView) { self.readReceiptsContentView.vc_removeAllSubviews() diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib new file mode 100644 index 000000000..774a36c25 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib b/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib deleted file mode 100644 index ac074f0ca..000000000 --- a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellWithoutSenderInfoContentView.xib +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 28bd41f19711aac386cfa1e30dd619cc9c871972 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 20:10:13 +0100 Subject: [PATCH 16/26] KeyVerificationBaseBubbleCell: Use BubbleCellContentView. Improve cell height caching. --- .../KeyVerificationBaseBubbleCell.swift | 74 ++++++++++++++----- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift index a280a979e..0344b20b9 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift @@ -30,11 +30,12 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { // MARK: Public weak var keyVerificationCellInnerContentView: KeyVerificationCellInnerContentView? - weak var bubbleCellWithoutSenderInfoContentView: BubbleCellWithoutSenderInfoContentView? + + weak var bubbleCellContentView: BubbleCellContentView? override var bubbleInfoContainer: UIView! { get { - guard let infoContainer = self.bubbleCellWithoutSenderInfoContentView?.bubbleInfoContainer else { + guard let infoContainer = self.bubbleCellContentView?.bubbleInfoContainer else { fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainer should not be used before set") } return infoContainer @@ -46,7 +47,7 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { override var bubbleOverlayContainer: UIView! { get { - guard let overlayContainer = self.bubbleCellWithoutSenderInfoContentView?.bubbleOverlayContainer else { + guard let overlayContainer = self.bubbleCellContentView?.bubbleOverlayContainer else { fatalError("[KeyVerificationBaseBubbleCell] bubbleOverlayContainer should not be used before set") } return overlayContainer @@ -58,7 +59,7 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! { get { - guard let infoContainerTopConstraint = self.bubbleCellWithoutSenderInfoContentView?.bubbleInfoContainerTopConstraint else { + guard let infoContainerTopConstraint = self.bubbleCellContentView?.bubbleInfoContainerTopConstraint else { fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainerTopConstraint should not be used before set") } return infoContainerTopConstraint @@ -91,7 +92,7 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { // MARK: - Public func update(theme: Theme) { - self.bubbleCellWithoutSenderInfoContentView?.update(theme: theme) + self.bubbleCellContentView?.update(theme: theme) self.keyVerificationCellInnerContentView?.update(theme: theme) } @@ -120,13 +121,35 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { return senderDisplayName } - class func sizingView() -> MXKRoomBubbleTableViewCell { - fatalError("[KeyVerificationBaseBubbleCell] Subclass should implement this method") + class func sizingView() -> KeyVerificationBaseBubbleCell { + fatalError("[KeyVerificationBaseBubbleCell] Subclass should implement this method") } - // TODO: Implement thiscmethod in subclasses - class func sizingHeightHashValue(from bubbleData: MXKRoomBubbleCellData) -> Int { - return bubbleData.hashValue + class func sizingViewHeightHashValue(from bubbleCellData: MXKRoomBubbleCellData) -> Int { + + var hasher = Hasher() + + let sizingView = self.sizingView() + sizingView.render(bubbleCellData) + + // Add cell class name + hasher.combine(self.defaultReuseIdentifier()) + + if let keyVerificationCellInnerContentView = sizingView.keyVerificationCellInnerContentView { + + // Add other user info + if let otherUserInfo = keyVerificationCellInnerContentView.otherUserInfo { + hasher.combine(otherUserInfo) + } + + // Add request status text + if keyVerificationCellInnerContentView.isRequestStatusHidden == false, + let requestStatusText = sizingView.keyVerificationCellInnerContentView?.requestStatusText { + hasher.combine(requestStatusText) + } + } + + return hasher.finalize() } // MARK: - Overrides @@ -163,20 +186,31 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { return height } + override func render(_ cellData: MXKCellData!) { + super.render(cellData) + + if let bubbleData = self.bubbleData, + let bubbleCellContentView = self.bubbleCellContentView, + let paginationDate = bubbleData.date, + bubbleCellContentView.showPaginationTitle { + bubbleCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased() + } + } + // MARK: - Private private func setupContentView() { - if self.bubbleCellWithoutSenderInfoContentView == nil { + if self.bubbleCellContentView == nil { - let bubbleCellWithoutSenderInfoContentView = BubbleCellWithoutSenderInfoContentView.instantiate() + let bubbleCellContentView = BubbleCellContentView.instantiate() let innerContentView = KeyVerificationCellInnerContentView.instantiate() - bubbleCellWithoutSenderInfoContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView) + bubbleCellContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView) - self.contentView.vc_addSubViewMatchingParent(bubbleCellWithoutSenderInfoContentView) + self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView) - self.bubbleCellWithoutSenderInfoContentView = bubbleCellWithoutSenderInfoContentView + self.bubbleCellContentView = bubbleCellContentView self.keyVerificationCellInnerContentView = innerContentView } } @@ -204,7 +238,11 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { sizingView.layoutIfNeeded() let fittingSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height) - let height = sizingView.systemLayoutSizeFitting(fittingSize).height + var height = sizingView.systemLayoutSizeFitting(fittingSize).height + + if let roomBubbleCellData = cellData as? RoomBubbleCellData, let readReceipts = roomBubbleCellData.readReceipts, readReceipts.count > 0 { + height+=RoomBubbleCellLayout.readReceiptsViewHeight + } return height } @@ -214,10 +252,10 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell { extension KeyVerificationBaseBubbleCell: BubbleCellReadReceiptsDisplayable { func addReadReceiptsView(_ readReceiptsView: UIView) { - self.bubbleCellWithoutSenderInfoContentView?.addReadReceiptsView(readReceiptsView) + self.bubbleCellContentView?.addReadReceiptsView(readReceiptsView) } func removeReadReceiptsView() { - self.bubbleCellWithoutSenderInfoContentView?.removeReadReceiptsView() + self.bubbleCellContentView?.removeReadReceiptsView() } } From 148c0686fa7aa7872f435f1a3f43dc6c458e8894 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 20:14:17 +0100 Subject: [PATCH 17/26] Handle key verification cells data filling. --- .../KeyVerificationCellInnerContentView.swift | 33 ++++-- .../KeyVerificationCellInnerContentView.xib | 100 +++++++++++------- .../KeyVerificationConclusionBubbleCell.swift | 45 +++++--- ...ionIncomingRequestApprovalBubbleCell.swift | 25 +++-- ...yVerificationRequestStatusBubbleCell.swift | 66 +++++++++--- 5 files changed, 181 insertions(+), 88 deletions(-) diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift index 4b859339f..1402be19f 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.swift @@ -23,7 +23,7 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { private enum Constants { static let cornerRadius: CGFloat = 8.0 - static let buttonBackgroundColorAlpha: CGFloat = 0.8 + static let buttonBackgroundColorAlpha: CGFloat = 0.2 static let buttonCornerRadius: CGFloat = 6.0 } @@ -34,10 +34,11 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { @IBOutlet private weak var badgeImageView: UIImageView! @IBOutlet private weak var titleLabel: UILabel! - @IBOutlet private weak var userInformationsLabel: UILabel! + @IBOutlet private weak var otherUserInformationLabel: UILabel! @IBOutlet private weak var requestStatusLabel: UILabel! + @IBOutlet private weak var buttonsContainerView: UIView! @IBOutlet private weak var acceptButton: UIButton! @IBOutlet private weak var declineButton: UIButton! @@ -48,8 +49,7 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { return self.acceptButton.isHidden && self.declineButton.isHidden } set { - self.acceptButton.isHidden = newValue - self.declineButton.isHidden = newValue + self.buttonsContainerView.isHidden = newValue } } @@ -80,6 +80,10 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { } } + var otherUserInfo: String? { + return self.otherUserInformationLabel.text + } + var requestStatusText: String? { get { return self.requestStatusLabel.text @@ -106,6 +110,21 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { super.awakeFromNib() self.layer.masksToBounds = true + self.acceptButton.layer.masksToBounds = true + + self.acceptButton.titleLabel?.adjustsFontSizeToFitWidth = true + self.acceptButton.titleLabel?.minimumScaleFactor = 0.5 + self.acceptButton.titleLabel?.baselineAdjustment = .alignCenters + + self.acceptButton.setTitle(VectorL10n.keyVerificationTileRequestIncomingApprovalAccept, for: .normal) + + self.declineButton.layer.masksToBounds = true + + self.declineButton.titleLabel?.adjustsFontSizeToFitWidth = true + self.declineButton.titleLabel?.minimumScaleFactor = 0.5 + self.declineButton.titleLabel?.baselineAdjustment = .alignCenters + + self.declineButton.setTitle(VectorL10n.keyVerificationTileRequestIncomingApprovalDecline, for: .normal) } override func layoutSubviews() { @@ -124,14 +143,14 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { func update(theme: Theme) { self.backgroundColor = theme.headerBackgroundColor self.titleLabel.textColor = theme.textPrimaryColor - self.userInformationsLabel.textColor = theme.textSecondaryColor + self.otherUserInformationLabel.textColor = theme.textSecondaryColor self.acceptButton.vc_setBackgroundColor(theme.tintColor.withAlphaComponent(Constants.buttonBackgroundColorAlpha), for: .normal) self.declineButton.vc_setBackgroundColor(theme.noticeColor.withAlphaComponent(Constants.buttonBackgroundColorAlpha), for: .normal) } func updateSenderInfo(with userId: String, userDisplayName: String?) { - self.userInformationsLabel.text = self.buildUserInfoText(with: userId, userDisplayName: userDisplayName) + self.otherUserInformationLabel.text = self.buildUserInfoText(with: userId, userDisplayName: userDisplayName) } // MARK: - Private @@ -149,6 +168,8 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { return userInfoText } + // MARK: - Action + @IBAction private func declineButtonAction(_ sender: Any) { self.declineActionHandler?() } diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib index ca7a98a8c..404d95945 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationCellInnerContentView.xib @@ -1,10 +1,6 @@ - - - - @@ -12,64 +8,85 @@ - + - - + + - + - - + + - - + + + @@ -85,12 +102,13 @@ + + - - + diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift index 6bf6b0a5d..41761b380 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift @@ -17,8 +17,8 @@ import UIKit @objcMembers -final class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { - +class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { + // MARK: - Constants private enum Sizing { @@ -47,7 +47,7 @@ final class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { super.render(cellData) guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView, - let bubbleData = self.bubbleData, + let bubbleData = self.bubbleData as? RoomBubbleCellData, let viewData = self.viewData(from: bubbleData) else { NSLog("[KeyVerificationConclusionBubbleCell] Fail to render \(String(describing: cellData))") return @@ -58,37 +58,52 @@ final class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName) } - override class func sizingView() -> MXKRoomBubbleTableViewCell { + override class func sizingView() -> KeyVerificationBaseBubbleCell { return self.Sizing.view } // MARK: - Private - // TODO: Handle view data filling - private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationConclusionViewData? { - guard let event = bubbleData.bubbleComponents.first?.event else { + private func viewData(from roomBubbleData: RoomBubbleCellData) -> KeyVerificationConclusionViewData? { + guard let event = roomBubbleData.bubbleComponents.first?.event else { return nil } - + let viewData: KeyVerificationConclusionViewData? - + let senderId = self.senderId(from: bubbleData) let senderDisplayName = self.senderDisplayName(from: bubbleData) let title: String? - let badgeImage: UIImage? - + let badgeImage: UIImage? + switch event.eventType { case .keyVerificationDone: - title = "Verified" badgeImage = Asset.Images.encryptionTrusted.image + title = VectorL10n.keyVerificationTileConclusionDoneTitle case .keyVerificationCancel: - title = "Cancelled" badgeImage = Asset.Images.encryptionNormal.image + + // TODO: Use right titles here + if let keyVerification = roomBubbleData.keyVerification, let cancelCodeValue = keyVerification.transaction?.reasonCancelCode?.value { + switch cancelCodeValue { + case MXTransactionCancelCode.mismatchedSas().value: + title = "TODO" + case MXTransactionCancelCode.unexpectedMessage().value: + title = "TODO" + case MXTransactionCancelCode.mismatchedCommitment().value: + title = "TODO" + default: + title = nil + } + } else { + title = nil + } + default: badgeImage = nil title = nil } - + if let title = title, let badgeImage = badgeImage { viewData = KeyVerificationConclusionViewData(badgeImage: badgeImage, title: title, @@ -97,7 +112,7 @@ final class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { } else { viewData = nil } - + return viewData } } diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift index 9cc1c0136..3093b5206 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalBubbleCell.swift @@ -17,12 +17,12 @@ import UIKit @objcMembers -final class KeyVerificationIncomingRequestApprovalBubbleCell: KeyVerificationBaseBubbleCell { - +class KeyVerificationIncomingRequestApprovalBubbleCell: KeyVerificationBaseBubbleCell { + // MARK: - Constants private enum Sizing { - static let view = KeyVerificationConclusionBubbleCell(style: .default, reuseIdentifier: nil) + static let view = KeyVerificationIncomingRequestApprovalBubbleCell(style: .default, reuseIdentifier: nil) } // MARK: - Setup @@ -68,29 +68,34 @@ final class KeyVerificationIncomingRequestApprovalBubbleCell: KeyVerificationBas keyVerificationCellInnerContentView.title = viewData.title keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName) + let actionUserInfo: [AnyHashable: Any]? + + if let eventId = bubbleData.getFirstBubbleComponentWithDisplay()?.event.eventId { + actionUserInfo = [kMXKRoomBubbleCellEventIdKey: eventId] + } else { + actionUserInfo = nil + } + keyVerificationCellInnerContentView.acceptActionHandler = { [weak self] in - // TODO: Use correct action identifier - self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellTapOnContentView, userInfo: nil) + self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed, userInfo: actionUserInfo) } keyVerificationCellInnerContentView.declineActionHandler = { [weak self] in - // TODO: Use correct action identifier - self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellTapOnContentView, userInfo: nil) + self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed, userInfo: actionUserInfo) } } - override class func sizingView() -> MXKRoomBubbleTableViewCell { + override class func sizingView() -> KeyVerificationBaseBubbleCell { return self.Sizing.view } // MARK: - Private - // TODO: Handle view data filling private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationIncomingRequestApprovalViewData? { let senderId = self.senderId(from: bubbleData) let senderDisplayName = self.senderDisplayName(from: bubbleData) - let title = "Verification request" + let title = VectorL10n.keyVerificationTileRequestIncomingTitle return KeyVerificationIncomingRequestApprovalViewData(title: title, senderId: senderId, diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift index 453407ced..b5af25a5a 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusBubbleCell.swift @@ -17,8 +17,8 @@ import UIKit @objcMembers -final class KeyVerificationRequestStatusBubbleCell: KeyVerificationBaseBubbleCell { - +class KeyVerificationRequestStatusBubbleCell: KeyVerificationBaseBubbleCell { + // MARK: - Constants private enum Sizing { @@ -52,8 +52,8 @@ final class KeyVerificationRequestStatusBubbleCell: KeyVerificationBaseBubbleCel super.render(cellData) guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView, - let bubbleData = self.bubbleData, - let viewData = self.viewData(from: bubbleData) else { + let roomBubbleCellData = self.bubbleData as? RoomBubbleCellData, + let viewData = self.viewData(from: roomBubbleCellData) else { NSLog("[KeyVerificationRequestStatusBubbleCell] Fail to render \(String(describing: cellData))") return } @@ -63,29 +63,63 @@ final class KeyVerificationRequestStatusBubbleCell: KeyVerificationBaseBubbleCel keyVerificationCellInnerContentView.requestStatusText = viewData.statusText } - override class func sizingView() -> MXKRoomBubbleTableViewCell { + override class func sizingView() -> KeyVerificationBaseBubbleCell { return self.Sizing.view } // MARK: - Private - // TODO: Handle view data filling - private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationRequestStatusViewData? { + private func viewData(from roomBubbleCellData: RoomBubbleCellData) -> KeyVerificationRequestStatusViewData? { let senderId = self.senderId(from: bubbleData) - let senderDisplayName = self.senderDisplayName(from: bubbleData) + let senderDisplayName = self.senderDisplayName(from: bubbleData) let title: String - let statusText: String = "You accepted" + let statusText: String? - if senderId.isEmpty == false { - title = "Verification request" + if roomBubbleCellData.isIncoming { + title = VectorL10n.keyVerificationTileRequestIncomingTitle } else { - title = "Verification sent" + title = VectorL10n.keyVerificationTileRequestOutgoingTitle } - return KeyVerificationRequestStatusViewData(title: title, - senderId: senderId, - senderDisplayName: senderDisplayName, - statusText: statusText) + if let keyVerification = roomBubbleCellData.keyVerification { + switch keyVerification.state { + case .requestPending: + if !roomBubbleCellData.isIncoming { + statusText = VectorL10n.keyVerificationTileRequestStatusWaiting + } else { + if roomBubbleCellData.isKeyVerificationOperationPending { + statusText = VectorL10n.keyVerificationTileRequestStatusDataLoading + } else { + // Should not happen, KeyVerificationIncomingRequestApprovalBubbleCell should be displayed in this case. + statusText = nil + } + } + case .requestExpired: + statusText = VectorL10n.keyVerificationTileRequestStatusExpired + case .requestCancelled, .transactionCancelled: + let userName = senderDisplayName ?? senderId + statusText = VectorL10n.keyVerificationTileRequestStatusCancelled(userName) + case .requestCancelledByMe, .transactionCancelledByMe: + statusText = VectorL10n.keyVerificationTileRequestStatusCancelledByMe + default: + statusText = VectorL10n.keyVerificationTileRequestStatusAccepted + } + } else { + statusText = VectorL10n.keyVerificationTileRequestStatusDataLoading + } + + let viewData: KeyVerificationRequestStatusViewData? + + if let statusText = statusText { + viewData = KeyVerificationRequestStatusViewData(title: title, + senderId: senderId, + senderDisplayName: senderDisplayName, + statusText: statusText) + } else { + viewData = nil + } + + return viewData } } From d290938fb10d9d9b6b5ee1bfc0938d75db020220 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 20:15:28 +0100 Subject: [PATCH 18/26] Add key verification cells with pagination title. --- ...clusionWithPaginationTitleBubbleCell.swift | 52 +++++++++++++++++++ ...pprovalWithPaginationTitleBubbleCell.swift | 52 +++++++++++++++++++ ...tStatusWithPaginationTitleBubbleCell.swift | 52 +++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionWithPaginationTitleBubbleCell.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift create mode 100644 Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionWithPaginationTitleBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionWithPaginationTitleBubbleCell.swift new file mode 100644 index 000000000..7cc1b8277 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionWithPaginationTitleBubbleCell.swift @@ -0,0 +1,52 @@ +/* + Copyright 2019 New Vector 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 UIKit + +@objcMembers +final class KeyVerificationConclusionWithPaginationTitleBubbleCell: KeyVerificationConclusionBubbleCell { + + // MARK: - Constants + + private enum Sizing { + static let view = KeyVerificationConclusionWithPaginationTitleBubbleCell(style: .default, reuseIdentifier: nil) + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + guard let bubbleCellContentView = self.bubbleCellContentView else { + fatalError("[KeyVerificationConclusionWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil") + } + + bubbleCellContentView.showPaginationTitle = true + } + + // MARK: - Overrides + + override class func sizingView() -> KeyVerificationBaseBubbleCell { + return self.Sizing.view + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift new file mode 100644 index 000000000..6b4b529f1 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift @@ -0,0 +1,52 @@ +/* + Copyright 2019 New Vector 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 UIKit + +@objcMembers +final class KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell: KeyVerificationIncomingRequestApprovalBubbleCell { + + // MARK: - Constants + + private enum Sizing { + static let view = KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell(style: .default, reuseIdentifier: nil) + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + guard let bubbleCellContentView = self.bubbleCellContentView else { + fatalError("[KeyVerificationRequestStatusWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil") + } + + bubbleCellContentView.showPaginationTitle = true + } + + // MARK: - Overrides + + override class func sizingView() -> KeyVerificationBaseBubbleCell { + return self.Sizing.view + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift new file mode 100644 index 000000000..f9c0e6465 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift @@ -0,0 +1,52 @@ +/* + Copyright 2019 New Vector 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 UIKit + +@objcMembers +final class KeyVerificationRequestStatusWithPaginationTitleBubbleCell: KeyVerificationRequestStatusBubbleCell { + + // MARK: - Constants + + private enum Sizing { + static let view = KeyVerificationRequestStatusWithPaginationTitleBubbleCell(style: .default, reuseIdentifier: nil) + } + + // MARK: - Setup + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func commonInit() { + guard let bubbleCellContentView = self.bubbleCellContentView else { + fatalError("[KeyVerificationRequestStatusWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil") + } + + bubbleCellContentView.showPaginationTitle = true + } + + // MARK: - Overrides + + override class func sizingView() -> KeyVerificationBaseBubbleCell { + return self.Sizing.view + } +} From 3ea3f1f84728dd4b8ab9f4e77a446580dcc4e4fe Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 20:23:36 +0100 Subject: [PATCH 19/26] RoomViewController: Handle key verification cells with pagination title. Handle key verification incoming request approval actions. Remove copy action in context menu for key verification cells. --- Riot/Modules/Room/RoomViewController.m | 70 +++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 03ccc1656..4053321be 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -354,8 +354,12 @@ [self.bubblesTableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier]; [self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier]; + [self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier]; [self.bubblesTableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier]; + [self.bubblesTableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier]; [self.bubblesTableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier]; + [self.bubblesTableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier]; + // Prepare expanded header expandedHeader = [ExpandedRoomTitleView roomTitleView]; @@ -2043,17 +2047,17 @@ { cellViewClass = RoomPredecessorBubbleCell.class; } - else if (bubbleData.tag == RoomBubbleCellDataTagDeviceKeyVerificationRequestIncomingApproval) + else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval) { - cellViewClass = KeyVerificationIncomingRequestApprovalBubbleCell.class; + cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class : KeyVerificationIncomingRequestApprovalBubbleCell.class; } - else if (bubbleData.tag == RoomBubbleCellDataTagDeviceKeyVerificationRequest) + else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequest) { - cellViewClass = KeyVerificationRequestStatusBubbleCell.class; + cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class : KeyVerificationRequestStatusBubbleCell.class; } - else if (bubbleData.tag == RoomBubbleCellDataTagDeviceKeyVerificationConclusion) + else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationConclusion) { - cellViewClass = KeyVerificationConclusionBubbleCell.class; + cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationConclusionWithPaginationTitleBubbleCell.class : KeyVerificationConclusionBubbleCell.class; } else if (bubbleData.tag == RoomBubbleCellDataTagMembership) { @@ -2271,6 +2275,30 @@ [self showContextualMenuForEvent:selectedEvent fromSingleTapGesture:YES cell:cell animated:YES]; } } + else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed]) + { + NSString *eventId = userInfo[kMXKRoomBubbleCellEventIdKey]; + + RoomDataSource *roomDataSource = (RoomDataSource*)self.roomDataSource; + + [roomDataSource acceptVerificationRequestForEventId:eventId success:^{ + + } failure:^(NSError *error) { + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed]) + { + NSString *eventId = userInfo[kMXKRoomBubbleCellEventIdKey]; + + RoomDataSource *roomDataSource = (RoomDataSource*)self.roomDataSource; + + [roomDataSource declineVerificationRequestForEventId:eventId success:^{ + + } failure:^(NSError *error) { + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnAttachmentView]) { if (((MXKRoomBubbleTableViewCell*)cell).bubbleData.attachment.eventSentState == MXEventSentStateFailed) @@ -5319,8 +5347,36 @@ // Copy action + BOOL isCopyActionEnabled = !attachment || attachment.type != MXKAttachmentTypeSticker; + + if (isCopyActionEnabled) + { + switch (event.eventType) { + case MXEventTypeRoomMessage: + { + NSString *messageType = event.content[@"msgtype"]; + + if ([messageType isEqualToString:kMXMessageTypeKeyVerificationRequest]) + { + isCopyActionEnabled = NO; + } + break; + } + case MXEventTypeKeyVerificationStart: + case MXEventTypeKeyVerificationAccept: + case MXEventTypeKeyVerificationKey: + case MXEventTypeKeyVerificationMac: + case MXEventTypeKeyVerificationDone: + case MXEventTypeKeyVerificationCancel: + isCopyActionEnabled = NO; + break; + default: + break; + } + } + RoomContextualMenuItem *copyMenuItem = [[RoomContextualMenuItem alloc] initWithMenuAction:RoomContextualMenuActionCopy]; - copyMenuItem.isEnabled = !attachment || attachment.type != MXKAttachmentTypeSticker; + copyMenuItem.isEnabled = isCopyActionEnabled; copyMenuItem.action = ^{ MXStrongifyAndReturnIfNil(self); From 0ad759c18e9197ddc7d87d43efeaa3196c84d02a Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 21:47:16 +0100 Subject: [PATCH 20/26] RoomDataSource: Handle RoomBubbleCellData key verification update. Handle incoming key verification approval. --- Riot/AppDelegate.h | 9 + Riot/AppDelegate.m | 26 ++ .../Modules/Room/DataSources/RoomDataSource.h | 22 ++ .../Modules/Room/DataSources/RoomDataSource.m | 253 ++++++++++++++++++ 4 files changed, 310 insertions(+) diff --git a/Riot/AppDelegate.h b/Riot/AppDelegate.h index 1ecb646da..70984e2b9 100644 --- a/Riot/AppDelegate.h +++ b/Riot/AppDelegate.h @@ -130,6 +130,15 @@ extern NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey; - (void)logoutSendingRequestServer:(BOOL)sendLogoutServerRequest completion:(void (^)(BOOL isLoggedOut))completion; +/** + Present incoming key verification request to accept. + + @param incomingKeyVerificationRequest The incoming key verification request. + @param The matrix session. + @return Indicate NO if the key verification screen could not be presented. + */ +- (BOOL)presentIncomingKeyVerificationRequest:(MXKeyVerificationRequest*)incomingKeyVerificationRequest + inSession:(MXSession*)session; #pragma mark - Matrix Accounts handling diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 517395fb0..df926b902 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -4826,6 +4826,32 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe } } +- (BOOL)presentIncomingKeyVerificationRequest:(MXKeyVerificationRequest*)incomingKeyVerificationRequest + inSession:(MXSession*)session +{ + BOOL presented = NO; + + if (!deviceVerificationCoordinatorBridgePresenter) + { + NSLog(@"[AppDelegate] presentIncomingKeyVerificationRequest"); + + UIViewController *presentingViewController = self.window.rootViewController.presentedViewController ?: self.window.rootViewController; + + deviceVerificationCoordinatorBridgePresenter = [[DeviceVerificationCoordinatorBridgePresenter alloc] initWithSession:session]; + deviceVerificationCoordinatorBridgePresenter.delegate = self; + + [deviceVerificationCoordinatorBridgePresenter presentFrom:presentingViewController incomingKeyVerificationRequest:incomingKeyVerificationRequest animated:YES]; + + presented = YES; + } + else + { + NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingDeviceVerification: Controller already presented."); + } + + return presented; +} + - (BOOL)presentIncomingDeviceVerification:(MXIncomingSASTransaction*)transaction inSession:(MXSession*)mxSession { NSLog(@"[AppDelegate][MXKeyVerification] presentIncomingDeviceVerification: %@", transaction); diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.h b/Riot/Modules/Room/DataSources/RoomDataSource.h index 1c7dfda5a..fd01e5ad6 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.h +++ b/Riot/Modules/Room/DataSources/RoomDataSource.h @@ -62,4 +62,26 @@ success:(void (^)(NSString *eventId))success failure:(void (^)(NSError *error))failure; +/** + Accept incoming key verification request. + + @param eventId Event id associated to the key verification request event. + @param success A block object called when the operation succeeds. + @param failure A block object called when the operation fails. + */ +- (void)acceptVerificationRequestForEventId:(NSString*)eventId + success:(void(^)(void))success + failure:(void(^)(NSError*))failure; + +/** + Decline incoming key verification request. + + @param eventId Event id associated to the key verification request event. + @param success A block object called when the operation succeeds. + @param failure A block object called when the operation fails. + */ +- (void)declineVerificationRequestForEventId:(NSString*)eventId + success:(void(^)(void))success + failure:(void(^)(NSError*))failure; + @end diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 5b82ce4fe..280eef50d 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -35,6 +35,15 @@ id kThemeServiceDidChangeThemeNotificationObserver; } +// Observe key verification request changes +@property (nonatomic, weak) id keyVerificationRequestDidChangeNotificationObserver; + +// Observe key verification transaction changes +@property (nonatomic, weak) id deviceVerificationTransactionDidChangeNotificationObserver; + +// Timer used to debounce cells refresh +@property (nonatomic, strong) NSTimer *refreshCellsTimer; + @end @implementation RoomDataSource @@ -71,6 +80,9 @@ [self reload]; }]; + + [self registerKeyVerificationRequestNotification]; + [self registerDeviceVerificationTransactionNotification]; } return self; } @@ -117,6 +129,16 @@ kThemeServiceDidChangeThemeNotificationObserver = nil; } + if (self.keyVerificationRequestDidChangeNotificationObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:self.keyVerificationRequestDidChangeNotificationObserver]; + } + + if (self.deviceVerificationTransactionDidChangeNotificationObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:self.deviceVerificationTransactionDidChangeNotificationObserver]; + } + [super destroy]; } @@ -189,6 +211,8 @@ { roomBubbleCellData.senderAvatarPlaceholder = [AvatarGenerator generateAvatarForMatrixItem:roomBubbleCellData.senderId withDisplayName:roomBubbleCellData.senderDisplayName]; } + + [self updateKeyVerificationIfNeededForRoomBubbleCellData:roomBubbleCellData]; UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; @@ -526,6 +550,173 @@ return cell; } +- (RoomBubbleCellData*)roomBubbleCellDataForEventId:(NSString*)eventId +{ + id cellData = [self cellDataOfEventWithEventId:eventId]; + RoomBubbleCellData *roomBubbleCellData; + + if ([cellData isKindOfClass:RoomBubbleCellData.class]) + { + roomBubbleCellData = (RoomBubbleCellData*)cellData; + } + + return roomBubbleCellData; +} + +- (MXKeyVerificationRequest*)keyVerificationRequestFromEventId:(NSString*)eventId +{ + RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:eventId]; + + return roomBubbleCellData.keyVerification.request; +} + +- (void)refreshCellsWithDelay +{ + if (self.refreshCellsTimer) + { + return; + } + + self.refreshCellsTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(refreshCellsTimerFired) userInfo:nil repeats:NO]; +} + +- (void)refreshCellsTimerFired +{ + [self refreshCells]; + self.refreshCellsTimer = nil; +} + +- (void)refreshCells +{ + if (self.delegate) + { + [self.delegate dataSource:self didCellChange:nil]; + } +} + +- (void)registerKeyVerificationRequestNotification +{ + self.keyVerificationRequestDidChangeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:MXKeyVerificationRequestDidChangeNotification + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *notification) + { + id notificationObject = notification.object; + + if ([notificationObject isKindOfClass:MXKeyVerificationByDMRequest.class]) + { + MXKeyVerificationByDMRequest *keyVerificationByDMRequest = (MXKeyVerificationByDMRequest*)notificationObject; + + if ([keyVerificationByDMRequest.roomId isEqualToString:self.roomId]) + { + RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:keyVerificationByDMRequest.eventId]; + + roomBubbleCellData.isKeyVerificationOperationPending = NO; + roomBubbleCellData.keyVerification = nil; + + if (roomBubbleCellData) + { + [self refreshCellsWithDelay]; + } + } + } + }]; +} + +- (void)registerDeviceVerificationTransactionNotification +{ + self.deviceVerificationTransactionDidChangeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:MXDeviceVerificationTransactionDidChangeNotification + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *notification) + { + MXDeviceVerificationTransaction *deviceVerificationTransaction = (MXDeviceVerificationTransaction*)notification.object; + + if ([deviceVerificationTransaction.dmRoomId isEqualToString:self.roomId]) + { + RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:deviceVerificationTransaction.dmEventId]; + + roomBubbleCellData.isKeyVerificationOperationPending = NO; + roomBubbleCellData.keyVerification = nil; + + if (roomBubbleCellData) + { + [self refreshCellsWithDelay]; + } + } + }]; +} + +- (BOOL)shouldFetchKeyVerificationForEvent:(MXEvent*)event +{ + if (!event) + { + return NO; + } + + BOOL shouldFetchKeyVerification = NO; + + switch (event.eventType) + { + case MXEventTypeKeyVerificationDone: + case MXEventTypeKeyVerificationCancel: + shouldFetchKeyVerification = YES; + break; + case MXEventTypeRoomMessage: + { + NSString *msgType = event.content[@"msgtype"]; + + if ([msgType isEqualToString:kMXMessageTypeKeyVerificationRequest]) + { + shouldFetchKeyVerification = YES; + } + } + break; + default: + break; + } + + return shouldFetchKeyVerification; +} + +- (void)updateKeyVerificationIfNeededForRoomBubbleCellData:(RoomBubbleCellData*)bubbleCellData +{ + MXEvent *event = bubbleCellData.getFirstBubbleComponentWithDisplay.event; + + if (![self shouldFetchKeyVerificationForEvent:event]) + { + return; + } + + if (bubbleCellData.keyVerification != nil || bubbleCellData.isKeyVerificationOperationPending) + { + // Key verification already fetched or request is pending do nothing + return; + } + + __block MXHTTPOperation *operation = [self.mxSession.crypto.deviceVerificationManager keyVerificationFromKeyVerificationEvent:event + success:^(MXKeyVerification * _Nonnull keyVerification) + { + BOOL shouldRefreshCells = bubbleCellData.isKeyVerificationOperationPending || bubbleCellData.keyVerification == nil; + + bubbleCellData.keyVerification = keyVerification; + bubbleCellData.isKeyVerificationOperationPending = NO; + + if (shouldRefreshCells) + { + [self refreshCellsWithDelay]; + } + + } failure:^(NSError * _Nonnull error) { + + NSLog(@"[RoomDataSource] updateKeyVerificationIfNeededForRoomBubbleCellData; keyVerificationFromKeyVerificationEvent fails with error: %@", error); + + bubbleCellData.isKeyVerificationOperationPending = NO; + }]; + + bubbleCellData.isKeyVerificationOperationPending = !operation; +} + #pragma mark - - (void)setSelectedEventId:(NSString *)selectedEventId @@ -577,6 +768,68 @@ [self sendVideo:videoLocalURL withThumbnail:videoThumbnail success:success failure:failure]; } +- (void)acceptVerificationRequestForEventId:(NSString*)eventId success:(void(^)(void))success failure:(void(^)(NSError*))failure +{ + MXKeyVerificationRequest *keyVerificationRequest = [self keyVerificationRequestFromEventId:eventId]; + + if (!keyVerificationRequest) + { + NSError *error; + + if (failure) + { + failure(error); + } + return; + } + + [[AppDelegate theDelegate] presentIncomingKeyVerificationRequest:keyVerificationRequest inSession:self.mxSession]; + + if (success) + { + success(); + } +} + +- (void)declineVerificationRequestForEventId:(NSString*)eventId success:(void(^)(void))success failure:(void(^)(NSError*))failure +{ + MXKeyVerificationRequest *keyVerificationRequest = [self keyVerificationRequestFromEventId:eventId]; + + if (!keyVerificationRequest) + { + NSError *error; + + if (failure) + { + failure(error); + } + return; + } + + RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:eventId]; + roomBubbleCellData.isKeyVerificationOperationPending = YES; + + [self refreshCells]; + + [keyVerificationRequest cancelWithCancelCode:MXTransactionCancelCode.user success:^{ + + // roomBubbleCellData.isKeyVerificationOperationPending will be set to NO by MXKeyVerificationRequestDidChangeNotification notification + + if (success) + { + success(); + } + + } failure:^(NSError * _Nonnull error) { + + roomBubbleCellData.isKeyVerificationOperationPending = NO; + + if (failure) + { + failure(error); + } + }]; +} #pragma - Accessibility From 972a1174c891a561a0134567bb219bb1d408301f Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 21:51:05 +0100 Subject: [PATCH 21/26] DeviceVerificationCoordinator: Handle incoming key verification to accept. --- .../DeviceVerificationCoordinator.swift | 40 +++++- ...rificationCoordinatorBridgePresenter.swift | 12 ++ ...ceVerificationDataLoadingCoordinator.swift | 17 ++- ...rificationDataLoadingCoordinatorType.swift | 1 + ...erificationDataLoadingViewController.swift | 32 ++++- ...viceVerificationDataLoadingViewModel.swift | 123 +++++++++++++++--- ...VerificationDataLoadingViewModelType.swift | 1 + 7 files changed, 197 insertions(+), 29 deletions(-) diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift index 3687da88a..84dca9666 100644 --- a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift @@ -31,6 +31,7 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { private let otherDeviceId: String private var incomingTransaction: MXIncomingSASTransaction? + private var incomingKeyVerificationRequest: MXKeyVerificationRequest? // MARK: Public @@ -66,12 +67,29 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { self.incomingTransaction = incomingTransaction } + /// Contrustor to manage an incoming SAS device verification transaction + /// + /// - Parameters: + /// - session: the MXSession + /// - incomingKeyVerificationRequest: An existing incoming key verification request to accept + convenience init(session: MXSession, incomingKeyVerificationRequest: MXKeyVerificationRequest) { + self.init(session: session, otherUserId: incomingKeyVerificationRequest.sender, otherDeviceId: incomingKeyVerificationRequest.fromDevice) + self.incomingKeyVerificationRequest = incomingKeyVerificationRequest + } + // MARK: - Public methods func start() { - let rootCoordinator = self.createDataLoadingScreenCoordinator() + let rootCoordinator: Coordinator & Presentable + + if let incomingKeyVerificationRequest = self.incomingKeyVerificationRequest { + rootCoordinator = self.createDataLoadingScreenCoordinator(with: incomingKeyVerificationRequest) + } else { + rootCoordinator = self.createDataLoadingScreenCoordinator() + } + rootCoordinator.start() - + self.add(childCoordinator: rootCoordinator) self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in self?.remove(childCoordinator: rootCoordinator) @@ -91,6 +109,14 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { return coordinator } + + private func createDataLoadingScreenCoordinator(with keyVerificationRequest: MXKeyVerificationRequest) -> DeviceVerificationDataLoadingCoordinator { + let coordinator = DeviceVerificationDataLoadingCoordinator(incomingKeyVerificationRequest: keyVerificationRequest) + coordinator.delegate = self + coordinator.start() + + return coordinator + } private func showStart(otherUser: MXUser, otherDevice: MXDeviceInfo) { let coordinator = DeviceVerificationStartCoordinator(session: self.session, otherUser: otherUser, otherDevice: otherDevice) @@ -141,6 +167,16 @@ extension DeviceVerificationCoordinator: DeviceVerificationDataLoadingCoordinato self.showStart(otherUser: user, otherDevice: device) } } + + func deviceVerificationDataLoadingCoordinator(_ coordinator: DeviceVerificationDataLoadingCoordinatorType, didAcceptKeyVerificationRequestWithTransaction transaction: MXDeviceVerificationTransaction) { + + if let sasTransaction = transaction as? MXSASTransaction { + self.showVerify(transaction: sasTransaction, animated: true) + } else { + NSLog("[DeviceVerificationCoordinator] Transaction \(transaction) is not supported") + self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId) + } + } func deviceVerificationDataLoadingCoordinatorDidCancel(_ coordinator: DeviceVerificationDataLoadingCoordinatorType) { self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId) diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift index c809533a3..bdd170fb6 100644 --- a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift @@ -73,6 +73,18 @@ final class DeviceVerificationCoordinatorBridgePresenter: NSObject { viewController.present(deviceVerificationCoordinator.toPresentable(), animated: animated, completion: nil) deviceVerificationCoordinator.start() + self.coordinator = deviceVerificationCoordinator + } + + func present(from viewController: UIViewController, incomingKeyVerificationRequest: MXKeyVerificationRequest, animated: Bool) { + + NSLog("[DeviceVerificationCoordinatorBridgePresenter] Present incoming key verification request from \(viewController)") + + let deviceVerificationCoordinator = DeviceVerificationCoordinator(session: self.session, incomingKeyVerificationRequest: incomingKeyVerificationRequest) + deviceVerificationCoordinator.delegate = self + viewController.present(deviceVerificationCoordinator.toPresentable(), animated: animated, completion: nil) + deviceVerificationCoordinator.start() + self.coordinator = deviceVerificationCoordinator } diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinator.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinator.swift index ece7185af..9e4e9309e 100644 --- a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinator.swift +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinator.swift @@ -25,7 +25,6 @@ final class DeviceVerificationDataLoadingCoordinator: DeviceVerificationDataLoad // MARK: Private - private let session: MXSession private var deviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadingViewModelType private let deviceVerificationDataLoadingViewController: DeviceVerificationDataLoadingViewController @@ -39,9 +38,14 @@ final class DeviceVerificationDataLoadingCoordinator: DeviceVerificationDataLoad // MARK: - Setup init(session: MXSession, otherUserId: String, otherDeviceId: String) { - self.session = session - - let deviceVerificationDataLoadingViewModel = DeviceVerificationDataLoadingViewModel(session: self.session, otherUserId: otherUserId, otherDeviceId: otherDeviceId) + let deviceVerificationDataLoadingViewModel = DeviceVerificationDataLoadingViewModel(session: session, otherUserId: otherUserId, otherDeviceId: otherDeviceId) + let deviceVerificationDataLoadingViewController = DeviceVerificationDataLoadingViewController.instantiate(with: deviceVerificationDataLoadingViewModel) + self.deviceVerificationDataLoadingViewModel = deviceVerificationDataLoadingViewModel + self.deviceVerificationDataLoadingViewController = deviceVerificationDataLoadingViewController + } + + init(incomingKeyVerificationRequest: MXKeyVerificationRequest) { + let deviceVerificationDataLoadingViewModel = DeviceVerificationDataLoadingViewModel(keyVerificationRequest: incomingKeyVerificationRequest) let deviceVerificationDataLoadingViewController = DeviceVerificationDataLoadingViewController.instantiate(with: deviceVerificationDataLoadingViewModel) self.deviceVerificationDataLoadingViewModel = deviceVerificationDataLoadingViewModel self.deviceVerificationDataLoadingViewController = deviceVerificationDataLoadingViewController @@ -60,6 +64,11 @@ final class DeviceVerificationDataLoadingCoordinator: DeviceVerificationDataLoad // MARK: - DeviceVerificationDataLoadingViewModelCoordinatorDelegate extension DeviceVerificationDataLoadingCoordinator: DeviceVerificationDataLoadingViewModelCoordinatorDelegate { + + func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didAcceptKeyVerificationWithTransaction transaction: MXDeviceVerificationTransaction) { + self.delegate?.deviceVerificationDataLoadingCoordinator(self, didAcceptKeyVerificationRequestWithTransaction: transaction) + } + func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didLoadUser user: MXUser, device: MXDeviceInfo) { self.delegate?.deviceVerificationDataLoadingCoordinator(self, didLoadUser: user, device: device) } diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinatorType.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinatorType.swift index c70b8cc50..9f8ef8976 100644 --- a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinatorType.swift +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingCoordinatorType.swift @@ -20,6 +20,7 @@ import Foundation protocol DeviceVerificationDataLoadingCoordinatorDelegate: class { func deviceVerificationDataLoadingCoordinator(_ coordinator: DeviceVerificationDataLoadingCoordinatorType, didLoadUser user: MXUser, device: MXDeviceInfo) + func deviceVerificationDataLoadingCoordinator(_ coordinator: DeviceVerificationDataLoadingCoordinatorType, didAcceptKeyVerificationRequestWithTransaction transaction: MXDeviceVerificationTransaction) func deviceVerificationDataLoadingCoordinatorDidCancel(_ coordinator: DeviceVerificationDataLoadingCoordinatorType) } diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift index 80ae30af7..a21cc9f31 100644 --- a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift @@ -112,9 +112,35 @@ final class DeviceVerificationDataLoadingViewController: UIViewController { } private func render(error: Error) { - self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: { - self.viewModel.process(viewAction: .cancel) - }) + + var shouldDisplayError = true + var message: String? + + switch error { + case DeviceVerificationDataLoadingViewModelError.transactionCancelled: + message = VectorL10n.deviceVerificationCancelled + case DeviceVerificationDataLoadingViewModelError.transactionCancelledByMe(reason: let reason): + if reason.value != MXTransactionCancelCode.user().value { + message = VectorL10n.deviceVerificationCancelledByMe(reason.humanReadable) + } else { + shouldDisplayError = false + } + default: + break + } + + if shouldDisplayError { + + let completion = { + self.viewModel.process(viewAction: .cancel) + } + + if let message = message { + self.errorPresenter.presentError(from: self, title: "", message: message, animated: true, handler: completion) + } else { + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: completion) + } + } } private func renderError(message: String) { diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModel.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModel.swift index ed9ddb2fa..47c7799a9 100644 --- a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModel.swift +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModel.swift @@ -20,6 +20,8 @@ import Foundation enum DeviceVerificationDataLoadingViewModelError: Error { case unknown + case transactionCancelled + case transactionCancelledByMe(reason: MXTransactionCancelCode) } final class DeviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadingViewModelType { @@ -28,9 +30,13 @@ final class DeviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadin // MARK: Private - private let session: MXSession - private let otherUserId: String - private let otherDeviceId: String + private let session: MXSession? + private let otherUserId: String? + private let otherDeviceId: String? + + private let keyVerificationRequest: MXKeyVerificationRequest? + + private var currentOperation: MXHTTPOperation? // MARK: Public @@ -43,9 +49,18 @@ final class DeviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadin self.session = session self.otherUserId = otherUserId self.otherDeviceId = otherDeviceId + self.keyVerificationRequest = nil + } + + init(keyVerificationRequest: MXKeyVerificationRequest) { + self.session = nil + self.otherUserId = nil + self.otherDeviceId = nil + self.keyVerificationRequest = keyVerificationRequest } deinit { + self.currentOperation?.cancel() } // MARK: - Public @@ -60,40 +75,74 @@ final class DeviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadin } // MARK: - Private - + private func loadData() { - guard let crypto = self.session.crypto else { + if let keyVerificationRequest = self.keyVerificationRequest { + self.acceptKeyVerificationRequest(keyVerificationRequest) + } else { + self.downloadOtherDeviceKeys() + } + } + + private func acceptKeyVerificationRequest(_ keyVerificationRequest: MXKeyVerificationRequest) { + + self.update(viewState: .loading) + + keyVerificationRequest.accept(withMethod: MXKeyVerificationMethodSAS, success: { [weak self] (deviceVerificationTransaction) in + guard let self = self else { + return + } + + if let outgoingSASTransaction = deviceVerificationTransaction as? MXOutgoingSASTransaction { + self.registerTransactionDidStateChangeNotification(transaction: outgoingSASTransaction) + } else { + self.update(viewState: .error(DeviceVerificationDataLoadingViewModelError.unknown)) + } + + }, failure: { [weak self] (error) in + guard let self = self else { + return + } + self.update(viewState: .error(error)) + }) + } + + private func downloadOtherDeviceKeys() { + guard let session = self.session, + let crypto = session.crypto, + let otherUserId = self.otherUserId, + let otherDeviceId = self.otherDeviceId else { self.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice)) NSLog("[DeviceVerificationDataLoadingViewModel] Error session.crypto is nil") return } - - if let otherUser = self.session.user(withUserId: otherUserId) { + + if let otherUser = session.user(withUserId: otherUserId) { self.update(viewState: .loading) - crypto.downloadKeys([self.otherUserId], forceDownload: false, success: { [weak self] (usersDevicesMap) in + self.currentOperation = crypto.downloadKeys([otherUserId], forceDownload: false, success: { [weak self] (usersDevicesMap) in guard let sself = self else { return } - - if let otherDevice = usersDevicesMap?.object(forDevice: sself.otherDeviceId, forUser: sself.otherUserId) { + + if let otherDevice = usersDevicesMap?.object(forDevice: otherDeviceId, forUser: otherUserId) { sself.update(viewState: .loaded) sself.coordinatorDelegate?.deviceVerificationDataLoadingViewModel(sself, didLoadUser: otherUser, device: otherDevice) } else { - sself.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice)) - } - - }, failure: { [weak self] (error) in - guard let sself = self else { - return + sself.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice)) } - let finalError = error ?? DeviceVerificationDataLoadingViewModelError.unknown - - sself.update(viewState: .error(finalError)) + }, failure: { [weak self] (error) in + guard let sself = self else { + return + } + + let finalError = error ?? DeviceVerificationDataLoadingViewModelError.unknown + + sself.update(viewState: .error(finalError)) }) - + } else { self.update(viewState: .errorMessage(VectorL10n.deviceVerificationErrorCannotLoadDevice)) } @@ -102,4 +151,38 @@ final class DeviceVerificationDataLoadingViewModel: DeviceVerificationDataLoadin private func update(viewState: DeviceVerificationDataLoadingViewState) { self.viewDelegate?.deviceVerificationDataLoadingViewModel(self, didUpdateViewState: viewState) } + + // MARK: MXDeviceVerificationTransactionDidChange + + private func registerTransactionDidStateChangeNotification(transaction: MXOutgoingSASTransaction) { + NotificationCenter.default.addObserver(self, selector: #selector(transactionDidStateChange(notification:)), name: NSNotification.Name.MXDeviceVerificationTransactionDidChange, object: transaction) + } + + private func unregisterTransactionDidStateChangeNotification() { + NotificationCenter.default.removeObserver(self, name: .MXDeviceVerificationTransactionDidChange, object: nil) + } + + @objc private func transactionDidStateChange(notification: Notification) { + guard let transaction = notification.object as? MXOutgoingSASTransaction else { + return + } + + switch transaction.state { + case MXSASTransactionStateShowSAS: + self.unregisterTransactionDidStateChangeNotification() + self.update(viewState: .loaded) + self.coordinatorDelegate?.deviceVerificationDataLoadingViewModel(self, didAcceptKeyVerificationWithTransaction: transaction) + case MXSASTransactionStateCancelled: + self.unregisterTransactionDidStateChangeNotification() + self.update(viewState: .error(DeviceVerificationDataLoadingViewModelError.transactionCancelled)) + case MXSASTransactionStateCancelledByMe: + guard let reason = transaction.reasonCancelCode else { + return + } + self.unregisterTransactionDidStateChangeNotification() + self.update(viewState: .error(DeviceVerificationDataLoadingViewModelError.transactionCancelledByMe(reason: reason))) + default: + break + } + } } diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModelType.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModelType.swift index 0121c0028..7808df654 100644 --- a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModelType.swift +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewModelType.swift @@ -24,6 +24,7 @@ protocol DeviceVerificationDataLoadingViewModelViewDelegate: class { protocol DeviceVerificationDataLoadingViewModelCoordinatorDelegate: class { func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didLoadUser user: MXUser, device: MXDeviceInfo) + func deviceVerificationDataLoadingViewModel(_ viewModel: DeviceVerificationDataLoadingViewModelType, didAcceptKeyVerificationWithTransaction transaction: MXDeviceVerificationTransaction) func deviceVerificationDataLoadingViewModelDidCancel(_ viewModel: DeviceVerificationDataLoadingViewModelType) } From f5ca4d4bf80969738a889b0b48037df813a7fd9a Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 14 Jan 2020 21:52:02 +0100 Subject: [PATCH 22/26] Update pbxproj --- Riot.xcodeproj/project.pbxproj | 88 ++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index fd3d454aa..fb93d2e5f 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -129,6 +129,12 @@ B105778B221304FA00334B1E /* KeyBackupSetupSuccessFromPassphraseViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B105778A221304FA00334B1E /* KeyBackupSetupSuccessFromPassphraseViewController.storyboard */; }; B105778D2213051E00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B105778C2213051E00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.swift */; }; B105778F2213052A00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B105778E2213052A00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.storyboard */; }; + B108931F23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108931E23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift */; }; + B108932123AB8D7D00802670 /* KeyVerificationIncomingRequestApprovalViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932023AB8D7D00802670 /* KeyVerificationIncomingRequestApprovalViewData.swift */; }; + B108932323AB908A00802670 /* KeyVerificationRequestStatusViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932223AB908A00802670 /* KeyVerificationRequestStatusViewData.swift */; }; + B108932523AB93A200802670 /* KeyVerificationConclusionViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932423AB93A200802670 /* KeyVerificationConclusionViewData.swift */; }; + B108932823ABEE6800802670 /* BubbleCellReadReceiptsDisplayable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */; }; + B108932A23ACBA0B00802670 /* SizingViewHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932923ACBA0B00802670 /* SizingViewHeight.swift */; }; B1098BDF21ECE09F000DDA48 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDA21ECE09E000DDA48 /* Strings.swift */; }; B1098BE121ECE09F000DDA48 /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDC21ECE09E000DDA48 /* Images.swift */; }; B1098BE321ECE09F000DDA48 /* RiotDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDE21ECE09E000DDA48 /* RiotDefaults.swift */; }; @@ -175,6 +181,11 @@ B139C22121FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B139C22021FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift */; }; B139C22321FF01B200BB68EC /* KeyBackupRecoverFromPassphraseCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B139C22221FF01B200BB68EC /* KeyBackupRecoverFromPassphraseCoordinatorType.swift */; }; B139C22521FF01C100BB68EC /* KeyBackupRecoverFromPassphraseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B139C22421FF01C100BB68EC /* KeyBackupRecoverFromPassphraseCoordinator.swift */; }; + B14084C623BF76890010F692 /* BubbleCellContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14084C523BF76890010F692 /* BubbleCellContentView.swift */; }; + B14084C823BF76CB0010F692 /* BubbleCellContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B14084C723BF76CB0010F692 /* BubbleCellContentView.xib */; }; + B14084CA23BF89310010F692 /* KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14084C923BF89310010F692 /* KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift */; }; + B14084CC23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14084CB23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift */; }; + B14084CE23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14084CD23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift */; }; B140B4A221F87F7100E3F5FE /* OperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = B140B4A121F87F7100E3F5FE /* OperationQueue.swift */; }; B140B4A621F89E7600E3F5FE /* KeyBackupSetupCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B140B4A521F89E7600E3F5FE /* KeyBackupSetupCoordinatorBridgePresenter.swift */; }; B140B4A821F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B140B4A721F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift */; }; @@ -531,6 +542,11 @@ B1C45A8A232A8C2600165425 /* SettingsIdentityServerCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C45A81232A8C2600165425 /* SettingsIdentityServerCoordinatorBridgePresenter.swift */; }; B1C45A8B232A8C2600165425 /* SettingsIdentityServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C45A82232A8C2600165425 /* SettingsIdentityServerViewModel.swift */; }; B1C45A8C232A8C2600165425 /* SettingsIdentityServerViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C45A83232A8C2600165425 /* SettingsIdentityServerViewAction.swift */; }; + B1C543A4239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C543A3239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift */; }; + B1C543A6239E999700DCA1FA /* KeyVerificationCellInnerContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1C543A5239E999700DCA1FA /* KeyVerificationCellInnerContentView.xib */; }; + B1C543AE23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C543AD23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift */; }; + B1C543B023A2871300DCA1FA /* KeyVerificationBaseBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C543AF23A2871300DCA1FA /* KeyVerificationBaseBubbleCell.swift */; }; + B1C543B223A2913F00DCA1FA /* KeyVerificationConclusionBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C543B123A2913F00DCA1FA /* KeyVerificationConclusionBubbleCell.swift */; }; B1C562CA2289C2690037F12A /* UIGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C562C92289C2690037F12A /* UIGestureRecognizer.swift */; }; B1C562CC228AB3510037F12A /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C562CB228AB3510037F12A /* UIStackView.swift */; }; B1C562D9228C0B760037F12A /* RoomContextualMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C562D8228C0B760037F12A /* RoomContextualMenuItem.swift */; }; @@ -806,6 +822,12 @@ B105778A221304FA00334B1E /* KeyBackupSetupSuccessFromPassphraseViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = KeyBackupSetupSuccessFromPassphraseViewController.storyboard; sourceTree = ""; }; B105778C2213051E00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupSetupSuccessFromRecoveryKeyViewController.swift; sourceTree = ""; }; B105778E2213052A00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = KeyBackupSetupSuccessFromRecoveryKeyViewController.storyboard; sourceTree = ""; }; + B108931E23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationIncomingRequestApprovalBubbleCell.swift; sourceTree = ""; }; + B108932023AB8D7D00802670 /* KeyVerificationIncomingRequestApprovalViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationIncomingRequestApprovalViewData.swift; sourceTree = ""; }; + B108932223AB908A00802670 /* KeyVerificationRequestStatusViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationRequestStatusViewData.swift; sourceTree = ""; }; + B108932423AB93A200802670 /* KeyVerificationConclusionViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationConclusionViewData.swift; sourceTree = ""; }; + B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleCellReadReceiptsDisplayable.swift; sourceTree = ""; }; + B108932923ACBA0B00802670 /* SizingViewHeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizingViewHeight.swift; sourceTree = ""; }; B1098BDA21ECE09E000DDA48 /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; B1098BDC21ECE09E000DDA48 /* Images.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Images.swift; sourceTree = ""; }; B1098BDE21ECE09E000DDA48 /* RiotDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RiotDefaults.swift; sourceTree = ""; }; @@ -852,6 +874,11 @@ B139C22021FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseViewState.swift; sourceTree = ""; }; B139C22221FF01B200BB68EC /* KeyBackupRecoverFromPassphraseCoordinatorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseCoordinatorType.swift; sourceTree = ""; }; B139C22421FF01C100BB68EC /* KeyBackupRecoverFromPassphraseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseCoordinator.swift; sourceTree = ""; }; + B14084C523BF76890010F692 /* BubbleCellContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleCellContentView.swift; sourceTree = ""; }; + B14084C723BF76CB0010F692 /* BubbleCellContentView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BubbleCellContentView.xib; sourceTree = ""; }; + B14084C923BF89310010F692 /* KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift; sourceTree = ""; }; + B14084CB23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationConclusionWithPaginationTitleBubbleCell.swift; sourceTree = ""; }; + B14084CD23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift; sourceTree = ""; }; B140B4A121F87F7100E3F5FE /* OperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationQueue.swift; sourceTree = ""; }; B140B4A521F89E7600E3F5FE /* KeyBackupSetupCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyBackupSetupCoordinatorBridgePresenter.swift; sourceTree = ""; }; B140B4A721F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverCoordinatorBridgePresenter.swift; sourceTree = ""; }; @@ -1393,6 +1420,11 @@ B1C45A81232A8C2600165425 /* SettingsIdentityServerCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsIdentityServerCoordinatorBridgePresenter.swift; sourceTree = ""; }; B1C45A82232A8C2600165425 /* SettingsIdentityServerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsIdentityServerViewModel.swift; sourceTree = ""; }; B1C45A83232A8C2600165425 /* SettingsIdentityServerViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsIdentityServerViewAction.swift; sourceTree = ""; }; + B1C543A3239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationCellInnerContentView.swift; sourceTree = ""; }; + B1C543A5239E999700DCA1FA /* KeyVerificationCellInnerContentView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KeyVerificationCellInnerContentView.xib; sourceTree = ""; }; + B1C543AD23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationRequestStatusBubbleCell.swift; sourceTree = ""; }; + B1C543AF23A2871300DCA1FA /* KeyVerificationBaseBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationBaseBubbleCell.swift; sourceTree = ""; }; + B1C543B123A2913F00DCA1FA /* KeyVerificationConclusionBubbleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationConclusionBubbleCell.swift; sourceTree = ""; }; B1C562C92289C2690037F12A /* UIGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIGestureRecognizer.swift; sourceTree = ""; }; B1C562CB228AB3510037F12A /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = ""; }; B1C562D8228C0B760037F12A /* RoomContextualMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomContextualMenuItem.swift; sourceTree = ""; }; @@ -1911,6 +1943,16 @@ path = Success; sourceTree = ""; }; + B108932623ABE82C00802670 /* BaseContentViews */ = { + isa = PBXGroup; + children = ( + B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */, + B14084C523BF76890010F692 /* BubbleCellContentView.swift */, + B14084C723BF76CB0010F692 /* BubbleCellContentView.xib */, + ); + path = BaseContentViews; + sourceTree = ""; + }; B1098BD921ECE09E000DDA48 /* Generated */ = { isa = PBXGroup; children = ( @@ -2395,6 +2437,33 @@ path = Riot/Modules/Common/CollectionView; sourceTree = SOURCE_ROOT; }; + B1A12C64239AB74500AA2B86 /* CrossSigning */ = { + isa = PBXGroup; + children = ( + ); + path = CrossSigning; + sourceTree = ""; + }; + B1A12C65239ABBDB00AA2B86 /* KeyVerification */ = { + isa = PBXGroup; + children = ( + B108932923ACBA0B00802670 /* SizingViewHeight.swift */, + B1C543A3239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift */, + B1C543A5239E999700DCA1FA /* KeyVerificationCellInnerContentView.xib */, + B1C543AF23A2871300DCA1FA /* KeyVerificationBaseBubbleCell.swift */, + B108932023AB8D7D00802670 /* KeyVerificationIncomingRequestApprovalViewData.swift */, + B108931E23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift */, + B14084CD23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift */, + B108932223AB908A00802670 /* KeyVerificationRequestStatusViewData.swift */, + B1C543AD23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift */, + B14084C923BF89310010F692 /* KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift */, + B108932423AB93A200802670 /* KeyVerificationConclusionViewData.swift */, + B1C543B123A2913F00DCA1FA /* KeyVerificationConclusionBubbleCell.swift */, + B14084CB23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift */, + ); + path = KeyVerification; + sourceTree = ""; + }; B1A6C10523881ECB002882FD /* SlidingModal */ = { isa = PBXGroup; children = ( @@ -2413,6 +2482,7 @@ B1B5567620EE6C4C00210D55 /* Modules */ = { isa = PBXGroup; children = ( + B1A12C64239AB74500AA2B86 /* CrossSigning */, B1A6C10523881ECB002882FD /* SlidingModal */, 32DB556722FDADE50016329E /* ServiceTerms */, 3232AB94225730E100AD6A5C /* DeviceVerification */, @@ -3249,6 +3319,8 @@ B1B5583F20EF768E00210D55 /* BubbleCells */ = { isa = PBXGroup; children = ( + B108932623ABE82C00802670 /* BaseContentViews */, + B1A12C65239ABBDB00AA2B86 /* KeyVerification */, B1B5584220EF768E00210D55 /* Encryption */, B1B5589220EF768E00210D55 /* RoomEmptyBubbleCell.h */, B1B558B620EF768E00210D55 /* RoomEmptyBubbleCell.m */, @@ -4176,6 +4248,7 @@ B1B558FB20EF768F00210D55 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib in Resources */, B1B558BB20EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib in Resources */, B1B557A720EF5A1B00210D55 /* DeviceTableViewCell.xib in Resources */, + B14084C823BF76CB0010F692 /* BubbleCellContentView.xib in Resources */, B1B557D220EF5E3500210D55 /* MediaAlbumTableCell.xib in Resources */, B1B558C520EF768F00210D55 /* RoomOutgoingEncryptedTextMsgBubbleCell.xib in Resources */, B1B5582B20EF666100210D55 /* DirectoryRecentTableViewCell.xib in Resources */, @@ -4198,6 +4271,7 @@ B1B557A220EF58AD00210D55 /* ContactTableViewCell.xib in Resources */, B1B558EB20EF768F00210D55 /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib in Resources */, B10B3B5C2201DD740072C76B /* KeyBackupBannerCell.xib in Resources */, + B1C543A6239E999700DCA1FA /* KeyVerificationCellInnerContentView.xib in Resources */, 32891D76226728EF00C82226 /* DeviceVerificationDataLoadingViewController.storyboard in Resources */, B1B5581820EF625800210D55 /* PreviewRoomTitleView.xib in Resources */, B1B5583020EF66BA00210D55 /* RoomIdOrAliasTableViewCell.xib in Resources */, @@ -4481,6 +4555,7 @@ B169330B20F3CA3A00746532 /* Contact.m in Sources */, B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */, B1D4752A21EE52B10067973F /* KeyBackupSetupIntroViewController.swift in Sources */, + B108931F23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift in Sources */, B1B5599220EFC5E400210D55 /* Analytics.m in Sources */, B14F143422144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewAction.swift in Sources */, B1098BF621ECFE65000DDA48 /* KeyBackupSetupPassphraseCoordinator.swift in Sources */, @@ -4521,6 +4596,7 @@ B1B5581A20EF625800210D55 /* ExpandedRoomTitleView.m in Sources */, B1107EC82200B0720038014B /* KeyBackupRecoverSuccessViewController.swift in Sources */, B1B9DEEB22EB34EF0065E677 /* ReactionHistoryViewModel.swift in Sources */, + B1C543B023A2871300DCA1FA /* KeyVerificationBaseBubbleCell.swift in Sources */, B1963B2F228F1C4900CBA17F /* BubbleReactionViewCell.swift in Sources */, B1B558E920EF768F00210D55 /* RoomSelectedStickerBubbleCell.m in Sources */, B1C3360222F1ED600021BA8D /* MediaPickerCoordinatorBridgePresenter.swift in Sources */, @@ -4535,6 +4611,7 @@ 3209451221F1C1430088CAA2 /* BlackTheme.swift in Sources */, B1B5572720EE6C4D00210D55 /* RoomSearchViewController.m in Sources */, 3232ABBC2257BE6500AD6A5C /* DeviceVerificationVerifyViewAction.swift in Sources */, + B14084C623BF76890010F692 /* BubbleCellContentView.swift in Sources */, F05927C91FDED836009F2A68 /* MXGroup+Riot.m in Sources */, B1B5594520EF7BD000210D55 /* TableViewCellWithCollectionView.m in Sources */, B1A6C109238828A6002882FD /* SlidingModalPresentationDelegate.swift in Sources */, @@ -4570,11 +4647,13 @@ 32242F1421E8FBA900725742 /* DefaultTheme.swift in Sources */, B1963B2D228F1C4900CBA17F /* BubbleReactionsViewModel.swift in Sources */, 32242F1321E8FBA900725742 /* Theme.swift in Sources */, + B108932523AB93A200802670 /* KeyVerificationConclusionViewData.swift in Sources */, B1B5582520EF638A00210D55 /* RoomMemberTitleView.m in Sources */, B1B5582C20EF666100210D55 /* DirectoryRecentTableViewCell.m in Sources */, B1B558E420EF768F00210D55 /* RoomMembershipWithPaginationTitleBubbleCell.m in Sources */, B1B5573620EE6C4D00210D55 /* GroupsViewController.m in Sources */, B125FE21231D5E1D00B72806 /* SettingsDiscoveryViewAction.swift in Sources */, + B108932323AB908A00802670 /* KeyVerificationRequestStatusViewData.swift in Sources */, 3232ABB82257BE6500AD6A5C /* DeviceVerificationVerifyCoordinator.swift in Sources */, B142317A22CCFA2000FFA96A /* EditHistoryCell.swift in Sources */, B1DCC62622E60CC600625807 /* EmojiItem.swift in Sources */, @@ -4619,6 +4698,7 @@ 32863A5C2384074C00D07C4A /* RiotSettingAllowedWidgets.swift in Sources */, B1B9DEDA22E9B7350065E677 /* SerializationService.swift in Sources */, B1B5572520EE6C4D00210D55 /* RoomMessagesSearchViewController.m in Sources */, + B1C543AE23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift in Sources */, B139C22121FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift in Sources */, B1B5579120EF568D00210D55 /* GroupInviteTableViewCell.m in Sources */, B1B5579A20EF575B00210D55 /* ForgotPasswordInputsView.m in Sources */, @@ -4634,6 +4714,7 @@ B1B5574020EE6C4D00210D55 /* SegmentedViewController.m in Sources */, B1B5599320EFC5E400210D55 /* DecryptionFailure.m in Sources */, B125FE1F231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift in Sources */, + B108932A23ACBA0B00802670 /* SizingViewHeight.swift in Sources */, B157FAA323264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewState.swift in Sources */, B1098BF921ECFE65000DDA48 /* KeyBackupSetupCoordinator.swift in Sources */, B140B4A821F8AB4600E3F5FE /* KeyBackupRecoverCoordinatorBridgePresenter.swift in Sources */, @@ -4652,10 +4733,12 @@ B1B557B420EF5AEF00210D55 /* EventDetailsView.m in Sources */, B1B5577E20EE84BF00210D55 /* IncomingCallView.m in Sources */, B1DCC62822E60CE300625807 /* EmojiCategory.swift in Sources */, + B14084CC23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift in Sources */, B1B5578F20EF568D00210D55 /* GroupTableViewCell.m in Sources */, B1B5573220EE6C4D00210D55 /* GroupHomeViewController.m in Sources */, B1B5595220EF9A8700210D55 /* RecentTableViewCell.m in Sources */, 32F6B96C2270623100BBA352 /* DeviceVerificationDataLoadingCoordinatorType.swift in Sources */, + B14084CA23BF89310010F692 /* KeyVerificationRequestStatusWithPaginationTitleBubbleCell.swift in Sources */, B1DCC61D22E5E17100625807 /* EmojiPickerViewModelType.swift in Sources */, B1B5574120EE6C4D00210D55 /* RecentsViewController.m in Sources */, B1D250D82118AA0A000F4E93 /* RoomPredecessorBubbleCell.m in Sources */, @@ -4709,6 +4792,7 @@ B1B5575A20EE6C4D00210D55 /* UnifiedSearchViewController.m in Sources */, 3232AB492256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift in Sources */, B1B5572820EE6C4D00210D55 /* RoomViewController.m in Sources */, + B108932123AB8D7D00802670 /* KeyVerificationIncomingRequestApprovalViewData.swift in Sources */, B1B9DEED22EB34EF0065E677 /* ReactionHistoryCoordinator.swift in Sources */, B1DCC62A22E60D1000625807 /* EmojiMartService.swift in Sources */, B1B558C720EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */, @@ -4734,6 +4818,7 @@ B157FAA223264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewAction.swift in Sources */, 3232ABA1225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift in Sources */, B1C562D9228C0B760037F12A /* RoomContextualMenuItem.swift in Sources */, + B1C543B223A2913F00DCA1FA /* KeyVerificationConclusionBubbleCell.swift in Sources */, 323AB947232BD74600C1451F /* AuthFallBackViewController.m in Sources */, B1C562E1228C7C8C0037F12A /* RoomContextualMenuToolbarView.swift in Sources */, B1B557BF20EF5B4500210D55 /* DisabledRoomInputToolbarView.m in Sources */, @@ -4745,6 +4830,7 @@ B1098C0D21ED07E4000DDA48 /* NavigationRouter.swift in Sources */, B110872321F098F0003554A5 /* ActivityIndicatorPresenterType.swift in Sources */, B139C22321FF01B200BB68EC /* KeyBackupRecoverFromPassphraseCoordinatorType.swift in Sources */, + B14084CE23BFA0990010F692 /* KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.swift in Sources */, B14F143222144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinator.swift in Sources */, B110872621F098F0003554A5 /* ActivityIndicatorView.swift in Sources */, B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */, @@ -4802,11 +4888,13 @@ B1B5577D20EE84BF00210D55 /* CircleButton.m in Sources */, 32BF995521FA2AB700698084 /* SettingsKeyBackupViewAction.swift in Sources */, B109D6F1222D8C400061B6D9 /* UIApplication.swift in Sources */, + B108932823ABEE6800802670 /* BubbleCellReadReceiptsDisplayable.swift in Sources */, B1B558FF20EF768F00210D55 /* RoomIncomingTextMsgBubbleCell.m in Sources */, B1098C0021ECFE65000DDA48 /* KeyBackupSetupPassphraseViewController.swift in Sources */, B1B5591020EF782800210D55 /* TableViewCellWithPhoneNumberTextField.m in Sources */, B1DB4F06223015080065DBFA /* Character.swift in Sources */, B1B9DEEE22EB34EF0065E677 /* ReactionHistoryViewAction.swift in Sources */, + B1C543A4239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift in Sources */, 32B94DFA228EC26400716A26 /* ReactionsMenuButton.swift in Sources */, B1B9DEEC22EB34EF0065E677 /* ReactionHistoryViewModelType.swift in Sources */, B157FAA523264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift in Sources */, From b41343f3f6f3f8aab755221423df419ac29e2fb8 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Wed, 15 Jan 2020 10:50:36 +0100 Subject: [PATCH 23/26] KeyVerificationConclusionBubbleCell: Update warning title and badge image. --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ .../KeyVerificationConclusionBubbleCell.swift | 20 ++----------------- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 2b9f1c04d..b647ea9fb 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1106,3 +1106,4 @@ "key_verification_tile_request_incoming_approval_decline" = "Decline"; "key_verification_tile_conclusion_done_title" = "Verified"; +"key_verification_tile_conclusion_warning_title" = "Unstrusted sign in"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 6240b5928..a45f06cda 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1474,6 +1474,10 @@ internal enum VectorL10n { internal static var keyVerificationTileConclusionDoneTitle: String { return VectorL10n.tr("Vector", "key_verification_tile_conclusion_done_title") } + /// Unstrusted sign in + internal static var keyVerificationTileConclusionWarningTitle: String { + return VectorL10n.tr("Vector", "key_verification_tile_conclusion_warning_title") + } /// Accept internal static var keyVerificationTileRequestIncomingApprovalAccept: String { return VectorL10n.tr("Vector", "key_verification_tile_request_incoming_approval_accept") diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift index 41761b380..70353531f 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationConclusionBubbleCell.swift @@ -81,24 +81,8 @@ class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell { badgeImage = Asset.Images.encryptionTrusted.image title = VectorL10n.keyVerificationTileConclusionDoneTitle case .keyVerificationCancel: - badgeImage = Asset.Images.encryptionNormal.image - - // TODO: Use right titles here - if let keyVerification = roomBubbleData.keyVerification, let cancelCodeValue = keyVerification.transaction?.reasonCancelCode?.value { - switch cancelCodeValue { - case MXTransactionCancelCode.mismatchedSas().value: - title = "TODO" - case MXTransactionCancelCode.unexpectedMessage().value: - title = "TODO" - case MXTransactionCancelCode.mismatchedCommitment().value: - title = "TODO" - default: - title = nil - } - } else { - title = nil - } - + badgeImage = Asset.Images.encryptionWarning.image + title = VectorL10n.keyVerificationTileConclusionWarningTitle default: badgeImage = nil title = nil From dd3740aad658118831f1c1466e8c82558b986d57 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Wed, 15 Jan 2020 18:18:22 +0100 Subject: [PATCH 24/26] Update Riot/Assets/en.lproj/Vector.strings Co-Authored-By: manuroe --- Riot/Assets/en.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index b647ea9fb..e9618727f 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1096,7 +1096,7 @@ "key_verification_tile_request_outgoing_title" = "Verification sent"; "key_verification_tile_request_status_data_loading" = "Data loading …"; -"key_verification_tile_request_status_waiting" = "Waiting …"; +"key_verification_tile_request_status_waiting" = "Waiting…"; "key_verification_tile_request_status_expired" = "Expired"; "key_verification_tile_request_status_cancelled_by_me" = "You cancel"; "key_verification_tile_request_status_cancelled" = "%@ cancelled"; From cd7b31fb8fb40a0bb0624123ea8512a7cc02f131 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Wed, 15 Jan 2020 18:18:32 +0100 Subject: [PATCH 25/26] Update Riot/Assets/en.lproj/Vector.strings Co-Authored-By: manuroe --- Riot/Assets/en.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index e9618727f..668072889 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1095,7 +1095,7 @@ "key_verification_tile_request_incoming_title" = "Verification request"; "key_verification_tile_request_outgoing_title" = "Verification sent"; -"key_verification_tile_request_status_data_loading" = "Data loading …"; +"key_verification_tile_request_status_data_loading" = "Data loading…"; "key_verification_tile_request_status_waiting" = "Waiting…"; "key_verification_tile_request_status_expired" = "Expired"; "key_verification_tile_request_status_cancelled_by_me" = "You cancel"; From 2025d09e9c228cae78af05a7871a04db9a2677c4 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Wed, 15 Jan 2020 18:18:46 +0100 Subject: [PATCH 26/26] Update Riot/Assets/en.lproj/Vector.strings Co-Authored-By: manuroe --- Riot/Assets/en.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 668072889..2870a0e01 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1098,7 +1098,7 @@ "key_verification_tile_request_status_data_loading" = "Data loading…"; "key_verification_tile_request_status_waiting" = "Waiting…"; "key_verification_tile_request_status_expired" = "Expired"; -"key_verification_tile_request_status_cancelled_by_me" = "You cancel"; +"key_verification_tile_request_status_cancelled_by_me" = "You cancelled"; "key_verification_tile_request_status_cancelled" = "%@ cancelled"; "key_verification_tile_request_status_accepted" = "You accepted";