| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/reading_list/ios/reading_list_model_impl.h" | 5 #include "components/reading_list/ios/reading_list_model_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| 11 #include "components/prefs/pref_service.h" | 11 #include "components/prefs/pref_service.h" |
| 12 #include "components/reading_list/ios/reading_list_model_storage.h" | 12 #include "components/reading_list/ios/reading_list_model_storage.h" |
| 13 #include "components/reading_list/ios/reading_list_pref_names.h" | 13 #include "components/reading_list/ios/reading_list_pref_names.h" |
| 14 #include "url/gurl.h" | 14 #include "url/gurl.h" |
| 15 | 15 |
| 16 ReadingListModelImpl::Cache::Cache() | |
| 17 : read_entries(std::vector<GURL>()), | |
| 18 unread_entries(std::vector<GURL>()), | |
| 19 dirty(false) {} | |
| 20 | |
| 21 ReadingListModelImpl::Cache::~Cache() {} | |
| 22 | |
| 23 ReadingListModelImpl::ReadingListModelImpl() | 16 ReadingListModelImpl::ReadingListModelImpl() |
| 24 : ReadingListModelImpl(nullptr, nullptr) {} | 17 : ReadingListModelImpl(nullptr, nullptr) {} |
| 25 | 18 |
| 26 ReadingListModelImpl::ReadingListModelImpl( | 19 ReadingListModelImpl::ReadingListModelImpl( |
| 27 std::unique_ptr<ReadingListModelStorage> storage, | 20 std::unique_ptr<ReadingListModelStorage> storage, |
| 28 PrefService* pref_service) | 21 PrefService* pref_service) |
| 29 : unread_entry_count_(0), | 22 : unread_entry_count_(0), |
| 30 read_entry_count_(0), | 23 read_entry_count_(0), |
| 31 cache_(base::MakeUnique<struct Cache>()), | |
| 32 pref_service_(pref_service), | 24 pref_service_(pref_service), |
| 33 has_unseen_(false), | 25 has_unseen_(false), |
| 34 loaded_(false), | 26 loaded_(false), |
| 35 weak_ptr_factory_(this) { | 27 weak_ptr_factory_(this) { |
| 36 DCHECK(CalledOnValidThread()); | 28 DCHECK(CalledOnValidThread()); |
| 37 if (storage) { | 29 if (storage) { |
| 38 storage_layer_ = std::move(storage); | 30 storage_layer_ = std::move(storage); |
| 39 storage_layer_->SetReadingListModel(this, this); | 31 storage_layer_->SetReadingListModel(this, this); |
| 40 } else { | 32 } else { |
| 41 loaded_ = true; | 33 loaded_ = true; |
| 42 entries_ = base::MakeUnique<ReadingListEntries>(); | 34 entries_ = base::MakeUnique<ReadingListEntries>(); |
| 43 cache_->dirty = true; | |
| 44 } | 35 } |
| 45 has_unseen_ = GetPersistentHasUnseen(); | 36 has_unseen_ = GetPersistentHasUnseen(); |
| 46 } | 37 } |
| 47 | 38 |
| 48 ReadingListModelImpl::~ReadingListModelImpl() {} | 39 ReadingListModelImpl::~ReadingListModelImpl() {} |
| 49 | 40 |
| 50 void ReadingListModelImpl::StoreLoaded( | 41 void ReadingListModelImpl::StoreLoaded( |
| 51 std::unique_ptr<ReadingListEntries> entries) { | 42 std::unique_ptr<ReadingListEntries> entries) { |
| 52 DCHECK(CalledOnValidThread()); | 43 DCHECK(CalledOnValidThread()); |
| 53 entries_ = std::move(entries); | 44 entries_ = std::move(entries); |
| 54 cache_->dirty = true; | |
| 55 for (auto& iterator : *entries_) { | 45 for (auto& iterator : *entries_) { |
| 56 if (iterator.second.IsRead()) { | 46 if (iterator.second.IsRead()) { |
| 57 read_entry_count_++; | 47 read_entry_count_++; |
| 58 } else { | 48 } else { |
| 59 unread_entry_count_++; | 49 unread_entry_count_++; |
| 60 } | 50 } |
| 61 } | 51 } |
| 62 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size()); | 52 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size()); |
| 63 loaded_ = true; | 53 loaded_ = true; |
| 64 for (auto& observer : observers_) | 54 for (auto& observer : observers_) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 86 } | 76 } |
| 87 | 77 |
| 88 size_t ReadingListModelImpl::unread_size() const { | 78 size_t ReadingListModelImpl::unread_size() const { |
| 89 DCHECK(CalledOnValidThread()); | 79 DCHECK(CalledOnValidThread()); |
| 90 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size()); | 80 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size()); |
| 91 if (!loaded()) | 81 if (!loaded()) |
| 92 return 0; | 82 return 0; |
| 93 return unread_entry_count_; | 83 return unread_entry_count_; |
| 94 } | 84 } |
| 95 | 85 |
| 96 size_t ReadingListModelImpl::read_size() const { | |
| 97 DCHECK(CalledOnValidThread()); | |
| 98 DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size()); | |
| 99 if (!loaded()) | |
| 100 return 0; | |
| 101 return read_entry_count_; | |
| 102 } | |
| 103 | |
| 104 bool ReadingListModelImpl::HasUnseenEntries() const { | 86 bool ReadingListModelImpl::HasUnseenEntries() const { |
| 105 DCHECK(CalledOnValidThread()); | 87 DCHECK(CalledOnValidThread()); |
| 106 if (!loaded()) | 88 if (!loaded()) |
| 107 return false; | 89 return false; |
| 108 return unread_entry_count_ > 0 && has_unseen_; | 90 return unread_entry_count_ > 0 && has_unseen_; |
| 109 } | 91 } |
| 110 | 92 |
| 111 void ReadingListModelImpl::ResetUnseenEntries() { | 93 void ReadingListModelImpl::ResetUnseenEntries() { |
| 112 DCHECK(CalledOnValidThread()); | 94 DCHECK(CalledOnValidThread()); |
| 113 DCHECK(loaded()); | 95 DCHECK(loaded()); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 124 return keys; | 106 return keys; |
| 125 } | 107 } |
| 126 | 108 |
| 127 const ReadingListEntry* ReadingListModelImpl::GetEntryByURL( | 109 const ReadingListEntry* ReadingListModelImpl::GetEntryByURL( |
| 128 const GURL& gurl) const { | 110 const GURL& gurl) const { |
| 129 DCHECK(CalledOnValidThread()); | 111 DCHECK(CalledOnValidThread()); |
| 130 DCHECK(loaded()); | 112 DCHECK(loaded()); |
| 131 return GetMutableEntryFromURL(gurl); | 113 return GetMutableEntryFromURL(gurl); |
| 132 } | 114 } |
| 133 | 115 |
| 134 const ReadingListEntry& ReadingListModelImpl::GetReadEntryAtIndex( | |
| 135 size_t index) const { | |
| 136 DCHECK(CalledOnValidThread()); | |
| 137 DCHECK(loaded()); | |
| 138 DCHECK(index < read_entry_count_); | |
| 139 if (cache_->dirty) { | |
| 140 RebuildIndex(); | |
| 141 } | |
| 142 return *GetEntryByURL(cache_->read_entries[index]); | |
| 143 } | |
| 144 | |
| 145 const ReadingListEntry& ReadingListModelImpl::GetUnreadEntryAtIndex( | |
| 146 size_t index) const { | |
| 147 DCHECK(CalledOnValidThread()); | |
| 148 DCHECK(loaded()); | |
| 149 DCHECK(index < unread_entry_count_); | |
| 150 if (cache_->dirty) { | |
| 151 RebuildIndex(); | |
| 152 } | |
| 153 return *GetEntryByURL(cache_->unread_entries[index]); | |
| 154 } | |
| 155 | |
| 156 void ReadingListModelImpl::RebuildIndex() const { | |
| 157 DCHECK(CalledOnValidThread()); | |
| 158 DCHECK(loaded()); | |
| 159 if (!cache_->dirty) { | |
| 160 return; | |
| 161 } | |
| 162 cache_->dirty = false; | |
| 163 cache_->read_entries.clear(); | |
| 164 cache_->unread_entries.clear(); | |
| 165 for (auto& iterator : *entries_) { | |
| 166 if (iterator.second.IsRead()) { | |
| 167 cache_->read_entries.push_back(iterator.first); | |
| 168 } else { | |
| 169 cache_->unread_entries.push_back(iterator.first); | |
| 170 } | |
| 171 } | |
| 172 DCHECK(read_entry_count_ == cache_->read_entries.size()); | |
| 173 DCHECK(unread_entry_count_ == cache_->unread_entries.size()); | |
| 174 std::sort(cache_->read_entries.begin(), cache_->read_entries.end(), | |
| 175 [this](const GURL& left_url, const GURL& right_url) { | |
| 176 return this->entries_->at(left_url).UpdateTime() > | |
| 177 this->entries_->at(right_url).UpdateTime(); | |
| 178 }); | |
| 179 std::sort(cache_->unread_entries.begin(), cache_->unread_entries.end(), | |
| 180 [this](const GURL& left_url, const GURL& right_url) { | |
| 181 return this->entries_->at(left_url).UpdateTime() > | |
| 182 this->entries_->at(right_url).UpdateTime(); | |
| 183 }); | |
| 184 } | |
| 185 | |
| 186 ReadingListEntry* ReadingListModelImpl::GetMutableEntryFromURL( | 116 ReadingListEntry* ReadingListModelImpl::GetMutableEntryFromURL( |
| 187 const GURL& url) const { | 117 const GURL& url) const { |
| 188 DCHECK(CalledOnValidThread()); | 118 DCHECK(CalledOnValidThread()); |
| 189 DCHECK(loaded()); | 119 DCHECK(loaded()); |
| 190 auto iterator = entries_->find(url); | 120 auto iterator = entries_->find(url); |
| 191 if (iterator == entries_->end()) { | 121 if (iterator == entries_->end()) { |
| 192 return nullptr; | 122 return nullptr; |
| 193 } | 123 } |
| 194 return &(iterator->second); | 124 return &(iterator->second); |
| 195 } | 125 } |
| 196 | 126 |
| 197 void ReadingListModelImpl::SyncAddEntry( | 127 void ReadingListModelImpl::SyncAddEntry( |
| 198 std::unique_ptr<ReadingListEntry> entry) { | 128 std::unique_ptr<ReadingListEntry> entry) { |
| 199 DCHECK(CalledOnValidThread()); | 129 DCHECK(CalledOnValidThread()); |
| 200 DCHECK(loaded()); | 130 DCHECK(loaded()); |
| 201 // entry must not already exist. | 131 // entry must not already exist. |
| 202 DCHECK(GetMutableEntryFromURL(entry->URL()) == nullptr); | 132 DCHECK(GetMutableEntryFromURL(entry->URL()) == nullptr); |
| 203 for (auto& observer : observers_) | 133 for (auto& observer : observers_) |
| 204 observer.ReadingListWillAddEntry(this, *entry); | 134 observer.ReadingListWillAddEntry(this, *entry); |
| 205 if (entry->IsRead()) { | 135 if (entry->IsRead()) { |
| 206 read_entry_count_++; | 136 read_entry_count_++; |
| 207 } else { | 137 } else { |
| 208 unread_entry_count_++; | 138 unread_entry_count_++; |
| 209 SetPersistentHasUnseen(true); | 139 SetPersistentHasUnseen(true); |
| 210 } | 140 } |
| 211 GURL url = entry->URL(); | 141 GURL url = entry->URL(); |
| 212 entries_->insert(std::make_pair(url, std::move(*entry))); | 142 entries_->insert(std::make_pair(url, std::move(*entry))); |
| 213 cache_->dirty = true; | |
| 214 for (auto& observer : observers_) { | 143 for (auto& observer : observers_) { |
| 215 observer.ReadingListDidAddEntry(this, url); | 144 observer.ReadingListDidAddEntry(this, url); |
| 216 observer.ReadingListDidApplyChanges(this); | 145 observer.ReadingListDidApplyChanges(this); |
| 217 } | 146 } |
| 218 } | 147 } |
| 219 | 148 |
| 220 ReadingListEntry* ReadingListModelImpl::SyncMergeEntry( | 149 ReadingListEntry* ReadingListModelImpl::SyncMergeEntry( |
| 221 std::unique_ptr<ReadingListEntry> entry) { | 150 std::unique_ptr<ReadingListEntry> entry) { |
| 222 DCHECK(CalledOnValidThread()); | 151 DCHECK(CalledOnValidThread()); |
| 223 DCHECK(loaded()); | 152 DCHECK(loaded()); |
| 224 ReadingListEntry* existing_entry = GetMutableEntryFromURL(entry->URL()); | 153 ReadingListEntry* existing_entry = GetMutableEntryFromURL(entry->URL()); |
| 225 DCHECK(existing_entry); | 154 DCHECK(existing_entry); |
| 226 DCHECK(existing_entry->UpdateTime() < entry->UpdateTime()); | 155 DCHECK(existing_entry->UpdateTime() < entry->UpdateTime()); |
| 227 | 156 |
| 228 GURL url = entry->URL(); | 157 GURL url = entry->URL(); |
| 229 | 158 |
| 230 for (auto& observer : observers_) | 159 for (auto& observer : observers_) |
| 231 observer.ReadingListWillMoveEntry(this, url); | 160 observer.ReadingListWillMoveEntry(this, url); |
| 232 | 161 |
| 233 if (existing_entry->IsRead()) { | 162 if (existing_entry->IsRead()) { |
| 234 read_entry_count_--; | 163 read_entry_count_--; |
| 235 } else { | 164 } else { |
| 236 unread_entry_count_--; | 165 unread_entry_count_--; |
| 237 } | 166 } |
| 238 // Merge local data in new entry. | 167 // Merge local data in new entry. |
| 239 entry->MergeLocalStateFrom(*existing_entry); | 168 entry->MergeLocalStateFrom(*existing_entry); |
| 240 | 169 |
| 241 entries_->find(url)->second = std::move(*entry); | 170 entries_->find(url)->second = std::move(*entry); |
| 242 cache_->dirty = true; | |
| 243 | 171 |
| 244 existing_entry = GetMutableEntryFromURL(url); | 172 existing_entry = GetMutableEntryFromURL(url); |
| 245 if (existing_entry->IsRead()) { | 173 if (existing_entry->IsRead()) { |
| 246 read_entry_count_++; | 174 read_entry_count_++; |
| 247 } else { | 175 } else { |
| 248 unread_entry_count_++; | 176 unread_entry_count_++; |
| 249 } | 177 } |
| 250 for (auto& observer : observers_) | 178 for (auto& observer : observers_) |
| 251 observer.ReadingListDidApplyChanges(this); | 179 observer.ReadingListDidApplyChanges(this); |
| 252 return existing_entry; | 180 return existing_entry; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 273 | 201 |
| 274 if (storage_layer_ && !from_sync) { | 202 if (storage_layer_ && !from_sync) { |
| 275 storage_layer_->RemoveEntry(*entry); | 203 storage_layer_->RemoveEntry(*entry); |
| 276 } | 204 } |
| 277 if (entry->IsRead()) { | 205 if (entry->IsRead()) { |
| 278 read_entry_count_--; | 206 read_entry_count_--; |
| 279 } else { | 207 } else { |
| 280 unread_entry_count_--; | 208 unread_entry_count_--; |
| 281 } | 209 } |
| 282 entries_->erase(url); | 210 entries_->erase(url); |
| 283 cache_->dirty = true; | |
| 284 for (auto& observer : observers_) | 211 for (auto& observer : observers_) |
| 285 observer.ReadingListDidApplyChanges(this); | 212 observer.ReadingListDidApplyChanges(this); |
| 286 } | 213 } |
| 287 | 214 |
| 288 const ReadingListEntry& ReadingListModelImpl::AddEntry( | 215 const ReadingListEntry& ReadingListModelImpl::AddEntry( |
| 289 const GURL& url, | 216 const GURL& url, |
| 290 const std::string& title) { | 217 const std::string& title) { |
| 291 DCHECK(CalledOnValidThread()); | 218 DCHECK(CalledOnValidThread()); |
| 292 DCHECK(loaded()); | 219 DCHECK(loaded()); |
| 293 RemoveEntryByURL(url); | 220 RemoveEntryByURL(url); |
| 294 | 221 |
| 295 std::string trimmedTitle(title); | 222 std::string trimmedTitle(title); |
| 296 base::TrimWhitespaceASCII(trimmedTitle, base::TRIM_ALL, &trimmedTitle); | 223 base::TrimWhitespaceASCII(trimmedTitle, base::TRIM_ALL, &trimmedTitle); |
| 297 | 224 |
| 298 ReadingListEntry entry(url, trimmedTitle); | 225 ReadingListEntry entry(url, trimmedTitle); |
| 299 for (auto& observer : observers_) | 226 for (auto& observer : observers_) |
| 300 observer.ReadingListWillAddEntry(this, entry); | 227 observer.ReadingListWillAddEntry(this, entry); |
| 301 has_unseen_ = true; | 228 has_unseen_ = true; |
| 302 SetPersistentHasUnseen(true); | 229 SetPersistentHasUnseen(true); |
| 303 entries_->insert(std::make_pair(url, std::move(entry))); | 230 entries_->insert(std::make_pair(url, std::move(entry))); |
| 304 unread_entry_count_++; | 231 unread_entry_count_++; |
| 305 if (storage_layer_) { | 232 if (storage_layer_) { |
| 306 storage_layer_->SaveEntry(*GetEntryByURL(url)); | 233 storage_layer_->SaveEntry(*GetEntryByURL(url)); |
| 307 } | 234 } |
| 308 cache_->dirty = true; | |
| 309 | 235 |
| 310 for (auto& observer : observers_) { | 236 for (auto& observer : observers_) { |
| 311 observer.ReadingListDidAddEntry(this, url); | 237 observer.ReadingListDidAddEntry(this, url); |
| 312 observer.ReadingListDidApplyChanges(this); | 238 observer.ReadingListDidApplyChanges(this); |
| 313 } | 239 } |
| 314 | 240 |
| 315 return entries_->at(url); | 241 return entries_->at(url); |
| 316 } | 242 } |
| 317 | 243 |
| 318 void ReadingListModelImpl::MarkReadByURL(const GURL& url) { | |
| 319 return SetReadStatus(url, true); | |
| 320 } | |
| 321 | |
| 322 void ReadingListModelImpl::MarkUnreadByURL(const GURL& url) { | |
| 323 return SetReadStatus(url, false); | |
| 324 } | |
| 325 | |
| 326 void ReadingListModelImpl::SetReadStatus(const GURL& url, bool read) { | 244 void ReadingListModelImpl::SetReadStatus(const GURL& url, bool read) { |
| 327 DCHECK(CalledOnValidThread()); | 245 DCHECK(CalledOnValidThread()); |
| 328 DCHECK(loaded()); | 246 DCHECK(loaded()); |
| 329 auto iterator = entries_->find(url); | 247 auto iterator = entries_->find(url); |
| 330 if (iterator == entries_->end()) { | 248 if (iterator == entries_->end()) { |
| 331 return; | 249 return; |
| 332 } | 250 } |
| 333 ReadingListEntry& entry = iterator->second; | 251 ReadingListEntry& entry = iterator->second; |
| 334 if (entry.IsRead() == read) { | 252 if (entry.IsRead() == read) { |
| 335 return; | 253 return; |
| 336 } | 254 } |
| 337 for (ReadingListModelObserver& observer : observers_) { | 255 for (ReadingListModelObserver& observer : observers_) { |
| 338 observer.ReadingListWillMoveEntry(this, url); | 256 observer.ReadingListWillMoveEntry(this, url); |
| 339 } | 257 } |
| 340 if (read) { | 258 if (read) { |
| 341 read_entry_count_++; | 259 read_entry_count_++; |
| 342 unread_entry_count_--; | 260 unread_entry_count_--; |
| 343 } else { | 261 } else { |
| 344 unread_entry_count_++; | 262 unread_entry_count_++; |
| 345 read_entry_count_--; | 263 read_entry_count_--; |
| 346 } | 264 } |
| 347 entry.SetRead(read); | 265 entry.SetRead(read); |
| 348 entry.MarkEntryUpdated(); | 266 entry.MarkEntryUpdated(); |
| 349 cache_->dirty = true; | |
| 350 if (storage_layer_) { | 267 if (storage_layer_) { |
| 351 storage_layer_->SaveEntry(entry); | 268 storage_layer_->SaveEntry(entry); |
| 352 } | 269 } |
| 353 for (ReadingListModelObserver& observer : observers_) { | 270 for (ReadingListModelObserver& observer : observers_) { |
| 354 observer.ReadingListDidApplyChanges(this); | 271 observer.ReadingListDidApplyChanges(this); |
| 355 } | 272 } |
| 356 } | 273 } |
| 357 | 274 |
| 358 void ReadingListModelImpl::SetEntryTitle(const GURL& url, | 275 void ReadingListModelImpl::SetEntryTitle(const GURL& url, |
| 359 const std::string& title) { | 276 const std::string& title) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 syncer::ModelTypeSyncBridge* ReadingListModelImpl::GetModelTypeSyncBridge() { | 404 syncer::ModelTypeSyncBridge* ReadingListModelImpl::GetModelTypeSyncBridge() { |
| 488 DCHECK(loaded()); | 405 DCHECK(loaded()); |
| 489 if (!storage_layer_) | 406 if (!storage_layer_) |
| 490 return nullptr; | 407 return nullptr; |
| 491 return storage_layer_->GetModelTypeSyncBridge(); | 408 return storage_layer_->GetModelTypeSyncBridge(); |
| 492 } | 409 } |
| 493 | 410 |
| 494 ReadingListModelStorage* ReadingListModelImpl::StorageLayer() { | 411 ReadingListModelStorage* ReadingListModelImpl::StorageLayer() { |
| 495 return storage_layer_.get(); | 412 return storage_layer_.get(); |
| 496 } | 413 } |
| OLD | NEW |