}
}
+trait FileDataSource {
+ fn get(&self, client: &mut Client) -> (Vec<String>, isize);
+ fn init(&self, client: &mut Client) -> Result<(), ClientError>;
+ fn try_extend(&self, client: &mut Client) -> Result<bool, ClientError>;
+ fn updated(&self, feeds_updated: &HashSet<FeedId>) -> bool;
+ fn extendable(&self) -> bool;
+}
+
+struct FeedSource {
+ id: FeedId,
+}
+
+impl FeedSource {
+ fn new(id: FeedId) -> Self { FeedSource { id } }
+}
+
+impl FileDataSource for FeedSource {
+ fn get(&self, client: &mut Client) -> (Vec<String>, isize) {
+ let feed = client.borrow_feed(&self.id);
+ let ids = feed.ids.iter().map(|x| x.clone()).collect();
+ (ids, feed.origin)
+ }
+
+ fn init(&self, client: &mut Client) -> Result<(), ClientError> {
+ client.fetch_feed(&self.id, FeedExtend::Initial)?;
+ Ok(())
+ }
+
+ fn try_extend(&self, client: &mut Client) -> Result<bool, ClientError> {
+ client.fetch_feed(&self.id, FeedExtend::Past)
+ }
+
+ fn updated(&self, feeds_updated: &HashSet<FeedId>) -> bool {
+ feeds_updated.contains(&self.id)
+ }
+
+ fn extendable(&self) -> bool { true }
+}
+
trait FileType {
type Item: TextFragment + Sized;
}
}
-struct FileContents<Type: FileType> {
- id: FeedId,
+struct FileContents<Type: FileType, Source: FileDataSource> {
+ source: Source,
header: FileHeader,
extender: Option<ExtendableIndicator>,
origin: isize,
items: Vec<Type::Item>,
}
-impl<Type: FileType> FileContents<Type> {
+impl<Type: FileType, Source: FileDataSource> FileContents<Type,Source> {
fn update_items(&mut self, client: &mut Client) {
// FIXME: if the feed has been extended rather than created,
// we should be able to make less effort than this
- let feed = client.borrow_feed(&self.id);
- let ids: Vec<_> = feed.ids.iter().map(|x| x.clone()).collect();
- self.origin = feed.origin;
+ let (ids, origin) = self.source.get(client);
+ self.origin = origin;
self.items.clear();
for id in ids {
}
}
-struct File<Type: FileType> {
- contents: FileContents<Type>,
+struct File<Type: FileType, Source: FileDataSource> {
+ contents: FileContents<Type, Source>,
rendered: HashMap<isize, Vec<ColouredString>>,
pos: FilePosition,
last_size: Option<(usize, usize)>,
}
-impl<Type: FileType> File<Type> {
- fn new(client: &mut Client, id: FeedId, desc: ColouredString) ->
+impl<Type: FileType, Source: FileDataSource> File<Type, Source> {
+ fn new(client: &mut Client, source: Source, desc: ColouredString) ->
Result<Self, ClientError>
{
- client.fetch_feed(&id, FeedExtend::Initial)?;
+ source.init(client)?;
+
+ let extender = if source.extendable() {
+ Some(ExtendableIndicator::new())
+ } else {
+ None
+ };
let mut contents = FileContents {
- id: id,
+ source: source,
header: FileHeader::new(desc),
- extender: Some(ExtendableIndicator::new()),
+ extender,
origin: 0,
items: Vec::new(),
};
}
}
-impl<Type: FileType> ActivityState for File<Type> {
+impl<Type: FileType, Source: FileDataSource>
+ ActivityState for File<Type, Source>
+{
fn resize(&mut self, w: usize, h: usize) {
if self.last_size != Some((w, h)) {
self.last_size = Some((w, h));
},
Pr('0') | Home => {
if self.at_top() && self.contents.extender.is_some() {
- let action = match client.fetch_feed(&self.contents.id,
- FeedExtend::Past) {
+ let action = match self.contents.source.try_extend(client) {
Ok(any_new) => {
self.rendered.remove(&self.contents.first_index());
if let Some(i) = self.contents.extender_index() {
fn handle_feed_updates(&mut self, feeds_updated: &HashSet<FeedId>,
client: &mut Client) {
- if feeds_updated.contains(&self.contents.id) {
+ if self.contents.source.updated(feeds_updated) {
self.contents.update_items(client);
self.ensure_enough_rendered();
}
pub fn home_timeline(client: &mut Client) ->
Result<Box<dyn ActivityState>, ClientError>
{
- let file = File::<StatusFeedType>::new(
- client, FeedId::Home, ColouredString::general(
+ let file = File::<StatusFeedType, _>::new(
+ client, FeedSource::new(FeedId::Home), ColouredString::general(
"Home timeline <H>",
"HHHHHHHHHHHHHHHHHKH"))?;
Ok(Box::new(file))
pub fn local_timeline(client: &mut Client) ->
Result<Box<dyn ActivityState>, ClientError>
{
- let file = File::<StatusFeedType>::new(
- client, FeedId::Local, ColouredString::general(
+ let file = File::<StatusFeedType, _>::new(
+ client, FeedSource::new(FeedId::Local), ColouredString::general(
"Local public timeline <L>",
"HHHHHHHHHHHHHHHHHHHHHHHHHKH"))?;
Ok(Box::new(file))
pub fn public_timeline(client: &mut Client) ->
Result<Box<dyn ActivityState>, ClientError>
{
- let file = File::<StatusFeedType>::new(
- client, FeedId::Public, ColouredString::general(
+ let file = File::<StatusFeedType, _>::new(
+ client, FeedSource::new(FeedId::Public), ColouredString::general(
"Public timeline <P>",
"HHHHHHHHHHHHHHHHHHHKH"))?;
Ok(Box::new(file))
pub fn mentions(client: &mut Client) ->
Result<Box<dyn ActivityState>, ClientError>
{
- let file = File::<NotificationStatusFeedType>::new(
- client, FeedId::Mentions, ColouredString::general(
+ let file = File::<NotificationStatusFeedType, _>::new(
+ client, FeedSource::new(FeedId::Mentions), ColouredString::general(
"Mentions [ESC][R]",
"HHHHHHHHHHHHKKKHHKH"))?;
Ok(Box::new(file))
pub fn ego_log(client: &mut Client) ->
Result<Box<dyn ActivityState>, ClientError>
{
- let file = File::<EgoNotificationFeedType>::new(
- client, FeedId::Ego, ColouredString::general(
+ let file = File::<EgoNotificationFeedType, _>::new(
+ client, FeedSource::new(FeedId::Ego), ColouredString::general(
"Ego Log [ESC][L][L][E]",
"HHHHHHHHHHHKKKHHKHHKHHKH"))?;
Ok(Box::new(file))