blob: 7a0f2b6753aac9f216b43cd6914cbcfd7f868587 [file] [log] [blame]
// Copyright 2020 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.
#ifndef COMPONENTS_FEED_CORE_V2_STREAM_MODEL_H_
#define COMPONENTS_FEED_CORE_V2_STREAM_MODEL_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/proto/v2/wire/content_id.pb.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/public/stream_type.h"
#include "components/feed/core/v2/stream_model/ephemeral_change.h"
#include "components/feed/core/v2/stream_model/feature_tree.h"
#include "components/feed/core/v2/types.h"
namespace feedwire {
class DataOperation;
} // namespace feedwire
namespace feed {
struct StreamModelUpdateRequest;
// An in-memory stream model.
class StreamModel {
public:
// Information about an update to the model.
struct UiUpdate {
struct SharedStateInfo {
// The shared state's unique ID.
std::string shared_state_id;
// Whether the shared state was just modified or added.
bool updated = false;
};
UiUpdate();
~UiUpdate();
UiUpdate(const UiUpdate&);
UiUpdate& operator=(const UiUpdate&);
// Whether the list of content has changed. Use
// |StreamModel::GetContentList()| to get the updated list of content.
bool content_list_changed = false;
// The list of shared states in the model.
std::vector<SharedStateInfo> shared_states;
};
struct StoreUpdate {
StoreUpdate();
~StoreUpdate();
StoreUpdate(StoreUpdate&&);
StoreUpdate& operator=(StoreUpdate&&);
StreamType stream_type;
// Sequence number to use when writing to the store.
int32_t sequence_number = 0;
// Whether the |update_request| should overwrite all stream data.
bool overwrite_stream_data = false;
// Data to write. Either a list of operations or a
// |StreamModelUpdateRequest|.
std::vector<feedstore::DataOperation> operations;
std::unique_ptr<StreamModelUpdateRequest> update_request;
};
class Observer : public base::CheckedObserver {
public:
// Called when the UI model changes.
virtual void OnUiUpdate(const UiUpdate& update) = 0;
};
class StoreObserver {
public:
// Called when the peristent store should be modified to reflect a model
// change.
virtual void OnStoreChange(StoreUpdate update) = 0;
};
StreamModel();
~StreamModel();
StreamModel(const StreamModel& src) = delete;
StreamModel& operator=(const StreamModel&) = delete;
void SetStreamType(const StreamType& stream_type);
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
void SetStoreObserver(StoreObserver* store_observer);
// Data access.
// Was this feed signed in.
bool signed_in() const { return stream_data_.signed_in(); }
// Is activity logging enabled?
bool logging_enabled() const { return stream_data_.logging_enabled(); }
// Has the privacy notice been fulfilled?
bool privacy_notice_fulfilled() const {
return stream_data_.privacy_notice_fulfilled();
}
// Returns the full list of content in the order it should be presented.
const std::vector<ContentRevision>& GetContentList() const {
return content_list_;
}
// Returns a list of all shared state IDs.
std::vector<std::string> GetSharedStateIds() const;
// Apply an update from the network or storage.
void Update(std::unique_ptr<StreamModelUpdateRequest> update_request);
// Returns the content identified by |ContentRevision|.
const feedstore::Content* FindContent(ContentRevision revision) const;
// Returns the ContentId of the content.
feedwire::ContentId FindContentId(ContentRevision revision) const;
// Returns the shared state data identified by |id|.
const std::string* FindSharedStateData(const std::string& id) const;
// Apply |operations| to the model.
void ExecuteOperations(std::vector<feedstore::DataOperation> operations);
// Create a temporary change that may be undone or committed later.
EphemeralChangeId CreateEphemeralChange(
std::vector<feedstore::DataOperation> operations);
// Commits a change. Returns false if the change does not exist.
bool CommitEphemeralChange(EphemeralChangeId id);
// Rejects a change. Returns false if the change does not exist.
bool RejectEphemeralChange(EphemeralChangeId id);
const std::string& GetNextPageToken() const;
// Time the client received this stream data. 'NextPage' requests do not
// change this time.
base::Time GetLastAddedTime() const;
// Returns a set of content IDs contained. This remains constant even
// after data operations or next-page requests.
ContentIdSet GetContentIds() const;
// Outputs a string representing the model state for debugging or testing.
std::string DumpStateForTesting();
// Returns true if one or more "cards" can be rendered from the content.
bool HasVisibleContent();
private:
struct SharedState {
// Whether the data has been changed since the last call to |OnUiUpdate()|.
bool updated = true;
std::string data;
};
// The final feature tree after applying any ephemeral changes.
// May link directly to |base_feature_tree_|.
stream_model::FeatureTree* GetFinalFeatureTree();
const stream_model::FeatureTree* GetFinalFeatureTree() const;
void UpdateFlattenedTree();
// The stream type for which this model is used. Used only for forwarding to
// observers.
StreamType stream_type_;
base::ObserverList<Observer> observers_;
StoreObserver* store_observer_ = nullptr; // Unowned.
stream_model::ContentMap content_map_;
stream_model::FeatureTree base_feature_tree_{&content_map_};
// |base_feature_tree_| with |ephemeral_changes_| applied.
// Null if there are no ephemeral changes.
std::unique_ptr<stream_model::FeatureTree> feature_tree_after_changes_;
stream_model::EphemeralChangeList ephemeral_changes_;
// The following data is associated with the stream, but lives outside of the
// tree.
feedstore::StreamData stream_data_;
base::flat_map<std::string, SharedState> shared_states_;
int32_t next_structure_sequence_number_ = 0;
// Current state of the flattened tree.
// Updated after each tree change.
std::vector<ContentRevision> content_list_;
};
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_STREAM_MODEL_H_