diff --git a/Classes/InAppProductsManager.h b/Classes/InAppProductsManager.h index b3f19a6da..a9677478f 100644 --- a/Classes/InAppProductsManager.h +++ b/Classes/InAppProductsManager.h @@ -80,16 +80,22 @@ typedef NSString *IAPPurchaseNotificationStatus; // TRUE if accountActivate was started but we did not receive response from server yet @property(readonly) BOOL accountActivationInProgress; +// TRUE if accountActivate activated +@property(readonly) BOOL accountActivated; + - (BOOL)isPurchasedWithID:(NSString *)productId; // Purchase an account. You should not use this if manager is not available yet. -- (BOOL)purchaseAccount:(NSString *)phoneNumber +/*- (BOOL)purchaseAccount:(NSString *)phoneNumber withPassword:(NSString *)password andEmail:(NSString *)email monthly:(BOOL)monthly; +*/ // Purchase a product. You should not use this if manager is not available yet. - (BOOL)purchaseWithID:(NSString *)productID; // Activate purchased account. -- (BOOL)activateAccount:(NSString *)phoneNumber; +//- (BOOL)activateAccount:(NSString *)phoneNumber; +// Check if account is activated. +//- (BOOL)checkAccountActivated:(NSString *)phoneNumber; // restore user purchases. You should not use this if manager is not available yet. Must be at a user action ONLY. - (BOOL)restore; @@ -101,6 +107,6 @@ typedef NSString *IAPPurchaseNotificationStatus; - (void)check; // deal with xmlrpc response -- (void)dealWithXmlRpcResponse:(LinphoneXmlRpcRequest *)request; +//- (void)dealWithXmlRpcResponse:(LinphoneXmlRpcRequest *)request; @end diff --git a/Classes/InAppProductsManager.m b/Classes/InAppProductsManager.m index 310357b7c..b4f807e93 100644 --- a/Classes/InAppProductsManager.m +++ b/Classes/InAppProductsManager.m @@ -64,6 +64,7 @@ [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; [self loadProducts]; } + //[self check]; } return self; } @@ -117,95 +118,6 @@ } } -- (BOOL)purchaseAccount:(NSString *)phoneNumber - withPassword:(NSString *)password - andEmail:(NSString *)email - monthly:(BOOL)monthly { - if (phoneNumber) { - NSString *productID = - [LinphoneManager.instance lpConfigStringForKey:(monthly ? @"paid_account_id_monthly" : @"paid_account_id") - inSection:@"in_app_purchase"]; - self.accountCreationData = @{ @"phoneNumber" : phoneNumber, @"password" : password, @"email" : email }; - - if (![self purchaseWithID:productID]) { - self.accountCreationData = nil; - } - return true; - } - return false; -} - -- (BOOL)activateAccount:(NSString *)phoneNumber { - if (phoneNumber) { - NSString *receiptBase64 = [self getReceipt]; - if (receiptBase64) { - // const char *URL = [LinphoneManager.instance lpConfigStringForKey:@"receipt_validation_url" - // inSection:@"in_app_purchase"].UTF8String; - - // buying for the first time: need to create the account - // if ([transaction.transactionIdentifier - // isEqualToString:transaction.originalTransaction.transactionIdentifier]) { - - [XMLRPCHelper.self sendXMLRPCRequestWithParams:@"activate_account" - withParams:@[ @"", phoneNumber, receiptBase64, @"", @"apple" ] - onSuccess:^(NSString *response) { - if (response) { - [self setAccountBiteActivationInProgress:NO]; - LOGI(@"Account activated callback - response: %@", response); - } - }]; - - _accountActivationInProgress = YES; - LOGI(@"XMLRPC query "); - return true; - } else { - LOGE(@"Trying to activate account but no receipt available yet (probably doing it too soon)"); - } - } - return false; -} - -// onError Callback block -/*- (void)XMLRPCRequest:(LinphoneXmlRpcRequest *)request didFailWithError:(NSError *)error { - if (!_enabled) - return; - - _available = true; - - if ([[request method] isEqualToString:@"activate_account"]) { - _accountActivationInProgress = NO; - } - - LOGE(@"Communication issue (%@)", [error localizedDescription]); - NSString *errorString = - [NSString stringWithFormat:NSLocalizedString(@"Communication issue (%@)", nil), [error localizedDescription]]; - UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Communication issue", nil) - message:errorString - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) - otherButtonTitles:nil, nil]; - [errorView show]; - latestReceiptMD5 = nil; - NSDictionary *dict = @{ @"error_msg" : errorString }; - [self postNotificationforStatus:kIAPReceiptFailed withDict:dict]; -} -*/ - -- (void)setAccountBiteActivationInProgress:(BOOL)activationInProgress { - _accountActivationInProgress = activationInProgress; -} - -- (void)dealWithXmlRpcResponse:(LinphoneXmlRpcRequest *)request { - //[ShopView hideWaitingView:TRUE]; - LOGI(@"XMLRPC query "); - const char *requestContent = linphone_xml_rpc_request_get_content(request); - NSString *rContent = [NSString stringWithFormat:@"%s", requestContent]; - if ([rContent containsString:@"activate_account"]) { - _accountActivationInProgress = NO; - LOGI(@"Account activated callback"); - } -} - - (BOOL)restore { if (!_enabled || !_initialized || !_available) { NSDictionary *dict = @{ @"error_msg" : NSLocalizedString(@"In apps not ready yet", nil) }; @@ -321,52 +233,59 @@ [req start]; return; } + // Hide waiting view + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + UIView *topView = window.rootViewController.view; + UIView *waitview = (UIView *)[topView viewWithTag:288]; + [waitview setHidden:TRUE]; // only check the receipt if it has changed if (latestReceiptMD5 == nil || ![latestReceiptMD5 isEqualToString:[receiptBase64 md5]]) { - // transaction is null when restoring user purchases at application start or if user clicks the "restore" button - // We must validate the receipt on our server - // buying for the first time: need to create the account - // if ([transaction.transactionIdentifier - // isEqualToString:transaction.originalTransaction.transactionIdentifier]) { - - if (self.accountCreationData.count == 3) { - NSString *dataPhone = [_accountCreationData objectForKey:@"phoneNumber"]; - NSString *dataEmail = [_accountCreationData objectForKey:@"email"]; + if ([[self getPhoneNumber] length] > 0) { + NSString *phoneNumber = [self getPhoneNumber]; + NSString *password = [self getPassword]; [XMLRPCHelper.self - sendXMLRPCRequestWithParams:@"activate_account" - withParams:@[ dataPhone, receiptBase64, @"", @"apple", dataEmail ] + sendXMLRPCRequestWithParams:@"update_expiration_date" + withParams:@[ + phoneNumber, + password, + @"", + receiptBase64 + ] // keep @"" mandatory for optional domain //, @"", @"apple" ] onSuccess:^(NSString *response) { if (response) { - LOGI(@"create and activate_account callback - response: %@", response); - UIWindow *window = [[UIApplication sharedApplication] keyWindow]; - UIView *topView = window.rootViewController.view; - UIView *waitview = (UIView *)[topView viewWithTag:288]; - [waitview setHidden:TRUE]; + // NSString *productID = [LinphoneManager.instance + // lpConfigStringForKey:@"paid_account_id" inSection:@"in_app_purchase"]; + LOGI(@"update_expiration_date callback - response: %@", response); + if ([response containsString:@"ERROR"]) { + LOGE(@"Failed with error %@", response); + NSString *errorMsg; + if ([response isEqualToString:@"ERROR_ACCOUNT_ALREADY_EXISTS"]) { + errorMsg = + NSLocalizedString(@"This account is already registered.", nil); + } else if ([response isEqualToString:@"ERROR_UID_ALREADY_IN_USE"]) { + errorMsg = NSLocalizedString(@"You already own an account.", nil); + } else if ([response isEqualToString:@"ERROR_ACCOUNT_DOESNT_EXIST"]) { + errorMsg = NSLocalizedString(@"You have already purchased an account " + @"but it does not exist anymore.", + nil); + } else if ([response isEqualToString:@"ERROR_PURCHASE_CANCELLED"]) { + errorMsg = NSLocalizedString(@"You cancelled your account.", nil); + } else { + errorMsg = [NSString + stringWithFormat:NSLocalizedString(@"Unknown error (%@).", nil), + response]; + } + // NSDictionary *dict = @{ @"product_id" : productID, @"error_msg" : + // errorMsg }; + //[self postNotificationforStatus:kIAPPurchaseFailed withDict:dict]; + } } }]; - self.accountCreationData = nil; // otherwise simply renewing } else { - if ([[self getPhoneNumber] length] > 0) { - NSString *phoneNumber = [self getPhoneNumber]; - [XMLRPCHelper.self - sendXMLRPCRequestWithParams:@"update_expiration_date" - withParams:@[ phoneNumber, receiptBase64, @"", @"apple" ] - onSuccess:^(NSString *response) { - if (response) { - LOGI(@"update_expiration_date callback - response: %@", response); - UIWindow *window = [[UIApplication sharedApplication] keyWindow]; - UIView *topView = window.rootViewController.view; - UIView *waitview = (UIView *)[topView viewWithTag:288]; - [waitview setHidden:TRUE]; - } - }]; - - } else { - LOGW(@"No SIP URI configured, doing nothing"); - _available = true; - return; - } + LOGW(@"No SIP URI configured, doing nothing"); + _available = true; + return; } latestReceiptMD5 = [receiptBase64 md5]; @@ -389,6 +308,22 @@ return phoneNumber; } +- (NSString *)getPassword { + NSString *pass; + LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(LC); + if (cfg && strcmp("sip.linphone.org", linphone_proxy_config_get_domain(cfg)) == 0) { + const LinphoneAuthInfo *info = linphone_proxy_config_find_auth_info(cfg); + const char *tmpPass; + if (linphone_auth_info_get_passwd(info)) { + tmpPass = linphone_auth_info_get_passwd(info); + } else { + tmpPass = linphone_auth_info_get_ha1(info); + } + pass = [NSString stringWithFormat:@"%s", tmpPass]; + } + return pass; +} + - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { @@ -451,110 +386,17 @@ _status = status; LOGI(@"Triggering notification for status %@", status); [NSNotificationCenter.defaultCenter postNotificationName:status object:self userInfo:dict]; + if ([status isEqual:kIAPPurchaseFailed] || [status isEqual:kIAPPurchaseCancelled]) { + // Hide waiting view + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + UIView *topView = window.rootViewController.view; + UIView *waitview = (UIView *)[topView viewWithTag:288]; + [waitview setHidden:TRUE]; + } } -/* +#pragma mark expiration notif - - (void)XMLRPCRequest:(LinphoneXmlRpcRequest *)request didReceiveResponse:(XMLRPCResponse *)response { - if (!_enabled) - return; - - _available = true; - - if ([[request method] isEqualToString:@"activate_account"]) { - _accountActivationInProgress = NO; - } - - LOGI(@"XMLRPC response %@: %@", [request method], [response body]); - NSString *productID = [LinphoneManager.instance lpConfigStringForKey:@"paid_account_id" - inSection:@"in_app_purchase"]; - - // validation succeeded - if (![response isFault] && [response object] != nil) { - if (([[request method] isEqualToString:@"get_account_expiration"]) || ([[request method] - isEqualToString:@"create_account_from_in_app_purchase"])) { - [_productsIDPurchased removeObject:productID]; - // response object can either be expiration date (long long number or an error string) - double timeinterval = [[response object] doubleValue]; - if (timeinterval != 0.0f) { - self.expirationDate = [NSDate dateWithTimeIntervalSince1970:timeinterval / 1000]; - NSDate *now = [[NSDate alloc] init]; - NSDictionary *dict = @{ @"product_id" : productID, @"expires_date" : self.expirationDate }; - if ([self.expirationDate earlierDate:now] == self.expirationDate) { - LOGW(@"Account has expired"); - [self postNotificationforStatus:kIAPPurchaseExpired withDict:dict]; - } else { - LOGI(@"Account valid until %@", self.expirationDate); - [_productsIDPurchased addObject:productID]; - [self postNotificationforStatus:kIAPPurchaseSucceeded withDict:dict]; - } - } else { - self.expirationDate = nil; - NSString *error = [response object]; - LOGE(@"Failed with error %@", error); - NSString *errorMsg; - if ([error isEqualToString:@"ERROR_ACCOUNT_ALREADY_EXISTS"]) { - errorMsg = NSLocalizedString(@"This account is already registered.", nil); - } else if ([error isEqualToString:@"ERROR_UID_ALREADY_IN_USE"]) { - errorMsg = NSLocalizedString(@"You already own an account.", nil); - } else if ([error isEqualToString:@"ERROR_ACCOUNT_DOESNT_EXIST"]) { - errorMsg = NSLocalizedString(@"You have already purchased an account but it does not exist - anymore.", nil); - } else if ([error isEqualToString:@"ERROR_PURCHASE_CANCELLED"]) { - errorMsg = NSLocalizedString(@"You cancelled your account.", nil); - } else { - errorMsg = [NSString stringWithFormat:NSLocalizedString(@"Unknown error (%@).", nil), error]; - } - NSDictionary *dict = @{ @"product_id" : productID, @"error_msg" : errorMsg }; - [self postNotificationforStatus:kIAPPurchaseFailed withDict:dict]; - } - } - } else { - NSString *errorString = NSLocalizedString(@"Unknown error", nil); - if ([response isFault]) { - errorString = [NSString stringWithFormat:NSLocalizedString(@"Communication issue (%@)", nil), [response - faultString]]; - } else if ([response object] == nil) { - errorString = NSLocalizedString(@"Invalid server response", nil); - } - LOGE(@"Communication issue (%@)", [response faultString]); - UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Communication issue", nil) - message:errorString - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) - otherButtonTitles:nil, nil]; - [errorView show]; - - latestReceiptMD5 = nil; - NSDictionary *dict = @{ @"error_msg" : errorString }; - [self postNotificationforStatus:kIAPPurchaseFailed withDict:dict]; - } - } - - - (void)XMLRPCRequest:(LinphoneXmlRpcRequest *)request didFailWithError:(NSError *)error { - if (!_enabled) - return; - - _available = true; - - if ([[request method] isEqualToString:@"activate_account"]) { - _accountActivationInProgress = NO; - } - - LOGE(@"Communication issue (%@)", [error localizedDescription]); - NSString *errorString = - [NSString stringWithFormat:NSLocalizedString(@"Communication issue (%@)", nil), [error localizedDescription]]; - UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Communication issue", nil) - message:errorString - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) - otherButtonTitles:nil, nil]; - [errorView show]; - latestReceiptMD5 = nil; - NSDictionary *dict = @{ @"error_msg" : errorString }; - [self postNotificationforStatus:kIAPReceiptFailed withDict:dict]; - } - */ - (void) presentNotification:(int64_t) remaining{ if (notificationCategory == nil) return; int days = (int)remaining / (3600 * 24); @@ -613,41 +455,13 @@ } } +#pragma mark Other #else - (void)postNotificationforStatus:(IAPPurchaseNotificationStatus)status { _status = status; [NSNotificationCenter.defaultCenter postNotificationName:status object:self userInfo:nil]; LOGE(@"Not supported, triggering %@", status); } -- (BOOL)purchaseAccount:(NSString *)phoneNumber - withPassword:(NSString *)password - andEmail:(NSString *)email - monthly:(BOOL)monthly { - [self postNotificationforStatus:kIAPPurchaseFailed]; - return false; -} -- (BOOL)restore { - [self postNotificationforStatus:kIAPRestoreFailed]; - return false; -} -- (BOOL)retrievePurchases { - [self postNotificationforStatus:kIAPRestoreFailed]; - return false; -} -- (BOOL)purchaseWithID:(NSString *)productID { - [self postNotificationforStatus:kIAPPurchaseFailed]; - return FALSE; -} -- (BOOL)isPurchasedWithID:(NSString *)productId { - return FALSE; -} -- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { -} -- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { -} -- (BOOL)activateAccount:(NSString *)phoneNumber { - return FALSE; -} #endif @end diff --git a/Classes/ShopTableView.m b/Classes/ShopTableView.m index ea14c5bb1..1c5393c93 100644 --- a/Classes/ShopTableView.m +++ b/Classes/ShopTableView.m @@ -51,8 +51,8 @@ cell.descriptionLabel.minimumScaleFactor = .5; cell.descriptionLabel.adjustsFontSizeToFitWidth = cell.detailTextLabel.adjustsLetterSpacingToFitWidth = YES; cell.descriptionLabel.text = [NSString stringWithFormat:@"%@", product.localizedDescription]; - LOGE(@"ShopTableView : name = %@ - descr = %@", - [NSString stringWithFormat:@"%@ (%@)", product.localizedTitle, price], product.localizedDescription); + // LOGE(@"ShopTableView : name = %@ - descr = %@", + // [NSString stringWithFormat:@"%@ (%@)", product.localizedTitle, price], product.localizedDescription); [cell.linphoneImage setImage:[UIImage imageNamed:@"linphone_logo"]]; return cell; diff --git a/Classes/ShopView.h b/Classes/ShopView.h index 9b9af1c2f..93892ae33 100644 --- a/Classes/ShopView.h +++ b/Classes/ShopView.h @@ -27,6 +27,5 @@ @property(strong, nonatomic) IBOutlet ShopTableView *tableViewController; @property(weak, nonatomic) IBOutlet UIView *waitingView; - (IBAction)onDialerBackClick:(id)sender; -- (void)hideWaitingView; @end diff --git a/Classes/ShopView.m b/Classes/ShopView.m index 95137ebd7..e1ac838b8 100644 --- a/Classes/ShopView.m +++ b/Classes/ShopView.m @@ -49,19 +49,15 @@ static UICompositeViewDescription *compositeDescription = nil; [super viewWillAppear:animated]; [_tableViewController.tableView reloadData]; } + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [_waitingView setHidden:TRUE]; +} #pragma mark - Action Functions - (IBAction)onDialerBackClick:(id)sender { [PhoneMainView.instance popToView:DialerView.compositeViewDescription]; } -- (IBAction)hideWaitingView { - LOGE(@"====>>> ShopView hideWaitingView - bool = %d"); - if (_waitingView.isHidden) { - [_waitingView setHidden:NO]; - } else { - [_waitingView setHidden:YES]; - } -} - @end diff --git a/Resources/linphonerc b/Resources/linphonerc index ff3ef32ff..d85cdbb9b 100644 --- a/Resources/linphonerc +++ b/Resources/linphonerc @@ -13,12 +13,35 @@ start_at_boot_preference=1 stun_preference=stun.linphone.org voiceproc_preference=1 +[in_app_purchase] +#set to 1 if in-app purchases are to be shown in the application +enabled=0 + +#specify here the id of the sip account in-app purchase service to be shown in the shop section of the app +paid_account_id=sipAccount_12m + +#the url of the inapp/account management server, for submitting the receipt and validating the account. +receipt_validation_url=https://subscribe.linphone.org:444/inapp.php + +#for future use, to specify the full list of paying services to show in the shop view +products_list=sipAccount_12m,sipAccount_6m + +#minimum period of time between notifications to the user about his expiring/expired account, in seconds. +expiry_check_period=30 + +#period of time before account expiry, to start notifying the user about expiration arriving, in seconds. +warn_before_expiry_period=160 + +#for test only, simulate an account expiry after the specified number of seconds +expiry_time_test=180 + [default_values] reg_expires=1314000 [misc] file_transfer_server_url=https://www.linphone.org:444/lft.php max_calls=3 +real_early_media=1 [net] download_bw=380 diff --git a/Resources/linphonerc-factory b/Resources/linphonerc-factory index c499346d5..d19b01d10 100644 --- a/Resources/linphonerc-factory +++ b/Resources/linphonerc-factory @@ -21,24 +21,6 @@ publish_presence=0 password_length=-1 username_length=-1 -#specify here the id of the sip account in-app purchase service to be shown in the shop section of the app -paid_account_id=sipAccount_12m - -#the url of the inapp/account management server, for submitting the receipt and validating the account. -receipt_validation_url=https://subscribe.linphone.org:444/inapp.php - -#for future use, to specify the full list of paying services to show in the shop view -products_list=sipAccount_12m,sipAccount_6m - -#minimum period of time between notifications to the user about his expiring/expired account, in seconds. -expiry_check_period=30 - -#period of time before account expiry, to start notifying the user about expiration arriving, in seconds. -warn_before_expiry_period=160 - -#for test only, simulate an account expiry after the specified number of seconds -expiry_time_test=180 - [sip] sip_random_port=0 #whether SIP passwords must be encrypted in configuration storage file diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 03d7bd0e2..496026e1f 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -34,6 +34,8 @@ 22D1B68112A3E0BE001AE361 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 22D1B68012A3E0BE001AE361 /* libresolv.dylib */; }; 22E0A822111C44E100B04932 /* AboutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22E0A81C111C44E100B04932 /* AboutView.m */; }; 22F2508E107141E100AC9B3F /* DialerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22F2508C107141E100AC9B3F /* DialerView.m */; }; + 24A3459E1D95797700881A5C /* UIShopTableCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24A3459D1D95797700881A5C /* UIShopTableCell.xib */; }; + 24A345A61D95798A00881A5C /* UIShopTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 24A345A51D95798A00881A5C /* UIShopTableCell.m */; }; 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; 340751971506459A00B89C47 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 340751961506459A00B89C47 /* CoreTelephony.framework */; }; 340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 340751E6150F38FD00B89C47 /* UIVideoButton.m */; }; @@ -919,6 +921,9 @@ 22E0A81D111C44E100B04932 /* AboutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutView.h; sourceTree = ""; }; 22F2508B107141E100AC9B3F /* DialerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DialerView.h; sourceTree = ""; }; 22F2508C107141E100AC9B3F /* DialerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DialerView.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 24A3459D1D95797700881A5C /* UIShopTableCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UIShopTableCell.xib; sourceTree = ""; }; + 24A345A51D95798A00881A5C /* UIShopTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIShopTableCell.m; sourceTree = ""; }; + 24A345A71D95799900881A5C /* UIShopTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIShopTableCell.h; sourceTree = ""; }; 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* linphone_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linphone_Prefix.pch; sourceTree = ""; }; @@ -2127,6 +2132,9 @@ D3A55FBA15877E5E003FD403 /* UIContactCell.h */, D3A55FBB15877E5E003FD403 /* UIContactCell.m */, F088488D19FF8C41007FFCF3 /* UIContactCell.xib */, + 24A345A71D95799900881A5C /* UIShopTableCell.h */, + 24A345A51D95798A00881A5C /* UIShopTableCell.m */, + 24A3459D1D95797700881A5C /* UIShopTableCell.xib */, D3C6526515AC1A8F0092A874 /* UIContactDetailsCell.h */, D3C6526615AC1A8F0092A874 /* UIContactDetailsCell.m */, 639E9CAE1C0DB80300019A75 /* UIContactDetailsCell.xib */, @@ -3163,6 +3171,10 @@ ja, nl, zh_TW, + pl, + sv, + tr, + zh_CN, ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; projectDirPath = ""; @@ -3572,7 +3584,7 @@ 633FEE741D3CD5590014B822 /* history_all_disabled.png in Resources */, 633FEE081D3CD5590014B822 /* chat_add_disabled.png in Resources */, 633FEF1D1D3CD55A0014B822 /* presence_offline@2x.png in Resources */, - 8C5D1B9D1D9BC48100DC6539 /* UIShopTableCell.xib in Resources */, + 24A3459E1D95797700881A5C /* UIShopTableCell.xib in Resources */, 633FEE231D3CD5590014B822 /* chat_start_body_over@2x.png in Resources */, 633FEEBE1D3CD55A0014B822 /* numpad_4_over@2x.png in Resources */, 633FEF471D3CD55A0014B822 /* speaker_disabled@2x.png in Resources */, @@ -3855,7 +3867,7 @@ D3ED3E871586291E006C0DE4 /* TabBarView.m in Sources */, D3ED3EA71587334E006C0DE4 /* HistoryListTableView.m in Sources */, D3ED3EB81587392C006C0DE4 /* HistoryListView.m in Sources */, - 8C5D1B9C1D9BC48100DC6539 /* UIShopTableCell.m in Sources */, + 24A345A61D95798A00881A5C /* UIShopTableCell.m in Sources */, D35497FE15875372000081D8 /* ContactsListView.m in Sources */, 635173F91BA082A40095EB0A /* UIChatBubblePhotoCell.m in Sources */, D3549816158761D0000081D8 /* ContactsListTableView.m in Sources */,