// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <memory>
#import "base/functional/bind.h"
#import "base/strings/sys_string_conversions.h"
#import "components/autofill/core/browser/payments/legal_message_line.h"
#import "components/autofill/core/browser/payments/payments_autofill_client.h"
#import "ios/web/public/thread/web_task_traits.h"
#import "ios/web/public/thread/web_thread.h"
#import "ios/web_view/internal/autofill/cwv_autofill_util.h"
#import "ios/web_view/internal/autofill/cwv_credit_card_internal.h"
#import "ios/web_view/internal/autofill/cwv_credit_card_saver_internal.h"
#import "net/base/apple/url_conversions.h"
#import "ui/gfx/range/range.h"
NS_ASSUME_NONNULL_BEGIN
@implementation CWVCreditCardSaver {
autofill::payments::PaymentsAutofillClient::SaveCreditCardOptions
_saveOptions;
autofill::payments::PaymentsAutofillClient::UploadSaveCardPromptCallback
_saveCardCallback;
// The callback to invoke for save completion results.
void (^_Nullable _saveCompletionHandler)(BOOL);
// The callback to invoke for returning risk data.
base::OnceCallback<void(const std::string&)> _riskDataCallback;
// Whether or not either |acceptCreditCardWithRiskData:completionHandler:| or
// |declineCreditCardSave| has been called.
BOOL _decisionMade;
}
@synthesize creditCard = _creditCard;
@synthesize legalMessages = _legalMessages;
- (instancetype)
initWithCreditCard:(const autofill::CreditCard&)creditCard
saveOptions:(autofill::payments::PaymentsAutofillClient::
SaveCreditCardOptions)saveOptions
legalMessageLines:(autofill::LegalMessageLines)legalMessageLines
savePromptCallback:(autofill::payments::PaymentsAutofillClient::
UploadSaveCardPromptCallback)savePromptCallback {
self = [super init];
if (self) {
_creditCard = [[CWVCreditCard alloc] initWithCreditCard:creditCard];
_saveOptions = saveOptions;
_legalMessages = CWVLegalMessagesFromLegalMessageLines(legalMessageLines);
_saveCardCallback = std::move(savePromptCallback);
_decisionMade = NO;
}
return self;
}
- (void)dealloc {
// If the user did not choose, the decision should be marked as ignored.
if (_saveCardCallback) {
std::move(_saveCardCallback)
.Run(autofill::payments::PaymentsAutofillClient::
SaveCardOfferUserDecision::kIgnored,
/*user_provided_card_details=*/{});
}
}
#pragma mark - Public Methods
- (void)acceptWithCardHolderFullName:(NSString*)cardHolderFullName
expirationMonth:(NSString*)expirationMonth
expirationYear:(NSString*)expirationYear
riskData:(NSString*)riskData
completionHandler:(void (^)(BOOL))completionHandler {
DCHECK(!_decisionMade)
<< "You may only call -acceptWithRiskData:completionHandler: or "
"-decline: once per instance.";
DCHECK(_riskDataCallback && riskData);
std::move(_riskDataCallback).Run(base::SysNSStringToUTF8(riskData));
_saveCompletionHandler = completionHandler;
DCHECK(_saveCardCallback);
autofill::payments::PaymentsAutofillClient::UserProvidedCardDetails details;
details.cardholder_name = base::SysNSStringToUTF16(cardHolderFullName);
details.expiration_date_month = base::SysNSStringToUTF16(expirationMonth);
details.expiration_date_year = base::SysNSStringToUTF16(expirationYear);
std::move(_saveCardCallback)
.Run(autofill::payments::PaymentsAutofillClient::
SaveCardOfferUserDecision::kAccepted,
details);
_decisionMade = YES;
}
- (void)decline {
DCHECK(!_decisionMade)
<< "You may only call -acceptWithRiskData:completionHandler: or "
"-decline: once per instance.";
DCHECK(_saveCardCallback);
std::move(_saveCardCallback)
.Run(autofill::payments::PaymentsAutofillClient::
SaveCardOfferUserDecision::kDeclined,
/*user_provided_card_details=*/{});
_decisionMade = YES;
}
#pragma mark - Internal Methods
- (void)handleCreditCardUploadCompleted:(BOOL)cardSaved {
if (_saveCompletionHandler) {
_saveCompletionHandler(cardSaved);
_saveCompletionHandler = nil;
}
}
- (void)loadRiskData:(base::OnceCallback<void(const std::string&)>)callback {
_riskDataCallback = std::move(callback);
}
@end
NS_ASSUME_NONNULL_END