Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: components/reading_list/ios/reading_list_model_impl.cc

Issue 2763233003: Move ReadingList model to components/reading_list/core (Closed)
Patch Set: last? Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #include "components/reading_list/ios/reading_list_model_impl.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/time/clock.h"
12 #include "components/prefs/pref_service.h"
13 #include "components/reading_list/ios/reading_list_model_storage.h"
14 #include "components/reading_list/ios/reading_list_pref_names.h"
15 #include "url/gurl.h"
16
17 ReadingListModelImpl::ReadingListModelImpl(
18 std::unique_ptr<ReadingListModelStorage> storage,
19 PrefService* pref_service,
20 std::unique_ptr<base::Clock> clock)
21 : entries_(base::MakeUnique<ReadingListEntries>()),
22 unread_entry_count_(0),
23 read_entry_count_(0),
24 unseen_entry_count_(0),
25 clock_(std::move(clock)),
26 pref_service_(pref_service),
27 has_unseen_(false),
28 loaded_(false),
29 weak_ptr_factory_(this) {
30 DCHECK(CalledOnValidThread());
31 DCHECK(clock_);
32 if (storage) {
33 storage_layer_ = std::move(storage);
34 storage_layer_->SetReadingListModel(this, this, clock_.get());
35 } else {
36 loaded_ = true;
37 }
38 has_unseen_ = GetPersistentHasUnseen();
39 }
40
41 ReadingListModelImpl::~ReadingListModelImpl() {}
42
43 void ReadingListModelImpl::StoreLoaded(
44 std::unique_ptr<ReadingListEntries> entries) {
45 DCHECK(CalledOnValidThread());
46 DCHECK(entries);
47 entries_ = std::move(entries);
48 for (auto& iterator : *entries_) {
49 UpdateEntryStateCountersOnEntryInsertion(iterator.second);
50 }
51 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size());
52 loaded_ = true;
53 for (auto& observer : observers_)
54 observer.ReadingListModelLoaded(this);
55 }
56
57 void ReadingListModelImpl::Shutdown() {
58 DCHECK(CalledOnValidThread());
59 for (auto& observer : observers_)
60 observer.ReadingListModelBeingDeleted(this);
61 loaded_ = false;
62 }
63
64 bool ReadingListModelImpl::loaded() const {
65 DCHECK(CalledOnValidThread());
66 return loaded_;
67 }
68
69 size_t ReadingListModelImpl::size() const {
70 DCHECK(CalledOnValidThread());
71 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size());
72 if (!loaded())
73 return 0;
74 return entries_->size();
75 }
76
77 size_t ReadingListModelImpl::unread_size() const {
78 DCHECK(CalledOnValidThread());
79 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size());
80 if (!loaded())
81 return 0;
82 return unread_entry_count_;
83 }
84
85 size_t ReadingListModelImpl::unseen_size() const {
86 DCHECK(CalledOnValidThread());
87 if (!loaded())
88 return 0;
89 return unseen_entry_count_;
90 }
91
92 void ReadingListModelImpl::SetUnseenFlag() {
93 if (!has_unseen_) {
94 has_unseen_ = true;
95 if (!IsPerformingBatchUpdates()) {
96 SetPersistentHasUnseen(true);
97 }
98 }
99 }
100
101 bool ReadingListModelImpl::GetLocalUnseenFlag() const {
102 DCHECK(CalledOnValidThread());
103 if (!loaded())
104 return false;
105 // If there are currently no unseen entries, return false even if has_unseen_
106 // is true.
107 // This is possible if the last unseen entry has be removed via sync.
108 return has_unseen_ && unseen_entry_count_;
109 }
110
111 void ReadingListModelImpl::ResetLocalUnseenFlag() {
112 DCHECK(CalledOnValidThread());
113 if (!loaded()) {
114 return;
115 }
116 has_unseen_ = false;
117 if (!IsPerformingBatchUpdates())
118 SetPersistentHasUnseen(false);
119 }
120
121 void ReadingListModelImpl::MarkAllSeen() {
122 DCHECK(CalledOnValidThread());
123 DCHECK(loaded());
124 if (unseen_entry_count_ == 0) {
125 return;
126 }
127 std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate>
128 model_batch_updates = BeginBatchUpdates();
129 for (auto& iterator : *entries_) {
130 ReadingListEntry& entry = iterator.second;
131 if (entry.HasBeenSeen()) {
132 continue;
133 }
134 for (auto& observer : observers_) {
135 observer.ReadingListWillUpdateEntry(this, iterator.first);
136 }
137 UpdateEntryStateCountersOnEntryRemoval(entry);
138 entry.SetRead(false, clock_->Now());
139 UpdateEntryStateCountersOnEntryInsertion(entry);
140 if (storage_layer_) {
141 storage_layer_->SaveEntry(entry);
142 }
143 for (auto& observer : observers_) {
144 observer.ReadingListDidApplyChanges(this);
145 }
146 }
147 DCHECK(unseen_entry_count_ == 0);
148 }
149
150 bool ReadingListModelImpl::DeleteAllEntries() {
151 DCHECK(CalledOnValidThread());
152 if (!loaded()) {
153 return false;
154 }
155 auto scoped_model_batch_updates = BeginBatchUpdates();
156 for (const auto& url : Keys()) {
157 RemoveEntryByURL(url);
158 }
159 return entries_->empty();
160 }
161
162 void ReadingListModelImpl::UpdateEntryStateCountersOnEntryRemoval(
163 const ReadingListEntry& entry) {
164 if (!entry.HasBeenSeen()) {
165 unseen_entry_count_--;
166 }
167 if (entry.IsRead()) {
168 read_entry_count_--;
169 } else {
170 unread_entry_count_--;
171 }
172 }
173
174 void ReadingListModelImpl::UpdateEntryStateCountersOnEntryInsertion(
175 const ReadingListEntry& entry) {
176 if (!entry.HasBeenSeen()) {
177 unseen_entry_count_++;
178 }
179 if (entry.IsRead()) {
180 read_entry_count_++;
181 } else {
182 unread_entry_count_++;
183 }
184 }
185
186 const std::vector<GURL> ReadingListModelImpl::Keys() const {
187 std::vector<GURL> keys;
188 for (const auto& iterator : *entries_) {
189 keys.push_back(iterator.first);
190 }
191 return keys;
192 }
193
194 const ReadingListEntry* ReadingListModelImpl::GetEntryByURL(
195 const GURL& gurl) const {
196 DCHECK(CalledOnValidThread());
197 DCHECK(loaded());
198 return GetMutableEntryFromURL(gurl);
199 }
200
201 const ReadingListEntry* ReadingListModelImpl::GetFirstUnreadEntry(
202 bool distilled) const {
203 DCHECK(CalledOnValidThread());
204 DCHECK(loaded());
205 if (unread_entry_count_ == 0) {
206 return nullptr;
207 }
208 int64_t update_time_all = 0;
209 const ReadingListEntry* first_entry_all = nullptr;
210 int64_t update_time_distilled = 0;
211 const ReadingListEntry* first_entry_distilled = nullptr;
212 for (auto& iterator : *entries_) {
213 ReadingListEntry& entry = iterator.second;
214 if (entry.IsRead()) {
215 continue;
216 }
217 if (entry.UpdateTime() > update_time_all) {
218 update_time_all = entry.UpdateTime();
219 first_entry_all = &entry;
220 }
221 if (entry.DistilledState() == ReadingListEntry::PROCESSED &&
222 entry.UpdateTime() > update_time_distilled) {
223 update_time_distilled = entry.UpdateTime();
224 first_entry_distilled = &entry;
225 }
226 }
227 DCHECK(first_entry_all);
228 DCHECK_GT(update_time_all, 0);
229 if (distilled && first_entry_distilled) {
230 return first_entry_distilled;
231 }
232 return first_entry_all;
233 }
234
235 ReadingListEntry* ReadingListModelImpl::GetMutableEntryFromURL(
236 const GURL& url) const {
237 DCHECK(CalledOnValidThread());
238 DCHECK(loaded());
239 auto iterator = entries_->find(url);
240 if (iterator == entries_->end()) {
241 return nullptr;
242 }
243 return &(iterator->second);
244 }
245
246 void ReadingListModelImpl::SyncAddEntry(
247 std::unique_ptr<ReadingListEntry> entry) {
248 DCHECK(CalledOnValidThread());
249 DCHECK(loaded());
250 // entry must not already exist.
251 DCHECK(GetMutableEntryFromURL(entry->URL()) == nullptr);
252 for (auto& observer : observers_)
253 observer.ReadingListWillAddEntry(this, *entry);
254 UpdateEntryStateCountersOnEntryInsertion(*entry);
255 if (!entry->HasBeenSeen()) {
256 SetUnseenFlag();
257 }
258 GURL url = entry->URL();
259 entries_->insert(std::make_pair(url, std::move(*entry)));
260 for (auto& observer : observers_) {
261 observer.ReadingListDidAddEntry(this, url, reading_list::ADDED_VIA_SYNC);
262 observer.ReadingListDidApplyChanges(this);
263 }
264 }
265
266 ReadingListEntry* ReadingListModelImpl::SyncMergeEntry(
267 std::unique_ptr<ReadingListEntry> entry) {
268 DCHECK(CalledOnValidThread());
269 DCHECK(loaded());
270 ReadingListEntry* existing_entry = GetMutableEntryFromURL(entry->URL());
271 DCHECK(existing_entry);
272 GURL url = entry->URL();
273
274 for (auto& observer : observers_)
275 observer.ReadingListWillMoveEntry(this, url);
276
277 bool was_seen = existing_entry->HasBeenSeen();
278 UpdateEntryStateCountersOnEntryRemoval(*existing_entry);
279 existing_entry->MergeWithEntry(*entry);
280 existing_entry = GetMutableEntryFromURL(url);
281 UpdateEntryStateCountersOnEntryInsertion(*existing_entry);
282 if (was_seen && !existing_entry->HasBeenSeen()) {
283 // Only set the flag if a new unseen entry is added.
284 SetUnseenFlag();
285 }
286 for (auto& observer : observers_) {
287 observer.ReadingListDidMoveEntry(this, url);
288 observer.ReadingListDidApplyChanges(this);
289 }
290
291 return existing_entry;
292 }
293
294 void ReadingListModelImpl::SyncRemoveEntry(const GURL& url) {
295 RemoveEntryByURLImpl(url, true);
296 }
297
298 void ReadingListModelImpl::RemoveEntryByURL(const GURL& url) {
299 RemoveEntryByURLImpl(url, false);
300 }
301
302 void ReadingListModelImpl::RemoveEntryByURLImpl(const GURL& url,
303 bool from_sync) {
304 DCHECK(CalledOnValidThread());
305 DCHECK(loaded());
306 const ReadingListEntry* entry = GetEntryByURL(url);
307 if (!entry)
308 return;
309
310 for (auto& observer : observers_)
311 observer.ReadingListWillRemoveEntry(this, url);
312
313 if (storage_layer_ && !from_sync) {
314 storage_layer_->RemoveEntry(*entry);
315 }
316 UpdateEntryStateCountersOnEntryRemoval(*entry);
317
318 entries_->erase(url);
319 for (auto& observer : observers_)
320 observer.ReadingListDidApplyChanges(this);
321 }
322
323 const ReadingListEntry& ReadingListModelImpl::AddEntry(
324 const GURL& url,
325 const std::string& title,
326 reading_list::EntrySource source) {
327 DCHECK(CalledOnValidThread());
328 DCHECK(loaded());
329 DCHECK(url.SchemeIsHTTPOrHTTPS());
330 RemoveEntryByURL(url);
331
332 std::string trimmed_title = base::CollapseWhitespaceASCII(title, false);
333
334 ReadingListEntry entry(url, trimmed_title, clock_->Now());
335 for (auto& observer : observers_)
336 observer.ReadingListWillAddEntry(this, entry);
337 UpdateEntryStateCountersOnEntryInsertion(entry);
338 SetUnseenFlag();
339 entries_->insert(std::make_pair(url, std::move(entry)));
340
341 if (storage_layer_) {
342 storage_layer_->SaveEntry(*GetEntryByURL(url));
343 }
344
345 for (auto& observer : observers_) {
346 observer.ReadingListDidAddEntry(this, url, source);
347 observer.ReadingListDidApplyChanges(this);
348 }
349
350 return entries_->at(url);
351 }
352
353 void ReadingListModelImpl::SetReadStatus(const GURL& url, bool read) {
354 DCHECK(CalledOnValidThread());
355 DCHECK(loaded());
356 auto iterator = entries_->find(url);
357 if (iterator == entries_->end()) {
358 return;
359 }
360 ReadingListEntry& entry = iterator->second;
361 if (entry.IsRead() == read) {
362 return;
363 }
364 for (ReadingListModelObserver& observer : observers_) {
365 observer.ReadingListWillMoveEntry(this, url);
366 }
367 UpdateEntryStateCountersOnEntryRemoval(entry);
368 entry.SetRead(read, clock_->Now());
369 entry.MarkEntryUpdated(clock_->Now());
370 UpdateEntryStateCountersOnEntryInsertion(entry);
371
372 if (storage_layer_) {
373 storage_layer_->SaveEntry(entry);
374 }
375 for (ReadingListModelObserver& observer : observers_) {
376 observer.ReadingListDidMoveEntry(this, url);
377 observer.ReadingListDidApplyChanges(this);
378 }
379 }
380
381 void ReadingListModelImpl::SetEntryTitle(const GURL& url,
382 const std::string& title) {
383 DCHECK(CalledOnValidThread());
384 DCHECK(loaded());
385 auto iterator = entries_->find(url);
386 if (iterator == entries_->end()) {
387 return;
388 }
389 ReadingListEntry& entry = iterator->second;
390 std::string trimmed_title = base::CollapseWhitespaceASCII(title, false);
391 if (entry.Title() == trimmed_title) {
392 return;
393 }
394
395 for (ReadingListModelObserver& observer : observers_) {
396 observer.ReadingListWillUpdateEntry(this, url);
397 }
398 entry.SetTitle(trimmed_title, clock_->Now());
399 if (storage_layer_) {
400 storage_layer_->SaveEntry(entry);
401 }
402 for (ReadingListModelObserver& observer : observers_) {
403 observer.ReadingListDidApplyChanges(this);
404 }
405 }
406
407 void ReadingListModelImpl::SetEntryDistilledInfo(
408 const GURL& url,
409 const base::FilePath& distilled_path,
410 const GURL& distilled_url,
411 int64_t distillation_size,
412 const base::Time& distillation_date) {
413 DCHECK(CalledOnValidThread());
414 DCHECK(loaded());
415 auto iterator = entries_->find(url);
416 if (iterator == entries_->end()) {
417 return;
418 }
419 ReadingListEntry& entry = iterator->second;
420 if (entry.DistilledState() == ReadingListEntry::PROCESSED &&
421 entry.DistilledPath() == distilled_path) {
422 return;
423 }
424
425 for (ReadingListModelObserver& observer : observers_) {
426 observer.ReadingListWillUpdateEntry(this, url);
427 }
428 entry.SetDistilledInfo(distilled_path, distilled_url, distillation_size,
429 distillation_date);
430 if (storage_layer_) {
431 storage_layer_->SaveEntry(entry);
432 }
433 for (ReadingListModelObserver& observer : observers_) {
434 observer.ReadingListDidApplyChanges(this);
435 }
436 }
437
438 void ReadingListModelImpl::SetEntryDistilledState(
439 const GURL& url,
440 ReadingListEntry::DistillationState state) {
441 DCHECK(CalledOnValidThread());
442 DCHECK(loaded());
443 auto iterator = entries_->find(url);
444 if (iterator == entries_->end()) {
445 return;
446 }
447 ReadingListEntry& entry = iterator->second;
448 if (entry.DistilledState() == state) {
449 return;
450 }
451
452 for (ReadingListModelObserver& observer : observers_) {
453 observer.ReadingListWillUpdateEntry(this, url);
454 }
455 entry.SetDistilledState(state);
456 if (storage_layer_) {
457 storage_layer_->SaveEntry(entry);
458 }
459 for (ReadingListModelObserver& observer : observers_) {
460 observer.ReadingListDidApplyChanges(this);
461 }
462 }
463
464 std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate>
465 ReadingListModelImpl::CreateBatchToken() {
466 return base::MakeUnique<ReadingListModelImpl::ScopedReadingListBatchUpdate>(
467 this);
468 }
469
470 ReadingListModelImpl::ScopedReadingListBatchUpdate::
471 ScopedReadingListBatchUpdate(ReadingListModelImpl* model)
472 : ReadingListModel::ScopedReadingListBatchUpdate::
473 ScopedReadingListBatchUpdate(model) {
474 if (model->StorageLayer()) {
475 storage_token_ = model->StorageLayer()->EnsureBatchCreated();
476 }
477 }
478
479 ReadingListModelImpl::ScopedReadingListBatchUpdate::
480 ~ScopedReadingListBatchUpdate() {
481 storage_token_.reset();
482 }
483
484 void ReadingListModelImpl::LeavingBatchUpdates() {
485 DCHECK(CalledOnValidThread());
486 if (storage_layer_) {
487 SetPersistentHasUnseen(has_unseen_);
488 }
489 ReadingListModel::LeavingBatchUpdates();
490 }
491
492 void ReadingListModelImpl::EnteringBatchUpdates() {
493 DCHECK(CalledOnValidThread());
494 ReadingListModel::EnteringBatchUpdates();
495 }
496
497 void ReadingListModelImpl::SetPersistentHasUnseen(bool has_unseen) {
498 DCHECK(CalledOnValidThread());
499 if (!pref_service_) {
500 return;
501 }
502 pref_service_->SetBoolean(reading_list::prefs::kReadingListHasUnseenEntries,
503 has_unseen);
504 }
505
506 bool ReadingListModelImpl::GetPersistentHasUnseen() {
507 DCHECK(CalledOnValidThread());
508 if (!pref_service_) {
509 return false;
510 }
511 return pref_service_->GetBoolean(
512 reading_list::prefs::kReadingListHasUnseenEntries);
513 }
514
515 syncer::ModelTypeSyncBridge* ReadingListModelImpl::GetModelTypeSyncBridge() {
516 if (!storage_layer_)
517 return nullptr;
518 return storage_layer_.get();
519 }
520
521 ReadingListModelStorage* ReadingListModelImpl::StorageLayer() {
522 return storage_layer_.get();
523 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698