RoomInfoTableViewController.m 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566
  1. /**
  2. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. #import "RoomInfoTableViewController.h"
  6. @import NextcloudKit;
  7. #import <QuickLook/QuickLook.h>
  8. #import "UIView+Toast.h"
  9. #import "JDStatusBarNotification.h"
  10. #import "NextcloudTalk-Swift.h"
  11. #import "AddParticipantsTableViewController.h"
  12. #import "CallConstants.h"
  13. #import "ContactsTableViewCell.h"
  14. #import "HeaderWithButton.h"
  15. #import "NCAPIController.h"
  16. #import "NCAppBranding.h"
  17. #import "NCChatFileController.h"
  18. #import "NCDatabaseManager.h"
  19. #import "NCNavigationController.h"
  20. #import "NCRoomsManager.h"
  21. #import "NCRoomParticipant.h"
  22. #import "NCSettingsController.h"
  23. #import "NCUserInterfaceController.h"
  24. #import "NCUserStatus.h"
  25. typedef enum RoomInfoSection {
  26. kRoomInfoSectionName = 0,
  27. kRoomInfoSectionDescription,
  28. kRoomInfoSectionFile,
  29. kRoomInfoSectionSharedItems,
  30. kRoomInfoSectionNotifications,
  31. kRoomInfoSectionGuests,
  32. kRoomInfoSectionConversation,
  33. kRoomInfoSectionWebinar,
  34. kRoomInfoSectionSIP,
  35. kRoomInfoSectionParticipants,
  36. kRoomInfoSectionDestructive
  37. } RoomInfoSection;
  38. typedef enum NotificationAction {
  39. kNotificationActionChatNotifications = 0,
  40. kNotificationActionCallNotifications
  41. } NotificationAction;
  42. typedef enum GuestAction {
  43. kGuestActionPublicToggle = 0,
  44. kGuestActionPassword,
  45. kGuestActionResendInvitations
  46. } GuestAction;
  47. typedef enum ConversationAction {
  48. kConversationActionMessageExpiration = 0,
  49. kConversationActionBannedActors,
  50. kConversationActionListable,
  51. kConversationActionListableForEveryone,
  52. kConversationActionMentionPermission,
  53. kConversationActionReadOnly,
  54. kConversationActionShareLink
  55. } ConversationAction;
  56. typedef enum WebinarAction {
  57. kWebinarActionLobby = 0,
  58. kWebinarActionLobbyTimer,
  59. kWebinarActionSIP,
  60. kWebinarActionSIPNoPIN
  61. } WebinarAction;
  62. typedef enum SIPAction {
  63. kSIPActionSIPInfo = 0,
  64. kSIPActionMeetingId,
  65. kSIPActionPIN,
  66. kSIPActionNumber
  67. } SIPAction;
  68. typedef enum DestructiveAction {
  69. kDestructiveActionLeave = 0,
  70. kDestructiveActionClearHistory,
  71. kDestructiveActionDelete
  72. } DestructiveAction;
  73. typedef enum ModificationError {
  74. kModificationErrorChatNotifications = 0,
  75. kModificationErrorCallNotifications,
  76. kModificationErrorShare,
  77. kModificationErrorPassword,
  78. kModificationErrorResendInvitations,
  79. kModificationErrorSendCallNotification,
  80. kModificationErrorLobby,
  81. kModificationErrorSIP,
  82. kModificationErrorModeration,
  83. kModificationErrorRemove,
  84. kModificationErrorLeave,
  85. kModificationErrorLeaveModeration,
  86. kModificationErrorDelete,
  87. kModificationErrorClearHistory,
  88. kModificationErrorListable,
  89. kModificationErrorReadOnly,
  90. kModificationErrorMessageExpiration,
  91. kModificationErrorRoomDescription,
  92. kModificationErrorBanActor,
  93. kModificationErrorMentionPermissions,
  94. } ModificationError;
  95. typedef enum FileAction {
  96. kFileActionPreview = 0,
  97. kFileActionOpenInFilesApp
  98. } FileAction;
  99. @interface RoomInfoTableViewController () <UITextFieldDelegate, AddParticipantsTableViewControllerDelegate, NCChatFileControllerDelegate, QLPreviewControllerDelegate, QLPreviewControllerDataSource>
  100. @property (nonatomic, strong) NCRoom *room;
  101. @property (nonatomic, strong) ChatViewController *chatViewController;
  102. @property (nonatomic, strong) NSString *roomName;
  103. @property (nonatomic, strong) NSMutableArray *roomParticipants;;
  104. @property (nonatomic, strong) UISwitch *publicSwitch;
  105. @property (nonatomic, strong) UISwitch *listableSwitch;
  106. @property (nonatomic, strong) UISwitch *listableForEveryoneSwitch;
  107. @property (nonatomic, strong) UISwitch *mentionPermissionsSwitch;
  108. @property (nonatomic, strong) UISwitch *readOnlySwitch;
  109. @property (nonatomic, strong) UISwitch *lobbySwitch;
  110. @property (nonatomic, strong) UISwitch *sipSwitch;
  111. @property (nonatomic, strong) UISwitch *sipNoPINSwitch;
  112. @property (nonatomic, strong) UISwitch *callNotificationSwitch;
  113. @property (nonatomic, strong) UIDatePicker *lobbyDatePicker;
  114. @property (nonatomic, strong) UITextField *lobbyDateTextField;
  115. @property (nonatomic, strong) UIActivityIndicatorView *modifyingRoomView;
  116. @property (nonatomic, strong) HeaderWithButton *headerView;
  117. @property (nonatomic, strong) UIAlertAction *setPasswordAction;
  118. @property (nonatomic, strong) UIActivityIndicatorView *fileDownloadIndicator;
  119. @property (nonatomic, strong) NSString *previewControllerFilePath;
  120. @property (nonatomic, strong) UIAlertAction *banAction;
  121. @property (nonatomic, weak) UITextField *setPasswordTextField;
  122. @property (nonatomic, weak) UITextField *banInternalNoteTextField;
  123. @end
  124. @implementation RoomInfoTableViewController
  125. - (instancetype)initForRoom:(NCRoom *)room
  126. {
  127. return [self initForRoom:room fromChatViewController:nil];
  128. }
  129. - (instancetype)initForRoom:(NCRoom *)room fromChatViewController:(ChatViewController *)chatViewController
  130. {
  131. self = [super init];
  132. if (self) {
  133. _room = room;
  134. _chatViewController = chatViewController;
  135. }
  136. return self;
  137. }
  138. - (void)viewDidLoad
  139. {
  140. [super viewDidLoad];
  141. self.navigationItem.title = NSLocalizedString(@"Conversation settings", nil);
  142. [self.navigationController.navigationBar setTitleTextAttributes:
  143. @{NSForegroundColorAttributeName:[NCAppBranding themeTextColor]}];
  144. self.navigationController.navigationBar.tintColor = [NCAppBranding themeTextColor];
  145. self.navigationController.navigationBar.translucent = NO;
  146. self.navigationController.navigationBar.barTintColor = [NCAppBranding themeColor];
  147. UIColor *themeColor = [NCAppBranding themeColor];
  148. UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
  149. [appearance configureWithOpaqueBackground];
  150. appearance.backgroundColor = themeColor;
  151. appearance.titleTextAttributes = @{NSForegroundColorAttributeName:[NCAppBranding themeTextColor]};
  152. self.navigationItem.standardAppearance = appearance;
  153. self.navigationItem.compactAppearance = appearance;
  154. self.navigationItem.scrollEdgeAppearance = appearance;
  155. _roomParticipants = [[NSMutableArray alloc] init];
  156. _publicSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  157. [_publicSwitch addTarget: self action: @selector(publicValueChanged:) forControlEvents:UIControlEventValueChanged];
  158. _listableSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  159. [_listableSwitch addTarget: self action: @selector(listableValueChanged:) forControlEvents:UIControlEventValueChanged];
  160. _listableForEveryoneSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  161. [_listableForEveryoneSwitch addTarget: self action: @selector(listableForEveryoneValueChanged:) forControlEvents:UIControlEventValueChanged];
  162. _mentionPermissionsSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  163. [_mentionPermissionsSwitch addTarget: self action: @selector(mentionPermissionsValueChanged:) forControlEvents:UIControlEventValueChanged];
  164. _readOnlySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  165. [_readOnlySwitch addTarget: self action: @selector(readOnlyValueChanged:) forControlEvents:UIControlEventValueChanged];
  166. _lobbySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  167. [_lobbySwitch addTarget: self action: @selector(lobbyValueChanged:) forControlEvents:UIControlEventValueChanged];
  168. _sipSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  169. [_sipSwitch addTarget: self action: @selector(sipValueChanged:) forControlEvents:UIControlEventValueChanged];
  170. _sipNoPINSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  171. [_sipNoPINSwitch addTarget: self action: @selector(sipNoPINValueChanged:) forControlEvents:UIControlEventValueChanged];
  172. _callNotificationSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  173. [_callNotificationSwitch addTarget: self action: @selector(callNotificationValueChanged:) forControlEvents:UIControlEventValueChanged];
  174. _lobbyDatePicker = [[UIDatePicker alloc] init];
  175. _lobbyDatePicker.datePickerMode = UIDatePickerModeDateAndTime;
  176. _lobbyDatePicker.preferredDatePickerStyle = UIDatePickerStyleWheels;
  177. _lobbyDateTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 00, 150, 30)];
  178. _lobbyDateTextField.textAlignment = NSTextAlignmentRight;
  179. _lobbyDateTextField.placeholder = NSLocalizedString(@"Manual", @"TRANSLATORS this is used when no meeting start time is set and the meeting will be started manually");
  180. _lobbyDateTextField.adjustsFontSizeToFitWidth = YES;
  181. _lobbyDateTextField.minimumFontSize = 9;
  182. [_lobbyDateTextField setInputView:_lobbyDatePicker];
  183. [self setupLobbyDatePicker];
  184. _modifyingRoomView = [[UIActivityIndicatorView alloc] init];
  185. _modifyingRoomView.color = [NCAppBranding themeTextColor];
  186. _headerView = [[HeaderWithButton alloc] init];
  187. [_headerView.button setTitle:NSLocalizedString(@"Add", nil) forState:UIControlStateNormal];
  188. [_headerView.button addTarget:self action:@selector(addParticipantsButtonPressed) forControlEvents:UIControlEventTouchUpInside];
  189. [self.tableView registerNib:[UINib nibWithNibName:kContactsTableCellNibName bundle:nil] forCellReuseIdentifier:kContactCellIdentifier];
  190. [self.tableView registerNib:[UINib nibWithNibName:RoomNameTableViewCell.nibName bundle:nil] forCellReuseIdentifier:RoomNameTableViewCell.identifier];
  191. [self.tableView registerNib:[UINib nibWithNibName:RoomDescriptionTableViewCell.nibName bundle:nil] forCellReuseIdentifier:RoomDescriptionTableViewCell.identifier];
  192. if (!_chatViewController || [self.navigationController.viewControllers count] == 1) {
  193. UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
  194. target:self action:@selector(cancelButtonPressed)];
  195. self.navigationController.navigationBar.topItem.leftBarButtonItem = cancelButton;
  196. }
  197. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRoom:) name:NCRoomsManagerDidUpdateRoomNotification object:nil];
  198. }
  199. - (void)viewDidAppear:(BOOL)animated
  200. {
  201. [super viewDidAppear:animated];
  202. [[NCRoomsManager sharedInstance] updateRoom:_room.token withCompletionBlock:nil];
  203. [self getRoomParticipants];
  204. }
  205. - (void)didReceiveMemoryWarning
  206. {
  207. [super didReceiveMemoryWarning];
  208. // Dispose of any resources that can be recreated.
  209. }
  210. - (void)cancelButtonPressed
  211. {
  212. [self dismissViewControllerAnimated:YES completion:nil];
  213. }
  214. - (void)dealloc
  215. {
  216. [[NSNotificationCenter defaultCenter] removeObserver:self];
  217. }
  218. #pragma mark - Utils
  219. - (void)getRoomParticipants
  220. {
  221. [[NCAPIController sharedInstance] getParticipantsFromRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSMutableArray *participants, NSError *error) {
  222. self->_roomParticipants = participants;
  223. [self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange([self getSectionForRoomInfoSection:kRoomInfoSectionParticipants], 1)] withRowAnimation:UITableViewRowAnimationNone];
  224. [self removeModifyingRoomUI];
  225. }];
  226. }
  227. - (NSArray *)getRoomInfoSections
  228. {
  229. NSMutableArray *sections = [[NSMutableArray alloc] init];
  230. // Room name section
  231. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionName]];
  232. // Room description section
  233. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityRoomDescription] && _room.roomDescription && ![_room.roomDescription isEqualToString:@""]) {
  234. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionDescription]];
  235. }
  236. // File actions section
  237. if ([_room.objectType isEqualToString:NCRoomObjectTypeFile]) {
  238. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionFile]];
  239. }
  240. // Shared items section
  241. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityRichObjectListMedia] &&
  242. ![self.room isFederated]) {
  243. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionSharedItems]];
  244. }
  245. // Notifications section
  246. if ([self getNotificationsActions].count > 0) {
  247. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionNotifications]];
  248. }
  249. // Conversation section
  250. if ([self getConversationActions].count > 0) {
  251. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionConversation]];
  252. }
  253. // Moderator sections
  254. if (_room.canModerate) {
  255. // Guests section
  256. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionGuests]];
  257. // Webinar section
  258. if (_room.type != kNCRoomTypeOneToOne && _room.type != kNCRoomTypeFormerOneToOne && [[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityWebinaryLobby]) {
  259. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionWebinar]];
  260. }
  261. }
  262. // SIP section
  263. if (_room.sipState > NCRoomSIPStateDisabled) {
  264. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionSIP]];
  265. }
  266. // Participants section
  267. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionParticipants]];
  268. // Destructive actions section
  269. if (!_hideDestructiveActions) {
  270. [sections addObject:[NSNumber numberWithInt:kRoomInfoSectionDestructive]];
  271. }
  272. return [NSArray arrayWithArray:sections];
  273. }
  274. - (NSInteger)getSectionForRoomInfoSection:(RoomInfoSection)section
  275. {
  276. NSInteger sectionNumber = [[self getRoomInfoSections] indexOfObject:[NSNumber numberWithInt:section]];
  277. if(NSNotFound != sectionNumber) {
  278. return sectionNumber;
  279. }
  280. return 0;
  281. }
  282. - (NSArray *)getNotificationsActions
  283. {
  284. NSMutableArray *actions = [[NSMutableArray alloc] init];
  285. if (_room.type == kNCRoomTypeChangelog || _room.type == kNCRoomTypeNoteToSelf) {
  286. return actions;
  287. }
  288. // Chat notifications levels action
  289. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityNotificationLevels]) {
  290. [actions addObject:[NSNumber numberWithInt:kNotificationActionChatNotifications]];
  291. }
  292. // Call notifications action
  293. if ([[NCDatabaseManager sharedInstance] roomHasTalkCapability:kCapabilityNotificationCalls forRoom:self.room] &&
  294. [[NCDatabaseManager sharedInstance] roomTalkCapabilitiesForRoom:self.room].callEnabled &&
  295. ![self.room isFederated]) {
  296. [actions addObject:[NSNumber numberWithInt:kNotificationActionCallNotifications]];
  297. }
  298. return [NSArray arrayWithArray:actions];
  299. }
  300. - (NSIndexPath *)getIndexPathForNotificationAction:(NotificationAction)action
  301. {
  302. NSInteger section = [self getSectionForRoomInfoSection:kRoomInfoSectionNotifications];
  303. NSIndexPath *actionIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
  304. NSInteger actionRow = [[self getNotificationsActions] indexOfObject:[NSNumber numberWithInt:action]];
  305. if(NSNotFound != actionRow) {
  306. actionIndexPath = [NSIndexPath indexPathForRow:actionRow inSection:section];
  307. }
  308. return actionIndexPath;
  309. }
  310. - (NSArray *)getFileActions
  311. {
  312. NSMutableArray *actions = [[NSMutableArray alloc] init];
  313. // File preview
  314. [actions addObject:[NSNumber numberWithInt:kFileActionPreview]];
  315. // Open file in nextcloud app
  316. [actions addObject:[NSNumber numberWithInt:kFileActionOpenInFilesApp]];
  317. return [NSArray arrayWithArray:actions];
  318. }
  319. - (NSArray *)getGuestsActions
  320. {
  321. NSMutableArray *actions = [[NSMutableArray alloc] init];
  322. // Public room toggle
  323. [actions addObject:[NSNumber numberWithInt:kGuestActionPublicToggle]];
  324. // Password protection
  325. if (_room.isPublic) {
  326. [actions addObject:[NSNumber numberWithInt:kGuestActionPassword]];
  327. }
  328. // Resend invitations
  329. if (_room.isPublic && [[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilitySIPSupport]) {
  330. [actions addObject:[NSNumber numberWithInt:kGuestActionResendInvitations]];
  331. }
  332. return [NSArray arrayWithArray:actions];
  333. }
  334. - (NSIndexPath *)getIndexPathForGuestAction:(GuestAction)action
  335. {
  336. NSInteger section = [self getSectionForRoomInfoSection:kRoomInfoSectionGuests];
  337. NSIndexPath *actionIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
  338. NSInteger actionRow = [[self getGuestsActions] indexOfObject:[NSNumber numberWithInt:action]];
  339. if(NSNotFound != actionRow) {
  340. actionIndexPath = [NSIndexPath indexPathForRow:actionRow inSection:section];
  341. }
  342. return actionIndexPath;
  343. }
  344. - (NSArray *)getConversationActions
  345. {
  346. NSMutableArray *actions = [[NSMutableArray alloc] init];
  347. // Message expiration action
  348. if ([_room supportsMessageExpirationModeration]) {
  349. [actions addObject:[NSNumber numberWithInt:kConversationActionMessageExpiration]];
  350. }
  351. // Banning actors
  352. if ([_room supportsBanningModeration]) {
  353. [actions addObject:[NSNumber numberWithInt:kConversationActionBannedActors]];
  354. }
  355. if (_room.canModerate) {
  356. // Listable room action
  357. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityListableRooms]) {
  358. [actions addObject:[NSNumber numberWithInt:kConversationActionListable]];
  359. if (_room.listable != NCRoomListableScopeParticipantsOnly && [[NCSettingsController sharedInstance] isGuestsAppEnabled]) {
  360. [actions addObject:[NSNumber numberWithInt:kConversationActionListableForEveryone]];
  361. }
  362. }
  363. // Mention permission
  364. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityMentionPermissions]) {
  365. [actions addObject:[NSNumber numberWithInt:kConversationActionMentionPermission]];
  366. }
  367. // Read only room action
  368. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityReadOnlyRooms]) {
  369. [actions addObject:[NSNumber numberWithInt:kConversationActionReadOnly]];
  370. }
  371. }
  372. if (_room.type != kNCRoomTypeChangelog && _room.type != kNCRoomTypeNoteToSelf) {
  373. [actions addObject:[NSNumber numberWithInt:kConversationActionShareLink]];
  374. }
  375. return [NSArray arrayWithArray:actions];
  376. }
  377. - (NSIndexPath *)getIndexPathForConversationAction:(ConversationAction)action
  378. {
  379. NSInteger section = [self getSectionForRoomInfoSection:kRoomInfoSectionConversation];
  380. NSIndexPath *actionIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
  381. NSInteger actionRow = [[self getConversationActions] indexOfObject:[NSNumber numberWithInt:action]];
  382. if(NSNotFound != actionRow) {
  383. actionIndexPath = [NSIndexPath indexPathForRow:actionRow inSection:section];
  384. }
  385. return actionIndexPath;
  386. }
  387. - (NSArray *)getWebinarActions
  388. {
  389. NSMutableArray *actions = [[NSMutableArray alloc] init];
  390. // Lobby toggle
  391. [actions addObject:[NSNumber numberWithInt:kWebinarActionLobby]];
  392. // Lobby timer
  393. if (_room.lobbyState == NCRoomLobbyStateModeratorsOnly) {
  394. [actions addObject:[NSNumber numberWithInt:kWebinarActionLobbyTimer]];
  395. }
  396. // SIP toggle
  397. if (_room.canEnableSIP) {
  398. [actions addObject:[NSNumber numberWithInt:kWebinarActionSIP]];
  399. if (_room.sipState > NCRoomSIPStateDisabled && [[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilitySIPSupportNoPIN]) {
  400. [actions addObject:[NSNumber numberWithInt:kWebinarActionSIPNoPIN]];
  401. }
  402. }
  403. return [NSArray arrayWithArray:actions];
  404. }
  405. - (NSArray *)getRoomDestructiveActions
  406. {
  407. NSMutableArray *actions = [[NSMutableArray alloc] init];
  408. // Leave room
  409. if (_room.isLeavable && _room.type != kNCRoomTypeNoteToSelf) {
  410. [actions addObject:[NSNumber numberWithInt:kDestructiveActionLeave]];
  411. }
  412. // Clear history
  413. if ((_room.canModerate || _room.type == kNCRoomTypeNoteToSelf) &&
  414. [[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityClearHistory]) {
  415. [actions addObject:[NSNumber numberWithInt:kDestructiveActionClearHistory]];
  416. }
  417. // Delete room
  418. if (_room.canModerate || _room.type == kNCRoomTypeNoteToSelf) {
  419. [actions addObject:[NSNumber numberWithInt:kDestructiveActionDelete]];
  420. }
  421. return [NSArray arrayWithArray:actions];
  422. }
  423. - (NSIndexPath *)getIndexPathForDestructiveAction:(DestructiveAction)action
  424. {
  425. NSInteger section = [self getSectionForRoomInfoSection:kRoomInfoSectionDestructive];
  426. NSIndexPath *actionIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
  427. NSInteger actionRow = [[self getRoomDestructiveActions] indexOfObject:[NSNumber numberWithInt:action]];
  428. if(NSNotFound != actionRow) {
  429. actionIndexPath = [NSIndexPath indexPathForRow:actionRow inSection:section];
  430. }
  431. return actionIndexPath;
  432. }
  433. - (BOOL)isAppUser:(NCRoomParticipant *)participant
  434. {
  435. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  436. if ([participant.participantId isEqualToString:activeAccount.userId]) {
  437. return YES;
  438. }
  439. return NO;
  440. }
  441. - (void)setModifyingRoomUI
  442. {
  443. [_modifyingRoomView startAnimating];
  444. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:_modifyingRoomView];
  445. self.tableView.userInteractionEnabled = NO;
  446. }
  447. - (void)removeModifyingRoomUI
  448. {
  449. [_modifyingRoomView stopAnimating];
  450. self.navigationItem.rightBarButtonItem = nil;
  451. self.tableView.userInteractionEnabled = YES;
  452. }
  453. - (void)showRoomModificationError:(ModificationError)error
  454. {
  455. [self showRoomModificationError:error withMessage:nil];
  456. }
  457. - (void)showRoomModificationError:(ModificationError)error withMessage:(NSString *)errorMessage
  458. {
  459. [self removeModifyingRoomUI];
  460. NSString *errorDescription = @"";
  461. switch (error) {
  462. case kModificationErrorChatNotifications:
  463. errorDescription = NSLocalizedString(@"Could not change notifications setting", nil);
  464. break;
  465. case kModificationErrorCallNotifications:
  466. errorDescription = NSLocalizedString(@"Could not change call notifications setting", nil);
  467. break;
  468. case kModificationErrorShare:
  469. errorDescription = NSLocalizedString(@"Could not change sharing permissions of the conversation", nil);
  470. break;
  471. case kModificationErrorPassword:
  472. errorDescription = NSLocalizedString(@"Could not change password protection settings", nil);
  473. break;
  474. case kModificationErrorResendInvitations:
  475. errorDescription = NSLocalizedString(@"Could not resend email invitations", nil);
  476. break;
  477. case kModificationErrorSendCallNotification:
  478. errorDescription = NSLocalizedString(@"Could not send call notification", nil);
  479. break;
  480. case kModificationErrorLobby:
  481. errorDescription = NSLocalizedString(@"Could not change lobby state of the conversation", nil);
  482. break;
  483. case kModificationErrorSIP:
  484. errorDescription = NSLocalizedString(@"Could not change SIP state of the conversation", nil);
  485. break;
  486. case kModificationErrorModeration:
  487. errorDescription = NSLocalizedString(@"Could not change moderation permissions of the participant", nil);
  488. break;
  489. case kModificationErrorRemove:
  490. errorDescription = NSLocalizedString(@"Could not remove participant", nil);
  491. break;
  492. case kModificationErrorLeave:
  493. errorDescription = NSLocalizedString(@"Could not leave conversation", nil);
  494. break;
  495. case kModificationErrorLeaveModeration:
  496. errorDescription = NSLocalizedString(@"You need to promote a new moderator before you can leave this conversation", nil);
  497. break;
  498. case kModificationErrorDelete:
  499. errorDescription = NSLocalizedString(@"Could not delete conversation", nil);
  500. break;
  501. case kModificationErrorClearHistory:
  502. errorDescription = NSLocalizedString(@"Could not clear chat history", nil);
  503. break;
  504. case kModificationErrorListable:
  505. errorDescription = NSLocalizedString(@"Could not change listable scope of the conversation", nil);
  506. break;
  507. case kModificationErrorReadOnly:
  508. errorDescription = NSLocalizedString(@"Could not change read-only state of the conversation", nil);
  509. break;
  510. case kModificationErrorMessageExpiration:
  511. errorDescription = NSLocalizedString(@"Could not set message expiration time", nil);
  512. break;
  513. case kModificationErrorRoomDescription:
  514. errorDescription = NSLocalizedString(@"Could not set conversation description", nil);
  515. break;
  516. case kModificationErrorBanActor:
  517. errorDescription = NSLocalizedString(@"Could not ban participant", nil);
  518. break;
  519. case kModificationErrorMentionPermissions:
  520. errorDescription = NSLocalizedString(@"Could not change mention permissions of the conversation", nil);
  521. break;
  522. default:
  523. break;
  524. }
  525. UIAlertController *renameDialog =
  526. [UIAlertController alertControllerWithTitle:errorDescription
  527. message:errorMessage
  528. preferredStyle:UIAlertControllerStyleAlert];
  529. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:nil];
  530. [renameDialog addAction:okAction];
  531. [self presentViewController:renameDialog animated:YES completion:nil];
  532. }
  533. - (void)showConfirmationDialogForDestructiveAction:(DestructiveAction)action
  534. {
  535. NSString *title = @"";
  536. NSString *message = @"";
  537. UIAlertAction *confirmAction = nil;
  538. switch (action) {
  539. case kDestructiveActionLeave:
  540. {
  541. title = NSLocalizedString(@"Leave conversation", nil);
  542. message = NSLocalizedString(@"Once a conversation is left, to rejoin a closed conversation, an invite is needed. An open conversation can be rejoined at any time.", nil);
  543. confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Leave", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
  544. [self leaveRoom];
  545. }];
  546. }
  547. break;
  548. case kDestructiveActionClearHistory:
  549. {
  550. title = NSLocalizedString(@"Delete all messages", nil);
  551. message = NSLocalizedString(@"Do you really want to delete all messages in this conversation?", nil);
  552. confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Delete all", "Short version for confirmation button. Complete text is 'Delete all messages'.") style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
  553. [self clearHistory];
  554. }];
  555. }
  556. break;
  557. case kDestructiveActionDelete:
  558. {
  559. title = NSLocalizedString(@"Delete conversation", nil);
  560. message = _room.deletionMessage;
  561. confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Delete", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
  562. [self deleteRoom];
  563. }];
  564. }
  565. break;
  566. }
  567. UIAlertController *confirmDialog =
  568. [UIAlertController alertControllerWithTitle:title
  569. message:message
  570. preferredStyle:UIAlertControllerStyleAlert];
  571. [confirmDialog addAction:confirmAction];
  572. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
  573. [confirmDialog addAction:cancelAction];
  574. [self presentViewController:confirmDialog animated:YES completion:nil];
  575. }
  576. - (void)presentNotificationLevelSelector
  577. {
  578. UIAlertController *optionsActionSheet =
  579. [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Notifications", nil)
  580. message:nil
  581. preferredStyle:UIAlertControllerStyleActionSheet];
  582. [optionsActionSheet addAction:[self actionForNotificationLevel:kNCRoomNotificationLevelAlways]];
  583. [optionsActionSheet addAction:[self actionForNotificationLevel:kNCRoomNotificationLevelMention]];
  584. [optionsActionSheet addAction:[self actionForNotificationLevel:kNCRoomNotificationLevelNever]];
  585. [optionsActionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
  586. // Presentation on iPads
  587. optionsActionSheet.popoverPresentationController.sourceView = self.tableView;
  588. optionsActionSheet.popoverPresentationController.sourceRect = [self.tableView rectForRowAtIndexPath:[self getIndexPathForNotificationAction:kNotificationActionChatNotifications]];
  589. [self presentViewController:optionsActionSheet animated:YES completion:nil];
  590. }
  591. - (UIAlertAction *)actionForNotificationLevel:(NCRoomNotificationLevel)level
  592. {
  593. UIAlertAction *action = [UIAlertAction actionWithTitle:[NCRoom stringForNotificationLevel:level]
  594. style:UIAlertActionStyleDefault
  595. handler:^void (UIAlertAction *action) {
  596. [self setNotificationLevel:level];
  597. }];
  598. if (_room.notificationLevel == level) {
  599. [action setValue:[[UIImage imageNamed:@"checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"];
  600. }
  601. return action;
  602. }
  603. - (void)presentMessageExpirationSelector
  604. {
  605. UIAlertController *optionsActionSheet =
  606. [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Message expiration time", nil)
  607. message:nil
  608. preferredStyle:UIAlertControllerStyleActionSheet];
  609. [optionsActionSheet addAction:[self actionForMessageExpiration:NCMessageExpirationOff]];
  610. [optionsActionSheet addAction:[self actionForMessageExpiration:NCMessageExpiration4Weeks]];
  611. [optionsActionSheet addAction:[self actionForMessageExpiration:NCMessageExpiration1Week]];
  612. [optionsActionSheet addAction:[self actionForMessageExpiration:NCMessageExpiration1Day]];
  613. [optionsActionSheet addAction:[self actionForMessageExpiration:NCMessageExpiration8Hours]];
  614. [optionsActionSheet addAction:[self actionForMessageExpiration:NCMessageExpiration1Hour]];
  615. [optionsActionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
  616. // Presentation on iPads
  617. optionsActionSheet.popoverPresentationController.sourceView = self.tableView;
  618. optionsActionSheet.popoverPresentationController.sourceRect = [self.tableView rectForRowAtIndexPath:[self getIndexPathForConversationAction:kConversationActionMessageExpiration]];
  619. [self presentViewController:optionsActionSheet animated:YES completion:nil];
  620. }
  621. - (UIAlertAction *)actionForMessageExpiration:(NCMessageExpiration)messageExpiration
  622. {
  623. UIAlertAction *action = [UIAlertAction actionWithTitle:[NCRoom stringForMessageExpiration:messageExpiration]
  624. style:UIAlertActionStyleDefault
  625. handler:^void (UIAlertAction *action) {
  626. [self setMessageExpiration:messageExpiration];
  627. }];
  628. if (_room.messageExpiration == messageExpiration) {
  629. [action setValue:[[UIImage imageNamed:@"checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"];
  630. }
  631. return action;
  632. }
  633. #pragma mark - Room Manager notifications
  634. - (void)didUpdateRoom:(NSNotification *)notification
  635. {
  636. [self removeModifyingRoomUI];
  637. NCRoom *room = [notification.userInfo objectForKey:@"room"];
  638. if (!room || ![room.token isEqualToString:_room.token]) {
  639. return;
  640. }
  641. _room = room;
  642. [self setupLobbyDatePicker];
  643. [self.tableView reloadData];
  644. }
  645. #pragma mark - Room options
  646. - (void)setNotificationLevel:(NCRoomNotificationLevel)level
  647. {
  648. if (level == _room.notificationLevel) {
  649. return;
  650. }
  651. [self setModifyingRoomUI];
  652. [[NCAPIController sharedInstance] setNotificationLevel:level forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  653. if (!error) {
  654. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  655. } else {
  656. NSLog(@"Error setting room notification level: %@", error.description);
  657. [self.tableView reloadData];
  658. [self showRoomModificationError:kModificationErrorChatNotifications];
  659. }
  660. }];
  661. }
  662. - (void)setMessageExpiration:(NCMessageExpiration)messageExpiration
  663. {
  664. if (messageExpiration == _room.messageExpiration) {
  665. return;
  666. }
  667. [self setModifyingRoomUI];
  668. [[NCAPIController sharedInstance] setMessageExpiration:messageExpiration forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  669. if (!error) {
  670. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  671. } else {
  672. NSLog(@"Error setting message expiration time: %@", error.description);
  673. [self.tableView reloadData];
  674. [self showRoomModificationError:kModificationErrorMessageExpiration];
  675. }
  676. }];
  677. }
  678. - (void)setCallNotificationEnabled:(BOOL)enabled
  679. {
  680. [self setModifyingRoomUI];
  681. [[NCAPIController sharedInstance] setCallNotificationEnabled:enabled forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  682. if (!error) {
  683. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  684. } else {
  685. NSLog(@"Error setting room call notification: %@", error.description);
  686. [self.tableView reloadData];
  687. [self showRoomModificationError:kModificationErrorCallNotifications];
  688. }
  689. self->_callNotificationSwitch.enabled = YES;
  690. }];
  691. }
  692. - (void)showPasswordOptions
  693. {
  694. NSString *alertTitle = _room.hasPassword ? NSLocalizedString(@"Set new password:", nil) : NSLocalizedString(@"Set password:", nil);
  695. UIAlertController *passwordDialog =
  696. [UIAlertController alertControllerWithTitle:alertTitle
  697. message:nil
  698. preferredStyle:UIAlertControllerStyleAlert];
  699. __weak typeof(self) weakSelf = self;
  700. [passwordDialog addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
  701. textField.placeholder = NSLocalizedString(@"Password", nil);
  702. textField.secureTextEntry = YES;
  703. textField.delegate = weakSelf;
  704. weakSelf.setPasswordTextField = textField;
  705. }];
  706. NSString *actionTitle = _room.hasPassword ? NSLocalizedString(@"Change password", nil) : NSLocalizedString(@"OK", nil);
  707. _setPasswordAction = [UIAlertAction actionWithTitle:actionTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  708. NSString *password = [[passwordDialog textFields][0] text];
  709. NSString *trimmedPassword = [password stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  710. [self setModifyingRoomUI];
  711. [[NCAPIController sharedInstance] setPassword:trimmedPassword toRoom:self->_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error, NSString *errorDescription) {
  712. if (!error) {
  713. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  714. } else {
  715. NSLog(@"Error setting room password: %@", error.description);
  716. [self.tableView reloadData];
  717. [self showRoomModificationError:kModificationErrorPassword withMessage:errorDescription];
  718. }
  719. }];
  720. }];
  721. _setPasswordAction.enabled = NO;
  722. [passwordDialog addAction:_setPasswordAction];
  723. if (_room.hasPassword) {
  724. UIAlertAction *removePasswordAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Remove password", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
  725. [self setModifyingRoomUI];
  726. [[NCAPIController sharedInstance] setPassword:@"" toRoom:self->_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error, NSString *errorDescription) {
  727. if (!error) {
  728. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  729. } else {
  730. NSLog(@"Error changing room password: %@", error.description);
  731. [self.tableView reloadData];
  732. [self showRoomModificationError:kModificationErrorPassword withMessage:errorDescription];
  733. }
  734. }];
  735. }];
  736. [passwordDialog addAction:removePasswordAction];
  737. }
  738. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
  739. [passwordDialog addAction:cancelAction];
  740. [self presentViewController:passwordDialog animated:YES completion:nil];
  741. }
  742. - (void)resendInvitations
  743. {
  744. NSIndexPath *indexPath = [self getIndexPathForGuestAction:kGuestActionResendInvitations];
  745. [self resendInvitationToParticipant:nil fromIndexPath:indexPath];
  746. }
  747. - (void)resendInvitationToParticipant:(NSString *)participant fromIndexPath:(NSIndexPath *)indexPath
  748. {
  749. [self setModifyingRoomUI];
  750. [[NCAPIController sharedInstance] resendInvitationToParticipant:participant inRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  751. if (!error) {
  752. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  753. NSString *toastText = participant ? NSLocalizedString(@"Invitation resent", nil) : NSLocalizedString(@"Invitations resent", nil);
  754. [[JDStatusBarNotificationPresenter sharedPresenter] presentWithText:toastText dismissAfterDelay:5.0 includedStyle:JDStatusBarNotificationIncludedStyleSuccess];
  755. } else {
  756. NSLog(@"Error resending email invitations: %@", error.description);
  757. [self.tableView reloadData];
  758. [self showRoomModificationError:kModificationErrorResendInvitations];
  759. }
  760. }];
  761. }
  762. - (void)sendCallNotificationToParticipant:(NSString *)participant fromIndexPath:(NSIndexPath *)indexPath
  763. {
  764. [self setModifyingRoomUI];
  765. [[NCAPIController sharedInstance] sendCallNotificationToParticipant:participant inRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  766. if (!error) {
  767. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  768. [[JDStatusBarNotificationPresenter sharedPresenter] presentWithText:NSLocalizedString(@"Call notification sent", nil) dismissAfterDelay:5.0 includedStyle:JDStatusBarNotificationIncludedStyleSuccess];
  769. } else {
  770. NSLog(@"Error sending call notification: %@", error.description);
  771. [self.tableView reloadData];
  772. [self showRoomModificationError:kModificationErrorSendCallNotification];
  773. }
  774. }];
  775. }
  776. - (void)makeRoomPublic
  777. {
  778. [self setModifyingRoomUI];
  779. [[NCAPIController sharedInstance] makeRoomPublic:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  780. if (!error) {
  781. NSIndexPath *indexPath = [self getIndexPathForGuestAction:kGuestActionPublicToggle];
  782. [self shareRoomLinkFromIndexPath:indexPath];
  783. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  784. } else {
  785. NSLog(@"Error making public the room: %@", error.description);
  786. [self.tableView reloadData];
  787. [self showRoomModificationError:kModificationErrorShare];
  788. }
  789. self->_publicSwitch.enabled = YES;
  790. }];
  791. }
  792. - (void)makeRoomPrivate
  793. {
  794. [self setModifyingRoomUI];
  795. [[NCAPIController sharedInstance] makeRoomPrivate:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  796. if (!error) {
  797. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  798. } else {
  799. NSLog(@"Error making private the room: %@", error.description);
  800. [self.tableView reloadData];
  801. [self showRoomModificationError:kModificationErrorShare];
  802. }
  803. self->_publicSwitch.enabled = YES;
  804. }];
  805. }
  806. - (void)shareRoomLinkFromIndexPath:(NSIndexPath *)indexPath
  807. {
  808. [[NCUserInterfaceController sharedInstance] presentShareLinkDialogForRoom:_room inViewContoller:self forIndexPath:indexPath];
  809. }
  810. - (void)setListableScope:(NCRoomListableScope)scope
  811. {
  812. if (scope == _room.listable) {
  813. return;
  814. }
  815. [self setModifyingRoomUI];
  816. [[NCAPIController sharedInstance] setListableScope:scope forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  817. if (!error) {
  818. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  819. } else {
  820. NSLog(@"Error setting room listable scope: %@", error.description);
  821. [self.tableView reloadData];
  822. [self showRoomModificationError:kModificationErrorListable];
  823. }
  824. self->_listableSwitch.enabled = YES;
  825. self->_listableForEveryoneSwitch.enabled = YES;
  826. }];
  827. }
  828. - (void)setMentionPermissions:(NCRoomMentionPermissions)permissions
  829. {
  830. if (permissions == _room.mentionPermissions) {
  831. return;
  832. }
  833. [self setModifyingRoomUI];
  834. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  835. [[NCAPIController sharedInstance] setMentionPermissions:permissions forRoom:_room.token forAccount:activeAccount completionBlock:^(NSError * _Nullable error) {
  836. if (!error) {
  837. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  838. } else {
  839. NSLog(@"Error setting room mention permissions state: %@", error.description);
  840. [self.tableView reloadData];
  841. [self showRoomModificationError:kModificationErrorMentionPermissions];
  842. }
  843. self->_mentionPermissionsSwitch.enabled = true;
  844. }];
  845. }
  846. - (void)setReadOnlyState:(NCRoomReadOnlyState)state
  847. {
  848. if (state == _room.readOnlyState) {
  849. return;
  850. }
  851. [self setModifyingRoomUI];
  852. [[NCAPIController sharedInstance] setReadOnlyState:state forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  853. if (!error) {
  854. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  855. } else {
  856. NSLog(@"Error setting room readonly state: %@", error.description);
  857. [self.tableView reloadData];
  858. [self showRoomModificationError:kModificationErrorReadOnly];
  859. }
  860. self->_readOnlySwitch.enabled = true;
  861. }];
  862. }
  863. - (void)previewRoomFile:(NSIndexPath *)indexPath
  864. {
  865. if (_fileDownloadIndicator) {
  866. // Already downloading a file
  867. return;
  868. }
  869. UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
  870. _fileDownloadIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 24, 24)];
  871. [_fileDownloadIndicator startAnimating];
  872. [cell setAccessoryView:_fileDownloadIndicator];
  873. NCChatFileController *downloader = [[NCChatFileController alloc] init];
  874. downloader.delegate = self;
  875. [downloader downloadFileWithFileId:_room.objectId];
  876. }
  877. - (void)openRoomFileInFilesApp:(NSIndexPath *)indexPath
  878. {
  879. UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
  880. UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 24, 24)];
  881. [activityIndicator startAnimating];
  882. [cell setAccessoryView:activityIndicator];
  883. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  884. [[NCAPIController sharedInstance] getFileByFileId:activeAccount fileId:_room.objectId withCompletionBlock:^(NKFile *file, NSInteger error, NSString *errorDescription) {
  885. dispatch_async(dispatch_get_main_queue(), ^{
  886. [activityIndicator stopAnimating];
  887. [cell setAccessoryView:nil];
  888. });
  889. if (file) {
  890. NSString *remoteDavPrefix = [NSString stringWithFormat:@"/remote.php/dav/files/%@/", activeAccount.userId];
  891. NSString *directoryPath = [file.path componentsSeparatedByString:remoteDavPrefix].lastObject;
  892. NSString *filePath = [NSString stringWithFormat:@"%@%@", directoryPath, file.fileName];
  893. NSString *fileLink = [NSString stringWithFormat:@"%@/index.php/f/%@", activeAccount.server, self->_room.objectId];
  894. NSLog(@"File path: %@ fileLink: %@", filePath, fileLink);
  895. [NCUtils openFileInNextcloudAppOrBrowserWithPath:filePath withFileLink:fileLink];
  896. } else {
  897. NSLog(@"An error occurred while getting file with fileId %@: %@", self->_room.objectId, errorDescription);
  898. UIAlertController * alert = [UIAlertController
  899. alertControllerWithTitle:NSLocalizedString(@"Unable to open file", nil)
  900. message:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while opening the file %@", nil), self->_room.name]
  901. preferredStyle:UIAlertControllerStyleAlert];
  902. UIAlertAction* okButton = [UIAlertAction
  903. actionWithTitle:NSLocalizedString(@"OK", nil)
  904. style:UIAlertActionStyleDefault
  905. handler:nil];
  906. [alert addAction:okButton];
  907. [[NCUserInterfaceController sharedInstance] presentAlertViewController:alert];
  908. }
  909. }];
  910. }
  911. - (void)presentSharedItemsView
  912. {
  913. RoomSharedItemsTableViewController *sharedItemsVC = [[RoomSharedItemsTableViewController alloc] initWithRoom:_room];
  914. [self.navigationController pushViewController:sharedItemsVC animated:YES];
  915. }
  916. - (void)presentNameInfoViewController
  917. {
  918. RoomAvatarInfoTableViewController *vc = [[RoomAvatarInfoTableViewController alloc] initWithRoom:_room];
  919. [self.navigationController pushViewController:vc animated:YES];
  920. }
  921. - (void)presentBannedActorsViewController
  922. {
  923. BannedActorTableViewController *vc = [[BannedActorTableViewController alloc] initWithRoom:_room];
  924. [self.navigationController pushViewController:vc animated:YES];
  925. }
  926. - (void)clearHistory
  927. {
  928. [[NCAPIController sharedInstance] clearChatHistoryInRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSDictionary *messageDict, NSError *error, NSInteger statusCode) {
  929. if (!error) {
  930. NSLog(@"Chat history cleared.");
  931. [[JDStatusBarNotificationPresenter sharedPresenter] presentWithText:NSLocalizedString(@"All messages were deleted", nil) dismissAfterDelay:5.0 includedStyle:JDStatusBarNotificationIncludedStyleSuccess];
  932. } else {
  933. NSLog(@"Error clearing chat history: %@", error.description);
  934. [self showRoomModificationError:kModificationErrorClearHistory];
  935. }
  936. }];
  937. }
  938. - (void)leaveRoom
  939. {
  940. [[NCAPIController sharedInstance] removeSelfFromRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSInteger errorCode, NSError *error) {
  941. if (!error) {
  942. if (self->_chatViewController) {
  943. [self->_chatViewController leaveChat];
  944. }
  945. [[NCUserInterfaceController sharedInstance] presentConversationsList];
  946. } else if (errorCode == 400) {
  947. [self showRoomModificationError:kModificationErrorLeaveModeration];
  948. } else {
  949. NSLog(@"Error leaving the room: %@", error.description);
  950. [self showRoomModificationError:kModificationErrorLeave];
  951. }
  952. }];
  953. }
  954. - (void)deleteRoom
  955. {
  956. [[NCAPIController sharedInstance] deleteRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  957. if (!error) {
  958. if (self->_chatViewController) {
  959. [self->_chatViewController leaveChat];
  960. }
  961. [[NCUserInterfaceController sharedInstance] presentConversationsList];
  962. } else {
  963. NSLog(@"Error deleting the room: %@", error.description);
  964. [self showRoomModificationError:kModificationErrorDelete];
  965. }
  966. }];
  967. }
  968. #pragma mark - Webinar options
  969. - (void)enableLobby
  970. {
  971. [self setLobbyState:NCRoomLobbyStateModeratorsOnly withTimer:0];
  972. }
  973. - (void)disableLobby
  974. {
  975. [self setLobbyState:NCRoomLobbyStateAllParticipants withTimer:0];
  976. }
  977. - (void)setLobbyState:(NCRoomLobbyState)lobbyState withTimer:(NSInteger)timer
  978. {
  979. [self setModifyingRoomUI];
  980. [[NCAPIController sharedInstance] setLobbyState:lobbyState withTimer:timer forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  981. if (!error) {
  982. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  983. } else {
  984. NSLog(@"Error changing lobby state in room: %@", error.description);
  985. [self.tableView reloadData];
  986. [self showRoomModificationError:kModificationErrorLobby];
  987. }
  988. self->_lobbySwitch.enabled = YES;
  989. }];
  990. }
  991. - (void)setLobbyDate
  992. {
  993. NSInteger lobbyTimer = _lobbyDatePicker.date.timeIntervalSince1970;
  994. [self setLobbyState:NCRoomLobbyStateModeratorsOnly withTimer:lobbyTimer];
  995. NSString *lobbyTimerReadable = [NCUtils readableDateTimeFromDate:_lobbyDatePicker.date];
  996. _lobbyDateTextField.text = [NSString stringWithFormat:@"%@",lobbyTimerReadable];
  997. [self dismissLobbyDatePicker];
  998. }
  999. - (void)removeLobbyDate
  1000. {
  1001. [self setLobbyState:NCRoomLobbyStateModeratorsOnly withTimer:0];
  1002. [self dismissLobbyDatePicker];
  1003. }
  1004. - (void)dismissLobbyDatePicker
  1005. {
  1006. [_lobbyDateTextField resignFirstResponder];
  1007. }
  1008. - (void)setupLobbyDatePicker
  1009. {
  1010. [_lobbyDatePicker setMinimumDate:[NSDate new]];
  1011. // Round up default lobby timer to next hour
  1012. NSCalendar *calendar = [NSCalendar currentCalendar];
  1013. NSDateComponents *components = [calendar components: NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour fromDate: [NSDate new]];
  1014. [components setHour: [components hour] + 1];
  1015. [_lobbyDatePicker setDate:[calendar dateFromComponents:components]];
  1016. UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
  1017. UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismissLobbyDatePicker)];
  1018. UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(setLobbyDate)];
  1019. UIBarButtonItem *space = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  1020. [toolBar setItems:[NSArray arrayWithObjects:cancelButton, space,doneButton, nil]];
  1021. [_lobbyDateTextField setInputAccessoryView:toolBar];
  1022. if (_room.lobbyTimer > 0) {
  1023. NSDate *date = [[NSDate alloc] initWithTimeIntervalSince1970:_room.lobbyTimer];
  1024. UIBarButtonItem *clearButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Remove", nil) style:UIBarButtonItemStylePlain target:self action:@selector(removeLobbyDate)];
  1025. [clearButton setTintColor:[UIColor redColor]];
  1026. [toolBar setItems:[NSArray arrayWithObjects:clearButton, space, doneButton, nil]];
  1027. [_lobbyDatePicker setDate:date];
  1028. }
  1029. }
  1030. - (void)setSIPState:(NCRoomSIPState)state
  1031. {
  1032. [self setModifyingRoomUI];
  1033. [[NCAPIController sharedInstance] setSIPState:state forRoom:_room.token forAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSError *error) {
  1034. if (!error) {
  1035. [[NCRoomsManager sharedInstance] updateRoom:self->_room.token withCompletionBlock:nil];
  1036. } else {
  1037. NSLog(@"Error changing SIP state in room: %@", error.description);
  1038. [self.tableView reloadData];
  1039. [self showRoomModificationError:kModificationErrorSIP];
  1040. }
  1041. self->_sipSwitch.enabled = YES;
  1042. self->_sipNoPINSwitch.enabled = YES;
  1043. }];
  1044. }
  1045. #pragma mark - Participant options
  1046. - (void)addParticipantsButtonPressed
  1047. {
  1048. AddParticipantsTableViewController *addParticipantsVC = [[AddParticipantsTableViewController alloc] initForRoom:_room];
  1049. addParticipantsVC.delegate = self;
  1050. NCNavigationController *navigationController = [[NCNavigationController alloc] initWithRootViewController:addParticipantsVC];
  1051. [self presentViewController:navigationController animated:YES completion:nil];
  1052. }
  1053. - (void)addParticipantsTableViewControllerDidFinish:(AddParticipantsTableViewController *)viewController
  1054. {
  1055. [self getRoomParticipants];
  1056. }
  1057. - (void)showOptionsForParticipantAtIndexPath:(NSIndexPath *)indexPath
  1058. {
  1059. NCRoomParticipant *participant = [_roomParticipants objectAtIndex:indexPath.row];
  1060. BOOL canParticipantBeModerated = participant.participantType != kNCParticipantTypeOwner && ![self isAppUser:participant] && _room.canModerate;
  1061. BOOL canParticipantBeNotifiedAboutCall =
  1062. ![self isAppUser:participant] &&
  1063. (_room.permissions & NCPermissionStartCall) &&
  1064. _room.participantFlags > CallFlagDisconnected &&
  1065. participant.inCall == CallFlagDisconnected &&
  1066. [participant.actorType isEqualToString:NCAttendeeTypeUser] &&
  1067. [[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilitySendCallNotification];
  1068. UIAlertController *optionsActionSheet =
  1069. [UIAlertController alertControllerWithTitle:[self detailedNameForParticipant:participant]
  1070. message:nil
  1071. preferredStyle:UIAlertControllerStyleActionSheet];
  1072. if (canParticipantBeModerated && participant.canBeDemoted) {
  1073. UIAlertAction *demoteFromModerator = [UIAlertAction actionWithTitle:NSLocalizedString(@"Demote from moderator", nil)
  1074. style:UIAlertActionStyleDefault
  1075. handler:^void (UIAlertAction *action) {
  1076. [self demoteFromModerator:participant];
  1077. }];
  1078. [demoteFromModerator setValue:[UIImage systemImageNamed:@"person"] forKey:@"image"];
  1079. [optionsActionSheet addAction:demoteFromModerator];
  1080. } else if (canParticipantBeModerated && participant.canBePromoted) {
  1081. UIAlertAction *promoteToModerator = [UIAlertAction actionWithTitle:NSLocalizedString(@"Promote to moderator", nil)
  1082. style:UIAlertActionStyleDefault
  1083. handler:^void (UIAlertAction *action) {
  1084. [self promoteToModerator:participant];
  1085. }];
  1086. [promoteToModerator setValue:[UIImage systemImageNamed:@"crown"] forKey:@"image"];
  1087. [optionsActionSheet addAction:promoteToModerator];
  1088. }
  1089. if (canParticipantBeNotifiedAboutCall) {
  1090. UIAlertAction *sendCallNotification = [UIAlertAction actionWithTitle:NSLocalizedString(@"Send call notification", nil)
  1091. style:UIAlertActionStyleDefault
  1092. handler:^void (UIAlertAction *action) {
  1093. [self sendCallNotificationToParticipant:[NSString stringWithFormat:@"%ld", (long)participant.attendeeId] fromIndexPath:indexPath];
  1094. }];
  1095. [sendCallNotification setValue:[UIImage systemImageNamed:@"bell"] forKey:@"image"];
  1096. [optionsActionSheet addAction:sendCallNotification];
  1097. }
  1098. if ([participant.actorType isEqualToString:NCAttendeeTypeEmail]) {
  1099. UIAlertAction *resendInvitation = [UIAlertAction actionWithTitle:NSLocalizedString(@"Resend invitation", nil)
  1100. style:UIAlertActionStyleDefault
  1101. handler:^void (UIAlertAction *action) {
  1102. [self resendInvitationToParticipant:[NSString stringWithFormat:@"%ld", (long)participant.attendeeId] fromIndexPath:indexPath];
  1103. }];
  1104. [resendInvitation setValue:[UIImage systemImageNamed:@"envelope"] forKey:@"image"];
  1105. [optionsActionSheet addAction:resendInvitation];
  1106. }
  1107. if (canParticipantBeModerated) {
  1108. if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityBanV1] && !participant.isGroup && !participant.isCircle && !participant.isFederated) {
  1109. NSString *banTitle = NSLocalizedString(@"Ban participant", nil);
  1110. UIAlertAction *banParticipant = [UIAlertAction actionWithTitle:banTitle
  1111. style:UIAlertActionStyleDestructive
  1112. handler:^void (UIAlertAction *action) {
  1113. [self banParticipant:participant];
  1114. }];
  1115. [banParticipant setValue:[UIImage systemImageNamed:@"person.badge.minus"] forKey:@"image"];
  1116. [optionsActionSheet addAction:banParticipant];
  1117. }
  1118. // Remove participant
  1119. NSString *title = NSLocalizedString(@"Remove participant", nil);
  1120. if (participant.isGroup) {
  1121. title = NSLocalizedString(@"Remove group and members", nil);
  1122. } else if (participant.isCircle) {
  1123. title = NSLocalizedString(@"Remove team and members", nil);
  1124. }
  1125. UIAlertAction *removeParticipant = [UIAlertAction actionWithTitle:title
  1126. style:UIAlertActionStyleDestructive
  1127. handler:^void (UIAlertAction *action) {
  1128. [self removeParticipant:participant];
  1129. }];
  1130. [removeParticipant setValue:[UIImage systemImageNamed:@"trash"] forKey:@"image"];
  1131. [optionsActionSheet addAction:removeParticipant];
  1132. }
  1133. if (optionsActionSheet.actions.count == 0) {return;}
  1134. [optionsActionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
  1135. // Presentation on iPads
  1136. optionsActionSheet.popoverPresentationController.sourceView = self.tableView;
  1137. optionsActionSheet.popoverPresentationController.sourceRect = [self.tableView rectForRowAtIndexPath:indexPath];
  1138. [self presentViewController:optionsActionSheet animated:YES completion:nil];
  1139. }
  1140. - (void)promoteToModerator:(NCRoomParticipant *)participant
  1141. {
  1142. [self setModifyingRoomUI];
  1143. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  1144. NSString *participantId = participant.participantId;
  1145. if ([[NCAPIController sharedInstance] conversationAPIVersionForAccount:activeAccount] >= APIv3) {
  1146. participantId = [NSString stringWithFormat:@"%ld", (long)participant.attendeeId];
  1147. }
  1148. [[NCAPIController sharedInstance] promoteParticipant:participantId toModeratorOfRoom:_room.token forAccount:activeAccount withCompletionBlock:^(NSError *error) {
  1149. if (!error) {
  1150. [self getRoomParticipants];
  1151. } else {
  1152. NSLog(@"Error promoting participant to moderator: %@", error.description);
  1153. [self showRoomModificationError:kModificationErrorModeration];
  1154. }
  1155. }];
  1156. }
  1157. - (void)demoteFromModerator:(NCRoomParticipant *)participant
  1158. {
  1159. [self setModifyingRoomUI];
  1160. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  1161. NSString *participantId = participant.participantId;
  1162. if ([[NCAPIController sharedInstance] conversationAPIVersionForAccount:activeAccount] >= APIv3) {
  1163. participantId = [NSString stringWithFormat:@"%ld", (long)participant.attendeeId];
  1164. }
  1165. [[NCAPIController sharedInstance] demoteModerator:participantId toParticipantOfRoom:_room.token forAccount:activeAccount withCompletionBlock:^(NSError *error) {
  1166. if (!error) {
  1167. [self getRoomParticipants];
  1168. } else {
  1169. NSLog(@"Error demoting participant from moderator: %@", error.description);
  1170. [self showRoomModificationError:kModificationErrorModeration];
  1171. }
  1172. }];
  1173. }
  1174. - (void)banParticipant:(NCRoomParticipant *)participant
  1175. {
  1176. UIAlertController *internalNoteController =
  1177. [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Ban %@", @"e.g. Ban John Doe"), participant.displayName]
  1178. message:NSLocalizedString(@"Add an internal note about this ban", nil)
  1179. preferredStyle:UIAlertControllerStyleAlert];
  1180. __weak typeof(self) weakSelf = self;
  1181. [internalNoteController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
  1182. textField.placeholder = NSLocalizedString(@"Internal note", @"Internal note about why a user/guest was banned");
  1183. textField.delegate = weakSelf;
  1184. weakSelf.banInternalNoteTextField = textField;
  1185. }];
  1186. _banAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ban", @"Ban a user/guest") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  1187. NSString *internalNote = [[internalNoteController textFields][0] text];
  1188. NSString *trimmedInternalNote = [internalNote stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  1189. [self setModifyingRoomUI];
  1190. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  1191. [[NCAPIController sharedInstance] banActorFor:activeAccount.accountId in:self->_room.token with:participant.actorType with:participant.actorId with:trimmedInternalNote completionBlock:^(BOOL success) {
  1192. if (success) {
  1193. [self removeParticipant:participant];
  1194. } else {
  1195. [self showRoomModificationError:kModificationErrorBanActor];
  1196. }
  1197. }];
  1198. }];
  1199. [internalNoteController addAction:_banAction];
  1200. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
  1201. [internalNoteController addAction:cancelAction];
  1202. [self presentViewController:internalNoteController animated:YES completion:nil];
  1203. }
  1204. - (void)removeParticipant:(NCRoomParticipant *)participant
  1205. {
  1206. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  1207. NSInteger conversationAPIVersion = [[NCAPIController sharedInstance] conversationAPIVersionForAccount:activeAccount];
  1208. if (conversationAPIVersion >= APIv3) {
  1209. [self setModifyingRoomUI];
  1210. [[NCAPIController sharedInstance] removeAttendee:participant.attendeeId fromRoom:_room.token forAccount:activeAccount withCompletionBlock:^(NSError *error) {
  1211. if (!error) {
  1212. [self getRoomParticipants];
  1213. } else {
  1214. NSLog(@"Error removing attendee from room: %@", error.description);
  1215. [self showRoomModificationError:kModificationErrorRemove];
  1216. }
  1217. }];
  1218. } else {
  1219. if (participant.isGuest) {
  1220. [self setModifyingRoomUI];
  1221. [[NCAPIController sharedInstance] removeGuest:participant.participantId fromRoom:_room.token forAccount:activeAccount withCompletionBlock:^(NSError *error) {
  1222. if (!error) {
  1223. [self getRoomParticipants];
  1224. } else {
  1225. NSLog(@"Error removing guest from room: %@", error.description);
  1226. [self showRoomModificationError:kModificationErrorRemove];
  1227. }
  1228. }];
  1229. } else {
  1230. [self setModifyingRoomUI];
  1231. [[NCAPIController sharedInstance] removeParticipant:participant.participantId fromRoom:_room.token forAccount:activeAccount withCompletionBlock:^(NSError *error) {
  1232. if (!error) {
  1233. [self getRoomParticipants];
  1234. } else {
  1235. NSLog(@"Error removing participant from room: %@", error.description);
  1236. [self showRoomModificationError:kModificationErrorRemove];
  1237. }
  1238. }];
  1239. }
  1240. }
  1241. }
  1242. - (NSString *)detailedNameForParticipant:(NCRoomParticipant *)participant
  1243. {
  1244. if (participant.canModerate && (_room.type == kNCRoomTypeOneToOne || _room.type == kNCRoomTypeFormerOneToOne || _room.type == kNCRoomTypeNoteToSelf)) {
  1245. return participant.displayName;
  1246. }
  1247. return participant.detailedName;
  1248. }
  1249. #pragma mark - Public switch
  1250. - (void)publicValueChanged:(id)sender
  1251. {
  1252. _publicSwitch.enabled = NO;
  1253. if (_publicSwitch.on) {
  1254. [self makeRoomPublic];
  1255. } else {
  1256. [self makeRoomPrivate];
  1257. }
  1258. }
  1259. #pragma mark - Lobby switch
  1260. - (void)lobbyValueChanged:(id)sender
  1261. {
  1262. _lobbySwitch.enabled = NO;
  1263. if (_lobbySwitch.on) {
  1264. [self enableLobby];
  1265. } else {
  1266. [self disableLobby];
  1267. }
  1268. }
  1269. #pragma mark - Listable switches
  1270. - (void)listableValueChanged:(id)sender
  1271. {
  1272. _listableSwitch.enabled = NO;
  1273. _listableForEveryoneSwitch.enabled = NO;
  1274. if (_listableSwitch.on) {
  1275. [self setListableScope:NCRoomListableScopeRegularUsersOnly];
  1276. } else {
  1277. [self setListableScope:NCRoomListableScopeParticipantsOnly];
  1278. }
  1279. }
  1280. - (void)listableForEveryoneValueChanged:(id)sender
  1281. {
  1282. _listableSwitch.enabled = NO;
  1283. _listableForEveryoneSwitch.enabled = NO;
  1284. if (_listableForEveryoneSwitch.on) {
  1285. [self setListableScope:NCRoomListableScopeEveryone];
  1286. } else {
  1287. [self setListableScope:NCRoomListableScopeRegularUsersOnly];
  1288. }
  1289. }
  1290. #pragma mark - Mention permissions switch
  1291. - (void)mentionPermissionsValueChanged:(id)sender
  1292. {
  1293. _mentionPermissionsSwitch.enabled = NO;
  1294. if (_mentionPermissionsSwitch.on) {
  1295. [self setMentionPermissions:NCRoomMentionPermissionsEveryone];
  1296. } else {
  1297. [self setMentionPermissions:NCRoomMentionPermissionsModeratorsOnly];
  1298. }
  1299. }
  1300. #pragma mark - ReadOnly switch
  1301. - (void)readOnlyValueChanged:(id)sender
  1302. {
  1303. _readOnlySwitch.enabled = NO;
  1304. if (_readOnlySwitch.on) {
  1305. [self setReadOnlyState:NCRoomReadOnlyStateReadOnly];
  1306. } else {
  1307. [self setReadOnlyState:NCRoomReadOnlyStateReadWrite];
  1308. }
  1309. }
  1310. #pragma mark - SIP switch
  1311. - (void)sipValueChanged:(id)sender
  1312. {
  1313. _sipSwitch.enabled = NO;
  1314. _sipNoPINSwitch.enabled = NO;
  1315. if (_sipSwitch.on) {
  1316. [self setSIPState:NCRoomSIPStateEnabled];
  1317. } else {
  1318. [self setSIPState:NCRoomSIPStateDisabled];
  1319. }
  1320. }
  1321. - (void)sipNoPINValueChanged:(id)sender
  1322. {
  1323. _sipSwitch.enabled = NO;
  1324. _sipNoPINSwitch.enabled = NO;
  1325. if (_sipNoPINSwitch.on) {
  1326. [self setSIPState:NCRoomSIPStateEnabledWithoutPIN];
  1327. } else {
  1328. [self setSIPState:NCRoomSIPStateEnabled];
  1329. }
  1330. }
  1331. #pragma mark - Call notifications switch
  1332. - (void)callNotificationValueChanged:(id)sender
  1333. {
  1334. _callNotificationSwitch.enabled = NO;
  1335. if (_callNotificationSwitch.on) {
  1336. [self setCallNotificationEnabled:YES];
  1337. } else {
  1338. [self setCallNotificationEnabled:NO];
  1339. }
  1340. }
  1341. #pragma mark - UITextField delegate
  1342. - (BOOL)textFieldShouldReturn:(UITextField *)textField {
  1343. [textField resignFirstResponder];
  1344. return YES;
  1345. }
  1346. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
  1347. // Prevent crashing undo bug
  1348. // https://stackoverflow.com/questions/433337/set-the-maximum-character-length-of-a-uitextfield
  1349. if (range.length + range.location > textField.text.length) {
  1350. return NO;
  1351. }
  1352. // Set maximum character length
  1353. NSUInteger newLength = [textField.text length] + [string length] - range.length;
  1354. NSUInteger allowedLength = 200;
  1355. if (textField == _banInternalNoteTextField) {
  1356. allowedLength = 4000;
  1357. }
  1358. BOOL hasAllowedLength = newLength <= allowedLength;
  1359. // An internal note on banning is optional, so only enable/disable password confirmation button
  1360. if (hasAllowedLength && textField == _setPasswordTextField) {
  1361. NSString *newValue = [[textField.text stringByReplacingCharactersInRange:range withString:string] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  1362. _setPasswordAction.enabled = (newValue.length > 0);
  1363. }
  1364. return hasAllowedLength;
  1365. }
  1366. #pragma mark - Table view data source
  1367. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  1368. {
  1369. return [self getRoomInfoSections].count;
  1370. }
  1371. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  1372. {
  1373. NSArray *sections = [self getRoomInfoSections];
  1374. RoomInfoSection infoSection = [[sections objectAtIndex:section] intValue];
  1375. switch (infoSection) {
  1376. case kRoomInfoSectionNotifications:
  1377. return [self getNotificationsActions].count;
  1378. break;
  1379. case kRoomInfoSectionFile:
  1380. return [self getFileActions].count;
  1381. break;
  1382. case kRoomInfoSectionSharedItems:
  1383. return 1;
  1384. break;
  1385. case kRoomInfoSectionGuests:
  1386. return [self getGuestsActions].count;
  1387. break;
  1388. case kRoomInfoSectionConversation:
  1389. return [self getConversationActions].count;
  1390. break;
  1391. case kRoomInfoSectionWebinar:
  1392. return [self getWebinarActions].count;
  1393. break;
  1394. case kRoomInfoSectionSIP:
  1395. return kSIPActionNumber;
  1396. break;
  1397. case kRoomInfoSectionParticipants:
  1398. return _roomParticipants.count;
  1399. break;
  1400. case kRoomInfoSectionDestructive:
  1401. return [self getRoomDestructiveActions].count;
  1402. break;
  1403. default:
  1404. break;
  1405. }
  1406. return 1;
  1407. }
  1408. - (CGFloat)heightForDescription:(NSString *)description
  1409. {
  1410. CGFloat width = CGRectGetWidth(self.tableView.frame) - 32;
  1411. width -= self.tableView.safeAreaInsets.left + self.tableView.safeAreaInsets.right;
  1412. NSDictionary *attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:17]};
  1413. CGRect bodyBounds = [description boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:NULL];
  1414. return ceil(bodyBounds.size.height) + 22;
  1415. }
  1416. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
  1417. {
  1418. NSArray *sections = [self getRoomInfoSections];
  1419. RoomInfoSection infoSection = [[sections objectAtIndex:section] intValue];
  1420. switch (infoSection) {
  1421. case kRoomInfoSectionFile:
  1422. return NSLocalizedString(@"Linked file", nil);
  1423. break;
  1424. case kRoomInfoSectionSharedItems:
  1425. return NSLocalizedString(@"Shared items", nil);
  1426. break;
  1427. case kRoomInfoSectionNotifications:
  1428. return NSLocalizedString(@"Notifications", nil);
  1429. break;
  1430. case kRoomInfoSectionGuests:
  1431. return NSLocalizedString(@"Guests access", nil);
  1432. break;
  1433. case kRoomInfoSectionConversation:
  1434. return NSLocalizedString(@"Conversation settings", nil);
  1435. break;
  1436. case kRoomInfoSectionWebinar:
  1437. return NSLocalizedString(@"Meeting settings", nil);
  1438. break;
  1439. case kRoomInfoSectionSIP:
  1440. return NSLocalizedString(@"SIP dial-in", nil);
  1441. break;
  1442. default:
  1443. break;
  1444. }
  1445. return nil;
  1446. }
  1447. - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
  1448. {
  1449. NSArray *sections = [self getRoomInfoSections];
  1450. RoomInfoSection infoSection = [[sections objectAtIndex:section] intValue];
  1451. switch (infoSection) {
  1452. case kRoomInfoSectionParticipants:
  1453. {
  1454. NSString *title = [NSString localizedStringWithFormat:NSLocalizedString(@"%ld participants", nil), _roomParticipants.count];
  1455. _headerView.label.text = [title uppercaseString];
  1456. _headerView.button.hidden = (_room.canModerate) ? NO : YES;
  1457. return _headerView;
  1458. }
  1459. break;
  1460. default:
  1461. break;
  1462. }
  1463. return nil;
  1464. }
  1465. - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
  1466. {
  1467. NSArray *sections = [self getRoomInfoSections];
  1468. RoomInfoSection infoSection = [[sections objectAtIndex:section] intValue];
  1469. switch (infoSection) {
  1470. case kRoomInfoSectionDescription:
  1471. return 2;
  1472. break;
  1473. case kRoomInfoSectionNotifications:
  1474. case kRoomInfoSectionFile:
  1475. case kRoomInfoSectionSharedItems:
  1476. case kRoomInfoSectionGuests:
  1477. case kRoomInfoSectionConversation:
  1478. case kRoomInfoSectionWebinar:
  1479. case kRoomInfoSectionSIP:
  1480. return 36;
  1481. break;
  1482. case kRoomInfoSectionParticipants:
  1483. return 40;
  1484. break;
  1485. default:
  1486. break;
  1487. }
  1488. return 25;
  1489. }
  1490. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  1491. UITableViewCell *cell = nil;
  1492. static NSString *chatnotificationLevelCellIdentifier = @"ChatNotificationLevelCellIdentifier";
  1493. static NSString *callnotificationCellIdentifier = @"CallNotificationCellIdentifier";
  1494. static NSString *allowGuestsCellIdentifier = @"AllowGuestsCellIdentifier";
  1495. static NSString *passwordCellIdentifier = @"PasswordCellIdentifier";
  1496. static NSString *shareLinkCellIdentifier = @"ShareLinkCellIdentifier";
  1497. static NSString *resendInvitationsCellIdentifier = @"ResendInvitationsCellIdentifier";
  1498. static NSString *previewFileCellIdentifier = @"PreviewFileCellIdentifier";
  1499. static NSString *openFileCellIdentifier = @"OpenFileCellIdentifier";
  1500. static NSString *lobbyCellIdentifier = @"LobbyCellIdentifier";
  1501. static NSString *lobbyTimerCellIdentifier = @"LobbyTimerCellIdentifier";
  1502. static NSString *sipCellIdentifier = @"SIPCellIdentifier";
  1503. static NSString *sipNoPINCellIdentifier = @"SIPNoPINCellIdentifier";
  1504. static NSString *sipMeetingIDCellIdentifier = @"SIPMeetingIDCellIdentifier";
  1505. static NSString *sipUserPINCellIdentifier = @"SIPUserPINCellIdentifier";
  1506. static NSString *clearHistoryCellIdentifier = @"ClearHistoryCellIdentifier";
  1507. static NSString *leaveRoomCellIdentifier = @"LeaveRoomCellIdentifier";
  1508. static NSString *deleteRoomCellIdentifier = @"DeleteRoomCellIdentifier";
  1509. static NSString *sharedItemsCellIdentifier = @"SharedItemsCellIdentifier";
  1510. static NSString *messageExpirationCellIdentifier = @"MessageExpirationCellIdentifier";
  1511. static NSString *bannedActorsCellIdentifier = @"BannedActorsCellIdentifier";
  1512. static NSString *listableCellIdentifier = @"ListableCellIdentifier";
  1513. static NSString *listableForEveryoneCellIdentifier = @"ListableForEveryoneCellIdentifier";
  1514. static NSString *mentionPermissionsCellIdentifier = @"mentionPermissionsCellIdentifier";
  1515. static NSString *readOnlyStateCellIdentifier = @"ReadOnlyStateCellIdentifier";
  1516. NSArray *sections = [self getRoomInfoSections];
  1517. RoomInfoSection section = [[sections objectAtIndex:indexPath.section] intValue];
  1518. switch (section) {
  1519. case kRoomInfoSectionName:
  1520. {
  1521. RoomNameTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RoomNameTableViewCell.identifier];
  1522. if (!cell) {
  1523. cell = [[RoomNameTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RoomNameTableViewCell.identifier];
  1524. }
  1525. cell.roomNameTextField.text = _room.name;
  1526. if (_room.type == kNCRoomTypeOneToOne || _room.type == kNCRoomTypeFormerOneToOne || _room.type == kNCRoomTypeChangelog) {
  1527. cell.roomNameTextField.text = _room.displayName;
  1528. }
  1529. [cell.roomImage setAvatarFor:_room];
  1530. if (_room.hasCall) {
  1531. [cell.favoriteImage setTintColor:[UIColor systemRedColor]];
  1532. [cell.favoriteImage setImage:[UIImage systemImageNamed:@"video.fill"]];
  1533. } else if (_room.isFavorite) {
  1534. [cell.favoriteImage setTintColor:[UIColor systemYellowColor]];
  1535. [cell.favoriteImage setImage:[UIImage systemImageNamed:@"star.fill"]];
  1536. }
  1537. cell.roomNameTextField.userInteractionEnabled = NO;
  1538. if (_room.canModerate || _room.type == kNCRoomTypeNoteToSelf) {
  1539. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  1540. cell.userInteractionEnabled = YES;
  1541. } else {
  1542. cell.accessoryType = UITableViewCellAccessoryNone;
  1543. cell.userInteractionEnabled = NO;
  1544. }
  1545. return cell;
  1546. }
  1547. break;
  1548. case kRoomInfoSectionDescription:
  1549. {
  1550. RoomDescriptionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RoomDescriptionTableViewCell.identifier];
  1551. if (!cell) {
  1552. cell = [[RoomDescriptionTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RoomDescriptionTableViewCell.identifier];
  1553. }
  1554. cell.textView.text = _room.roomDescription;
  1555. cell.selectionStyle = UITableViewCellSelectionStyleDefault;
  1556. return cell;
  1557. }
  1558. break;
  1559. case kRoomInfoSectionNotifications:
  1560. {
  1561. NSArray *actions = [self getNotificationsActions];
  1562. NotificationAction action = [[actions objectAtIndex:indexPath.row] intValue];
  1563. switch (action) {
  1564. case kNotificationActionChatNotifications:
  1565. {
  1566. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:chatnotificationLevelCellIdentifier];
  1567. if (!cell) {
  1568. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:chatnotificationLevelCellIdentifier];
  1569. }
  1570. cell.textLabel.text = NSLocalizedString(@"Chat messages", nil);
  1571. cell.textLabel.numberOfLines = 0;
  1572. cell.detailTextLabel.text = _room.notificationLevelString;
  1573. [cell.imageView setImage:[UIImage systemImageNamed:@"bell"]];
  1574. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1575. return cell;
  1576. }
  1577. break;
  1578. case kNotificationActionCallNotifications:
  1579. {
  1580. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:callnotificationCellIdentifier];
  1581. if (!cell) {
  1582. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:callnotificationCellIdentifier];
  1583. }
  1584. cell.textLabel.text = NSLocalizedString(@"Calls", nil);
  1585. cell.textLabel.numberOfLines = 0;
  1586. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1587. cell.accessoryView = _callNotificationSwitch;
  1588. _callNotificationSwitch.on = _room.notificationCalls;
  1589. [cell.imageView setImage:[UIImage systemImageNamed:@"phone"]];
  1590. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1591. return cell;
  1592. }
  1593. break;
  1594. }
  1595. }
  1596. break;
  1597. case kRoomInfoSectionFile:
  1598. {
  1599. NSArray *actions = [self getFileActions];
  1600. FileAction action = [[actions objectAtIndex:indexPath.row] intValue];
  1601. switch (action) {
  1602. case kFileActionPreview:
  1603. {
  1604. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:previewFileCellIdentifier];
  1605. if (!cell) {
  1606. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:previewFileCellIdentifier];
  1607. }
  1608. cell.textLabel.text = NSLocalizedString(@"Preview", nil);
  1609. cell.textLabel.numberOfLines = 0;
  1610. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  1611. [cell.imageView setImage:[UIImage systemImageNamed:@"eye"]];
  1612. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1613. if (_fileDownloadIndicator) {
  1614. // Set download indicator in case we're already downloading a file
  1615. [cell setAccessoryView:_fileDownloadIndicator];
  1616. }
  1617. return cell;
  1618. }
  1619. break;
  1620. case kFileActionOpenInFilesApp:
  1621. {
  1622. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:openFileCellIdentifier];
  1623. if (!cell) {
  1624. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:openFileCellIdentifier];
  1625. }
  1626. cell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Open in %@", nil), filesAppName];
  1627. cell.textLabel.numberOfLines = 0;
  1628. UIImage *nextcloudActionImage = [[UIImage imageNamed:@"logo-action"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
  1629. [cell.imageView setImage:nextcloudActionImage];
  1630. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1631. return cell;
  1632. }
  1633. break;
  1634. }
  1635. }
  1636. break;
  1637. case kRoomInfoSectionSharedItems:
  1638. {
  1639. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sharedItemsCellIdentifier];
  1640. if (!cell) {
  1641. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sharedItemsCellIdentifier];
  1642. }
  1643. cell.textLabel.text = NSLocalizedString(@"Images, files, voice messages…", nil);
  1644. cell.textLabel.numberOfLines = 0;
  1645. [cell.imageView setImage:[UIImage systemImageNamed:@"photo.on.rectangle.angled"]];
  1646. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1647. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  1648. return cell;
  1649. }
  1650. break;
  1651. case kRoomInfoSectionGuests:
  1652. {
  1653. NSArray *actions = [self getGuestsActions];
  1654. GuestAction action = [[actions objectAtIndex:indexPath.row] intValue];
  1655. switch (action) {
  1656. case kGuestActionPublicToggle:
  1657. {
  1658. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:allowGuestsCellIdentifier];
  1659. if (!cell) {
  1660. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:allowGuestsCellIdentifier];
  1661. }
  1662. cell.textLabel.text = NSLocalizedString(@"Allow guests", nil);
  1663. cell.textLabel.numberOfLines = 0;
  1664. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1665. cell.accessoryView = _publicSwitch;
  1666. _publicSwitch.on = (_room.type == kNCRoomTypePublic) ? YES : NO;
  1667. [cell.imageView setImage:[UIImage systemImageNamed:@"link"]];
  1668. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1669. return cell;
  1670. }
  1671. break;
  1672. case kGuestActionPassword:
  1673. {
  1674. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:passwordCellIdentifier];
  1675. if (!cell) {
  1676. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:passwordCellIdentifier];
  1677. }
  1678. cell.textLabel.text = (_room.hasPassword) ? NSLocalizedString(@"Change password", nil) : NSLocalizedString(@"Set password", nil);
  1679. cell.textLabel.numberOfLines = 0;
  1680. [cell.imageView setImage:(_room.hasPassword) ? [UIImage systemImageNamed:@"lock"] : [UIImage systemImageNamed:@"lock.open"]];
  1681. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1682. return cell;
  1683. }
  1684. break;
  1685. case kGuestActionResendInvitations:
  1686. {
  1687. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:resendInvitationsCellIdentifier];
  1688. if (!cell) {
  1689. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:resendInvitationsCellIdentifier];
  1690. }
  1691. cell.textLabel.text = NSLocalizedString(@"Resend invitations", nil);
  1692. cell.textLabel.numberOfLines = 0;
  1693. [cell.imageView setImage:[UIImage systemImageNamed:@"envelope"]];
  1694. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1695. return cell;
  1696. }
  1697. break;
  1698. }
  1699. }
  1700. break;
  1701. case kRoomInfoSectionConversation:
  1702. {
  1703. NSArray *actions = [self getConversationActions];
  1704. ConversationAction action = [[actions objectAtIndex:indexPath.row] intValue];
  1705. switch (action) {
  1706. case kConversationActionMessageExpiration:
  1707. {
  1708. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:messageExpirationCellIdentifier];
  1709. if (!cell) {
  1710. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:messageExpirationCellIdentifier];
  1711. }
  1712. cell.textLabel.text = NSLocalizedString(@"Message expiration", nil);
  1713. cell.textLabel.numberOfLines = 0;
  1714. cell.detailTextLabel.text = _room.messageExpirationString;
  1715. [cell.imageView setImage:[UIImage systemImageNamed:@"timer"]];
  1716. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1717. return cell;
  1718. }
  1719. break;
  1720. case kConversationActionBannedActors:
  1721. {
  1722. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:bannedActorsCellIdentifier];
  1723. if (!cell) {
  1724. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:bannedActorsCellIdentifier];
  1725. }
  1726. cell.textLabel.text = NSLocalizedString(@"Banned users and guests", nil);
  1727. cell.textLabel.numberOfLines = 0;
  1728. [cell.imageView setImage:[UIImage systemImageNamed:@"person.badge.minus"]];
  1729. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1730. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  1731. return cell;
  1732. }
  1733. break;
  1734. case kConversationActionListable:
  1735. {
  1736. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:listableCellIdentifier];
  1737. if (!cell) {
  1738. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:listableCellIdentifier];
  1739. }
  1740. cell.textLabel.text = NSLocalizedString(@"Open conversation to registered users", nil);
  1741. cell.textLabel.numberOfLines = 0;
  1742. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1743. cell.accessoryView = _listableSwitch;
  1744. _listableSwitch.on = (_room.listable != NCRoomListableScopeParticipantsOnly);
  1745. [cell.imageView setImage:[UIImage systemImageNamed:@"list.bullet"]];
  1746. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1747. return cell;
  1748. }
  1749. break;
  1750. case kConversationActionListableForEveryone:
  1751. {
  1752. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:listableForEveryoneCellIdentifier];
  1753. if (!cell) {
  1754. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:listableForEveryoneCellIdentifier];
  1755. }
  1756. cell.textLabel.text = NSLocalizedString(@"Also open to guest app users", nil);
  1757. cell.textLabel.numberOfLines = 0;
  1758. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1759. cell.accessoryView = _listableForEveryoneSwitch;
  1760. _listableForEveryoneSwitch.on = (_room.listable == NCRoomListableScopeEveryone);
  1761. // Still assign an image, but hide it to keep the margin the same as the other cells
  1762. [cell.imageView setImage:[UIImage systemImageNamed:@"list.bullet"]];
  1763. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1764. [cell.imageView setHidden:YES];
  1765. return cell;
  1766. }
  1767. break;
  1768. case kConversationActionMentionPermission:
  1769. {
  1770. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:mentionPermissionsCellIdentifier];
  1771. if (!cell) {
  1772. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:mentionPermissionsCellIdentifier];
  1773. }
  1774. cell.textLabel.text = NSLocalizedString(@"Allow participants to mention @all", @"'@all' should not be translated");
  1775. cell.textLabel.numberOfLines = 0;
  1776. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1777. cell.accessoryView = _mentionPermissionsSwitch;
  1778. _mentionPermissionsSwitch.on = (_room.mentionPermissions == NCRoomMentionPermissionsEveryone);
  1779. [cell.imageView setImage:[UIImage systemImageNamed:@"at.circle"]];
  1780. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1781. return cell;
  1782. }
  1783. break;
  1784. case kConversationActionReadOnly:
  1785. {
  1786. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:readOnlyStateCellIdentifier];
  1787. if (!cell) {
  1788. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:readOnlyStateCellIdentifier];
  1789. }
  1790. cell.textLabel.text = NSLocalizedString(@"Lock conversation", nil);
  1791. cell.textLabel.numberOfLines = 0;
  1792. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1793. cell.accessoryView = _readOnlySwitch;
  1794. _readOnlySwitch.on = _room.readOnlyState;
  1795. [cell.imageView setImage:[UIImage systemImageNamed:@"lock.square"]];
  1796. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1797. return cell;
  1798. }
  1799. break;
  1800. case kConversationActionShareLink:
  1801. {
  1802. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:shareLinkCellIdentifier];
  1803. if (!cell) {
  1804. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:shareLinkCellIdentifier];
  1805. }
  1806. cell.textLabel.text = NSLocalizedString(@"Share link", nil);
  1807. cell.textLabel.numberOfLines = 0;
  1808. [cell.imageView setImage:[UIImage systemImageNamed:@"square.and.arrow.up"]];
  1809. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1810. return cell;
  1811. }
  1812. break;
  1813. }
  1814. }
  1815. break;
  1816. case kRoomInfoSectionWebinar:
  1817. {
  1818. NSArray *actions = [self getWebinarActions];
  1819. WebinarAction action = [[actions objectAtIndex:indexPath.row] intValue];
  1820. switch (action) {
  1821. case kWebinarActionLobby:
  1822. {
  1823. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:lobbyCellIdentifier];
  1824. if (!cell) {
  1825. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:lobbyCellIdentifier];
  1826. }
  1827. cell.textLabel.text = NSLocalizedString(@"Lobby", nil);
  1828. cell.textLabel.numberOfLines = 0;
  1829. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1830. cell.accessoryView = _lobbySwitch;
  1831. _lobbySwitch.on = (_room.lobbyState == NCRoomLobbyStateModeratorsOnly) ? YES : NO;
  1832. [cell.imageView setImage:[[UIImage imageNamed:@"lobby"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
  1833. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1834. return cell;
  1835. }
  1836. break;
  1837. case kWebinarActionLobbyTimer:
  1838. {
  1839. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:lobbyTimerCellIdentifier];
  1840. if (!cell) {
  1841. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:lobbyTimerCellIdentifier];
  1842. }
  1843. cell.textLabel.text = NSLocalizedString(@"Start time", nil);
  1844. cell.textLabel.numberOfLines = 0;
  1845. cell.textLabel.adjustsFontSizeToFitWidth = YES;
  1846. cell.textLabel.minimumScaleFactor = 0.6;
  1847. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1848. cell.accessoryView = _lobbyDateTextField;
  1849. NSDate *date = [[NSDate alloc] initWithTimeIntervalSince1970:_room.lobbyTimer];
  1850. _lobbyDateTextField.text = _room.lobbyTimer > 0 ? [NCUtils readableDateTimeFromDate:date] : nil;
  1851. [cell.imageView setImage:[UIImage systemImageNamed:@"calendar.badge.clock"]];
  1852. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1853. return cell;
  1854. }
  1855. break;
  1856. case kWebinarActionSIP:
  1857. {
  1858. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sipCellIdentifier];
  1859. if (!cell) {
  1860. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sipCellIdentifier];
  1861. }
  1862. cell.textLabel.text = NSLocalizedString(@"SIP dial-in", nil);
  1863. cell.textLabel.numberOfLines = 0;
  1864. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1865. cell.accessoryView = _sipSwitch;
  1866. _sipSwitch.on = _room.sipState > NCRoomSIPStateDisabled;
  1867. [cell.imageView setImage:[UIImage systemImageNamed:@"phone"]];
  1868. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1869. return cell;
  1870. }
  1871. break;
  1872. case kWebinarActionSIPNoPIN:
  1873. {
  1874. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sipNoPINCellIdentifier];
  1875. if (!cell) {
  1876. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sipNoPINCellIdentifier];
  1877. }
  1878. cell.textLabel.text = NSLocalizedString(@"Allow to dial-in without a pin", nil);
  1879. cell.textLabel.numberOfLines = 0;
  1880. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1881. cell.accessoryView = _sipNoPINSwitch;
  1882. _sipNoPINSwitch.on = _room.sipState > NCRoomSIPStateEnabled;
  1883. // Still assign an image, but hide it to keep the margin the same as the other cells
  1884. [cell.imageView setImage:[UIImage systemImageNamed:@"phone"]];
  1885. cell.imageView.tintColor = [UIColor secondaryLabelColor];
  1886. [cell.imageView setHidden:YES];
  1887. return cell;
  1888. }
  1889. break;
  1890. }
  1891. }
  1892. break;
  1893. case kRoomInfoSectionSIP:
  1894. {
  1895. switch (indexPath.row) {
  1896. case kSIPActionSIPInfo:
  1897. {
  1898. RoomDescriptionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RoomDescriptionTableViewCell.identifier];
  1899. if (!cell) {
  1900. cell = [[RoomDescriptionTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RoomDescriptionTableViewCell.identifier];
  1901. }
  1902. TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
  1903. SignalingSettings *activeAccountSignalingConfig = [[[NCSettingsController sharedInstance] signalingConfigurations] objectForKey:activeAccount.accountId];
  1904. if (activeAccountSignalingConfig.sipDialinInfo) {
  1905. cell.textView.text = activeAccountSignalingConfig.sipDialinInfo;
  1906. } else {
  1907. cell.textView.text = @"";
  1908. }
  1909. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1910. return cell;
  1911. }
  1912. break;
  1913. case kSIPActionMeetingId:
  1914. {
  1915. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sipMeetingIDCellIdentifier];
  1916. if (!cell) {
  1917. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sipMeetingIDCellIdentifier];
  1918. }
  1919. cell.textLabel.text = NSLocalizedString(@"Meeting ID", nil);
  1920. cell.textLabel.numberOfLines = 0;
  1921. UILabel *valueLabel = [UILabel new];
  1922. valueLabel.text = _room.token;
  1923. valueLabel.textColor = [UIColor secondaryLabelColor];
  1924. [valueLabel sizeToFit];
  1925. cell.accessoryView = valueLabel;
  1926. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1927. return cell;
  1928. }
  1929. break;
  1930. case kSIPActionPIN:
  1931. {
  1932. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:sipUserPINCellIdentifier];
  1933. if (!cell) {
  1934. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sipUserPINCellIdentifier];
  1935. }
  1936. cell.textLabel.text = NSLocalizedString(@"Your PIN", nil);
  1937. cell.textLabel.numberOfLines = 0;
  1938. UILabel *valueLabel = [UILabel new];
  1939. valueLabel.text = _room.attendeePin;
  1940. valueLabel.textColor = [UIColor secondaryLabelColor];
  1941. [valueLabel sizeToFit];
  1942. cell.accessoryView = valueLabel;
  1943. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  1944. return cell;
  1945. }
  1946. break;
  1947. }
  1948. }
  1949. break;
  1950. case kRoomInfoSectionParticipants:
  1951. {
  1952. NCRoomParticipant *participant = [_roomParticipants objectAtIndex:indexPath.row];
  1953. ContactsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kContactCellIdentifier forIndexPath:indexPath];
  1954. if (!cell) {
  1955. cell = [[ContactsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kContactCellIdentifier];
  1956. }
  1957. // Display name
  1958. cell.labelTitle.text = [self detailedNameForParticipant:participant];
  1959. // Avatar
  1960. [cell.contactImage setActorAvatarForId:participant.actorId withType:participant.actorType withDisplayName:participant.displayName withRoomToken:self.room.token];
  1961. // User status
  1962. [cell setUserStatus:participant.status];
  1963. // User status message
  1964. [cell setUserStatusMessage:participant.statusMessage withIcon:participant.statusIcon];
  1965. if (!participant.statusMessage || [participant.statusMessage isEqualToString:@""]) {
  1966. if ([participant.status isEqualToString: kUserStatusDND]) {
  1967. [cell setUserStatusMessage:NSLocalizedString(@"Do not disturb", nil) withIcon:nil];
  1968. } else if ([participant.status isEqualToString:kUserStatusAway]) {
  1969. [cell setUserStatusMessage: NSLocalizedString(@"Away", nil) withIcon:nil];
  1970. }
  1971. }
  1972. // Federated users
  1973. if (participant.isFederated) {
  1974. UIImageSymbolConfiguration *conf = [UIImageSymbolConfiguration configurationWithPointSize:14];
  1975. UIImage *publicRoomImage = [UIImage systemImageNamed:@"globe"];
  1976. publicRoomImage = [publicRoomImage imageWithTintColor:[UIColor labelColor] renderingMode:UIImageRenderingModeAlwaysOriginal];
  1977. publicRoomImage = [publicRoomImage imageByApplyingSymbolConfiguration:conf];
  1978. [cell setUserStatusIconWithImage:publicRoomImage];
  1979. }
  1980. // Online status
  1981. if (participant.isOffline) {
  1982. cell.contactImage.alpha = 0.5;
  1983. cell.labelTitle.alpha = 0.5;
  1984. cell.userStatusMessageLabel.alpha = 0.5;
  1985. cell.userStatusImageView.alpha = 0.5;
  1986. } else {
  1987. cell.contactImage.alpha = 1;
  1988. cell.labelTitle.alpha = 1;
  1989. cell.userStatusMessageLabel.alpha = 1;
  1990. cell.userStatusImageView.alpha = 1;
  1991. }
  1992. // Call status
  1993. if (participant.callIconImageName) {
  1994. cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:participant.callIconImageName]];
  1995. [cell.accessoryView setTintColor:[UIColor secondaryLabelColor]];
  1996. } else {
  1997. cell.accessoryView = nil;
  1998. }
  1999. cell.layoutMargins = UIEdgeInsetsMake(0, 72, 0, 0);
  2000. return cell;
  2001. }
  2002. break;
  2003. case kRoomInfoSectionDestructive:
  2004. {
  2005. NSArray *actions = [self getRoomDestructiveActions];
  2006. DestructiveAction action = [[actions objectAtIndex:indexPath.row] intValue];
  2007. switch (action) {
  2008. case kDestructiveActionLeave:
  2009. {
  2010. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:leaveRoomCellIdentifier];
  2011. if (!cell) {
  2012. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:leaveRoomCellIdentifier];
  2013. }
  2014. cell.textLabel.text = NSLocalizedString(@"Leave conversation", nil);
  2015. cell.textLabel.numberOfLines = 0;
  2016. cell.textLabel.textColor = [UIColor systemRedColor];
  2017. [cell.imageView setImage:[UIImage systemImageNamed:@"arrow.right.square"]];
  2018. [cell.imageView setTintColor:[UIColor systemRedColor]];
  2019. return cell;
  2020. }
  2021. break;
  2022. case kDestructiveActionClearHistory:
  2023. {
  2024. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:clearHistoryCellIdentifier];
  2025. if (!cell) {
  2026. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:clearHistoryCellIdentifier];
  2027. }
  2028. cell.textLabel.text = NSLocalizedString(@"Delete all messages", nil);
  2029. cell.textLabel.numberOfLines = 0;
  2030. cell.textLabel.textColor = [UIColor systemRedColor];
  2031. if (@available(iOS 16.0, *)) {
  2032. [cell.imageView setImage:[UIImage systemImageNamed:@"eraser"]];
  2033. } else {
  2034. [cell.imageView setImage:[UIImage systemImageNamed:@"trash"]];
  2035. }
  2036. [cell.imageView setTintColor:[UIColor systemRedColor]];
  2037. return cell;
  2038. }
  2039. break;
  2040. case kDestructiveActionDelete:
  2041. {
  2042. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:deleteRoomCellIdentifier];
  2043. if (!cell) {
  2044. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:deleteRoomCellIdentifier];
  2045. }
  2046. cell.textLabel.text = NSLocalizedString(@"Delete conversation", nil);
  2047. cell.textLabel.numberOfLines = 0;
  2048. cell.textLabel.textColor = [UIColor systemRedColor];
  2049. [cell.imageView setImage:[UIImage systemImageNamed:@"trash"]];
  2050. [cell.imageView setTintColor:[UIColor systemRedColor]];
  2051. return cell;
  2052. }
  2053. break;
  2054. }
  2055. }
  2056. break;
  2057. }
  2058. return cell;
  2059. }
  2060. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  2061. NSArray *sections = [self getRoomInfoSections];
  2062. RoomInfoSection section = [[sections objectAtIndex:indexPath.section] intValue];
  2063. switch (section) {
  2064. case kRoomInfoSectionName:
  2065. case kRoomInfoSectionDescription:
  2066. {
  2067. if (_room.canModerate || _room.type == kNCRoomTypeNoteToSelf) {
  2068. [self presentNameInfoViewController];
  2069. }
  2070. }
  2071. break;
  2072. case kRoomInfoSectionFile:
  2073. {
  2074. NSArray *actions = [self getFileActions];
  2075. FileAction action = [[actions objectAtIndex:indexPath.row] intValue];
  2076. switch (action) {
  2077. case kFileActionPreview:
  2078. [self previewRoomFile:indexPath];
  2079. break;
  2080. case kFileActionOpenInFilesApp:
  2081. [self openRoomFileInFilesApp:indexPath];
  2082. break;
  2083. }
  2084. }
  2085. break;
  2086. case kRoomInfoSectionSharedItems:
  2087. {
  2088. [self presentSharedItemsView];
  2089. }
  2090. break;
  2091. case kRoomInfoSectionNotifications:
  2092. {
  2093. NSArray *actions = [self getNotificationsActions];
  2094. NotificationAction action = [[actions objectAtIndex:indexPath.row] intValue];
  2095. switch (action) {
  2096. case kNotificationActionChatNotifications:
  2097. [self presentNotificationLevelSelector];
  2098. break;
  2099. default:
  2100. break;
  2101. }
  2102. }
  2103. break;
  2104. case kRoomInfoSectionGuests:
  2105. {
  2106. NSArray *actions = [self getGuestsActions];
  2107. GuestAction action = [[actions objectAtIndex:indexPath.row] intValue];
  2108. switch (action) {
  2109. case kGuestActionPassword:
  2110. [self showPasswordOptions];
  2111. break;
  2112. case kGuestActionResendInvitations:
  2113. [self resendInvitations];
  2114. break;
  2115. default:
  2116. break;
  2117. }
  2118. }
  2119. break;
  2120. case kRoomInfoSectionConversation:
  2121. {
  2122. NSArray *actions = [self getConversationActions];
  2123. ConversationAction action = [[actions objectAtIndex:indexPath.row] intValue];
  2124. switch (action) {
  2125. case kConversationActionMessageExpiration:
  2126. [self presentMessageExpirationSelector];
  2127. break;
  2128. case kConversationActionBannedActors:
  2129. [self presentBannedActorsViewController];
  2130. break;
  2131. case kConversationActionShareLink:
  2132. [self shareRoomLinkFromIndexPath:indexPath];
  2133. break;
  2134. default:
  2135. break;
  2136. }
  2137. }
  2138. break;
  2139. case kRoomInfoSectionParticipants:
  2140. {
  2141. [self showOptionsForParticipantAtIndexPath:indexPath];
  2142. }
  2143. break;
  2144. case kRoomInfoSectionDestructive:
  2145. {
  2146. NSArray *actions = [self getRoomDestructiveActions];
  2147. DestructiveAction action = [[actions objectAtIndex:indexPath.row] intValue];
  2148. [self showConfirmationDialogForDestructiveAction:action];
  2149. }
  2150. break;
  2151. default:
  2152. break;
  2153. }
  2154. [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
  2155. }
  2156. #pragma mark - NCChatFileControllerDelegate
  2157. - (void)fileControllerDidLoadFile:(NCChatFileController *)fileController withFileStatus:(NCChatFileStatus *)fileStatus
  2158. {
  2159. dispatch_async(dispatch_get_main_queue(), ^{
  2160. if (self->_fileDownloadIndicator) {
  2161. [self->_fileDownloadIndicator stopAnimating];
  2162. [self->_fileDownloadIndicator removeFromSuperview];
  2163. self->_fileDownloadIndicator = nil;
  2164. }
  2165. NSInteger fileSection = [[self getRoomInfoSections] indexOfObject:@(kRoomInfoSectionFile)];
  2166. NSInteger previewRow = [[self getFileActions] indexOfObject:@(kFileActionPreview)];
  2167. NSIndexPath *previewActionIndexPath = [NSIndexPath indexPathForRow:previewRow inSection:fileSection];
  2168. UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:previewActionIndexPath];
  2169. if (cell) {
  2170. // Only show preview controller if cell is still visible
  2171. self->_previewControllerFilePath = fileStatus.fileLocalPath;
  2172. QLPreviewController * preview = [[QLPreviewController alloc] init];
  2173. UIColor *themeColor = [NCAppBranding themeColor];
  2174. preview.dataSource = self;
  2175. preview.delegate = self;
  2176. preview.navigationController.navigationBar.tintColor = [NCAppBranding themeTextColor];
  2177. preview.navigationController.navigationBar.barTintColor = themeColor;
  2178. preview.tabBarController.tabBar.tintColor = themeColor;
  2179. UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
  2180. [appearance configureWithOpaqueBackground];
  2181. appearance.backgroundColor = themeColor;
  2182. appearance.titleTextAttributes = @{NSForegroundColorAttributeName:[NCAppBranding themeTextColor]};
  2183. preview.navigationItem.standardAppearance = appearance;
  2184. preview.navigationItem.compactAppearance = appearance;
  2185. preview.navigationItem.scrollEdgeAppearance = appearance;
  2186. [self.navigationController pushViewController:preview animated:YES];
  2187. // Make sure disclosure indicator is visible again (otherwise accessoryView is empty)
  2188. cell.accessoryView = nil;
  2189. }
  2190. });
  2191. }
  2192. - (void)fileControllerDidFailLoadingFile:(NCChatFileController *)fileController withErrorDescription:(NSString *)errorDescription
  2193. {
  2194. UIAlertController * alert = [UIAlertController
  2195. alertControllerWithTitle:NSLocalizedString(@"Unable to load file", nil)
  2196. message:errorDescription
  2197. preferredStyle:UIAlertControllerStyleAlert];
  2198. UIAlertAction* okButton = [UIAlertAction
  2199. actionWithTitle:NSLocalizedString(@"OK", nil)
  2200. style:UIAlertActionStyleDefault
  2201. handler:nil];
  2202. [alert addAction:okButton];
  2203. [[NCUserInterfaceController sharedInstance] presentAlertViewController:alert];
  2204. }
  2205. #pragma mark - QLPreviewControllerDelegate/DataSource
  2206. - (NSInteger)numberOfPreviewItemsInPreviewController:(nonnull QLPreviewController *)controller {
  2207. return 1;
  2208. }
  2209. - (nonnull id<QLPreviewItem>)previewController:(nonnull QLPreviewController *)controller previewItemAtIndex:(NSInteger)index {
  2210. return [NSURL fileURLWithPath:_previewControllerFilePath];
  2211. }
  2212. @end