1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_DIALOG_VIEW_H_
6 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_DIALOG_VIEW_H_
7 
8 #include <map>
9 #include <memory>
10 
11 #include "base/callback_forward.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "chrome/browser/ui/views/payments/view_stack.h"
15 #include "components/payments/content/initialization_task.h"
16 #include "components/payments/content/payment_request_dialog.h"
17 #include "components/payments/content/payment_request_spec.h"
18 #include "components/payments/content/payment_request_state.h"
19 #include "ui/views/controls/throbber.h"
20 #include "ui/views/window/dialog_delegate.h"
21 
22 namespace autofill {
23 class AutofillProfile;
24 class CreditCard;
25 }  // namespace autofill
26 
27 class Profile;
28 
29 namespace payments {
30 
31 class PaymentRequest;
32 class PaymentRequestSheetController;
33 
34 // Maps views owned by PaymentRequestDialogView::view_stack_ to their
35 // controller. PaymentRequestDialogView is responsible for listening for those
36 // views being removed from the hierarchy and delete the associated controllers.
37 using ControllerMap =
38     std::map<views::View*, std::unique_ptr<PaymentRequestSheetController>>;
39 
40 enum class BackNavigationType {
41   kOneStep = 0,
42   kPaymentSheet,
43 };
44 
45 // The dialog delegate that represents a desktop WebPayments dialog. This class
46 // is responsible for displaying the view associated with the current state of
47 // the WebPayments flow and managing the transition between those states.
48 class PaymentRequestDialogView : public views::DialogDelegateView,
49                                  public PaymentRequestDialog,
50                                  public PaymentRequestSpec::Observer,
51                                  public InitializationTask::Observer {
52  public:
53   class ObserverForTest {
54    public:
55     virtual void OnDialogOpened() = 0;
56 
57     virtual void OnContactInfoOpened() = 0;
58 
59     virtual void OnOrderSummaryOpened() = 0;
60 
61     virtual void OnPaymentMethodOpened() = 0;
62 
63     virtual void OnShippingAddressSectionOpened() = 0;
64 
65     virtual void OnShippingOptionSectionOpened() = 0;
66 
67     virtual void OnCreditCardEditorOpened() = 0;
68 
69     virtual void OnShippingAddressEditorOpened() = 0;
70 
71     virtual void OnContactInfoEditorOpened() = 0;
72 
73     virtual void OnBackNavigation() = 0;
74 
75     virtual void OnBackToPaymentSheetNavigation() = 0;
76 
77     virtual void OnEditorViewUpdated() = 0;
78 
79     virtual void OnErrorMessageShown() = 0;
80 
81     virtual void OnSpecDoneUpdating() = 0;
82 
83     virtual void OnCvcPromptShown() = 0;
84 
85     virtual void OnProcessingSpinnerShown() = 0;
86 
87     virtual void OnProcessingSpinnerHidden() = 0;
88 
89     virtual void OnPaymentHandlerWindowOpened() = 0;
90   };
91 
92   // Build a Dialog around the PaymentRequest object. |observer| is used to
93   // be notified of dialog events as they happen (but may be NULL) and should
94   // outlive this object.
95   static base::WeakPtr<PaymentRequestDialogView> Create(
96       base::WeakPtr<PaymentRequest> request,
97       PaymentRequestDialogView::ObserverForTest* observer);
98 
99   // views::View
100   void RequestFocus() override;
101 
102   // views::WidgetDelegate:
103   ui::ModalType GetModalType() const override;
104   views::View* GetInitiallyFocusedView() override;
105 
106   // views::DialogDelegate:
107   bool ShouldShowCloseButton() const override;
108 
109   // payments::PaymentRequestDialog:
110   void ShowDialog() override;
111   void CloseDialog() override;
112   void ShowErrorMessage() override;
113   void ShowProcessingSpinner() override;
114   bool IsInteractive() const override;
115   void ShowPaymentHandlerScreen(
116       const GURL& url,
117       PaymentHandlerOpenWindowCallback callback) override;
118   void RetryDialog() override;
119   void ConfirmPaymentForTesting() override;
120 
121   // PaymentRequestSpec::Observer:
122   void OnStartUpdating(PaymentRequestSpec::UpdateReason reason) override;
123   void OnSpecUpdated() override;
124 
125   // InitializationTask::Observer:
126   void OnInitialized(InitializationTask* initialization_task) override;
127 
128   void Pay();
129   void GoBack();
130   void GoBackToPaymentSheet(bool animate = true);
131   void ShowContactProfileSheet();
132   void ShowOrderSummary();
133   void ShowShippingProfileSheet();
134   void ShowPaymentMethodSheet();
135   void ShowShippingOptionSheet();
136   // |credit_card| is the card to be edited, or nullptr for adding a card.
137   // |on_edited| is called when |credit_card| was successfully edited, and
138   // |on_added| is called when a new credit card was added (the reference is
139   // short-lived; callee should make a copy of the CreditCard object).
140   // |back_navigation_type| identifies the type of navigation to execute once
141   // the editor has completed successfully.
142   void ShowCreditCardEditor(
143       BackNavigationType back_navigation_type,
144       base::OnceClosure on_edited,
145       base::OnceCallback<void(const autofill::CreditCard&)> on_added,
146       autofill::CreditCard* credit_card = nullptr);
147   // |profile| is the address to be edited, or nullptr for adding an address.
148   // |on_edited| is called when |profile| was successfully edited, and
149   // |on_added| is called when a new profile was added (the reference is
150   // short-lived; callee should make a copy of the profile object).
151   // |back_navigation_type| identifies the type of navigation to execute once
152   // the editor has completed successfully.
153   void ShowShippingAddressEditor(
154       BackNavigationType back_navigation_type,
155       base::OnceClosure on_edited,
156       base::OnceCallback<void(const autofill::AutofillProfile&)> on_added,
157       autofill::AutofillProfile* profile);
158   // |profile| is the profile to be edited, or nullptr for adding a profile.
159   // |on_edited| is called when |profile| was successfully edited, and
160   // |on_added| is called when a new profile was added (the reference is
161   // short-lived; callee should make a copy of the profile object).
162   // |back_navigation_type| identifies the type of navigation to execute once
163   // the editor has completed successfully.
164   void ShowContactInfoEditor(
165       BackNavigationType back_navigation_type,
166       base::OnceClosure on_edited,
167       base::OnceCallback<void(const autofill::AutofillProfile&)> on_added,
168       autofill::AutofillProfile* profile = nullptr);
169   void EditorViewUpdated();
170 
171   void ShowCvcUnmaskPrompt(
172       const autofill::CreditCard& credit_card,
173       base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
174           result_delegate,
175       content::WebContents* web_contents) override;
176 
177   // Hides the full dialog spinner with the "processing" label.
178   void HideProcessingSpinner();
179 
180   Profile* GetProfile();
181 
182   // Calculates the actual payment handler dialog height based on the preferred
183   // height and current browser window size.
184   int GetActualPaymentHandlerDialogHeight() const;
185 
186   // Calculates the dialog width depending on whether or not the large payment
187   // handler window is currently showing.
188   int GetActualDialogWidth() const;
189 
view_stack_for_testing()190   ViewStack* view_stack_for_testing() { return view_stack_; }
throbber_overlay_for_testing()191   views::View* throbber_overlay_for_testing() { return throbber_overlay_; }
192 
193  private:
194   // The browsertest validates the calculated dialog size.
195   friend class PaymentHandlerWindowSizeTest;
196 
197   PaymentRequestDialogView(base::WeakPtr<PaymentRequest> request,
198                            PaymentRequestDialogView::ObserverForTest* observer);
199   ~PaymentRequestDialogView() override;
200 
201   void OnDialogOpened();
202   void ShowInitialPaymentSheet();
203   void SetupSpinnerOverlay();
204   void OnDialogClosed();
205   void ResizeDialogWindow();
206 
207   // views::View
208   gfx::Size CalculatePreferredSize() const override;
209   void ViewHierarchyChanged(
210       const views::ViewHierarchyChangedDetails& details) override;
211 
212   // The PaymentRequest object that initiated this dialog.
213   base::WeakPtr<PaymentRequest> request_;
214   ControllerMap controller_map_;
215   ViewStack* view_stack_;
216 
217   // A full dialog overlay that shows a spinner and the "processing" label. It's
218   // hidden until ShowProcessingSpinner is called.
219   views::View* throbber_overlay_;
220   views::Throbber* throbber_;
221 
222   // May be null.
223   ObserverForTest* observer_for_testing_;
224 
225   // Used when the dialog is being closed to avoid re-entrance into the
226   // controller_map_ or view_stack_.
227   bool being_closed_ = false;
228 
229   // The number of initialization tasks that are not yet initialized.
230   size_t number_of_initialization_tasks_ = 0;
231 
232   // True when payment handler screen is shown and the
233   // kPaymentHandlerPopUpSizeWindow runtime flag is set.
234   bool is_showing_large_payment_handler_window_ = false;
235 
236   // Calculated based on the browser content size at the time of opening payment
237   // handler window.
238   int payment_handler_window_height_ = 0;
239 
240   base::WeakPtrFactory<PaymentRequestDialogView> weak_ptr_factory_{this};
241 
242   DISALLOW_COPY_AND_ASSIGN(PaymentRequestDialogView);
243 };
244 
245 }  // namespace payments
246 
247 #endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_DIALOG_VIEW_H_
248