// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_BASE_MODELS_DIALOG_MODEL_FIELD_H_
#define UI_BASE_MODELS_DIALOG_MODEL_FIELD_H_

#include <optional>
#include <string>
#include <string_view>

#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/types/pass_key.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/models/image_model.h"
#include "ui/base/ui_base_types.h"

namespace ui {

class DialogModelParagraph;
class DialogModelCheckbox;
class DialogModelCombobox;
class DialogModelCustomField;
class DialogModelMenuItem;
class DialogModelTitleItem;
class DialogModelSection;
class DialogModelTextfield;
class DialogModelPasswordField;
class Event;

class DialogModelFieldHost {
 protected:
  // This PassKey is used to make sure that some methods on DialogModel
  // are only called as part of the host integration.
  static base::PassKey<DialogModelFieldHost> GetPassKey() {
    return base::PassKey<DialogModelFieldHost>();
  }
};

// TODO(pbos): Move this to separate header.
// DialogModelLabel is an exception to below classes. This is not a
// DialogModelField but rather represents a text label and styling. This is used
// with DialogModelParagraph and DialogModelCheckbox for instance and has
// support for styling text replacements and showing a link.
class COMPONENT_EXPORT(UI_BASE) DialogModelLabel {
 public:
  // TODO(pbos): Move this definition (maybe as a ui::LinkCallback) so it can
  // be reused with views::Link.
  using Callback = base::RepeatingCallback<void(const Event& event)>;

  class COMPONENT_EXPORT(UI_BASE) TextReplacement {
   public:
    TextReplacement(const TextReplacement&);
    ~TextReplacement();

    const std::u16string& text() const { return text_; }
    bool is_emphasized() const { return is_emphasized_; }
    const std::optional<Callback>& callback() const { return callback_; }
    const std::optional<std::u16string>& accessible_name() const {
      return accessible_name_;
    }

   private:
    friend class DialogModelLabel;

    // Used for regular and emphasized text.
    explicit TextReplacement(std::u16string text, bool is_emphasized = false);
    // Used for links.
    TextReplacement(int message_id,
                    Callback closure,
                    std::u16string accessible_name = std::u16string());

    const std::u16string text_;
    const bool is_emphasized_;
    const std::optional<Callback> callback_;
    const std::optional<std::u16string> accessible_name_;
  };

  explicit DialogModelLabel(int message_id);
  explicit DialogModelLabel(std::u16string fixed_string);

  DialogModelLabel(const DialogModelLabel&);
  DialogModelLabel& operator=(const DialogModelLabel&) = delete;
  ~DialogModelLabel();

  static DialogModelLabel CreateWithReplacement(int message_id,
                                                TextReplacement replacement);
  static DialogModelLabel CreateWithReplacements(
      int message_id,
      std::vector<TextReplacement> replacements);

  // Builder methods for TextReplacements.
  static TextReplacement CreateLink(
      int message_id,
      base::RepeatingClosure closure,
      std::u16string accessible_name = std::u16string());
  static TextReplacement CreateLink(
      int message_id,
      Callback callback,
      std::u16string accessible_name = std::u16string());
  static TextReplacement CreatePlainText(std::u16string text);
  static TextReplacement CreateEmphasizedText(std::u16string text);

  // Gets the string. Not for use with replacements, in which case the caller
  // must use replacements() and message_id() to construct the final label. This
  // is required to style the final label appropriately and support replacement
  // callbacks. The caller is responsible for checking replacements().empty()
  // before calling this.
  const std::u16string& GetString() const;

  DialogModelLabel& set_is_secondary() {
    is_secondary_ = true;
    return *this;
  }

  DialogModelLabel& set_allow_character_break() {
    allow_character_break_ = true;
    return *this;
  }

  int message_id() const { return message_id_; }
  const std::vector<TextReplacement>& replacements() const {
    return replacements_;
  }

  bool is_secondary() const { return is_secondary_; }
  bool allow_character_break() const { return allow_character_break_; }

 private:
  explicit DialogModelLabel(int message_id,
                            std::vector<TextReplacement> replacements);

  const int message_id_;
  const std::u16string string_;

  // Set of replacements that will be added to `message_id_`.
  const std::vector<TextReplacement> replacements_;

  bool is_secondary_ = false;
  bool allow_character_break_ = false;
};

// These "field" classes represent entries in a DialogModel. They are owned
// by the model and either created through the model or DialogModel::Builder.
// These entries can be referred to by setting the field's ElementIdentifier in
// construction parameters (::Params::SetId()). They can then
// later be acquired through DialogModel::GetFieldByUniqueId() methods.
// These fields own the data corresponding to their field. For instance, the
// text of a textfield in a model is read using DialogModelTextfield::text() and
// stays in sync with the visible dialog (through DialogModelHosts).
class COMPONENT_EXPORT(UI_BASE) DialogModelField {
 public:
  enum Type {
    kParagraph,
    kCheckbox,
    kCombobox,
    kCustom,
    kMenuItem,
    kSeparator,  // TODO(pbos): Remove kSeparator once it can be implied by
                 // having multiple subsequent kSections (3 sections imply 2
                 // separators).
    kSection,
    kTextfield,
    kPasswordField,
    kTitleItem  // TODO(pengchaocai): Remove kTitleItem once DialogModel
                // supports multiple sections.
  };

  class COMPONENT_EXPORT(UI_BASE) Params {
   public:
    Params() = default;
    Params(const Params&) = delete;
    Params& operator=(const Params&) = delete;
    ~Params() = default;

    Params& SetVisible(bool is_visible) {
      is_visible_ = is_visible;
      return *this;
    }

   private:
    friend class DialogModel;
    friend class DialogModelField;

    bool is_visible_ = true;
  };

  DialogModelField(const DialogModelField&) = delete;
  DialogModelField& operator=(const DialogModelField&) = delete;
  virtual ~DialogModelField();

  [[nodiscard]] base::CallbackListSubscription AddOnFieldChangedCallback(
      base::RepeatingClosure on_field_changed);

  Type type() const { return type_; }

  void SetVisible(bool visible);
  bool is_visible() const { return is_visible_; }

  const base::flat_set<Accelerator>& accelerators() const {
    return accelerators_;
  }
  ElementIdentifier id() const { return id_; }

  DialogModelParagraph* AsParagraph();
  DialogModelCheckbox* AsCheckbox();
  DialogModelCombobox* AsCombobox();
  DialogModelMenuItem* AsMenuItem();
  const DialogModelMenuItem* AsMenuItem() const;
  const DialogModelTitleItem* AsTitleItem() const;
  DialogModelTextfield* AsTextfield();
  DialogModelPasswordField* AsPasswordField();
  DialogModelSection* AsSection();
  DialogModelCustomField* AsCustomField();

 protected:
  DialogModelField(Type type,
                   ElementIdentifier id,
                   base::flat_set<Accelerator> accelerators,
                   const DialogModelField::Params& params);

  void NotifyOnFieldChanged();

 private:
  friend class DialogModel;
  FRIEND_TEST_ALL_PREFIXES(DialogModelButtonTest, UsesParamsUniqueId);

  const Type type_;
  const ElementIdentifier id_;

  const base::flat_set<Accelerator> accelerators_;

  bool is_visible_;

  base::RepeatingClosureList on_field_changed_;
};

// Field class representing a paragraph.
class COMPONENT_EXPORT(UI_BASE) DialogModelParagraph : public DialogModelField {
 public:
  DialogModelParagraph(const DialogModelLabel& label,
                       std::u16string header,
                       ElementIdentifier id);
  DialogModelParagraph(const DialogModelParagraph&) = delete;
  DialogModelParagraph& operator=(const DialogModelParagraph&) = delete;
  ~DialogModelParagraph() override;

  const DialogModelLabel& label() const { return label_; }

  const std::u16string header() const { return header_; }

 private:
  const DialogModelLabel label_;
  const std::u16string header_;
};

// Field class representing a checkbox with descriptive text.
class COMPONENT_EXPORT(UI_BASE) DialogModelCheckbox : public DialogModelField {
 public:
  class COMPONENT_EXPORT(UI_BASE) Params : public DialogModelField::Params {
   public:
    Params() = default;
    Params(const Params&) = delete;
    Params& operator=(const Params&) = delete;
    ~Params() = default;

    Params& SetIsChecked(bool is_checked) {
      is_checked_ = is_checked;
      return *this;
    }

    Params& SetVisible(bool is_visible) {
      DialogModelField::Params::SetVisible(is_visible);
      return *this;
    }

   private:
    friend class DialogModelCheckbox;

    bool is_checked_ = false;
  };

  DialogModelCheckbox(ElementIdentifier id,
                      const DialogModelLabel& label,
                      const Params& params);
  DialogModelCheckbox(const DialogModelCheckbox&) = delete;
  DialogModelCheckbox& operator=(const DialogModelCheckbox&) = delete;
  ~DialogModelCheckbox() override;

  bool is_checked() const { return is_checked_; }

  void OnChecked(base::PassKey<DialogModelFieldHost>, bool is_checked);
  const DialogModelLabel& label() const { return label_; }

 private:
  const DialogModelLabel label_;
  bool is_checked_;
};

// Field class representing a combobox and corresponding label to describe the
// combobox:
//
//     <label>   [combobox]
// Ex: Folder    [My Bookmarks]
class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField {
 public:
  class COMPONENT_EXPORT(UI_BASE) Params : public DialogModelField::Params {
   public:
    Params();
    Params(const Params&) = delete;
    Params& operator=(const Params&) = delete;
    ~Params();

    Params& AddAccelerator(Accelerator accelerator);

    Params& SetAccessibleName(std::u16string accessible_name) {
      accessible_name_ = std::move(accessible_name);
      return *this;
    }

    // The combobox callback is invoked when an item has been selected. This
    // nominally happens when selecting an item in the combobox menu. The
    // selection notably does not change by hovering different items in the
    // combobox menu or navigating it with up/down keys as long as the menu is
    // open.
    Params& SetCallback(base::RepeatingClosure callback);

    Params& SetVisible(bool is_visible) {
      DialogModelField::Params::SetVisible(is_visible);
      return *this;
    }

   private:
    friend class DialogModelCombobox;

    ElementIdentifier id_;
    std::u16string accessible_name_;
    base::RepeatingClosure callback_;
    base::flat_set<Accelerator> accelerators_;
  };

  DialogModelCombobox(ElementIdentifier id,
                      std::u16string label,
                      std::unique_ptr<ui::ComboboxModel> combobox_model,
                      const Params& params);
  DialogModelCombobox(const DialogModelCombobox&) = delete;
  DialogModelCombobox& operator=(const DialogModelCombobox&) = delete;
  ~DialogModelCombobox() override;

  size_t selected_index() const { return selected_index_; }
  ui::ComboboxModel* combobox_model() { return combobox_model_.get(); }

  const std::u16string& label() const { return label_; }
  const std::u16string& accessible_name() const { return accessible_name_; }
  void OnSelectedIndexChanged(base::PassKey<DialogModelFieldHost>,
                              size_t selected_index);
  void OnPerformAction(base::PassKey<DialogModelFieldHost>);

 private:
  friend class DialogModel;

  const std::u16string label_;
  const std::u16string accessible_name_;
  size_t selected_index_;
  std::unique_ptr<ui::ComboboxModel> combobox_model_;
  base::RepeatingClosure callback_;
};

// Field class representing a menu item:
//
//     <icon> <label>
// Ex: [icon] Open URL
class COMPONENT_EXPORT(UI_BASE) DialogModelMenuItem : public DialogModelField {
 public:
  class COMPONENT_EXPORT(UI_BASE) Params : public DialogModelField::Params {
   public:
    Params();
    Params(const Params&) = delete;
    Params& operator=(const Params&) = delete;
    ~Params();

    Params& SetIsEnabled(bool is_enabled);
    Params& SetId(ElementIdentifier id);

    Params& SetVisible(bool is_visible) {
      DialogModelField::Params::SetVisible(is_visible);
      return *this;
    }

   private:
    friend class DialogModelMenuItem;

    bool is_enabled_ = true;
    ElementIdentifier id_;
  };

  DialogModelMenuItem(ImageModel icon,
                      std::u16string label,
                      base::RepeatingCallback<void(int)> callback,
                      const Params& params);
  DialogModelMenuItem(const DialogModelMenuItem&) = delete;
  DialogModelMenuItem& operator=(const DialogModelMenuItem&) = delete;
  ~DialogModelMenuItem() override;

  const ImageModel& icon() const { return icon_; }
  const std::u16string& label() const { return label_; }
  bool is_enabled() const { return is_enabled_; }
  void OnActivated(base::PassKey<DialogModelFieldHost>, int event_flags);

 private:
  const ImageModel icon_;
  const std::u16string label_;
  const bool is_enabled_;
  base::RepeatingCallback<void(int)> callback_;
};

// Field class representing a separator.
class COMPONENT_EXPORT(UI_BASE) DialogModelSeparator : public DialogModelField {
 public:
  DialogModelSeparator();
  DialogModelSeparator(const DialogModelSeparator&) = delete;
  DialogModelSeparator& operator=(const DialogModelSeparator&) = delete;
  ~DialogModelSeparator() override;
};

// Field class representing a title.
// TODO(pengchaocai): Remove DialogModelTitleItem once DialogModel supports
// multiple sections and titles live in sections as optional strings.
class COMPONENT_EXPORT(UI_BASE) DialogModelTitleItem : public DialogModelField {
 public:
  explicit DialogModelTitleItem(std::u16string label,
                                ElementIdentifier id = ElementIdentifier());
  DialogModelTitleItem(const DialogModelSeparator&) = delete;
  DialogModelTitleItem& operator=(const DialogModelSeparator&) = delete;
  ~DialogModelTitleItem() override;
  const std::u16string& label() const { return label_; }

 private:
  const std::u16string label_;
};

// Field class representing a textfield and corresponding label to describe the
// textfield:
//
//     <label>   [textfield]
// Ex: Name      [My email]
class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField {
 public:
  class COMPONENT_EXPORT(UI_BASE) Params : public DialogModelField::Params {
   public:
    Params();
    Params(const Params&) = delete;
    Params& operator=(const Params&) = delete;
    ~Params();

    Params& AddAccelerator(Accelerator accelerator);

    Params& SetAccessibleName(std::u16string accessible_name) {
      accessible_name_ = std::move(accessible_name);
      return *this;
    }

    Params& SetVisible(bool is_visible) {
      DialogModelField::Params::SetVisible(is_visible);
      return *this;
    }

   private:
    friend class DialogModelTextfield;

    ElementIdentifier id_;
    std::u16string accessible_name_;
    base::flat_set<Accelerator> accelerators_;
  };

  DialogModelTextfield(ElementIdentifier id,
                       std::u16string label,
                       std::u16string text,
                       const Params& params);
  DialogModelTextfield(const DialogModelTextfield&) = delete;
  DialogModelTextfield& operator=(const DialogModelTextfield&) = delete;
  ~DialogModelTextfield() override;

  const std::u16string& text() const { return text_; }

  const std::u16string& label() const { return label_; }
  const std::u16string& accessible_name() const { return accessible_name_; }
  void OnTextChanged(base::PassKey<DialogModelFieldHost>,
                     std::u16string_view text);

 private:
  friend class DialogModel;

  const std::u16string label_;
  const std::u16string accessible_name_;
  std::u16string text_;
};

// Field class representing a password field and corresponding label to describe
// the password field. The password can be revealed by clicking on the eye icon.
// If the user enters an incorrect password, the field can be invalidated by
// calling `Invalidate()`:
// - the password field is cleared ;
// - the text field is invalidated, causing its outline to be red ;
// - `incorrect_password_text` is shown below the password field.
// The password field becomes valid again automatically when a new character is
// entered.
class COMPONENT_EXPORT(UI_BASE) DialogModelPasswordField
    : public DialogModelField {
 public:
  // using Params = DialogModelField::Params;

  DialogModelPasswordField(ElementIdentifier id,
                           std::u16string label,
                           std::u16string accessible_name,
                           std::u16string incorrect_password_text,
                           const DialogModelPasswordField::Params& params);
  DialogModelPasswordField(const DialogModelPasswordField&) = delete;
  DialogModelPasswordField& operator=(const DialogModelPasswordField&) = delete;
  ~DialogModelPasswordField() override;

  const std::u16string& text() const { return text_; }

  // Clears the password field, and displays `incorrect_password_text()` until
  // the user starts typing again.
  // Typically used when the user clicks the OK button after they are finished
  // typing, and the password is wrong.
  void Invalidate();

  const std::u16string& label() const { return label_; }
  const std::u16string& accessible_name() const { return accessible_name_; }
  const std::u16string& incorrect_password_text() const {
    return incorrect_password_text_;
  }

  void OnTextChanged(base::PassKey<DialogModelFieldHost>,
                     std::u16string_view text);
  base::CallbackListSubscription AddOnInvalidateCallback(
      base::PassKey<DialogModelFieldHost>,
      base::RepeatingClosure closure);

 private:
  friend class DialogModel;

  const std::u16string label_;
  const std::u16string accessible_name_;
  const std::u16string incorrect_password_text_;
  std::u16string text_;

  base::RepeatingClosureList on_invalidate_closures_;
};

// Field base class representing a "custom" field. Used for instance to inject
// custom Views into dialogs that use DialogModel.
class COMPONENT_EXPORT(UI_BASE) DialogModelCustomField
    : public DialogModelField {
 public:
  // Base class for fields held by DialogModelField. Calling code is responsible
  // for providing the subclass expected by the DialogModelHost used.
  class COMPONENT_EXPORT(UI_BASE) Field {
   public:
    virtual ~Field();
  };

  DialogModelCustomField(ElementIdentifier id,
                         std::unique_ptr<DialogModelCustomField::Field> field);
  DialogModelCustomField(const DialogModelCustomField&) = delete;
  DialogModelCustomField& operator=(const DialogModelCustomField&) = delete;
  ~DialogModelCustomField() override;

  DialogModelCustomField::Field* field() { return field_.get(); }

 private:
  friend class DialogModel;

  std::unique_ptr<DialogModelCustomField::Field> field_;
};

// Field class representing a section. A section is a list of fields which may
// include subsections too (tree structure).
class COMPONENT_EXPORT(UI_BASE) DialogModelSection final
    : public DialogModelField {
 public:
  class COMPONENT_EXPORT(UI_BASE) Builder final {
   public:
    Builder();
    Builder(const Builder&) = delete;
    Builder& operator=(const Builder&) = delete;
    ~Builder();

    [[nodiscard]] std::unique_ptr<DialogModelSection> Build();

    Builder& AddParagraph(const DialogModelLabel& label,
                          std::u16string header = std::u16string(),
                          ElementIdentifier id = ElementIdentifier()) {
      section_->AddParagraph(label, std::move(header), id);
      return *this;
    }

    Builder& AddCheckbox(ElementIdentifier id,
                         const DialogModelLabel& label,
                         const DialogModelCheckbox::Params& params =
                             DialogModelCheckbox::Params()) {
      section_->AddCheckbox(id, label, params);
      return *this;
    }

    Builder& AddCombobox(ElementIdentifier id,
                         std::u16string label,
                         std::unique_ptr<ui::ComboboxModel> combobox_model,
                         const DialogModelCombobox::Params& params =
                             DialogModelCombobox::Params()) {
      section_->AddCombobox(id, std::move(label), std::move(combobox_model),
                            params);
      return *this;
    }

    Builder& AddMenuItem(ImageModel icon,
                         std::u16string label,
                         base::RepeatingCallback<void(int)> callback,
                         const DialogModelMenuItem::Params& params =
                             DialogModelMenuItem::Params()) {
      section_->AddMenuItem(std::move(icon), std::move(label),
                            std::move(callback), params);
      return *this;
    }

    Builder& AddSeparator() {
      section_->AddSeparator();
      return *this;
    }

    Builder& AddTextfield(ElementIdentifier id,
                          std::u16string label,
                          std::u16string text,
                          const DialogModelTextfield::Params& params =
                              DialogModelTextfield::Params()) {
      section_->AddTextfield(id, std::move(label), std::move(text), params);
      return *this;
    }

    Builder& AddCustomField(
        std::unique_ptr<DialogModelCustomField::Field> field,
        ElementIdentifier id = ElementIdentifier()) {
      section_->AddCustomField(std::move(field), id);
      return *this;
    }

   private:
    std::unique_ptr<DialogModelSection> section_;
  };

  // TODO(pbos): Params may make sense here? An optional title should be here?
  // TODO(pbos): We may also want to add on_field_added as a callback to that
  // Params struct once it exists.
  DialogModelSection();
  DialogModelSection(const DialogModelSection&) = delete;
  DialogModelSection& operator=(const DialogModelSection&) = delete;
  ~DialogModelSection() override;

  [[nodiscard]] base::CallbackListSubscription AddOnFieldAddedCallback(
      base::RepeatingCallback<void(DialogModelField*)> on_field_added);

  [[nodiscard]] base::CallbackListSubscription AddOnFieldChangedCallback(
      base::RepeatingCallback<void(DialogModelField*)> on_field_changed);

  const std::vector<std::unique_ptr<DialogModelField>>& fields() const {
    return fields_;
  }

  DialogModelField* GetFieldByUniqueId(ElementIdentifier id);
  DialogModelCheckbox* GetCheckboxByUniqueId(ElementIdentifier id);
  DialogModelCombobox* GetComboboxByUniqueId(ElementIdentifier id);
  DialogModelTextfield* GetTextfieldByUniqueId(ElementIdentifier id);
  DialogModelPasswordField* GetPasswordFieldByUniqueId(ElementIdentifier id);

  // Adds a paragraph at the end of the section. A paragraph consists of a
  // label and an optional header.
  void AddParagraph(const DialogModelLabel& label,
                    std::u16string header = std::u16string(),
                    ElementIdentifier id = ElementIdentifier());

  // Adds a checkbox ([checkbox] label) at the end of the section.
  void AddCheckbox(ElementIdentifier id,
                   const DialogModelLabel& label,
                   const DialogModelCheckbox::Params& params =
                       DialogModelCheckbox::Params());

  // Adds a labeled combobox (label: [model]) at the end of the section.
  void AddCombobox(ElementIdentifier id,
                   std::u16string label,
                   std::unique_ptr<ui::ComboboxModel> combobox_model,
                   const DialogModelCombobox::Params& params =
                       DialogModelCombobox::Params());

  // Adds a menu item at the end of the section.
  void AddMenuItem(ImageModel icon,
                   std::u16string label,
                   base::RepeatingCallback<void(int)> callback,
                   const DialogModelMenuItem::Params& params =
                       DialogModelMenuItem::Params());

  // Adds a menu item at the end of the section.
  // TODO(pengchaocai): Refactor this method once dialog_model supports multiple
  // DialogModelSection, when the title would be an optional member of `this`
  // and explicitly adding it might not be needed.
  void AddTitleItem(std::u16string label,
                    ElementIdentifier id = ElementIdentifier());

  // Adds a separator at the end of the section.
  void AddSeparator();

  // Adds a labeled textfield (label: [text]) at the end of the section.
  void AddTextfield(ElementIdentifier id,
                    std::u16string label,
                    std::u16string text,
                    const DialogModelTextfield::Params& params =
                        DialogModelTextfield::Params());

  // Adds a labeled password field (label: [password field]) at the end of the
  // section.
  void AddPasswordField(ElementIdentifier id,
                        std::u16string label,
                        std::u16string accessible_text,
                        std::u16string incorrect_password_text,
                        const DialogModelPasswordField::Params& params =
                            DialogModelPasswordField::Params());

  // Adds a custom field at the end of the section. This is used to inject
  // framework-specific custom UI into dialogs that are otherwise constructed as
  // DialogModelBase derivatives.
  void AddCustomField(std::unique_ptr<DialogModelCustomField::Field> field,
                      ElementIdentifier id = ElementIdentifier());

 private:
  void AddField(std::unique_ptr<DialogModelField> field);
  void OnFieldChanged(DialogModelField* field);

  base::RepeatingCallbackList<void(DialogModelField*)> on_field_added_;
  base::RepeatingCallbackList<void(DialogModelField*)> on_field_changed_;

  std::vector<std::unique_ptr<DialogModelField>> fields_;

  std::vector<base::CallbackListSubscription> field_subscriptions_;
};

}  // namespace ui

#endif  // UI_BASE_MODELS_DIALOG_MODEL_FIELD_H_
