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 |