TypingIndicatorManager.m 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2012-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "TypingIndicatorManager.h"
  21. #import "Conversation.h"
  22. #import "Contact.h"
  23. #import "EntityManager.h"
  24. #ifdef DEBUG
  25. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  26. #else
  27. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  28. #endif
  29. @implementation TypingIndicatorManager {
  30. dispatch_source_t resetTimer;
  31. dispatch_queue_t resetQueue;
  32. }
  33. + (TypingIndicatorManager*)sharedInstance {
  34. static TypingIndicatorManager *sharedInstance;
  35. static dispatch_once_t pred;
  36. dispatch_once(&pred, ^{
  37. sharedInstance = [[TypingIndicatorManager alloc] init];
  38. });
  39. return sharedInstance;
  40. }
  41. - (id)init
  42. {
  43. self = [super init];
  44. if (self) {
  45. resetQueue = dispatch_queue_create("ch.threema.resetQueue", 0);
  46. resetTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, resetQueue);
  47. dispatch_source_set_timer(resetTimer, dispatch_time(DISPATCH_TIME_NOW, kTypingIndicatorTimeout/2 * NSEC_PER_SEC),
  48. kTypingIndicatorTimeout/2 * NSEC_PER_SEC, NSEC_PER_SEC);
  49. dispatch_source_set_event_handler(resetTimer, ^{
  50. [self resetTypingIndicators];
  51. });
  52. dispatch_resume(resetTimer);
  53. }
  54. return self;
  55. }
  56. - (void)resetTypingIndicators {
  57. /* Fetch all Conversations that are currently typing, and reset the typing
  58. indicator if it was received too long ago */
  59. DDLogVerbose(@"Resetting typing indicators");
  60. dispatch_async(dispatch_get_main_queue(), ^{
  61. EntityManager *entityManager = [[EntityManager alloc] init];
  62. NSArray *conversations = [entityManager.entityFetcher allConversations];
  63. if (conversations == nil) {
  64. DDLogError(@"No conversations found");
  65. return;
  66. }
  67. for (Conversation *conversation in conversations) {
  68. if (conversation.typing.boolValue && ((conversation.lastTypingStart != nil && [conversation.lastTypingStart timeIntervalSinceNow] < -kTypingIndicatorTimeout))) {
  69. DDLogVerbose(@"Reset typing indicator on conversation with %@", conversation.contact.identity);
  70. conversation.typing = [NSNumber numberWithBool:NO];
  71. }
  72. }
  73. });
  74. }
  75. - (void)setTypingIndicatorForIdentity:(NSString*)identity typing:(BOOL)typing {
  76. dispatch_async(dispatch_get_main_queue(), ^{
  77. EntityManager *entityManager = [[EntityManager alloc] init];
  78. Conversation *conversation = [entityManager.entityFetcher conversationForIdentity:identity];
  79. if (conversation == nil) {
  80. DDLogInfo(@"No conversation with identity %@ found", identity);
  81. return;
  82. }
  83. conversation.typing = [NSNumber numberWithBool:typing];
  84. });
  85. }
  86. @end