Update contact list and chat conversation creation view to use magic search

This commit is contained in:
QuentinArguillere 2022-04-01 12:26:01 +02:00
parent 78f33f6a93
commit 00728f3a04
21 changed files with 480 additions and 398 deletions

View file

@ -1,7 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -29,23 +32,23 @@
</connections>
</tapGestureRecognizer>
<view contentMode="scaleToFill" id="WKv-mw-S2B" userLabel="iphone6MetricsView">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5">
<rect key="frame" x="0.0" y="42" width="375" height="559"/>
<rect key="frame" x="0.0" y="42" width="414" height="788"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view alpha="0.90000000000000002" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7" userLabel="topBar">
<rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="66"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d5Q-XR-FNz" userLabel="switchView">
<rect key="frame" x="225" y="0.0" width="150" height="66"/>
<rect key="frame" x="248" y="0.0" width="166" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="r3z-SM-lMq" userLabel="allButton" customClass="UIInterfaceStyleButton">
<rect key="frame" x="0.0" y="0.0" width="75" height="66"/>
<rect key="frame" x="0.0" y="0.0" width="83" height="66"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<accessibility key="accessibilityConfiguration" label="All contacts filter"/>
<fontDescription key="fontDescription" type="system" pointSize="9"/>
@ -65,11 +68,11 @@
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="ibu-Ra-oZO" userLabel="selectedButtonImage">
<rect key="frame" x="0.0" y="63" width="75" height="3"/>
<rect key="frame" x="0.0" y="63" width="83" height="3"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8lQ-fv-INK" userLabel="sipButton" customClass="UIInterfaceStyleButton">
<rect key="frame" x="75" y="0.0" width="75" height="66"/>
<rect key="frame" x="83" y="0.0" width="83" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES"/>
<accessibility key="accessibilityConfiguration" label="Linphone contacts filter"/>
<fontDescription key="fontDescription" type="system" pointSize="9"/>
@ -89,7 +92,7 @@
</subviews>
</view>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fNt-yb-wsf" userLabel="backButton" customClass="UIInterfaceStyleButton">
<rect key="frame" x="0.0" y="0.0" width="75" height="66"/>
<rect key="frame" x="0.0" y="0.0" width="82" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<accessibility key="accessibilityConfiguration" label="Back"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
@ -143,7 +146,7 @@
</subviews>
</view>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rBc-dQ-eIj" userLabel="nextButton" customClass="UIInterfaceStyleButton">
<rect key="frame" x="300" y="0.0" width="75" height="66"/>
<rect key="frame" x="331" y="0.0" width="83" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<accessibility key="accessibilityConfiguration" label="Back">
<bool key="isElement" value="YES"/>
@ -160,18 +163,18 @@
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
</view>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KRQ-Fm-3cQ" userLabel="addedContacts" customClass="UICollectionView">
<rect key="frame" x="8" y="110" width="359" height="70"/>
<rect key="frame" x="8" y="110" width="398" height="70"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<accessibility key="accessibilityConfiguration" label="addedContacts"/>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="6">
<rect key="frame" x="5" y="178" width="365" height="381"/>
<rect key="frame" x="5" y="178" width="403" height="610"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<color key="separatorColor" red="0.67030966281890869" green="0.71867996454238892" blue="0.75078284740447998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="dataSource" destination="4" id="11"/>
@ -179,7 +182,7 @@
</connections>
</tableView>
<searchBar contentMode="redraw" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rd9-hK-nqR" userLabel="Contact address">
<rect key="frame" x="0.0" y="66" width="375" height="44"/>
<rect key="frame" x="0.0" y="66" width="414" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
<connections>
@ -187,19 +190,37 @@
</connections>
</searchBar>
<view hidden="YES" tag="8" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ztm-hK-aBp" userLabel="waitView">
<rect key="frame" x="0.0" y="0.0" width="375" height="559"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="788"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<activityIndicatorView opaque="NO" tag="9" contentMode="scaleToFill" fixedFrame="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="nqH-qD-vgE" userLabel="activityIndicatorView">
<rect key="frame" x="179" y="267" width="20" height="20"/>
<rect key="frame" x="199" y="380" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<gestureRecognizers/>
</view>
<view hidden="YES" contentMode="scaleToFill" id="Vhn-Z4-Z4Q" userLabel="loadingView">
<rect key="frame" x="5" y="178" width="403" height="610"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Loading contacts..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tQD-oL-wLO">
<rect key="frame" x="100" y="10" width="145" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="medium" id="xS4-I7-COE">
<rect key="frame" x="75" y="10" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -209,6 +230,7 @@
<extendedEdge key="edgesForExtendedLayout"/>
<nil key="simulatedStatusBarMetrics"/>
<connections>
<outlet property="loadingView" destination="Vhn-Z4-Z4Q" id="FvB-Bn-31o"/>
<outlet property="searchBar" destination="Rd9-hK-nqR" id="rLn-7q-CwC"/>
<outlet property="view" destination="6" id="13"/>
<outlet property="waitView" destination="Ztm-hK-aBp" id="uSB-4b-n7e"/>
@ -233,5 +255,11 @@
<image name="security_toogle_button.png" width="21" height="21"/>
<image name="security_toogle_icon_green.png" width="33.599998474121094" height="38.400001525878906"/>
<image name="security_toogle_icon_grey.png" width="33.599998474121094" height="38.400001525878906"/>
<systemColor name="secondarySystemBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View file

@ -1,7 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -10,6 +13,8 @@
<outlet property="addButton" destination="6" id="91"/>
<outlet property="allButton" destination="4" id="27"/>
<outlet property="linphoneButton" destination="5" id="31"/>
<outlet property="loadingLabel" destination="qSa-Ba-dq9" id="CPa-pO-OQD"/>
<outlet property="loadingView" destination="CM2-Aq-Q3g" id="uie-SJ-TKf"/>
<outlet property="searchBar" destination="5jE-oF-d45" id="xfS-xo-2Bm"/>
<outlet property="selectedButtonImage" destination="A9k-KU-Dlm" id="4dX-pd-Y2D"/>
<outlet property="tableController" destination="TJG-JZ-YRR" id="0lt-gC-EOm"/>
@ -153,7 +158,7 @@
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
</view>
<searchBar contentMode="redraw" fixedFrame="YES" showsCancelButton="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5jE-oF-d45" userLabel="searchBar">
<rect key="frame" x="0.0" y="66" width="375" height="44"/>
@ -166,7 +171,7 @@
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="zOo-FS-W6l" userLabel="tableView">
<rect key="frame" x="0.0" y="110" width="375" height="449"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<inset key="scrollIndicatorInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
<color key="separatorColor" red="0.67030966281890869" green="0.71867996454238892" blue="0.75078284740447998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
@ -177,11 +182,29 @@
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No contact found in your address book" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JR3-k7-gVP" userLabel="emptyTableLabel">
<rect key="frame" x="0.0" y="110" width="375" height="449"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view hidden="YES" contentMode="scaleToFill" id="CM2-Aq-Q3g">
<rect key="frame" x="0.0" y="110" width="375" height="449"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" animating="YES" style="medium" translatesAutoresizingMaskIntoConstraints="NO" id="udQ-TE-UlZ">
<rect key="frame" x="80" y="8" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Loading contacts..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="qSa-Ba-dq9">
<rect key="frame" x="108" y="8" width="145" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</subviews>
</view>
</subviews>
@ -218,5 +241,11 @@
<image name="deselect_all.png" width="43.200000762939453" height="43.200000762939453"/>
<image name="select_all_default.png" width="43.200000762939453" height="43.200000762939453"/>
<image name="select_all_disabled.png" width="43.200000762939453" height="43.200000762939453"/>
<systemColor name="secondarySystemBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View file

@ -22,13 +22,14 @@
@interface ChatConversationCreateTableView : UITableViewController <UISearchBarDelegate>
@property(nonatomic) Boolean allFilter;
@property(nonatomic) Boolean notFirstTime;
@property(nonatomic) Boolean reloadMagicSearch;
@property(nonatomic, strong) NSMutableArray *contactsGroup;
@property(nonatomic) LinphoneMagicSearch *magicSearch;
@property(weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (weak, nonatomic) IBOutlet UIButton *controllerNextButton;
@property (weak, nonatomic) IBOutlet UIView *waitView;
@property (weak, nonatomic) IBOutlet UIView *loadingView;
@property(nonatomic) Boolean isForEditing;
@property(nonatomic) Boolean isGroupChat;

View file

@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "linphoneapp-Swift.h"
#import "ChatConversationCreateTableView.h"
#import "UIChatCreateCell.h"
#import "LinphoneManager.h"
@ -28,14 +29,18 @@
@property(nonatomic, strong) NSMutableArray *addresses;
@property(nonatomic, strong) NSMutableArray *phoneOrAddr;
@property(nonatomic, strong) NSMutableArray *addressesCached;
@property(readonly, nonatomic) NSMutableDictionary *ldapContactAddressBookMap;
@end
@implementation ChatConversationCreateTableView
- (void)viewWillAppear:(BOOL)animated {
if (!_ldapContactAddressBookMap) {
_ldapContactAddressBookMap = [NSMutableDictionary dictionary];
}
[super viewWillAppear:animated];
_magicSearch = linphone_core_create_magic_search(LC);
int y = _contactsGroup.count > 0
? _collectionView.frame.origin.y + _collectionView.frame.size.height
: _searchBar.frame.origin.y + _searchBar.frame.size.height;
@ -53,6 +58,18 @@
_addresses = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
_phoneOrAddr = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
_addressesCached = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onChatMagicSearchStarted:)
name:kLinphoneMagicSearchStarted
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onChatMagicSearchFinished:)
name:kLinphoneMagicSearchFinished
object:nil];
if(_notFirstTime) {
for(NSString *addr in _contactsGroup) {
[_collectionView registerClass:UIChatCreateCollectionViewCell.class forCellWithReuseIdentifier:addr];
@ -64,32 +81,31 @@
[_searchBar setText:@""];
[self searchBar:_searchBar textDidChange:_searchBar.text];
self.tableView.accessibilityIdentifier = @"Suggested addresses";
}
- (void) viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
_notFirstTime = FALSE;
linphone_magic_search_unref(_magicSearch);
_magicSearch = NULL;
}
- (void) loadData {
[self reloadDataWithFilter:_searchBar.text];
- (void)onChatMagicSearchStarted:(NSNotification *)k {
_loadingView.hidden = FALSE;
}
- (void)onChatMagicSearchFinished:(NSNotification *)k {
[self buildChatContactTable];
_loadingView.hidden = TRUE;
}
- (void)reloadDataWithFilter:(NSString *)filter {
[_addresses removeAllObjects];
[_phoneOrAddr removeAllObjects];
[_addressesCached removeAllObjects];
if (!_magicSearch)
return;
bctbx_list_t *results = linphone_magic_search_get_contact_list_from_filter(_magicSearch, filter.UTF8String, _allFilter ? "" : "*");
- (void) buildChatContactTable {
[_ldapContactAddressBookMap removeAllObjects];
bctbx_list_t *results = [MagicSearchSingleton.instance getLastSearchResults];
while (results) {
LinphoneSearchResult *result = results->data;
const LinphoneAddress *addr = linphone_search_result_get_address(result);
const char *phoneNumber = NULL;
Contact *contact = nil;
char *uri = nil;
NSString *address = nil;
@ -99,10 +115,10 @@
contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:address]];
}
if (!addr || (!contact && linphone_search_result_get_friend(result))) {
const LinphoneFriend* friend = linphone_search_result_get_friend(result);
if (!addr || (!contact && friend)) {
phoneNumber = linphone_search_result_get_phone_number(result);
if (!phoneNumber) {
results = results->next;
continue;
}
@ -111,13 +127,17 @@
const char *normalizedPhoneNumber = linphone_account_normalize_phone_number(account, phoneNumber);
if (!normalizedPhoneNumber) {
// get invalid phone number, continue
results = results->next;
continue;
}
addr = linphone_account_normalize_sip_uri(account, normalizedPhoneNumber);
uri = linphone_address_as_string_uri_only(addr);
address = [NSString stringWithUTF8String:uri];
contact = [[Contact alloc] initWithFriend:friend];
[contact setCreatedFromLdap:TRUE];
[_ldapContactAddressBookMap setObject:contact forKey:address];
}
}
if (!addr) {
@ -125,18 +145,36 @@
continue;
}
ms_free(uri);
ms_free(uri);
[_addresses addObject:address];
[_phoneOrAddr addObject:phoneNumber ? [NSString stringWithUTF8String:phoneNumber] : address];
[_addressesCached addObject:[NSString stringWithFormat:@"%d",linphone_search_result_get_capabilities(result)]];
[_addressesCached addObject:[NSString stringWithFormat:@"%d",linphone_search_result_get_capabilities(result)]];
results = results->next;
}
_reloadMagicSearch = FALSE;
[self.tableView reloadData];
}
- (void) loadData {
[self reloadDataWithFilter:_searchBar.text];
}
- (void)reloadDataWithFilter:(NSString *)filter {
[_addresses removeAllObjects];
[_phoneOrAddr removeAllObjects];
[_addressesCached removeAllObjects];
_reloadMagicSearch = _reloadMagicSearch || [filter length]==0 || ![[MagicSearchSingleton.instance currentFilter] isEqualToString:filter];
[MagicSearchSingleton.instance setCurrentFilter:filter];
if (_reloadMagicSearch) {
[MagicSearchSingleton.instance searchForContactsWithDomain:_allFilter ? @"" : @"*" sourceFlags:LinphoneMagicSearchSourceAll clearCache:FALSE];
} else {
[self buildChatContactTable];
}
}
#pragma mark - TableView methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
@ -160,6 +198,10 @@
NSString *key = [_addresses objectAtIndex:indexPath.row];
NSString *phoneOrAddr = [_phoneOrAddr objectAtIndex:indexPath.row];
Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:key]];
if (!contact) {
contact = [_ldapContactAddressBookMap objectForKey:key];
}
const LinphonePresenceModel *model = contact.friend ? linphone_friend_get_presence_model(contact.friend) : NULL;
Boolean linphoneContact = [FastAddressBook contactHasValidSipDomain:contact]
|| (model && linphone_presence_model_get_basic_status(model) == LinphonePresenceBasicStatusOpen);
@ -173,7 +215,7 @@
BOOL greyCellForEncryptedChat = _isEncrypted ? capabilities > 1 : TRUE;
BOOL greyCellForGroupChat = _isGroupChat ? capabilities > 0 : TRUE;
cell.userInteractionEnabled = cell.greyView.hidden = greyCellForEncryptedChat && greyCellForGroupChat;
cell.displayNameLabel.text = [FastAddressBook displayNameForAddress:addr];
cell.displayNameLabel.text = [contact createdFromLdap] ? [contact displayName] : [FastAddressBook displayNameForAddress:addr];
char *str = linphone_address_as_string(addr);
cell.addressLabel.text = linphoneContact ? [NSString stringWithUTF8String:str] : phoneOrAddr;
ms_free(str);
@ -275,17 +317,11 @@
searchBar.showsCancelButton = (searchText.length > 0);
[self reloadDataWithFilter:searchText];
if ([searchText isEqualToString:@""]) {
if (_magicSearch)
linphone_magic_search_reset_search_cache(_magicSearch);
[_searchBar resignFirstResponder];
}
}
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(nonnull NSString *)text {
if (text.length < _searchBar.text.length && _magicSearch)
linphone_magic_search_reset_search_cache(_magicSearch);
return TRUE;
}
@ -302,9 +338,6 @@
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
if (_magicSearch)
linphone_magic_search_reset_search_cache(_magicSearch);
[searchBar resignFirstResponder];
}

View file

@ -188,20 +188,20 @@ typedef enum { ContactsAll, ContactsLinphone, ContactsMAX } ContactsCategory;
- (void)changeView:(ContactsCategory)view {
CGRect frame = _selectedButtonImage.frame;
if (_tableController.magicSearch)
linphone_magic_search_reset_search_cache(_tableController.magicSearch);
if (view == ContactsAll && !_allButton.selected) {
frame.origin.x = _allButton.frame.origin.x;
_allButton.selected = TRUE;
_linphoneButton.selected = FALSE;
_tableController.allFilter = TRUE;
_tableController.reloadMagicSearch = TRUE;
[_tableController loadData];
} else if (view == ContactsLinphone && !_linphoneButton.selected) {
frame.origin.x = _linphoneButton.frame.origin.x;
_linphoneButton.selected = TRUE;
_allButton.selected = FALSE;
_tableController.allFilter = FALSE;
_tableController.reloadMagicSearch = TRUE;
[_tableController loadData];
}
_selectedButtonImage.frame = frame;

View file

@ -35,6 +35,7 @@
@property(nonatomic, strong) NSMutableArray *sipAddresses;
@property(nonatomic, strong) NSMutableArray *emails;
@property(nonatomic, strong) NSMutableArray *phones;
@property BOOL createdFromLdap;
@property BOOL added;
- (void)setAvatar:(UIImage *)avatar;

View file

@ -36,6 +36,7 @@
_person = acncontact;
_friend = afriend ? linphone_friend_ref(afriend) : NULL;
_added = FALSE;
_createdFromLdap = FALSE;
_phones = [[NSMutableArray alloc] init];
_sipAddresses = [[NSMutableArray alloc] init];
_emails = [[NSMutableArray alloc] init];

View file

@ -160,7 +160,7 @@
/*first and last name only when editting */
return (self.tableView.isEditing) ? 1 : 0;
} else if (section == ContactSections_Sip) {
return _contact.sipAddresses.count;
return _contact.createdFromLdap ? 0 : _contact.sipAddresses.count;
} else if (section == ContactSections_Number) {
return _contact.phones.count;
} else if (section == ContactSections_Email) {
@ -193,30 +193,30 @@
value = _contact.lastName;
[cell hideDeleteButton:YES];
} else if ([indexPath section] == ContactSections_Number) {
value = _contact.phones[indexPath.row];
[cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad];
} else if ([indexPath section] == ContactSections_Sip) {
value = _contact.sipAddresses[indexPath.row];
LinphoneAddress *addr = NULL;
if ([LinphoneManager.instance
lpConfigBoolForKey:@"contact_display_username_only"] &&
(addr = linphone_core_interpret_url(LC, [value UTF8String]))) {
value =
[NSString stringWithCString:linphone_address_get_username(addr)
encoding:[NSString defaultCStringEncoding]];
linphone_address_destroy(addr);
}
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
} else if ([indexPath section] == ContactSections_Email) {
value = _contact.emails[indexPath.row];
[cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress];
}
if ([value hasPrefix:@" "])
value = [value substringFromIndex:1];
[cell setAddress:value];
value = _contact.phones[indexPath.row];
[cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad];
} else if ([indexPath section] == ContactSections_Sip) {
value = _contact.sipAddresses[indexPath.row];
LinphoneAddress *addr = NULL;
if ([LinphoneManager.instance
lpConfigBoolForKey:@"contact_display_username_only"] &&
(addr = linphone_core_interpret_url(LC, [value UTF8String]))) {
value =
[NSString stringWithCString:linphone_address_get_username(addr)
encoding:[NSString defaultCStringEncoding]];
linphone_address_destroy(addr);
}
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
} else if ([indexPath section] == ContactSections_Email) {
value = _contact.emails[indexPath.row];
[cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress];
}
if ([value hasPrefix:@" "])
value = [value substringFromIndex:1];
[cell setAddress:value];
cell.contentView.userInteractionEnabled = false;
return cell;
return cell;
}
- (void)tableView:(UITableView *)tableView
@ -283,7 +283,7 @@
if (section == ContactSections_Number) {
text = NSLocalizedString(@"Phone numbers", nil);
addEntryName = NSLocalizedString(@"Add new phone number", nil);
} else if (section == ContactSections_Sip) {
} else if (section == ContactSections_Sip && !_contact.createdFromLdap) {
text = NSLocalizedString(@"SIP addresses", nil);
addEntryName = NSLocalizedString(@"Add new SIP address", nil);
} else if (section == ContactSections_Email &&

View file

@ -119,8 +119,8 @@
_contact = acontact;
_emptyLabel.hidden = (_contact != NULL);
_avatarImage.hidden = !_emptyLabel.hidden;
_deleteButton.hidden = !_emptyLabel.hidden;
_editButton.hidden = !_emptyLabel.hidden;
_deleteButton.hidden = !_emptyLabel.hidden || [_contact createdFromLdap];
_editButton.hidden = !_emptyLabel.hidden || [_contact createdFromLdap];
[_avatarImage setImage:[FastAddressBook imageForContact:_contact] bordered:NO withRoundedRadius:YES];
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];

View file

@ -28,9 +28,9 @@
@private
OrderedDictionary *addressBookMap;
}
@property(nonatomic) BOOL ongoing;
@property(atomic) BOOL reloadMagicSearch;
- (void)loadData;
- (void)loadSearchedData;
- (void)loadDataWithFilter:(NSString *)filter;
- (void)removeAllContacts;
@end

View file

@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "linphoneapp-Swift.h"
#import "ContactsListTableView.h"
#import "UIContactCell.h"
#import "LinphoneManager.h"
@ -24,31 +25,33 @@
#import "Utils.h"
@implementation ContactsListTableView
NSArray *sortedAddresses;
#pragma mark - Lifecycle Functions
- (void)initContactsTableViewController {
addressBookMap = [[OrderedDictionary alloc] init];
sortedAddresses = [[NSArray alloc] init];
[NSNotificationCenter.defaultCenter
addObserver:self
selector:@selector(onAddressBookUpdate:)
name:kLinphoneAddressBookUpdate
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onAddressBookUpdate:)
name:CNContactStoreDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onAddressBookUpdate:)
name:CNContactStoreDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onMagicSearchFinished:)
name:kLinphoneMagicSearchFinished
object:nil];
}
- (void)onAddressBookUpdate:(NSNotification *)k {
if ((!_ongoing && (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription)) || (IPAD && PhoneMainView.instance.currentView == ContactDetailsView.compositeViewDescription)) {
if ((![MagicSearchSingleton.instance isSearchOngoing] && (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription)) || (IPAD && PhoneMainView.instance.currentView == ContactDetailsView.compositeViewDescription)) {
[self loadData];
}
}
- (void)onMagicSearchFinished:(NSNotification *)k {
[self buildContactTable];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (IPAD) {
@ -64,7 +67,7 @@ NSArray *sortedAddresses;
if (self) {
[self initContactsTableViewController];
}
_ongoing = FALSE;
_reloadMagicSearch = TRUE;
return self;
}
@ -114,118 +117,17 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
- (NSString *)displayNameForContact:(Contact *)person {
NSString *name = person.displayName;
if (name != nil && [name length] > 0 && ![name isEqualToString:NSLocalizedString(@"Unknown", nil)]) {
// Add the contact only if it fuzzy match filter too (if any)
if ([ContactSelection getNameOrEmailFilter] == nil ||
(ms_strcmpfuz([[[ContactSelection getNameOrEmailFilter] lowercaseString] UTF8String],
[[name lowercaseString] UTF8String]) == 0)) {
// Sort contacts by first letter. We need to translate the name to ASCII first, because of UTF-8
// issues. For instance expected order would be: Alberta(A tilde) before ASylvano.
NSData *name2ASCIIdata = [name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *name2ASCII = [[NSString alloc] initWithData:name2ASCIIdata encoding:NSASCIIStringEncoding];
return name2ASCII;
}
// Sort contacts by first letter. We need to translate the name to ASCII first, because of UTF-8
// issues. For instance expected order would be: Alberta(A tilde) before ASylvano.
NSData *name2ASCIIdata = [name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *name2ASCII = [[NSString alloc] initWithData:name2ASCIIdata encoding:NSASCIIStringEncoding];
return name2ASCII;
}
return NSLocalizedString(@"Unknown", nil);
}
- (void)loadData {
_ongoing = TRUE;
LOGI(@"====>>>> Load contact list - Start");
NSString* previous = [PhoneMainView.instance getPreviousViewName];
addressBookMap = [LinphoneManager.instance getLinphoneManagerAddressBookMap];
BOOL updated = [LinphoneManager.instance getContactsUpdated];
if(([previous isEqualToString:@"ContactsDetailsView"] && updated) || updated || [addressBookMap count] == 0){
[LinphoneManager.instance setContactsUpdated:FALSE];
@synchronized(addressBookMap) {
NSDictionary *allContacts = [[NSMutableDictionary alloc] initWithDictionary:LinphoneManager.instance.fastAddressBook.addressBookMap];
sortedAddresses = [[LinphoneManager.instance.fastAddressBook.addressBookMap allKeys] sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
Contact* first = [allContacts objectForKey:a];
Contact* second = [allContacts objectForKey:b];
if([[first.firstName lowercaseString] compare:[second.firstName lowercaseString]] == NSOrderedSame)
return [[first.lastName lowercaseString] compare:[second.lastName lowercaseString]];
else
return [[first.firstName lowercaseString] compare:[second.firstName lowercaseString]];
}];
LOGI(@"====>>>> Load contact list - Start 2 !!");
//Set all contacts from ContactCell to nil
for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j){
for (NSInteger i = 0; i < [self.tableView numberOfRowsInSection:j]; ++i)
{
[[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]] setContact:nil];
}
}
// Reset Address book
[addressBookMap removeAllObjects];
for (NSString *addr in sortedAddresses) {
Contact *contact = nil;
@synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) {
contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr];
}
BOOL add = true;
// Do not add the contact directly if we set some filter
if ([ContactSelection getSipFilter] ||
[ContactSelection emailFilterEnabled]) {
add = false;
}
if ([FastAddressBook contactHasValidSipDomain:contact]) {
add = true;
}else if (contact.friend &&
linphone_presence_model_get_basic_status(
linphone_friend_get_presence_model(
contact.friend)) ==
LinphonePresenceBasicStatusOpen) {
add = true;
}
if (!add && [ContactSelection emailFilterEnabled]) {
// Add this contact if it has an email
add = (contact.emails.count > 0);
}
NSMutableString *name = [[NSMutableString alloc] initWithString: [self displayNameForContact:contact]];
if (add && name != nil) {
NSString *firstChar = [[name substringToIndex:1] uppercaseString];
// Put in correct subAr
if ([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') {
firstChar = @"#";
}
NSMutableArray *subAr = [addressBookMap objectForKey:firstChar];
if (subAr == nil) {
subAr = [[NSMutableArray alloc] init];
[addressBookMap insertObject:subAr forKey:firstChar selector:@selector(caseInsensitiveCompare:)];
}
NSUInteger idx = [subAr indexOfObject:contact inSortedRange:(NSRange){0, subAr.count} options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult( Contact *_Nonnull obj1, Contact *_Nonnull obj2) {
return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2] options:NSCaseInsensitiveSearch];
}];
if (![subAr containsObject:contact]) {
[subAr insertObject:contact atIndex:idx];
}
}
}
// since we refresh the tableview, we must perform this on main
// thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (IPAD) {
if (!([self totalNumberOfItems] > 0)) {
ContactDetailsView *view = VIEW(ContactDetailsView);
[view setContact:nil];
}
}
});
}
[LinphoneManager.instance setLinphoneManagerAddressBookMap:addressBookMap];
}
LOGI(@"====>>>> Load contact list - End");
[super loadData];
_ongoing = FALSE;
}
- (void)loadSearchedData {
LOGI(@"Load search contact list");
- (void)buildContactTable {
@synchronized(addressBookMap) {
//Set all contacts from ContactCell to nil
for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j)
@ -237,101 +139,72 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
}
// Reset Address book
[addressBookMap removeAllObjects];
NSMutableArray *subAr = [NSMutableArray new];
NSMutableArray *subArBegin = [NSMutableArray new];
NSMutableArray *subArContain = [NSMutableArray new];
[addressBookMap insertObject:subAr forKey:@"" selector:@selector(caseInsensitiveCompare:)];
for (NSString *addr in sortedAddresses) {
@synchronized(
LinphoneManager.instance.fastAddressBook.addressBookMap) {
Contact *contact =
[LinphoneManager.instance.fastAddressBook.addressBookMap
objectForKey:addr];
BOOL add = true;
// Do not add the contact directly if we set some filter
if ([ContactSelection getSipFilter] ||
[ContactSelection emailFilterEnabled]) {
add = false;
}
NSString *filter = [ContactSelection getNameOrEmailFilter];
if ([FastAddressBook contactHasValidSipDomain:contact]) {
add = true;
}
if (contact.friend &&
linphone_presence_model_get_basic_status(
linphone_friend_get_presence_model(
contact.friend)) ==
LinphonePresenceBasicStatusOpen) {
add = true;
}
if (!add && [ContactSelection emailFilterEnabled]) {
// Add this contact if it has an email
add = (contact.emails.count > 0);
}
NSInteger idx_begin = -1;
NSInteger idx_sort = -1;
NSMutableString *name =
[self displayNameForContact:contact]
? [[NSMutableString alloc]
initWithString:
[self displayNameForContact:contact]]
: nil;
if (add && name != nil) {
if ([[contact displayName]
rangeOfString:filter
options:NSCaseInsensitiveSearch]
.location == 0) {
if (![subArBegin containsObject:contact]) {
idx_begin = idx_begin + 1;
[subArBegin insertObject:contact atIndex:idx_begin];
}
} else if ([[contact displayName]
rangeOfString:filter
options:NSCaseInsensitiveSearch]
.location != NSNotFound) {
if (![subArContain containsObject:contact]) {
idx_sort = idx_sort + 1;
[subArContain insertObject:contact atIndex:idx_sort];
}
}
}
}
}
[subArBegin
sortUsingComparator:^NSComparisonResult(
Contact *_Nonnull obj1, Contact *_Nonnull obj2) {
return [[self displayNameForContact:obj1]
compare:[self displayNameForContact:obj2]
options:NSCaseInsensitiveSearch];
}];
[subArContain
sortUsingComparator:^NSComparisonResult(
Contact *_Nonnull obj1, Contact *_Nonnull obj2) {
return [[self displayNameForContact:obj1]
compare:[self displayNameForContact:obj2]
options:NSCaseInsensitiveSearch];
}];
[subAr addObjectsFromArray:subArBegin];
[subAr addObjectsFromArray:subArContain];
[super loadData];
// since we refresh the tableview, we must perform this on main
// thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (IPAD) {
if (!([self totalNumberOfItems] > 0)) {
ContactDetailsView *view = VIEW(ContactDetailsView);
[view setContact:nil];
}
}
});
}
//
NSArray *searchResults = [MagicSearchSingleton.instance getLastSearchContacts];
for (Contact *contact in searchResults) {
NSMutableString *name = [[NSMutableString alloc] initWithString: [self displayNameForContact:contact]];
if (name != nil) {
NSString *firstChar = [[name substringToIndex:1] uppercaseString];
// Put in correct subAr
if ([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') {
firstChar = @"#";
}
NSMutableArray *subAr = [addressBookMap objectForKey:firstChar];
if (subAr == nil) {
subAr = [[NSMutableArray alloc] init];
[addressBookMap insertObject:subAr forKey:firstChar selector:@selector(caseInsensitiveCompare:)];
}
NSUInteger idx = [subAr indexOfObject:contact inSortedRange:(NSRange){0, subAr.count} options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult( Contact *_Nonnull obj1, Contact *_Nonnull obj2) {
return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2] options:NSCaseInsensitiveSearch];
}];
if (![subAr containsObject:contact]) {
[subAr insertObject:contact atIndex:idx];
}
}
}
[super loadData];
}
// since we refresh the tableview, we must perform this on main
// thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (IPAD) {
if (!([self totalNumberOfItems] > 0)) {
ContactDetailsView *view = VIEW(ContactDetailsView);
[view setContact:nil];
}
}
});
_reloadMagicSearch = FALSE;
}
- (void)loadData {
if (_reloadMagicSearch) {
NSString *domain = @"";
if ([ContactSelection getSipFilterEnabled]) {
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
if (defaultAccount) {
domain = [NSString stringWithUTF8String:linphone_account_params_get_domain(linphone_account_get_params(defaultAccount))];
}
}
int sourceFlags = LinphoneMagicSearchSourceFriends | LinphoneMagicSearchSourceLdapServers;
[MagicSearchSingleton.instance searchForContactsWithDomain:domain sourceFlags:sourceFlags clearCache:[LinphoneManager.instance getContactsUpdated]];
[LinphoneManager.instance setContactsUpdated:FALSE];
} else {
[self buildContactTable];
}
}
- (void)loadDataWithFilter: (NSString *)filter {
LOGI(@"Load search contact list");
_reloadMagicSearch = _reloadMagicSearch || [filter length]==0 || ![[MagicSearchSingleton.instance currentFilter] isEqualToString:filter];
[MagicSearchSingleton.instance setCurrentFilter:filter];
[self loadData];
}
#pragma mark - UITableViewDataSource Functions

View file

@ -34,39 +34,15 @@ typedef enum _ContactSelectionMode { ContactSelectionModeNone, ContactSelectionM
+ (NSString *)getAddAddress;
/*!
* Filters contacts by SIP domain.
* @param domain SIP domain to filter. Use @"*" or nil to disable it.
* @param enabled Wether SIP domain filter is enabled
*/
+ (void)setSipFilter:(NSString *)domain;
+ (void)enableSipFilter:(BOOL)enabled;
/*!
* Weither contacts are filtered by SIP domain or not.
* Wether SIP domain filter is enabled
* @return the filter used, or nil if none.
*/
+ (NSString *)getSipFilter;
/*!
* Weither always keep contacts with an email address or not.
* @param enable TRUE if you want to always keep contacts with an email.
*/
+ (void)enableEmailFilter:(BOOL)enable;
/*!
* Weither always keep contacts with an email address or not.
* @return TRUE if this behaviour is enabled.
*/
+ (BOOL)emailFilterEnabled;
/*!
* Filters contacts by name and/or email fuzzy matching pattern.
* @param fuzzyName fuzzy word to match. Use nil to disable it.
*/
+ (void)setNameOrEmailFilter:(NSString *)fuzzyName;
/*!
* Weither contacts are filtered by name and/or email.
* @return the filter used, or nil if none.
*/
+ (NSString *)getNameOrEmailFilter;
+ (BOOL)getSipFilterEnabled;
@end
@ -80,6 +56,8 @@ typedef enum _ContactSelectionMode { ContactSelectionModeNone, ContactSelectionM
@property(strong, nonatomic) IBOutlet UISearchBar *searchBar;
@property(weak, nonatomic) IBOutlet UIImageView *selectedButtonImage;
@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleSelectionButton;
@property (weak, nonatomic) IBOutlet UILabel *loadingLabel;
@property (weak, nonatomic) IBOutlet UIView *loadingView;
- (IBAction)onAllClick:(id)event;
- (IBAction)onLinphoneClick:(id)event;

View file

@ -17,15 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "linphoneapp-Swift.h"
#import "PhoneMainView.h"
@implementation ContactSelection
static ContactSelectionMode sSelectionMode = ContactSelectionModeNone;
static NSString *sAddAddress = nil;
static NSString *sSipFilter = nil;
static BOOL sEnableEmailFilter = FALSE;
static NSString *sNameOrEmailFilter;
static BOOL bSipFilterEnabled = FALSE;
static BOOL addAddressFromOthers = FALSE;
+ (void)setSelectionMode:(ContactSelectionMode)selectionMode {
@ -45,28 +44,12 @@ static BOOL addAddressFromOthers = FALSE;
return sAddAddress;
}
+ (void)setSipFilter:(NSString *)domain {
sSipFilter = domain;
+ (void)enableSipFilter:(BOOL)enabled {
bSipFilterEnabled = enabled;
}
+ (NSString *)getSipFilter {
return sSipFilter;
}
+ (void)enableEmailFilter:(BOOL)enable {
sEnableEmailFilter = enable;
}
+ (BOOL)emailFilterEnabled {
return sEnableEmailFilter;
}
+ (void)setNameOrEmailFilter:(NSString *)fuzzyName {
sNameOrEmailFilter = fuzzyName;
}
+ (NSString *)getNameOrEmailFilter {
return sNameOrEmailFilter;
+ (BOOL)getSipFilterEnabled {
return bSipFilterEnabled;
}
@end
@ -105,12 +88,16 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark - ViewController Functions
- (void)viewDidLoad {
NSLog(@"Debuglog viewDidLoad");
[super viewDidLoad];
_searchBar.text = [MagicSearchSingleton.instance currentFilter];
tableController.tableView.accessibilityIdentifier = @"Contacts table";
if (![[PhoneMainView.instance getPreviousViewName] isEqualToString:@"ContactDetailsView"]) {
_searchBar.text = @"";
}
[self changeView:ContactsAll];
/*if ([tableController totalNumberOfItems] == 0) {
[self changeView:ContactsAll];
}*/
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(dismissKeyboards)];
@ -120,8 +107,9 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (void)viewWillAppear:(BOOL)animated {
NSLog(@"Debuglog viewWillAppear");
[super viewWillAppear:animated];
[ContactSelection setNameOrEmailFilter:@""];
_searchBar.showsCancelButton = (_searchBar.text.length > 0);
int y = _searchBar.frame.origin.y + _searchBar.frame.size.height;
@ -143,9 +131,28 @@ static UICompositeViewDescription *compositeDescription = nil;
self.linphoneButton.hidden = TRUE;
self.selectedButtonImage.hidden = TRUE;
}
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onMagicSearchStarted:)
name:kLinphoneMagicSearchStarted
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(onMagicSearchFinished:)
name:kLinphoneMagicSearchFinished
object:nil];
}
- (void)onMagicSearchStarted:(NSNotification *)k {
_loadingView.hidden = FALSE;
}
- (void)onMagicSearchFinished:(NSNotification *)k {
_loadingView.hidden = TRUE;
}
- (void)viewDidAppear:(BOOL)animated {
NSLog(@"Debuglog viewDidAppear");
[super viewDidAppear:animated];
if (![FastAddressBook isAuthorized]) {
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Address book", nil)
@ -182,6 +189,7 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (void) viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.view = NULL;
[self.tableController removeAllContacts];
}
@ -189,25 +197,26 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark -
- (void)changeView:(ContactsCategory)view {
NSLog(@"Debuglog changeView");
CGRect frame = _selectedButtonImage.frame;
if (view == ContactsAll && !allButton.selected) {
//REQUIRED TO RELOAD WITH FILTER
[LinphoneManager.instance setContactsUpdated:TRUE];
frame.origin.x = allButton.frame.origin.x;
[ContactSelection setSipFilter:nil];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection enableSipFilter:FALSE];
allButton.selected = TRUE;
linphoneButton.selected = FALSE;
[tableController loadData];
[tableController setReloadMagicSearch:TRUE];
[tableController loadDataWithFilter: _searchBar.text];
} else if (view == ContactsLinphone && !linphoneButton.selected) {
//REQUIRED TO RELOAD WITH FILTER
[LinphoneManager.instance setContactsUpdated:TRUE];
frame.origin.x = linphoneButton.frame.origin.x;
[ContactSelection setSipFilter:LinphoneManager.instance.contactFilter];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection enableSipFilter:TRUE];
linphoneButton.selected = TRUE;
allButton.selected = FALSE;
[tableController loadData];
[tableController setReloadMagicSearch:TRUE];
[tableController loadDataWithFilter: _searchBar.text];
}
_selectedButtonImage.frame = frame;
if ([LinphoneManager.instance lpConfigBoolForKey:@"hide_linphone_contacts" inSection:@"app"]) {
@ -217,7 +226,7 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)refreshButtons {
[addButton setHidden:FALSE];
[self changeView:[ContactSelection getSipFilter] ? ContactsLinphone : ContactsAll];
[self changeView:[ContactSelection getSipFilterEnabled] ? ContactsLinphone : ContactsAll];
}
#pragma mark - Action Functions
@ -263,9 +272,9 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
searchBar.text = @"";
[self searchBar:searchBar textDidChange:@""];
[LinphoneManager.instance setContactsUpdated:TRUE];
[tableController loadData];
[self searchBar:searchBar textDidChange:@""];
[searchBar resignFirstResponder];
}
@ -278,14 +287,12 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark - searchBar delegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
// display searchtext in UPPERCASE
// searchBar.text = [searchText uppercaseString];
[ContactSelection setNameOrEmailFilter:searchText];
if (searchText.length == 0) {
[LinphoneManager.instance setContactsUpdated:TRUE];
[tableController loadData];
} else {
[tableController loadSearchedData];
NSLog(@"Debuglog textdidchange");
if (![searchText isEqualToString:[MagicSearchSingleton.instance currentFilter]]) {
if (searchText.length == 0) {
[LinphoneManager.instance setContactsUpdated:TRUE];
}
[tableController loadDataWithFilter:searchText];
}
}

View file

@ -390,9 +390,7 @@ static UICompositeViewDescription *compositeDescription = nil;
- (IBAction)onAddContactClick:(id)event {
[ContactSelection setSelectionMode:ContactSelectionModeEdit];
[ContactSelection setAddAddress:[_addressField text]];
[ContactSelection setSipFilter:nil];
[ContactSelection setNameOrEmailFilter:nil];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection enableSipFilter:FALSE];
[PhoneMainView.instance changeCurrentView:ContactsListView.compositeViewDescription];
}

View file

@ -194,10 +194,7 @@ static UICompositeViewDescription *compositeDescription = nil;
normSip = [normSip hasPrefix:@"sip:"] ? [normSip substringFromIndex:4] : normSip;
[ContactSelection setAddAddress:normSip];
[ContactSelection setSelectionMode:ContactSelectionModeEdit];
[ContactSelection setSipFilter:nil];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection setNameOrEmailFilter:nil];
[ContactSelection enableSipFilter:FALSE];
[PhoneMainView.instance changeCurrentView:ContactsListView.compositeViewDescription];
ms_free(lAddress);
}

View file

@ -63,6 +63,8 @@ extern NSString *const kLinphoneVoiceMessagePlayerEOF;
extern NSString *const kLinphoneVoiceMessagePlayerLostFocus;
extern NSString *const kLinphoneConfStateParticipantListChanged;
extern NSString *const kLinphoneConfStateChanged;
extern NSString *const kLinphoneMagicSearchStarted;
extern NSString *const kLinphoneMagicSearchFinished;
extern NSString *const kLinphoneMsgNotificationAppGroupId;
@ -178,9 +180,6 @@ typedef struct _LinphoneManagerSounds {
- (void)shouldPresentLinkPopup;
- (void) setLinphoneManagerAddressBookMap:(OrderedDictionary*) addressBook;
- (OrderedDictionary*) getLinphoneManagerAddressBookMap;
- (void) setContactsUpdated:(BOOL) updated;
- (BOOL) getContactsUpdated;

View file

@ -80,6 +80,8 @@ NSString *const kLinphoneVoiceMessagePlayerEOF = @"LinphoneVoiceMessagePlayerEOF
NSString *const kLinphoneVoiceMessagePlayerLostFocus = @"LinphoneVoiceMessagePlayerLostFocus";
NSString *const kLinphoneConfStateChanged = @"kLinphoneConfStateChanged";
NSString *const kLinphoneConfStateParticipantListChanged = @"kLinphoneConfStateParticipantListChanged";
NSString *const kLinphoneMagicSearchStarted = @"LinphoneMagicSearchStarted";
NSString *const kLinphoneMagicSearchFinished = @"LinphoneMagicSearchFinished";
NSString *const kLinphoneMsgNotificationAppGroupId = @"group.org.linphone.phone.msgNotification";
@ -286,15 +288,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
[NSNotificationCenter.defaultCenter removeObserver:self];
}
#pragma mark - AddressBookMap
- (void) setLinphoneManagerAddressBookMap:(OrderedDictionary*) addressBook{
_linphoneManagerAddressBookMap = addressBook;
}
- (OrderedDictionary*) getLinphoneManagerAddressBookMap{
return _linphoneManagerAddressBookMap;
}
#pragma mark - Contacts Updated
- (void) setContactsUpdated:(BOOL) updated{
_contactsUpdated = updated;

View file

@ -152,8 +152,6 @@
- (IBAction)onContactsClick:(id)event {
[ContactSelection setAddAddress:nil];
[ContactSelection enableEmailFilter:FALSE];
[ContactSelection setNameOrEmailFilter:nil];
[PhoneMainView.instance changeCurrentView:ContactsListView.compositeViewDescription];
}

141
Classes/MagicSearch.swift Normal file
View file

@ -0,0 +1,141 @@
//
// ContactListMagicSearch.swift
// linphone
//
// Created by QuentinArguillere on 25/03/2022.
//
import Foundation
import linphonesw
@objc class MagicSearchSingleton : NSObject {
static var theMagicSearchSingleton: MagicSearchSingleton?
var lc = CallManager.instance().lc
var ongoingSearch = false
var needUpdateLastSearchContacts = false
var lastSearchContacts : [Contact] = []
@objc var currentFilter : String = ""
var previousFilter : String?
var magicSearch : MagicSearch
var magicSearchDelegate : MagicSearchDelegate?
override init() {
magicSearch = try! lc!.createMagicSearch()
magicSearch.limitedSearch = false
super.init()
magicSearchDelegate = MagicSearchDelegateStub(onSearchResultsReceived: { (magicSearch: MagicSearch) in
self.needUpdateLastSearchContacts = true
self.ongoingSearch = false
Log.directLog(BCTBX_LOG_MESSAGE, text: "Contact magic search -- filter = \(String(describing: self.previousFilter)) -- \(magicSearch.lastSearch.count) contact founds")
NotificationCenter.default.post(name: Notification.Name(kLinphoneMagicSearchFinished), object: self)
}, onLdapHaveMoreResults: { (magicSearch: MagicSearch, ldap: Ldap) in
Log.directLog(BCTBX_LOG_MESSAGE, text: "Ldap have more result")
})
magicSearch.addDelegate(delegate: magicSearchDelegate!)
}
@objc static func instance() -> MagicSearchSingleton {
if (theMagicSearchSingleton == nil) {
theMagicSearchSingleton = MagicSearchSingleton()
}
return theMagicSearchSingleton!
}
func getContactFromAddr(addr: Address) -> Contact? {
return LinphoneManager.instance().fastAddressBook.addressBookMap.object(forKey: addr.asStringUriOnly() as Any) as? Contact
}
func getContactFromPhoneNb(phoneNb: String) -> Contact? {
let contactKey = FastAddressBook.localizedLabel(FastAddressBook.normalizeSipURI( lc?.defaultAccount?.normalizePhoneNumber(username: phoneNb) ?? phoneNb))
return LinphoneManager.instance().fastAddressBook.addressBookMap.object(forKey: contactKey as Any) as? Contact
}
func searchAndAddMatchingContact(searchResult: SearchResult) -> Contact? {
if let friend = searchResult.friend {
if let addr = friend.address, let foundContact = getContactFromAddr(addr: addr) {
return foundContact
}
for phoneNb in friend.phoneNumbers {
if let foundContact = getContactFromPhoneNb(phoneNb: phoneNb) {
return foundContact
}
}
// No contacts found (searchResult likely comes from LDAP), creating a new one
if let newContact = Contact(friend: friend.getCobject) {
newContact.createdFromLdap = true
return newContact
}
}
if let addr = searchResult.address, let foundContact = getContactFromAddr(addr: addr) {
return foundContact
}
if let foundContact = getContactFromPhoneNb(phoneNb: searchResult.phoneNumber) {
return foundContact
}
return nil
}
@objc func isSearchOngoing() -> Bool {
return ongoingSearch
}
@objc func getLastSearchResults() -> UnsafeMutablePointer<bctbx_list_t>? {
var cList: UnsafeMutablePointer<bctbx_list_t>? = nil
for data in magicSearch.lastSearch {
cList = bctbx_list_append(cList, UnsafeMutableRawPointer(data.getCobject))
}
return cList
}
@objc func getLastSearchContacts() -> [Contact] {
if (needUpdateLastSearchContacts) {
lastSearchContacts = []
var addedContactNames : [String] = []
for res in magicSearch.lastSearch {
if let contact = searchAndAddMatchingContact(searchResult: res) {
if (!addedContactNames.contains(contact.displayName)) {
addedContactNames.append(contact.displayName)
lastSearchContacts.append(contact)
}
}
}
needUpdateLastSearchContacts = false
}
return lastSearchContacts
}
@objc func searchForContacts(domain: String, sourceFlags: Int, clearCache: Bool) {
if (clearCache) {
magicSearch.resetSearchCache()
}
if let oldFilter = previousFilter {
if (oldFilter.count > currentFilter.count || oldFilter != currentFilter) {
magicSearch.resetSearchCache()
}
}
previousFilter = currentFilter
ongoingSearch = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if (self.ongoingSearch) {
NotificationCenter.default.post(name: Notification.Name(kLinphoneMagicSearchStarted), object: self)
}
}
magicSearch.getContactsListAsync(filter: currentFilter, domain: domain, sourceFlags: sourceFlags, aggregation: MagicSearchAggregation.Friend)
}
func setupLDAPTestSettings() {
}
}

View file

@ -5,7 +5,7 @@
#import <UIKit/UIkit.h>
#import "FastAddressBook.h"
#import "LinphoneManager.h"
#import "Log.h"
#import "AudioHelper.h"
#import "ChatConversationTableView.h"

View file

@ -628,6 +628,7 @@
63F1DF4F1BCE985F00EDED90 /* UICallConferenceCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF4D1BCE985F00EDED90 /* UICallConferenceCell.m */; };
63F1DF511BCE986A00EDED90 /* UICallConferenceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63F1DF531BCE986A00EDED90 /* UICallConferenceCell.xib */; };
63FB30351A680E73008CA393 /* UIRoundedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63FB30341A680E73008CA393 /* UIRoundedImageView.m */; };
662553B427EDFB35007F67D8 /* MagicSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662553B327EDFB35007F67D8 /* MagicSearch.swift */; };
669B140827A1821F0012220A /* scroll_to_bottom_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 669B140727A1821F0012220A /* scroll_to_bottom_default.png */; };
669B140C27A29D140012220A /* FloatingScrollDownButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 669B140B27A29D140012220A /* FloatingScrollDownButton.swift */; };
6F3A2542B1FC7C128439D37C /* Pods_linphone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFCC14A580A05DEC78090273 /* Pods_linphone.framework */; };
@ -1619,6 +1620,7 @@
63F1DF521BCE986A00EDED90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UICallConferenceCell.xib; sourceTree = "<group>"; };
63FB30331A680E73008CA393 /* UIRoundedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIRoundedImageView.h; sourceTree = "<group>"; };
63FB30341A680E73008CA393 /* UIRoundedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIRoundedImageView.m; sourceTree = "<group>"; };
662553B327EDFB35007F67D8 /* MagicSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicSearch.swift; sourceTree = "<group>"; };
669B140727A1821F0012220A /* scroll_to_bottom_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = scroll_to_bottom_default.png; sourceTree = "<group>"; };
669B140B27A29D140012220A /* FloatingScrollDownButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingScrollDownButton.swift; sourceTree = "<group>"; };
70E542F213E147E3002BA2C0 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
@ -2098,6 +2100,7 @@
D3549815158761D0000081D8 /* ContactsListTableView.m */,
D35497FB15875372000081D8 /* ContactsListView.h */,
D35497FC15875372000081D8 /* ContactsListView.m */,
662553B327EDFB35007F67D8 /* MagicSearch.swift */,
D38187C015FE342800C3EDCA /* ContactsListView.xib */,
631098471D4660580041F2B3 /* CountryListView.h */,
631098481D4660580041F2B3 /* CountryListView.m */,
@ -4379,6 +4382,7 @@
D3807FFC15C2894A005BE9BC /* IASKPSTitleValueSpecifierViewCell.m in Sources */,
D3807FFE15C2894A005BE9BC /* IASKSlider.m in Sources */,
D380800015C2894A005BE9BC /* IASKSwitch.m in Sources */,
662553B427EDFB35007F67D8 /* MagicSearch.swift in Sources */,
D380800215C2894A005BE9BC /* IASKTextField.m in Sources */,
D380801315C299D0005BE9BC /* ColorSpaceUtilites.m in Sources */,
C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */,