text: // Copyright 2021 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "ash/in_session_auth/authentication_dialog.h"
  #include <memory>
  #include "ash/public/cpp/shelf_config.h"
  #include "ash/strings/grit/ash_strings.h"
  #include "base/bind.h"
  #include "base/time/time.h"
  #include "ui/base/l10n/l10n_util.h"
  #include "ui/base/ui_base_types.h"
  #include "ui/display/screen.h"
  #include "ui/gfx/color_palette.h"
  #include "ui/gfx/geometry/insets.h"
  #include "ui/views/controls/button/label_button.h"
  #include "ui/views/controls/label.h"
  #include "ui/views/controls/textfield/textfield.h"
  #include "ui/views/layout/flex_layout.h"
  #include "ui/views/layout/layout_provider.h"
  #include "ui/views/layout/layout_types.h"
  #include "ui/views/view_class_properties.h"
  #include "ui/views/widget/widget.h"
  
  namespace ash {
  
  namespace {
  
  void AddMargins(views::View* view) {
    const auto* layout_provider = views::LayoutProvider::Get();
    const int horizontal_spacing = layout_provider->GetDistanceMetric(
        views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
    const int vertical_spacing = layout_provider->GetDistanceMetric(
        views::DISTANCE_RELATED_CONTROL_VERTICAL);
  
    view->SetProperty(views::kMarginsKey,
                      gfx::Insets(vertical_spacing, horizontal_spacing));
  }
  
  void ConfigurePasswordField(views::Textfield* password_field) {
    const auto password_field_name =
        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_PLACEHOLDER);
    password_field->SetAccessibleName(password_field_name);
    password_field->SetReadOnly(false);
    password_field->SetTextInputType(ui::TextInputType::TEXT_INPUT_TYPE_PASSWORD);
    password_field->SetPlaceholderText(password_field_name);
    AddMargins(password_field);
  }
  
  void ConfigureInvalidPasswordLabel(views::Label* invalid_password_label) {
    invalid_password_label->SetProperty(views::kCrossAxisAlignmentKey,
                                        views::LayoutAlignment::kStart);
    invalid_password_label->SetEnabledColor(SK_ColorRED);
    AddMargins(invalid_password_label);
  }
  
  void CenterWidgetOnPrimaryDisplay(views::Widget* widget) {
    auto bounds = display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
    bounds.ClampToCenteredSize(widget->GetContentsView()->GetPreferredSize());
    widget->SetBounds(bounds);
  }
  
  }  // namespace
  
  // static
  AuthenticationDialog* AuthenticationDialog::Show(
      OnSubmitCallback submit_callback) {
    auto* authentication_dialog =
        new AuthenticationDialog(std::move(submit_callback));
    auto* widget = DialogDelegateView::CreateDialogWidget(authentication_dialog,
                                                          /*context=*/nullptr,
                                                          /*parent=*/nullptr);
    CenterWidgetOnPrimaryDisplay(widget);
    widget->Show();
    authentication_dialog->Init();
    return authentication_dialog;
  }
  
  AuthenticationDialog::~AuthenticationDialog() = default;
  
  void AuthenticationDialog::Init() {
    ConfigureOkButton();
    password_field_->RequestFocus();
  }
  
  void AuthenticationDialog::NotifyResult(Result result,
                                          const std::u16string& token,
                                          base::TimeDelta timeout) {
    std::move(on_submit_).Run(result, token, timeout);
  }
  
  void AuthenticationDialog::CancelAuthAttempt() {
    NotifyResult(Result::kAborted, u"", base::Seconds(0));
  }
  
  void AuthenticationDialog::OnSubmit() {
    // TODO(crbug.com/1271551): Call appropriate backends to get token
    // and notify interested parties with |AuthenticationDialog::NotifyResult|
    // For now, we always assume the given password is invalid
    password_field_->SetInvalid(true);
    password_field_->SelectAll(false);
    invalid_password_label_->SetText(
        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_ERROR_AUTHENTICATING));
  }
  
  void AuthenticationDialog::ConfigureChildViews() {
    ConfigurePasswordField(password_field_);
    ConfigureInvalidPasswordLabel(invalid_password_label_);
  }
  
  void AuthenticationDialog::ConfigureOkButton() {
    views::LabelButton* ok_button = GetOkButton();
    ok_button->SetText(
        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SUBMIT_BUTTON_ACCESSIBLE_NAME));
    ok_button->SetCallback(base::BindRepeating(&AuthenticationDialog::OnSubmit,
                                               base::Unretained(this)));
  }
  
  AuthenticationDialog::AuthenticationDialog(OnSubmitCallback submit_callback)
      : password_field_(AddChildView(std::make_unique<views::Textfield>())),
        invalid_password_label_(AddChildView(std::make_unique<views::Label>())),
        on_submit_(std::move(submit_callback)) {
    // Dialog setup
    set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
        views::DistanceMetric::DISTANCE_BUBBLE_PREFERRED_WIDTH));
    SetTitle(l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_TITLE));
    SetModalType(ui::MODAL_TYPE_SYSTEM);
  
    // Callback setup
    SetCancelCallback(base::BindOnce(&AuthenticationDialog::CancelAuthAttempt,
                                     base::Unretained(this)));
    SetCloseCallback(base::BindOnce(&AuthenticationDialog::CancelAuthAttempt,
                                    base::Unretained(this)));
  
    SetLayoutManager(std::make_unique<views::FlexLayout>())
        ->SetOrientation(views::LayoutOrientation::kVertical)
        .SetCollapseMargins(true);
  
    ConfigureChildViews();
  }
  
  }  // namespace ash
  