| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of swarmlib; | 5 part of swarmlib; |
| 6 | 6 |
| 7 /** The top-level collection of all sections for a user. */ | 7 /** The top-level collection of all sections for a user. */ |
| 8 // TODO(jimhug): This is known as UserData in the server model. | 8 // TODO(jimhug): This is known as UserData in the server model. |
| 9 class Sections extends IterableBase<Section> { | 9 class Sections extends IterableBase<Section> { |
| 10 final List<Section> _sections; | 10 final List<Section> _sections; |
| 11 | 11 |
| 12 Sections(this._sections); | 12 Sections(this._sections); |
| 13 | 13 |
| 14 operator [](int i) => _sections[i]; | 14 operator [](int i) => _sections[i]; |
| 15 | 15 |
| 16 int get length => _sections.length; | 16 int get length => _sections.length; |
| 17 | 17 |
| 18 List<String> get sectionTitles => | 18 List<String> get sectionTitles => _sections.map((s) => s.title).toList(); |
| 19 _sections.map((s) => s.title).toList(); | |
| 20 | 19 |
| 21 void refresh() { | 20 void refresh() { |
| 22 // TODO(jimhug): http://b/issue?id=5351067 | 21 // TODO(jimhug): http://b/issue?id=5351067 |
| 23 } | 22 } |
| 24 | 23 |
| 25 /** | 24 /** |
| 26 * Find the Section object that has a given title. | 25 * Find the Section object that has a given title. |
| 27 * This is used to integrate well with [ConveyorView]. | 26 * This is used to integrate well with [ConveyorView]. |
| 28 */ | 27 */ |
| 29 Section findSection(String name) { | 28 Section findSection(String name) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 43 // Move this workaround to the DOM code. See bug 5389503. | 42 // Move this workaround to the DOM code. See bug 5389503. |
| 44 return '${window.location.protocol}//${window.location.host}'; | 43 return '${window.location.protocol}//${window.location.host}'; |
| 45 } | 44 } |
| 46 | 45 |
| 47 // This method is exposed for tests. | 46 // This method is exposed for tests. |
| 48 static void initializeFromData(String data, void callback(Sections sects)) { | 47 static void initializeFromData(String data, void callback(Sections sects)) { |
| 49 final decoder = new Decoder(data); | 48 final decoder = new Decoder(data); |
| 50 int nSections = decoder.readInt(); | 49 int nSections = decoder.readInt(); |
| 51 final sections = new List<Section>(); | 50 final sections = new List<Section>(); |
| 52 | 51 |
| 53 for (int i=0; i < nSections; i++) { | 52 for (int i = 0; i < nSections; i++) { |
| 54 sections.add(Section.decode(decoder)); | 53 sections.add(Section.decode(decoder)); |
| 55 } | 54 } |
| 56 callback(new Sections(sections)); | 55 callback(new Sections(sections)); |
| 57 } | 56 } |
| 58 | 57 |
| 59 static void initializeFromUrl(bool useCannedData, | 58 static void initializeFromUrl( |
| 60 void callback(Sections sections)) { | 59 bool useCannedData, void callback(Sections sections)) { |
| 61 if (Sections.runningFromFile || useCannedData) { | 60 if (Sections.runningFromFile || useCannedData) { |
| 62 initializeFromData(CannedData.data['user.data'], callback); | 61 initializeFromData(CannedData.data['user.data'], callback); |
| 63 } else { | 62 } else { |
| 64 // TODO(jmesserly): display an error if we fail here! Silent failure bad. | 63 // TODO(jmesserly): display an error if we fail here! Silent failure bad. |
| 65 HttpRequest.getString('data/user.data').then( | 64 HttpRequest |
| 66 EventBatch.wrap((responseText) { | 65 .getString('data/user.data') |
| 67 // TODO(jimhug): Nice response if get error back from server. | 66 .then(EventBatch.wrap((responseText) { |
| 68 // TODO(jimhug): Might be more efficient to parse request | 67 // TODO(jimhug): Nice response if get error back from server. |
| 69 // in sections. | 68 // TODO(jimhug): Might be more efficient to parse request |
| 70 initializeFromData(responseText, callback); | 69 // in sections. |
| 70 initializeFromData(responseText, callback); |
| 71 })); | 71 })); |
| 72 } | 72 } |
| 73 } | 73 } |
| 74 | 74 |
| 75 Section findSectionById(String id) { | 75 Section findSectionById(String id) { |
| 76 return CollectionUtils.find(_sections, (section) => section.id == id); | 76 return CollectionUtils.find(_sections, (section) => section.id == id); |
| 77 } | 77 } |
| 78 | 78 |
| 79 /** | 79 /** |
| 80 * Given the name of a section, find its index in the set. | 80 * Given the name of a section, find its index in the set. |
| 81 */ | 81 */ |
| 82 int findSectionIndex(String name) { | 82 int findSectionIndex(String name) { |
| 83 for (int i = 0; i < _sections.length; i++) { | 83 for (int i = 0; i < _sections.length; i++) { |
| 84 if (name == _sections[i].title) { | 84 if (name == _sections[i].title) { |
| 85 return i; | 85 return i; |
| 86 } | 86 } |
| 87 } | 87 } |
| 88 return -1; | 88 return -1; |
| 89 } | 89 } |
| 90 | 90 |
| 91 List<Section> get sections => _sections; | 91 List<Section> get sections => _sections; |
| 92 | 92 |
| 93 // TODO(jmesserly): this should be a property | 93 // TODO(jmesserly): this should be a property |
| 94 bool get isEmpty => length == 0; | 94 bool get isEmpty => length == 0; |
| 95 } | 95 } |
| 96 | 96 |
| 97 | |
| 98 /** A collection of data sources representing a page in the UI. */ | 97 /** A collection of data sources representing a page in the UI. */ |
| 99 class Section { | 98 class Section { |
| 100 final String id; | 99 final String id; |
| 101 final String title; | 100 final String title; |
| 102 ObservableList<Feed> feeds; | 101 ObservableList<Feed> feeds; |
| 103 | 102 |
| 104 // Public for testing. TODO(jacobr): find a cleaner solution. | 103 // Public for testing. TODO(jacobr): find a cleaner solution. |
| 105 Section(this.id, this.title, this.feeds); | 104 Section(this.id, this.title, this.feeds); |
| 106 | 105 |
| 107 void refresh() { | 106 void refresh() { |
| 108 for (final feed in feeds) { | 107 for (final feed in feeds) { |
| 109 // TODO(jimhug): http://b/issue?id=5351067 | 108 // TODO(jimhug): http://b/issue?id=5351067 |
| 110 } | 109 } |
| 111 } | 110 } |
| 112 | 111 |
| 113 static Section decode(Decoder decoder) { | 112 static Section decode(Decoder decoder) { |
| 114 final sectionId = decoder.readString(); | 113 final sectionId = decoder.readString(); |
| 115 final sectionTitle = decoder.readString(); | 114 final sectionTitle = decoder.readString(); |
| 116 | 115 |
| 117 final nSources = decoder.readInt(); | 116 final nSources = decoder.readInt(); |
| 118 final feeds = new ObservableList<Feed>(); | 117 final feeds = new ObservableList<Feed>(); |
| 119 for (int j=0; j < nSources; j++) { | 118 for (int j = 0; j < nSources; j++) { |
| 120 feeds.add(Feed.decode(decoder)); | 119 feeds.add(Feed.decode(decoder)); |
| 121 } | 120 } |
| 122 return new Section(sectionId, sectionTitle, feeds); | 121 return new Section(sectionId, sectionTitle, feeds); |
| 123 } | 122 } |
| 124 | 123 |
| 125 Feed findFeed(String id_) { | 124 Feed findFeed(String id_) { |
| 126 return CollectionUtils.find(feeds, (feed) => feed.id == id_); | 125 return CollectionUtils.find(feeds, (feed) => feed.id == id_); |
| 127 } | 126 } |
| 128 } | 127 } |
| 129 | 128 |
| 130 /** Provider of a news feed. */ | 129 /** Provider of a news feed. */ |
| 131 class Feed { | 130 class Feed { |
| 132 String id; | 131 String id; |
| 133 final String title; | 132 final String title; |
| 134 final String iconUrl; | 133 final String iconUrl; |
| 135 final String description; | 134 final String description; |
| 136 ObservableList<Article> articles; | 135 ObservableList<Article> articles; |
| 137 ObservableValue<bool> error; // TODO(jimhug): Check if dead code. | 136 ObservableValue<bool> error; // TODO(jimhug): Check if dead code. |
| 138 | 137 |
| 139 Feed(this.id, this.title, this.iconUrl, {this.description: ''}) | 138 Feed(this.id, this.title, this.iconUrl, {this.description: ''}) |
| 140 : articles = new ObservableList<Article>(), | 139 : articles = new ObservableList<Article>(), |
| 141 error = new ObservableValue<bool>(false); | 140 error = new ObservableValue<bool>(false); |
| 142 | 141 |
| 143 static Feed decode(Decoder decoder) { | 142 static Feed decode(Decoder decoder) { |
| 144 final sourceId = decoder.readString(); | 143 final sourceId = decoder.readString(); |
| 145 final sourceTitle = decoder.readString(); | 144 final sourceTitle = decoder.readString(); |
| 146 final sourceIcon = decoder.readString(); | 145 final sourceIcon = decoder.readString(); |
| 147 final feed = new Feed(sourceId, sourceTitle, sourceIcon); | 146 final feed = new Feed(sourceId, sourceTitle, sourceIcon); |
| 148 final nItems = decoder.readInt(); | 147 final nItems = decoder.readInt(); |
| 149 | 148 |
| 150 for (int i=0; i < nItems; i++) { | 149 for (int i = 0; i < nItems; i++) { |
| 151 feed.articles.add(Article.decodeHeader(feed, decoder)); | 150 feed.articles.add(Article.decodeHeader(feed, decoder)); |
| 152 } | 151 } |
| 153 return feed; | 152 return feed; |
| 154 } | 153 } |
| 155 | 154 |
| 156 Article findArticle(String id_) { | 155 Article findArticle(String id_) { |
| 157 return CollectionUtils.find(articles, (article) => article.id == id_); | 156 return CollectionUtils.find(articles, (article) => article.id == id_); |
| 158 } | 157 } |
| 159 | 158 |
| 160 void refresh() {} | 159 void refresh() {} |
| 161 } | 160 } |
| 162 | 161 |
| 163 | |
| 164 /** A single article or posting to display. */ | 162 /** A single article or posting to display. */ |
| 165 class Article { | 163 class Article { |
| 166 final String id; | 164 final String id; |
| 167 DateTime date; | 165 DateTime date; |
| 168 final String title; | 166 final String title; |
| 169 final String author; | 167 final String author; |
| 170 final bool hasThumbnail; | 168 final bool hasThumbnail; |
| 171 String textBody; // TODO(jimhug): rename to snipppet. | 169 String textBody; // TODO(jimhug): rename to snipppet. |
| 172 final Feed dataSource; // TODO(jimhug): rename to feed. | 170 final Feed dataSource; // TODO(jimhug): rename to feed. |
| 173 String _htmlBody; | 171 String _htmlBody; |
| 174 String srcUrl; | 172 String srcUrl; |
| 175 final ObservableValue<bool> unread; // TODO(jimhug): persist to server. | 173 final ObservableValue<bool> unread; // TODO(jimhug): persist to server. |
| 176 | 174 |
| 177 bool error; // TODO(jimhug): Check if this is dead and remove. | 175 bool error; // TODO(jimhug): Check if this is dead and remove. |
| 178 | 176 |
| 179 Article(this.dataSource, this.id, this.date, this.title, this.author, | 177 Article(this.dataSource, this.id, this.date, this.title, this.author, |
| 180 this.srcUrl, this.hasThumbnail, this.textBody, | 178 this.srcUrl, this.hasThumbnail, this.textBody, |
| 181 {htmlBody: null, bool unread: true, this.error: false}) | 179 {htmlBody: null, bool unread: true, this.error: false}) |
| 182 : unread = new ObservableValue<bool>(unread), this._htmlBody = htmlBody; | 180 : unread = new ObservableValue<bool>(unread), |
| 181 this._htmlBody = htmlBody; |
| 183 | 182 |
| 184 String get htmlBody { | 183 String get htmlBody { |
| 185 _ensureLoaded(); | 184 _ensureLoaded(); |
| 186 return _htmlBody; | 185 return _htmlBody; |
| 187 } | 186 } |
| 188 | 187 |
| 189 String get dataUri { | 188 String get dataUri { |
| 190 return SwarmUri.encodeComponent(id).replaceAll('%2F', '/'). | 189 return SwarmUri |
| 191 replaceAll('%253A', '%3A'); | 190 .encodeComponent(id) |
| 191 .replaceAll('%2F', '/') |
| 192 .replaceAll('%253A', '%3A'); |
| 192 } | 193 } |
| 193 | 194 |
| 194 String get thumbUrl { | 195 String get thumbUrl { |
| 195 if (!hasThumbnail) return null; | 196 if (!hasThumbnail) return null; |
| 196 | 197 |
| 197 var home; | 198 var home; |
| 198 if (Sections.runningFromFile) { | 199 if (Sections.runningFromFile) { |
| 199 home = 'http://dart.googleplex.com'; | 200 home = 'http://dart.googleplex.com'; |
| 200 } else { | 201 } else { |
| 201 home = Sections.home; | 202 home = Sections.home; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 225 } | 226 } |
| 226 | 227 |
| 227 static Article decodeHeader(Feed source, Decoder decoder) { | 228 static Article decodeHeader(Feed source, Decoder decoder) { |
| 228 final id = decoder.readString(); | 229 final id = decoder.readString(); |
| 229 final title = decoder.readString(); | 230 final title = decoder.readString(); |
| 230 final srcUrl = decoder.readString(); | 231 final srcUrl = decoder.readString(); |
| 231 final hasThumbnail = decoder.readBool(); | 232 final hasThumbnail = decoder.readBool(); |
| 232 final author = decoder.readString(); | 233 final author = decoder.readString(); |
| 233 final dateInSeconds = decoder.readInt(); | 234 final dateInSeconds = decoder.readInt(); |
| 234 final snippet = decoder.readString(); | 235 final snippet = decoder.readString(); |
| 235 final date = | 236 final date = new DateTime.fromMillisecondsSinceEpoch(dateInSeconds * 1000, |
| 236 new DateTime.fromMillisecondsSinceEpoch(dateInSeconds*1000, isUtc: true)
; | 237 isUtc: true); |
| 237 return new Article(source, id, date, title, author, srcUrl, hasThumbnail, | 238 return new Article( |
| 238 snippet); | 239 source, id, date, title, author, srcUrl, hasThumbnail, snippet); |
| 239 } | 240 } |
| 240 } | 241 } |
| OLD | NEW |