1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196

ash / public / cpp / holding_space / holding_space_model.h [blame]

// 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_
#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_

#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>

#include "ash/public/cpp/ash_public_export.h"
#include "ash/public/cpp/holding_space/holding_space_colors.h"
#include "ash/public/cpp/holding_space/holding_space_constants.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/holding_space/holding_space_progress.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "ui/color/color_id.h"

namespace base {
class FilePath;
}  // namespace base

namespace cros_styles {
enum class ColorName;
}  // namespace cros_styles

namespace ash {

class HoldingSpaceModelObserver;

// The data model for the temporary holding space UI. It contains the list of
// items that should be shown in the temporary holding space UI - each item will
// represent a piece of data added to the holding space by the user (for
// example, text, URLs, or images).
// The main goal of the class is to provide UI implementation agnostic
// information about items added to the holding space, and to provide an
// interface to propagate holding space changes between ash and Chrome.
class ASH_PUBLIC_EXPORT HoldingSpaceModel {
 public:
  using ItemList = std::vector<std::unique_ptr<HoldingSpaceItem>>;

  // A class which performs an atomic update of a single holding space item on
  // destruction, notifying model observers of the event if a change in state
  // did in fact occur.
  class ScopedItemUpdate {
   public:
    ScopedItemUpdate(const ScopedItemUpdate&) = delete;
    ScopedItemUpdate& operator=(const ScopedItemUpdate&) = delete;
    ~ScopedItemUpdate();

    // Sets the accessible name that should be used for the item and returns a
    // reference to `this`.
    ScopedItemUpdate& SetAccessibleName(
        const std::optional<std::u16string>& accessible_name);

    // Sets the backing file for the item and returns a reference to `this`.
    ScopedItemUpdate& SetBackingFile(const HoldingSpaceFile& file);

    // Sets the commands for an in-progress item which are shown in the item's
    // context menu and possibly, in the case of cancel/pause/resume, as
    // primary/secondary actions on the item view itself.
    ScopedItemUpdate& SetInProgressCommands(
        std::vector<HoldingSpaceItem::InProgressCommand> in_progress_commands);

    // Sets whether the image for the item should be forcibly invalidated and
    // returns a reference to `this`.
    ScopedItemUpdate& SetInvalidateImage(bool invalidate_image);

    // Sets the `progress` of the item and returns a reference to `this`.
    // NOTE: Only in-progress holding space items can be progressed.
    ScopedItemUpdate& SetProgress(const HoldingSpaceProgress& progress);

    // Sets the secondary text that should be shown for the item and returns a
    // reference to `this`.
    ScopedItemUpdate& SetSecondaryText(
        const std::optional<std::u16string>& secondary_text);

    // Sets the color variant for the secondary text that should be shown for
    // the item and returns a reference to `this`.
    ScopedItemUpdate& SetSecondaryTextColorVariant(
        const std::optional<HoldingSpaceColorVariant>&
            secondary_text_color_variant);

    // Sets the text that should be shown for the item and returns a reference
    // to `this`. If absent, the lossy display name of the backing file will be
    // used.
    ScopedItemUpdate& SetText(const std::optional<std::u16string>& text);

   private:
    friend class HoldingSpaceModel;
    ScopedItemUpdate(HoldingSpaceModel* model, HoldingSpaceItem* item);

    const raw_ptr<HoldingSpaceModel> model_;
    const raw_ptr<HoldingSpaceItem> item_;

    std::optional<std::optional<std::u16string>> accessible_name_;
    std::optional<HoldingSpaceFile> file_;
    std::optional<std::vector<HoldingSpaceItem::InProgressCommand>>
        in_progress_commands_;
    std::optional<HoldingSpaceProgress> progress_;
    std::optional<std::optional<std::u16string>> secondary_text_;
    std::optional<std::optional<HoldingSpaceColorVariant>>
        secondary_text_color_variant_;
    std::optional<std::optional<std::u16string>> text_;
    bool invalidate_image_ = false;
  };

  HoldingSpaceModel();
  HoldingSpaceModel(const HoldingSpaceModel& other) = delete;
  HoldingSpaceModel& operator=(const HoldingSpaceModel& other) = delete;
  ~HoldingSpaceModel();

  // Adds a single holding space item to the model.
  void AddItem(std::unique_ptr<HoldingSpaceItem> item);

  // Adds multiple holding space items to the model.
  void AddItems(std::vector<std::unique_ptr<HoldingSpaceItem>> items);

  // Removes a single holding space item from the model.
  void RemoveItem(const std::string& id);

  // Removes multiple holding space items from the model.
  void RemoveItems(const std::set<std::string>& ids);

  // Similar to `RemoveItem()` but returns the unique pointer to the removed
  // item. If the specified item does not exist in the model, returns `nullptr`.
  std::unique_ptr<HoldingSpaceItem> TakeItem(const std::string& id);

  // Fully initializes a partially initialized holding space item using the
  // provided `file`. The item will be removed if `file` system URL is empty.
  void InitializeOrRemoveItem(const std::string& id,
                              const HoldingSpaceFile& file);

  // Returns an object which, upon its destruction, performs an atomic update to
  // the holding space item associated with the specified `id`.
  std::unique_ptr<ScopedItemUpdate> UpdateItem(const std::string& id);

  // Removes all holding space items from the model for which the specified
  // `predicate` returns true. Returns the unique pointers to the items removed
  // from the model.
  using Predicate = base::RepeatingCallback<bool(const HoldingSpaceItem*)>;
  std::vector<std::unique_ptr<HoldingSpaceItem>> RemoveIf(Predicate predicate);

  // Invalidates image representations for items for which the specified
  // `predicate` returns true.
  void InvalidateItemImageIf(Predicate predicate);

  // Removes all the items from the model.
  void RemoveAll();

  // Gets a single holding space item.
  // Returns nullptr if the item does not exist in the model.
  const HoldingSpaceItem* GetItem(const std::string& id) const;

  // Gets a single holding space item with the specified `type` backed by the
  // specified `file_path`. Returns `nullptr` if the item does not exist in the
  // model.
  const HoldingSpaceItem* GetItem(HoldingSpaceItem::Type type,
                                  const base::FilePath& file_path) const;

  // Returns whether or not there exists a holding space item of the specified
  // `type` backed by the specified `file_path`.
  bool ContainsItem(HoldingSpaceItem::Type type,
                    const base::FilePath& file_path) const;

  // Returns `true` if the model contains any initialized items of the specified
  // `type`, `false` otherwise.
  bool ContainsInitializedItemOfType(HoldingSpaceItem::Type type) const;

  const ItemList& items() const { return items_; }

  void AddObserver(HoldingSpaceModelObserver* observer);
  void RemoveObserver(HoldingSpaceModelObserver* observer);

 private:
  // The list of items added to the model in the order they have been added to
  // the model.
  ItemList items_;

  // Caches the count of initialized items in the model for each holding space
  // item type. Used to quickly look up whether the model contains any
  // initialized items of a given type.
  std::map<HoldingSpaceItem::Type, size_t> initialized_item_counts_by_type_;

  base::ObserverList<HoldingSpaceModelObserver> observers_;
};

}  // namespace ash

#endif  // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_