Contact.m 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2012-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "Contact.h"
  21. #import "Conversation.h"
  22. #import "UserSettings.h"
  23. #import "BaseMessage.h"
  24. #import "ContactUtil.h"
  25. #import "BundleUtil.h"
  26. #import "ThreemaFramework/ThreemaFramework-swift.h"
  27. @implementation Contact
  28. @dynamic abRecordId;
  29. @dynamic featureLevel;
  30. @dynamic firstName;
  31. @dynamic identity;
  32. @dynamic imageData;
  33. @dynamic lastName;
  34. @dynamic publicKey;
  35. @dynamic publicNickname;
  36. @dynamic sortIndex;
  37. @dynamic sortInitial;
  38. @dynamic verificationLevel;
  39. @dynamic verifiedEmail;
  40. @dynamic verifiedMobileNo;
  41. @dynamic state;
  42. @dynamic conversations;
  43. @dynamic groupConversations;
  44. @dynamic messages;
  45. @dynamic contactImage;
  46. @dynamic profilePictureSended;
  47. @dynamic profilePictureUpload;
  48. @dynamic cnContactId;
  49. @dynamic workContact;
  50. @dynamic hidden;
  51. - (NSString *)displayName {
  52. NSMutableString *displayName = [ContactUtil nameFromFirstname:self.firstName lastname:self.lastName];
  53. if (displayName.length == 0 && self.publicNickname.length > 0 && [self.publicNickname isEqualToString:self.identity] == NO) {
  54. [displayName appendFormat:@"~%@", self.publicNickname];
  55. }
  56. if (displayName.length == 0 && self.identity != nil) {
  57. [displayName appendString:self.identity];
  58. }
  59. switch (self.state.intValue) {
  60. case kStateInactive:
  61. [displayName appendFormat:@" (%@)", [BundleUtil localizedStringForKey:@"inactive"]];
  62. break;
  63. case kStateInvalid:
  64. [displayName appendFormat:@" (%@)", [BundleUtil localizedStringForKey:@"invalid"]];
  65. break;
  66. default:
  67. break;
  68. }
  69. return displayName;
  70. }
  71. - (NSString *)mentionName {
  72. NSMutableString *mentionName = [ContactUtil nameFromFirstname:self.firstName lastname:self.lastName];
  73. if (mentionName.length == 0 && self.publicNickname.length > 0 && [self.publicNickname isEqualToString:self.identity] == NO) {
  74. [mentionName appendFormat:@"~%@", self.publicNickname];
  75. }
  76. if (mentionName.length == 0 && self.identity != nil) {
  77. [mentionName appendString:self.identity];
  78. }
  79. if (mentionName.length > 24) {
  80. mentionName = [NSMutableString stringWithFormat:@"%@...", [mentionName substringToIndex:24]];
  81. }
  82. return mentionName;
  83. }
  84. + (NSSet *)keyPathsForValuesAffectingDisplayName {
  85. return [NSSet setWithObjects:@"firstName", @"lastName", @"publicNickname", @"identity", nil];
  86. }
  87. - (void)setFirstName:(NSString *)firstName {
  88. [self willChangeValueForKey:@"firstName"];
  89. [self setPrimitiveValue:firstName forKey:@"firstName"];
  90. [self updateSortInitial];
  91. [self didChangeValueForKey:@"firstName"];
  92. }
  93. - (void)setLastName:(NSString *)lastName {
  94. [self willChangeValueForKey:@"lastName"];
  95. [self setPrimitiveValue:lastName forKey:@"lastName"];
  96. [self updateSortInitial];
  97. [self didChangeValueForKey:@"lastName"];
  98. }
  99. - (void)setIdentity:(NSString *)identity {
  100. [self willChangeValueForKey:@"identity"];
  101. [self setPrimitiveValue:identity forKey:@"identity"];
  102. [self updateSortInitial];
  103. [self didChangeValueForKey:@"identity"];
  104. }
  105. - (void)updateSortInitial {
  106. SEL stringSelector;
  107. if (self.isGatewayId) {
  108. stringSelector = @selector(identity);
  109. } else {
  110. if ([UserSettings sharedUserSettings].sortOrderFirstName) {
  111. if (self.firstName.length > 0) {
  112. stringSelector = @selector(firstName);
  113. } else if (self.lastName.length > 0) {
  114. stringSelector = @selector(lastName);
  115. } else if (self.publicNickname.length > 0) {
  116. stringSelector = @selector(publicNickname);
  117. } else {
  118. stringSelector = @selector(identity);
  119. }
  120. } else {
  121. if (self.lastName.length > 0) {
  122. stringSelector = @selector(lastName);
  123. } else if (self.firstName.length > 0) {
  124. stringSelector = @selector(firstName);
  125. } else if (self.publicNickname.length > 0) {
  126. stringSelector = @selector(publicNickname);
  127. } else {
  128. stringSelector = @selector(identity);
  129. }
  130. }
  131. }
  132. NSInteger idx = [[UILocalizedIndexedCollation currentCollation] sectionForObject:self collationStringSelector:stringSelector];
  133. NSString *sortInitial = [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:idx];
  134. NSNumber *sortIndex = [NSNumber numberWithInteger:idx];
  135. if ([self.sortInitial isEqualToString:sortInitial] == NO) {
  136. self.sortInitial = sortInitial;
  137. }
  138. if ([self.sortIndex isEqualToNumber:sortIndex] == NO) {
  139. self.sortIndex = sortIndex;
  140. }
  141. }
  142. - (BOOL)isActive {
  143. return (self.state.intValue == kStateActive);
  144. }
  145. - (BOOL)isValid {
  146. return (self.state.intValue != kStateInvalid);
  147. }
  148. - (void)setImageData:(NSData *)imageData {
  149. [self willChangeValueForKey:@"imageData"];
  150. [self setPrimitiveValue:imageData forKey:@"imageData"];
  151. [[NSNotificationCenter defaultCenter] postNotificationName:@"ThreemaContactImageChanged" object:self];
  152. [self didChangeValueForKey:@"imageData"];
  153. }
  154. - (void)setContactImage:(ImageData *)contactImage {
  155. [self willChangeValueForKey:@"contactImage"];
  156. [self setPrimitiveValue:contactImage forKey:@"contactImage"];
  157. [[NSNotificationCenter defaultCenter] postNotificationName:@"ThreemaContactImageChanged" object:self];
  158. [self didChangeValueForKey:@"contactImage"];
  159. }
  160. - (BOOL)isGatewayId {
  161. return [self.identity hasPrefix:@"*"];
  162. }
  163. - (BOOL)isEchoEcho {
  164. return [self.identity isEqualToString:@"ECHOECHO"];
  165. }
  166. - (BOOL)isProfilePictureSended {
  167. return self.profilePictureSended;
  168. }
  169. - (void)setFeatureMask:(NSNumber *)featureMask {
  170. if (featureMask != nil) {
  171. self.featureLevel = featureMask;
  172. } else {
  173. self.featureLevel = 0;
  174. }
  175. }
  176. - (NSNumber *)featureMask {
  177. return self.featureLevel;
  178. }
  179. // This only means it's a verified contact from the admin (in the same work package)
  180. // To check if this contact is a work ID, use the workidentities list in usersettings
  181. // bad naming because of the history...
  182. - (BOOL)isWorkContact {
  183. return self.workContact.boolValue;
  184. }
  185. - (int)workAdjustedVerificationLevel {
  186. int myVerificationLevel = self.verificationLevel.intValue;
  187. if ([self isWorkContact]) {
  188. if (myVerificationLevel == kVerificationLevelServerVerified || myVerificationLevel == kVerificationLevelFullyVerified) {
  189. myVerificationLevel += 2;
  190. } else {
  191. myVerificationLevel = kVerificationLevelWorkVerified;
  192. }
  193. }
  194. return myVerificationLevel;
  195. }
  196. - (UIImage*)verificationLevelImageSmall {
  197. int myVerificationLevel = [self workAdjustedVerificationLevel];
  198. switch (myVerificationLevel) {
  199. case 0:
  200. return [StyleKit verificationSmall0];
  201. case 1:
  202. return [StyleKit verificationSmall1];
  203. case 2:
  204. return [StyleKit verificationSmall2];
  205. case 3:
  206. return [StyleKit verificationSmall3];
  207. case 4:
  208. return [StyleKit verificationSmall4];
  209. default:
  210. return [StyleKit verificationSmall0];
  211. }
  212. }
  213. - (UIImage*)verificationLevelImage {
  214. int myVerificationLevel = [self workAdjustedVerificationLevel];
  215. switch (myVerificationLevel) {
  216. case 0:
  217. return [StyleKit verification0];
  218. case 1:
  219. return [StyleKit verification1];
  220. case 2:
  221. return [StyleKit verification2];
  222. case 3:
  223. return [StyleKit verification3];
  224. case 4:
  225. return [StyleKit verification4];
  226. default:
  227. return [StyleKit verification0];
  228. }
  229. }
  230. - (UIImage*)verificationLevelImageBig {
  231. int myVerificationLevel = [self workAdjustedVerificationLevel];
  232. switch (myVerificationLevel) {
  233. case 0:
  234. return [StyleKit verificationBig0];
  235. case 1:
  236. return [StyleKit verificationBig1];
  237. case 2:
  238. return [StyleKit verificationBig2];
  239. case 3:
  240. return [StyleKit verificationBig3];
  241. case 4:
  242. return [StyleKit verificationBig4];
  243. default:
  244. return [StyleKit verificationBig0];
  245. }
  246. }
  247. - (NSString*)verificationLevelAccessibilityLabel {
  248. int myVerificationLevel = [self workAdjustedVerificationLevel];
  249. NSString *localizationString = [NSString stringWithFormat:@"level%d_title", myVerificationLevel];
  250. return [BundleUtil localizedStringForKey:localizationString];
  251. }
  252. - (BOOL)isVideoCallAvailable {
  253. return [self.featureMask integerValue] & FEATURE_MASK_VOIP_VIDEO;
  254. }
  255. - (BOOL)isProfilePictureSet {
  256. if (self.contactImage != nil && [UserSettings sharedUserSettings].showProfilePictures) {
  257. return true;
  258. }
  259. if (self.imageData != nil) {
  260. return true;
  261. }
  262. return false;
  263. }
  264. @end