diff options
author | olivierrobin <olivierrobin@chromium.org> | 2016-03-24 09:17:18 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-24 16:18:36 +0000 |
commit | 883e7c4f4fe29b50cc43d15b9f0d8ef0f3a65e1f (patch) | |
tree | 983e2e7f8273d36fc7c6e0a71abc8dc9ab3535cf /ios/chrome/browser/reading_list | |
parent | 9741145b1c98047f11ed1b795166ea97ec0829a1 (diff) | |
download | chromium_src-883e7c4f4fe29b50cc43d15b9f0d8ef0f3a65e1f.zip chromium_src-883e7c4f4fe29b50cc43d15b9f0d8ef0f3a65e1f.tar.gz chromium_src-883e7c4f4fe29b50cc43d15b9f0d8ef0f3a65e1f.tar.bz2 |
Add persistence layer to Reading list model
Review URL: https://codereview.chromium.org/1815633003
Cr-Commit-Position: refs/heads/master@{#383073}
Diffstat (limited to 'ios/chrome/browser/reading_list')
7 files changed, 219 insertions, 3 deletions
diff --git a/ios/chrome/browser/reading_list/reading_list_model.h b/ios/chrome/browser/reading_list/reading_list_model.h index d731909..8c4c98f 100644 --- a/ios/chrome/browser/reading_list/reading_list_model.h +++ b/ios/chrome/browser/reading_list/reading_list_model.h @@ -99,7 +99,7 @@ class ReadingListModel { // Tells model that batch updates have completed. Called from // ReadingListBatchUpdateToken dtor. - void EndBatchUpdates(); + virtual void EndBatchUpdates(); private: unsigned int current_batch_updates_count_; diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc index dcf6c2b..1705249 100644 --- a/ios/chrome/browser/reading_list/reading_list_model_factory.cc +++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc @@ -11,6 +11,7 @@ #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/reading_list/reading_list_model_memory.h" +#include "ios/chrome/browser/reading_list/reading_list_model_storage_defaults.h" // static ReadingListModel* ReadingListModelFactory::GetForBrowserState( @@ -40,8 +41,10 @@ ReadingListModelFactory::~ReadingListModelFactory() {} scoped_ptr<KeyedService> ReadingListModelFactory::BuildServiceInstanceFor( web::BrowserState* context) const { + std::unique_ptr<ReadingListModelStorage> storage( + new ReadingListModelStorageDefaults()); scoped_ptr<ReadingListModelMemory> reading_list_model( - new ReadingListModelMemory()); + new ReadingListModelMemory(std::move(storage))); return std::move(reading_list_model); } diff --git a/ios/chrome/browser/reading_list/reading_list_model_memory.cc b/ios/chrome/browser/reading_list/reading_list_model_memory.cc index d5ff979..7d9f99a 100644 --- a/ios/chrome/browser/reading_list/reading_list_model_memory.cc +++ b/ios/chrome/browser/reading_list/reading_list_model_memory.cc @@ -3,11 +3,24 @@ // found in the LICENSE file. #include "ios/chrome/browser/reading_list/reading_list_model_memory.h" +#include "ios/chrome/browser/reading_list/reading_list_model_storage.h" #include "url/gurl.h" ReadingListModelMemory::ReadingListModelMemory() - : hasUnseen_(false), loaded_(true) {} + : ReadingListModelMemory(NULL) {} + +ReadingListModelMemory::ReadingListModelMemory( + std::unique_ptr<ReadingListModelStorage> storage) + : hasUnseen_(false) { + if (storage) { + storageLayer_ = std::move(storage); + read_ = storageLayer_->LoadPersistentReadList(); + unread_ = storageLayer_->LoadPersistentUnreadList(); + hasUnseen_ = storageLayer_->LoadPersistentHasUnseen(); + } + loaded_ = true; +} ReadingListModelMemory::~ReadingListModelMemory() {} void ReadingListModelMemory::Shutdown() { @@ -38,6 +51,9 @@ bool ReadingListModelMemory::HasUnseenEntries() const { void ReadingListModelMemory::ResetUnseenEntries() { DCHECK(loaded()); hasUnseen_ = false; + if (storageLayer_ && !IsPerformingBatchUpdates()) { + storageLayer_->SavePersistentHasUnseen(false); + } } // Returns a specific entry. @@ -62,6 +78,9 @@ void ReadingListModelMemory::RemoveEntryByUrl(const GURL& url) { ReadingListWillRemoveUnreadEntry( this, std::distance(unread_.begin(), result))); unread_.erase(result); + if (storageLayer_ && !IsPerformingBatchUpdates()) { + storageLayer_->SavePersistentUnreadList(unread_); + } FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, ReadingListDidApplyChanges(this)); return; @@ -73,6 +92,9 @@ void ReadingListModelMemory::RemoveEntryByUrl(const GURL& url) { ReadingListWillRemoveReadEntry( this, std::distance(read_.begin(), result))); read_.erase(result); + if (storageLayer_ && !IsPerformingBatchUpdates()) { + storageLayer_->SavePersistentReadList(read_); + } FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, ReadingListDidApplyChanges(this)); return; @@ -89,6 +111,10 @@ const ReadingListEntry& ReadingListModelMemory::AddEntry( ReadingListWillAddUnreadEntry(this, entry)); unread_.insert(unread_.begin(), entry); hasUnseen_ = true; + if (storageLayer_ && !IsPerformingBatchUpdates()) { + storageLayer_->SavePersistentUnreadList(unread_); + storageLayer_->SavePersistentHasUnseen(true); + } FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, ReadingListDidApplyChanges(this)); @@ -111,7 +137,21 @@ void ReadingListModelMemory::MarkReadByURL(const GURL& url) { read_.insert(read_.begin(), *result); unread_.erase(result); + if (storageLayer_ && !IsPerformingBatchUpdates()) { + storageLayer_->SavePersistentUnreadList(unread_); + storageLayer_->SavePersistentReadList(read_); + } FOR_EACH_OBSERVER(ReadingListModelObserver, observers_, ReadingListDidApplyChanges(this)); } + +void ReadingListModelMemory::EndBatchUpdates() { + ReadingListModel::EndBatchUpdates(); + if (IsPerformingBatchUpdates() || !storageLayer_) { + return; + } + storageLayer_->SavePersistentUnreadList(unread_); + storageLayer_->SavePersistentReadList(read_); + storageLayer_->SavePersistentHasUnseen(hasUnseen_); +} diff --git a/ios/chrome/browser/reading_list/reading_list_model_memory.h b/ios/chrome/browser/reading_list/reading_list_model_memory.h index bec14c4..584fba8 100644 --- a/ios/chrome/browser/reading_list/reading_list_model_memory.h +++ b/ios/chrome/browser/reading_list/reading_list_model_memory.h @@ -5,14 +5,25 @@ #ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_MEMORY_H_ #define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_MEMORY_H_ +#include "base/memory/scoped_ptr.h" #include "components/keyed_service/core/keyed_service.h" #include "ios/chrome/browser/reading_list/reading_list_entry.h" #include "ios/chrome/browser/reading_list/reading_list_model.h" +class ReadingListModelStorage; + // Concrete implementation of a reading list model using in memory lists. class ReadingListModelMemory : public ReadingListModel, public KeyedService { public: + // Initialize a ReadingListModelMemory to load and save data in + // |persistence_layer|. + ReadingListModelMemory( + std::unique_ptr<ReadingListModelStorage> storage_layer); + + // Initialize a ReadingListModelMemory without persistence. Data will not be + // persistent across sessions. ReadingListModelMemory(); + ~ReadingListModelMemory() override; void Shutdown() override; @@ -35,9 +46,13 @@ class ReadingListModelMemory : public ReadingListModel, public KeyedService { void MarkReadByURL(const GURL& url) override; + protected: + void EndBatchUpdates() override; + private: std::vector<ReadingListEntry> unread_; std::vector<ReadingListEntry> read_; + std::unique_ptr<ReadingListModelStorage> storageLayer_; bool hasUnseen_; bool loaded_; }; diff --git a/ios/chrome/browser/reading_list/reading_list_model_storage.h b/ios/chrome/browser/reading_list/reading_list_model_storage.h new file mode 100644 index 0000000..94f4a02 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_storage.h @@ -0,0 +1,27 @@ +// Copyright 2016 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 IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_STORAGE_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_STORAGE_H_ + +#include "ios/chrome/browser/reading_list/reading_list_entry.h" + +class ReadingListModel; + +// Interface for a persistence layer for reading list. +// All interface methods have to be called on main thread. +class ReadingListModelStorage { + public: + virtual std::vector<ReadingListEntry> LoadPersistentReadList() = 0; + virtual std::vector<ReadingListEntry> LoadPersistentUnreadList() = 0; + virtual bool LoadPersistentHasUnseen() = 0; + + virtual void SavePersistentReadList( + const std::vector<ReadingListEntry>& read) = 0; + virtual void SavePersistentUnreadList( + const std::vector<ReadingListEntry>& unread) = 0; + virtual void SavePersistentHasUnseen(bool has_unseen) = 0; +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_STORAGE_H_
\ No newline at end of file diff --git a/ios/chrome/browser/reading_list/reading_list_model_storage_defaults.h b/ios/chrome/browser/reading_list/reading_list_model_storage_defaults.h new file mode 100644 index 0000000..1f4fc1b --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_storage_defaults.h @@ -0,0 +1,28 @@ +// Copyright 2016 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 IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_STORAGE_DEFAULTS_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_STORAGE_DEFAULTS_H_ + +#include "ios/chrome/browser/reading_list/reading_list_entry.h" +#include "ios/chrome/browser/reading_list/reading_list_model_storage.h" + +class ReadingListModel; + +// Implementation of ReadingListModelStorage that stores reading list items in +// the system user defaults. +class ReadingListModelStorageDefaults : public ReadingListModelStorage { + public: + std::vector<ReadingListEntry> LoadPersistentReadList() override; + std::vector<ReadingListEntry> LoadPersistentUnreadList() override; + bool LoadPersistentHasUnseen() override; + + void SavePersistentReadList( + const std::vector<ReadingListEntry>& read) override; + void SavePersistentUnreadList( + const std::vector<ReadingListEntry>& unread) override; + void SavePersistentHasUnseen(bool has_unseen) override; +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_STORAGE_DEFAULTS_H_
\ No newline at end of file diff --git a/ios/chrome/browser/reading_list/reading_list_model_storage_defaults.mm b/ios/chrome/browser/reading_list/reading_list_model_storage_defaults.mm new file mode 100644 index 0000000..8c16429 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_storage_defaults.mm @@ -0,0 +1,103 @@ +// Copyright 2016 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. + +#import <Foundation/Foundation.h> + +#include "ios/chrome/browser/reading_list/reading_list_model_storage_defaults.h" + +#include "base/mac/foundation_util.h" +#include "base/strings/sys_string_conversions.h" +#import "net/base/mac/url_conversions.h" + +namespace { + +NSString* const kReadingListReadElements = @"ReadingListReadElements"; +NSString* const kReadingListUnreadElements = @"ReadingListUnreadElements"; +NSString* const kReadingListUnseenState = @"ReadingListUnseenState"; +NSString* const kReadingListEntryTitleKey = @"title"; +NSString* const kReadingListEntryURLKey = @"URL"; + +ReadingListEntry DecodeReadingListEntry(NSData* data) { + NSError* error = nil; + NSDictionary* dictionary = + [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:&error]; + NSString* title = base::mac::ObjCCastStrict<NSString>( + [dictionary objectForKey:kReadingListEntryTitleKey]); + NSURL* url = base::mac::ObjCCastStrict<NSURL>( + [dictionary objectForKey:kReadingListEntryURLKey]); + DCHECK(title && url); + GURL gurl(net::GURLWithNSURL(url)); + DCHECK(gurl.is_valid()); + return ReadingListEntry(gurl, base::SysNSStringToUTF8(title)); +} + +NSData* EncodeReadingListEntry(const ReadingListEntry& entry) { + NSDictionary* dictionary = @{ + kReadingListEntryTitleKey : base::SysUTF8ToNSString(entry.title()), + kReadingListEntryURLKey : net::NSURLWithGURL(entry.url()) + }; + return [NSKeyedArchiver archivedDataWithRootObject:dictionary]; +} + +} // namespace + +std::vector<ReadingListEntry> +ReadingListModelStorageDefaults::LoadPersistentReadList() { + std::vector<ReadingListEntry> read; + NSArray* readList = + base::mac::ObjCCastStrict<NSArray>([[NSUserDefaults standardUserDefaults] + objectForKey:kReadingListReadElements]); + if (readList) { + for (NSData* entryData : readList) { + read.push_back(DecodeReadingListEntry(entryData)); + } + } + return read; +} + +std::vector<ReadingListEntry> +ReadingListModelStorageDefaults::LoadPersistentUnreadList() { + std::vector<ReadingListEntry> unread; + NSArray* unreadList = + base::mac::ObjCCastStrict<NSArray>([[NSUserDefaults standardUserDefaults] + objectForKey:kReadingListUnreadElements]); + if (unreadList) { + for (NSData* entryData : unreadList) { + unread.push_back(DecodeReadingListEntry(entryData)); + } + } + return unread; +} + +bool ReadingListModelStorageDefaults::LoadPersistentHasUnseen() { + return [[[NSUserDefaults standardUserDefaults] + objectForKey:kReadingListUnseenState] boolValue]; +} + +void ReadingListModelStorageDefaults::SavePersistentReadList( + const std::vector<ReadingListEntry>& read) { + NSMutableArray* read_list = [NSMutableArray arrayWithCapacity:read.size()]; + for (const ReadingListEntry& entry : read) { + [read_list addObject:EncodeReadingListEntry(entry)]; + } + [[NSUserDefaults standardUserDefaults] setObject:read_list + forKey:kReadingListReadElements]; +} + +void ReadingListModelStorageDefaults::SavePersistentUnreadList( + const std::vector<ReadingListEntry>& unread) { + NSMutableArray* unread_list = + [NSMutableArray arrayWithCapacity:unread.size()]; + for (const ReadingListEntry& entry : unread) { + [unread_list addObject:EncodeReadingListEntry(entry)]; + } + [[NSUserDefaults standardUserDefaults] setValue:unread_list + forKey:kReadingListUnreadElements]; +} + +void ReadingListModelStorageDefaults::SavePersistentHasUnseen(bool has_unseen) { + [[NSUserDefaults standardUserDefaults] + setObject:[NSNumber numberWithBool:has_unseen] + forKey:kReadingListUnseenState]; +} |