diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a93306c2..c022d5967 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ Group changes to describe their impact on the project, as follows: ### Added - Auto-layout of images in chat messages +- Latest Calls widget +- Latest Chatrooms widget +- Homescreen quick action : New message +- Rich message notifications with Linphone UI ### Changed - Use of Photokit instead of Asset Library for image handling diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index c0c078c10..cac542ac5 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1230,7 +1230,39 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, LinphoneAut } content.sound = [UNNotificationSound soundNamed:@"msg.caf"]; content.categoryIdentifier = @"msg_cat"; - content.userInfo = @{@"from" : from, @"peer_addr" : peer_uri, @"local_addr" : local_uri, @"CallId" : callID}; + // save data to user info for rich notification content + NSMutableArray *msgs = [NSMutableArray array]; + bctbx_list_t *history = linphone_chat_room_get_history(room, 6); + while (history) { + NSMutableDictionary *msgData = [NSMutableDictionary dictionary]; + LinphoneChatMessage *msg = history->data; + const char *state = linphone_chat_message_state_to_string(linphone_chat_message_get_state(msg)); + bool_t isOutgoing = linphone_chat_message_is_outgoing(msg); + bool_t isFileTransfer = (linphone_chat_message_get_file_transfer_information(msg) != NULL); + const LinphoneAddress *fromAddress = linphone_chat_message_get_from_address(msg); + NSString *displayNameDate = [NSString stringWithFormat:@"%@ - %@", [LinphoneUtils timeToString:linphone_chat_message_get_time(msg) + withFormat:LinphoneDateChatBubble], + [FastAddressBook displayNameForAddress:fromAddress]]; + UIImage *fromImage = [UIImage resizeImage:[FastAddressBook imageForAddress:fromAddress] + withMaxWidth:200 + andMaxHeight:200]; + NSData *fromImageData = UIImageJPEGRepresentation(fromImage, 1); + [msgData setObject:[NSString stringWithUTF8String:state] forKey:@"state"]; + [msgData setObject:displayNameDate forKey:@"displayNameDate"]; + [msgData setObject:[NSNumber numberWithBool:isFileTransfer] forKey:@"isFileTransfer"]; + [msgData setObject:fromImageData forKey:@"fromImageData"]; + if (isFileTransfer) { + LinphoneContent *file = linphone_chat_message_get_file_transfer_information(msg); + const char *filename = linphone_content_get_name(file); + [msgData setObject:[NSString stringWithUTF8String:filename] forKey:@"msg"]; + } else { + [msgData setObject:[UIChatBubbleTextCell TextMessageForChat:msg] forKey:@"msg"]; + } + [msgData setObject:[NSNumber numberWithBool:isOutgoing] forKey:@"isOutgoing"]; + [msgs addObject:msgData]; + history = bctbx_list_next(history); + } + content.userInfo = @{@"from" : from, @"peer_addr" : peer_uri, @"local_addr" : local_uri, @"CallId" : callID, @"msgs" : msgs}; content.accessibilityLabel = @"Message notif"; UNNotificationRequest *req = [UNNotificationRequest requestWithIdentifier:@"call_request" content:content trigger:NULL]; [[UNUserNotificationCenter currentNotificationCenter] diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 5c654eff9..e7ceca8a3 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -64,12 +64,23 @@ 570742671D5A63DB004B9C84 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570742661D5A63DB004B9C84 /* StoreKit.framework */; }; 5E10ED4820D00630002BF6FE /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEBE61D3CD5570014B822 /* avatar.png */; }; 5E10ED4920D006C9002BF6FE /* chat_group_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2A81941F87B8000012A66B /* chat_group_avatar.png */; }; + 5E223A9920E244B400D06A36 /* NotificationTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */; }; 5E31290120D7A37E00CF3AAE /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EF0C33820C806A5005081B0 /* NotificationCenter.framework */; }; 5E31290520D7A37E00CF3AAE /* TodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E31290420D7A37E00CF3AAE /* TodayViewController.m */; }; 5E31290820D7A37E00CF3AAE /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E31290620D7A37E00CF3AAE /* MainInterface.storyboard */; }; 5E31290C20D7A37E00CF3AAE /* latestChatroomsWidget.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5E31291320D7AAA100CF3AAE /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEBE61D3CD5570014B822 /* avatar.png */; }; 5E31291A20D7AAAD00CF3AAE /* chat_group_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2A81941F87B8000012A66B /* chat_group_avatar.png */; }; + 5E32944520E4C29000BBA896 /* chat_delivered.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523AC1E8266CC0037A187 /* chat_delivered.png */; }; + 5E32944C20E4C29300BBA896 /* chat_error.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523AD1E8266CC0037A187 /* chat_error.png */; }; + 5E32944D20E4C29700BBA896 /* chat_read.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523AE1E8266CC0037A187 /* chat_read.png */; }; + 5E3391EC20E387E000F66299 /* color_A.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEC701D3CD5570014B822 /* color_A.png */; }; + 5E3391F320E387E700F66299 /* color_D.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEC721D3CD5570014B822 /* color_D.png */; }; + 5E58962420DCE5700030868C /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C73477B1D9BA3A00022EE8C /* UserNotifications.framework */; }; + 5E58962620DCE5700030868C /* UserNotificationsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E58962520DCE5700030868C /* UserNotificationsUI.framework */; }; + 5E58962A20DCE5700030868C /* NotificationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E58962920DCE5700030868C /* NotificationViewController.m */; }; + 5E58962D20DCE5700030868C /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E58962B20DCE5700030868C /* MainInterface.storyboard */; }; + 5E58963120DCE5710030868C /* richNotifications.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5E58962320DCE5700030868C /* richNotifications.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5EEE8F9B20C80C23006E4176 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EF0C33820C806A5005081B0 /* NotificationCenter.framework */; }; 5EEE8F9F20C80C23006E4176 /* TodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EEE8F9E20C80C23006E4176 /* TodayViewController.m */; }; 5EEE8FA220C80C23006E4176 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EEE8FA020C80C23006E4176 /* MainInterface.storyboard */; }; @@ -834,6 +845,13 @@ remoteGlobalIDString = 5E3128FF20D7A37E00CF3AAE; remoteInfo = latestChatroomsWidget; }; + 5E58962F20DCE5710030868C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5E58962220DCE5700030868C; + remoteInfo = richNotifications; + }; 5EEE8FA420C80C23006E4176 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -923,6 +941,7 @@ 61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */, 5E31290C20D7A37E00CF3AAE /* latestChatroomsWidget.appex in Embed App Extensions */, 5EEE8FA620C80C23006E4176 /* latestCallsWidget.appex in Embed App Extensions */, + 5E58963120DCE5710030868C /* richNotifications.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -1064,12 +1083,20 @@ 570742601D5A09B8004B9C84 /* ShopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShopView.h; sourceTree = ""; }; 570742631D5A1860004B9C84 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ShopView.strings; sourceTree = ""; }; 570742661D5A63DB004B9C84 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + 5E223A9720E244B400D06A36 /* NotificationTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationTableViewCell.h; sourceTree = ""; }; + 5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationTableViewCell.m; sourceTree = ""; }; 5E30780420D8F00D00256DAE /* latestChatroomsWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = latestChatroomsWidget.entitlements; sourceTree = ""; }; 5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = latestChatroomsWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 5E31290320D7A37E00CF3AAE /* TodayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TodayViewController.h; sourceTree = ""; }; 5E31290420D7A37E00CF3AAE /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = ""; }; 5E31290720D7A37E00CF3AAE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; 5E31290920D7A37E00CF3AAE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5E58962320DCE5700030868C /* richNotifications.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = richNotifications.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E58962520DCE5700030868C /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; }; + 5E58962820DCE5700030868C /* NotificationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationViewController.h; sourceTree = ""; }; + 5E58962920DCE5700030868C /* NotificationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationViewController.m; sourceTree = ""; }; + 5E58962C20DCE5700030868C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 5E58962E20DCE5710030868C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5EEE8F9A20C80C23006E4176 /* latestCallsWidget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = latestCallsWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 5EEE8F9D20C80C23006E4176 /* TodayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TodayViewController.h; sourceTree = ""; }; 5EEE8F9E20C80C23006E4176 /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = ""; }; @@ -2058,6 +2085,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E58962020DCE5700030868C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E58962620DCE5700030868C /* UserNotificationsUI.framework in Frameworks */, + 5E58962420DCE5700030868C /* UserNotifications.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5EEE8F9720C80C23006E4176 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2273,6 +2309,7 @@ 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */, 5EEE8F9A20C80C23006E4176 /* latestCallsWidget.appex */, 5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */, + 5E58962320DCE5700030868C /* richNotifications.appex */, ); name = Products; sourceTree = ""; @@ -2390,6 +2427,7 @@ 61AE364C20C00B370089D9D3 /* linphoneExtension */, 5EEE8F9C20C80C23006E4176 /* latestCallsWidget */, 5E31290220D7A37E00CF3AAE /* latestChatroomsWidget */, + 5E58962720DCE5700030868C /* richNotifications */, 29B97323FDCFA39411CA2CEA /* Frameworks */, F0938158188E629800A55DFA /* iTunesArtwork */, 63058A0C1B4E821E00EFAE36 /* LiblinphoneTester */, @@ -2481,6 +2519,7 @@ 2264B6D111200342002C2C53 /* SystemConfiguration.framework */, 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 5EF0C33820C806A5005081B0 /* NotificationCenter.framework */, + 5E58962520DCE5700030868C /* UserNotificationsUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -2497,6 +2536,19 @@ path = latestChatroomsWidget; sourceTree = ""; }; + 5E58962720DCE5700030868C /* richNotifications */ = { + isa = PBXGroup; + children = ( + 5E58962820DCE5700030868C /* NotificationViewController.h */, + 5E58962920DCE5700030868C /* NotificationViewController.m */, + 5E58962B20DCE5700030868C /* MainInterface.storyboard */, + 5E58962E20DCE5710030868C /* Info.plist */, + 5E223A9720E244B400D06A36 /* NotificationTableViewCell.h */, + 5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */, + ); + path = richNotifications; + sourceTree = ""; + }; 5EEE8F9C20C80C23006E4176 /* latestCallsWidget */ = { isa = PBXGroup; children = ( @@ -3314,6 +3366,7 @@ 61AE365520C00B370089D9D3 /* PBXTargetDependency */, 5EEE8FA520C80C23006E4176 /* PBXTargetDependency */, 5E31290B20D7A37E00CF3AAE /* PBXTargetDependency */, + 5E58963020DCE5710030868C /* PBXTargetDependency */, ); name = linphone; productName = linphone; @@ -3337,6 +3390,23 @@ productReference = 5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */; productType = "com.apple.product-type.app-extension"; }; + 5E58962220DCE5700030868C /* richNotifications */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E58963C20DCE5710030868C /* Build configuration list for PBXNativeTarget "richNotifications" */; + buildPhases = ( + 5E58961F20DCE5700030868C /* Sources */, + 5E58962020DCE5700030868C /* Frameworks */, + 5E58962120DCE5700030868C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = richNotifications; + productName = richNotifications; + productReference = 5E58962320DCE5700030868C /* richNotifications.appex */; + productType = "com.apple.product-type.app-extension"; + }; 5EEE8F9920C80C23006E4176 /* latestCallsWidget */ = { isa = PBXNativeTarget; buildConfigurationList = 5EEE8FA720C80C24006E4176 /* Build configuration list for PBXNativeTarget "latestCallsWidget" */; @@ -3462,6 +3532,11 @@ }; }; }; + 5E58962220DCE5700030868C = { + CreatedOnToolsVersion = 9.4; + DevelopmentTeam = Z2V957B3D6; + ProvisioningStyle = Automatic; + }; 5EEE8F9920C80C23006E4176 = { CreatedOnToolsVersion = 9.4; DevelopmentTeam = Z2V957B3D6; @@ -3536,6 +3611,7 @@ 61AE364A20C00B370089D9D3 /* linphoneExtension */, 5EEE8F9920C80C23006E4176 /* latestCallsWidget */, 5E3128FF20D7A37E00CF3AAE /* latestChatroomsWidget */, + 5E58962220DCE5700030868C /* richNotifications */, ); }; /* End PBXProject section */ @@ -4134,6 +4210,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E58962120DCE5700030868C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E32944C20E4C29300BBA896 /* chat_error.png in Resources */, + 5E32944D20E4C29700BBA896 /* chat_read.png in Resources */, + 5E32944520E4C29000BBA896 /* chat_delivered.png in Resources */, + 5E3391F320E387E700F66299 /* color_D.png in Resources */, + 5E58962D20DCE5700030868C /* MainInterface.storyboard in Resources */, + 5E3391EC20E387E000F66299 /* color_A.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5EEE8F9820C80C23006E4176 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -4382,6 +4471,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5E58961F20DCE5700030868C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E223A9920E244B400D06A36 /* NotificationTableViewCell.m in Sources */, + 5E58962A20DCE5700030868C /* NotificationViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5EEE8F9620C80C23006E4176 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -4441,6 +4539,11 @@ target = 5E3128FF20D7A37E00CF3AAE /* latestChatroomsWidget */; targetProxy = 5E31290A20D7A37E00CF3AAE /* PBXContainerItemProxy */; }; + 5E58963020DCE5710030868C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5E58962220DCE5700030868C /* richNotifications */; + targetProxy = 5E58962F20DCE5710030868C /* PBXContainerItemProxy */; + }; 5EEE8FA520C80C23006E4176 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5EEE8F9920C80C23006E4176 /* latestCallsWidget */; @@ -4487,6 +4590,14 @@ name = MainInterface.storyboard; sourceTree = ""; }; + 5E58962B20DCE5700030868C /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5E58962C20DCE5700030868C /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; 5EEE8FA020C80C23006E4176 /* MainInterface.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -5554,6 +5665,178 @@ }; name = DistributionAdhoc; }; + 5E58963220DCE5710030868C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = Z2V957B3D6; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = richNotifications/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5E58963320DCE5710030868C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = richNotifications/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5E58963420DCE5710030868C /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = richNotifications/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Distribution; + }; + 5E58963520DCE5710030868C /* DistributionAdhoc */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = richNotifications/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = DistributionAdhoc; + }; 5EEE8FA820C80C24006E4176 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -6558,6 +6841,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + 5E58963C20DCE5710030868C /* Build configuration list for PBXNativeTarget "richNotifications" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E58963220DCE5710030868C /* Debug */, + 5E58963320DCE5710030868C /* Release */, + 5E58963420DCE5710030868C /* Distribution */, + 5E58963520DCE5710030868C /* DistributionAdhoc */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; 5EEE8FA720C80C24006E4176 /* Build configuration list for PBXNativeTarget "latestCallsWidget" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/richNotifications/Base.lproj/MainInterface.storyboard b/richNotifications/Base.lproj/MainInterface.storyboard new file mode 100644 index 000000000..f50b1b59d --- /dev/null +++ b/richNotifications/Base.lproj/MainInterface.storyboard @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/richNotifications/Info.plist b/richNotifications/Info.plist new file mode 100644 index 000000000..f6e516e4d --- /dev/null +++ b/richNotifications/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + richNotifications + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + UNNotificationExtensionDefaultContentHidden + + UNNotificationExtensionCategory + msg_cat + UNNotificationExtensionInitialContentSizeRatio + 1 + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.usernotifications.content-extension + + + diff --git a/richNotifications/NotificationTableViewCell.h b/richNotifications/NotificationTableViewCell.h new file mode 100644 index 000000000..77b74e1d3 --- /dev/null +++ b/richNotifications/NotificationTableViewCell.h @@ -0,0 +1,24 @@ +// +// NotificationTableViewCell.h +// richNotifications +// +// Created by David Idmansour on 26/06/2018. +// + +#import + +@interface NotificationTableViewCell : UITableViewCell +@property (weak, nonatomic) IBOutlet UIImageView *contactImage; +@property (weak, nonatomic) IBOutlet UILabel *nameDate; +@property (strong, nonatomic) IBOutlet UITextView *msgText; +@property (weak, nonatomic) IBOutlet UILabel *imdm; +@property (weak, nonatomic) IBOutlet UIImageView *background; +@property (weak, nonatomic) IBOutlet UIImageView *bottomBarColor; +@property (weak, nonatomic) IBOutlet UIImageView *imdmImage; +@property BOOL isOutgoing; +@property float width; +@property float height; + +- (CGSize)ViewSizeForMessage:(NSString *)chat withWidth:(int)width; + +@end diff --git a/richNotifications/NotificationTableViewCell.m b/richNotifications/NotificationTableViewCell.m new file mode 100644 index 000000000..26fe0f188 --- /dev/null +++ b/richNotifications/NotificationTableViewCell.m @@ -0,0 +1,94 @@ +// +// NotificationTableViewCell.m +// richNotifications +// +// Created by David Idmansour on 26/06/2018. +// + +#import "NotificationTableViewCell.h" + +@implementation NotificationTableViewCell + +- (void)awakeFromNib { + [super awakeFromNib]; + // Initialization code + _contactImage.layer.cornerRadius = _contactImage.frame.size.height / 2; + _contactImage.clipsToBounds = YES; + [self.contentView sendSubviewToBack:_background]; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +- (void)layoutSubviews { + [super layoutSubviews]; + CGRect bubbleFrame = self.contentView.frame; + int originX; + + bubbleFrame.size = CGSizeMake(_width, _height); + + originX = (_isOutgoing ? self.frame.size.width - bubbleFrame.size.width - 5 : 5); + + bubbleFrame.origin.x = originX; + self.contentView.frame = bubbleFrame; + + _msgText.textContainerInset = UIEdgeInsetsZero; + _msgText.textContainer.lineFragmentPadding = 0; +} + +#pragma mark - Bubble size computing + +- (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font { + if (!text || text.length == 0) + return CGSizeMake(0, 0); + + return [text boundingRectWithSize:size + options:(NSStringDrawingUsesLineFragmentOrigin | + NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading) + attributes:@{ + NSFontAttributeName : font + } + context:nil].size; +} + +static const CGFloat CELL_MIN_HEIGHT = 60.0f; +static const CGFloat CELL_MIN_WIDTH = 190.0f; +static const CGFloat CELL_MESSAGE_X_MARGIN = 78 + 10.0f; +static const CGFloat CELL_MESSAGE_Y_MARGIN = 52; // 44; + +- (CGSize)ViewHeightForMessage:(NSString *)messageText withWidth:(int)width { + static UIFont *messageFont = nil; + + if (!messageFont) { + messageFont = _msgText.font; + } + CGSize size; + size = [self computeBoundingBox:messageText + size:CGSizeMake(width - CELL_MESSAGE_X_MARGIN - 4, CGFLOAT_MAX) + font:messageFont]; + + size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH); + size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT); + return size; +} +- (CGSize)ViewSizeForMessage:(NSString *)chat withWidth:(int)width { + static UIFont *dateFont = nil; + static CGSize dateViewSize; + + if (!dateFont) { + dateFont = _nameDate.font; + dateViewSize = _nameDate.frame.size; + dateViewSize.width = CGFLOAT_MAX; + } + + CGSize messageSize = [self ViewHeightForMessage:chat withWidth:width]; + CGSize dateSize = [self computeBoundingBox:_nameDate.text size:dateViewSize font:dateFont]; + messageSize.width = MAX(MAX(messageSize.width, MIN(dateSize.width + CELL_MESSAGE_X_MARGIN, width)), CELL_MIN_WIDTH); + + return messageSize; +} + +@end diff --git a/richNotifications/NotificationViewController.h b/richNotifications/NotificationViewController.h new file mode 100644 index 000000000..f96beffbd --- /dev/null +++ b/richNotifications/NotificationViewController.h @@ -0,0 +1,12 @@ +// +// NotificationViewController.h +// richNotifications +// +// Created by David Idmansour on 22/06/2018. +// + +#import + +@interface NotificationViewController : UITableViewController + +@end diff --git a/richNotifications/NotificationViewController.m b/richNotifications/NotificationViewController.m new file mode 100644 index 000000000..69aa955a8 --- /dev/null +++ b/richNotifications/NotificationViewController.m @@ -0,0 +1,110 @@ +// +// NotificationViewController.m +// richNotifications +// +// Created by David Idmansour on 22/06/2018. +// + +#import "NotificationViewController.h" +#import "NotificationTableViewCell.h" +#import +#import + +@interface NotificationViewController () + +@end + +@implementation NotificationViewController { + @private + NSMutableArray *msgs; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.tableView.scrollEnabled = TRUE; + // Do any required interface initialization here. +} + +- (void)didReceiveNotification:(UNNotification *)notification { +// static float initialHeight = -1; +// if (initialHeight < 0) +// initialHeight = self.tableView.frame.size.height; + if (msgs) + [msgs addObject:[((NSArray *)[[[[notification request] content] userInfo] objectForKey:@"msgs"]) lastObject]]; + else + msgs = [NSMutableArray arrayWithArray:[[[[notification request] content] userInfo] objectForKey:@"msgs"]]; + [self.tableView reloadData]; + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:msgs.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; +// float height = 0; +// for (int i = 0 ; i < self->msgs.count ; i++) { +// height += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]; +// } +// if (height > initialHeight) { +// CGRect frame = self.tableView.frame; +// frame.size.height = height; +// frame.origin = CGPointMake(0, 0); +// self.tableView.frame = frame; +// self.tableView.bounds = frame; +// self.preferredContentSize = CGSizeMake(self.preferredContentSize.width, height); +// } +} + +#pragma mark - UITableViewDataSource Functions + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return msgs.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + BOOL isOutgoing = ((NSNumber *)[msgs[indexPath.row] objectForKey:@"isOutgoing"]).boolValue; + NSString *display = ((NSString *)[msgs[indexPath.row] objectForKey:@"displayNameDate"]); + NSString *msgText = ((NSString *)[msgs[indexPath.row] objectForKey:@"msg"]); + NSString *imdm = ((NSString *)[msgs[indexPath.row] objectForKey:@"state"]); + NSData *imageData = [msgs[indexPath.row] objectForKey:@"fromImageData"]; + NotificationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"notificationCell" forIndexPath:indexPath]; + + cell.background.image = cell.bottomBarColor.image = [UIImage imageNamed:isOutgoing ? @"color_A" : @"color_D.png"]; + cell.contactImage.image = [UIImage imageWithData:imageData]; + cell.nameDate.text = display; + cell.msgText.text = msgText; + cell.isOutgoing = isOutgoing; + CGSize size = [cell ViewSizeForMessage:msgText withWidth:self.view.bounds.size.width - 10]; + cell.width = size.width; + cell.height = size.height; + cell.nameDate.textColor = [UIColor colorWithPatternImage:cell.background.image]; + cell.msgText.textColor = [UIColor darkGrayColor]; + cell.imdm.hidden = cell.imdmImage.hidden = !isOutgoing; + + if ([imdm isEqualToString:@"LinphoneChatMessageStateDelivered"] || [imdm isEqualToString:@"LinphoneChatMessageStateDeliveredToUser"]) { + cell.imdm.text = NSLocalizedString(@"Delivered", nil); + cell.imdm.textColor = [UIColor grayColor]; + cell.imdmImage.image = [UIImage imageNamed:@"chat_delivered.png"]; + } else if ([imdm isEqualToString:@"LinphoneChatMessageStateDisplayed"]) { + cell.imdm.text = NSLocalizedString(@"Read", nil); + cell.imdm.textColor = [UIColor colorWithRed:(24 / 255.0) green:(167 / 255.0) blue:(175 / 255.0) alpha:1.0]; + cell.imdmImage.image = [UIImage imageNamed:@"chat_read.png"]; + } else if ([imdm isEqualToString:@"LinphoneChatMessageStateNotDelivered"] || [imdm isEqualToString:@"LinphoneChatMessageStateFileTransferError"]) { + cell.imdm.text = NSLocalizedString(@"Error", nil); + cell.imdm.textColor = [UIColor redColor]; + cell.imdmImage.image = [UIImage imageNamed:@"chat_error.png"]; + } else + cell.imdm.hidden = YES; + + return cell; +} + +#pragma mark - UITableViewDelegate Functions + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + NotificationTableViewCell *cell = [[NotificationTableViewCell alloc] init]; + cell.msgText = [[UITextView alloc] init]; + cell.msgText.text = ((NSString *)[msgs[indexPath.row] objectForKey:@"msg"]); + cell.msgText.font = [UIFont systemFontOfSize:17]; + return [cell ViewSizeForMessage:cell.msgText.text withWidth:self.view.bounds.size.width - 10].height + 5; +} + +@end