diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostItem.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostItem.java index d8561ad4d0401e0256ae61c0be6f1c068db7511e..546f9ac18005508ef1e79de8cd539c6ccf05fe92 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostItem.java @@ -48,6 +48,10 @@ public class BlogPostItem implements Comparable<BlogPostItem> { return body; } + public boolean isRssFeed() { + return header.isRssFeed(); + } + public boolean isRead() { return read; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java index ba1d11e6832e2f319f4f7880260775ae0c9e83ed..b0f4187b404fdb388ff40f8a67e2b2345c1a1b10 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java @@ -108,7 +108,8 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { author.setAuthor(a); author.setAuthorStatus(post.getAuthorStatus()); author.setDate(post.getTimestamp()); - author.setPersona(AuthorView.NORMAL); + author.setPersona( + item.isRssFeed() ? AuthorView.RSS_FEED : AuthorView.NORMAL); // TODO make author clickable more often #624 if (item.getHeader().getType() == POST) { author.setBlogLink(post.getGroupId()); @@ -168,7 +169,9 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { reblogger.setVisibility(VISIBLE); reblogger.setPersona(AuthorView.REBLOGGER); - author.setPersona(AuthorView.COMMENTER); + author.setPersona(item.getHeader().getParent().isRssFeed() ? + AuthorView.RSS_FEED_REBLOGGED : + AuthorView.COMMENTER); // comments for (BlogCommentHeader c : item.getComments()) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java b/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java index fc145268d62be054bb95bfd0a3d45acc63732130..67aa5a3b925fd669aec17e395e9c5fc5be7cf2a3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java @@ -40,6 +40,8 @@ public class AuthorView extends RelativeLayout { public static final int REBLOGGER = 1; public static final int COMMENTER = 2; public static final int LIST = 3; + public static final int RSS_FEED = 4; + public static final int RSS_FEED_REBLOGGED = 5; private final CircleImageView avatar; private final ImageView avatarIcon; @@ -124,6 +126,12 @@ public class AuthorView extends RelativeLayout { setOnClickListener(null); } + /** + * Styles this view for a different persona. + * + * Attention: If used in a RecyclerView with RSS_FEED, + * call this after setAuthor() + */ public void setPersona(int persona) { switch (persona) { case NORMAL: @@ -158,6 +166,24 @@ public class AuthorView extends RelativeLayout { setCenterVertical(authorName, true); setCenterVertical(trustIndicator, true); break; + case RSS_FEED: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(VISIBLE); + avatar.setImageResource(R.drawable.ic_rss_feed); + setAvatarSize(R.dimen.blogs_avatar_normal_size); + setTextSize(authorName, R.dimen.text_size_small); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; + case RSS_FEED_REBLOGGED: + avatarIcon.setVisibility(INVISIBLE); + date.setVisibility(VISIBLE); + avatar.setImageResource(R.drawable.ic_rss_feed); + setAvatarSize(R.dimen.blogs_avatar_comment_size); + setTextSize(authorName, R.dimen.text_size_tiny); + setCenterVertical(authorName, false); + setCenterVertical(trustIndicator, false); + break; } } diff --git a/briar-android/src/main/res/drawable/ic_rss_feed.xml b/briar-android/src/main/res/drawable/ic_rss_feed.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d441fa064cd0a237076a0142d60f145059e0623 --- /dev/null +++ b/briar-android/src/main/res/drawable/ic_rss_feed.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="30dp" + android:height="30dp" + android:viewportHeight="30" + android:viewportWidth="30"> + + <path + android:fillColor="#ffa500" + android:pathData="M0,8.88178e-16 L30,8.88178e-16 L30,30 L0,30 L0,8.88178e-16 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M8.9322,18.0339 C10.6078,18.0339,11.9661,19.3922,11.9661,21.0678 +C11.9661,22.7434,10.6078,24.1017,8.9322,24.1017 +C7.25663,24.1017,5.8983,22.7434,5.8983,21.0678 +C5.8983,19.3922,7.25663,18.0339,8.9322,18.0339 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M5.8983,15 A9.1016949,9.1016949,0,0,1,15,24.1017 L18.0339,24.1017 +A12.135593,12.135593,0,0,0,5.8983,11.9661 Z"/> + <path + android:fillColor="#ffffff" + android:pathData="M5.8983,8.9322 A15.169492,15.169492,0,0,1,21.0678,24.1017 L24.1017,24.1017 +A18.20339,18.20339,0,0,0,5.8983,5.8983 Z"/> +</vector> \ No newline at end of file diff --git a/briar-android/src/main/res/values/attrs.xml b/briar-android/src/main/res/values/attrs.xml index 6d6207cd0b0843ee11b2a15f0c0ba2378a8ee350..8655d2126fc21b9c7a3fcc732e7c4ea30b7c0486 100644 --- a/briar-android/src/main/res/values/attrs.xml +++ b/briar-android/src/main/res/values/attrs.xml @@ -12,6 +12,8 @@ <enum name="reblogger" value="1"/> <enum name="commenter" value="2"/> <enum name="list" value="3"/> + <enum name="rss_feed" value="4"/> + <enum name="rss_feed_reblogged" value="5"/> </attr> </declare-styleable> diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogCommentHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogCommentHeader.java index 70fded28135d661b93bcb7500bb42082cefe6b15..af28ca1a2ebc26393bf7747af5eb952982d6c32d 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogCommentHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogCommentHeader.java @@ -26,7 +26,7 @@ public class BlogCommentHeader extends BlogPostHeader { Status authorStatus, boolean read) { super(type, groupId, id, parent.getId(), timestamp, - timeReceived, author, authorStatus, read); + timeReceived, author, authorStatus, false, read); if (type != COMMENT && type != WRAPPED_COMMENT) throw new IllegalArgumentException("Incompatible Message Type"); @@ -41,6 +41,9 @@ public class BlogCommentHeader extends BlogPostHeader { } public BlogPostHeader getParent() { + if (parent instanceof BlogCommentHeader) + return ((BlogCommentHeader) parent).getParent(); return parent; } + } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java index 99c4514b2639e51005df4459ad00d9ae28c11d86..4c8ff25d101c675ef0d92165a8b5ebf49708a954 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java @@ -28,6 +28,7 @@ public interface BlogConstants { String KEY_AUTHOR_NAME = "name"; String KEY_PUBLIC_KEY = "publicKey"; String KEY_AUTHOR = "author"; + String KEY_RSS_FEED = "rssFeed"; String KEY_READ = "read"; String KEY_COMMENT = "comment"; String KEY_ORIGINAL_MSG_ID = "originalMessageId"; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostHeader.java index cf01dfc57117deb72e48df2ba304dd16f90d9162..57a0ef58a93968c690335bb53736f76678eb2518 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogPostHeader.java @@ -17,21 +17,23 @@ public class BlogPostHeader extends PostHeader { private final MessageType type; private final GroupId groupId; private final long timeReceived; + private final boolean rssFeed; public BlogPostHeader(MessageType type, GroupId groupId, MessageId id, @Nullable MessageId parentId, long timestamp, long timeReceived, - Author author, Status authorStatus, boolean read) { + Author author, Status authorStatus, boolean rssFeed, boolean read) { super(id, parentId, timestamp, author, authorStatus, read); this.type = type; this.groupId = groupId; this.timeReceived = timeReceived; + this.rssFeed = rssFeed; } public BlogPostHeader(MessageType type, GroupId groupId, MessageId id, long timestamp, long timeReceived, Author author, - Status authorStatus, boolean read) { + Status authorStatus, boolean rssFeed, boolean read) { this(type, groupId, id, null, timestamp, timeReceived, author, - authorStatus, read); + authorStatus, rssFeed, read); } public MessageType getType() { @@ -45,4 +47,9 @@ public class BlogPostHeader extends PostHeader { public long getTimeReceived() { return timeReceived; } + + public boolean isRssFeed() { + return rssFeed; + } + } diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java index 22b8009167f654c2381430b52bbde1e18c7d7d90..91945f31089fb2bb5b31d8ebf35f2c3c890f9d09 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java @@ -61,6 +61,7 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_ORIGINAL_PARENT_ import static org.briarproject.briar.api.blog.BlogConstants.KEY_PARENT_MSG_ID; import static org.briarproject.briar.api.blog.BlogConstants.KEY_PUBLIC_KEY; import static org.briarproject.briar.api.blog.BlogConstants.KEY_READ; +import static org.briarproject.briar.api.blog.BlogConstants.KEY_RSS_FEED; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIMESTAMP; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE; @@ -253,15 +254,18 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, @Override public void addLocalPost(Transaction txn, BlogPost p) throws DbException { try { + GroupId groupId = p.getMessage().getGroupId(); + Blog b = getBlog(txn, groupId); + BdfDictionary meta = new BdfDictionary(); meta.put(KEY_TYPE, POST.getInt()); meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp()); meta.put(KEY_AUTHOR, authorToBdfDictionary(p.getAuthor())); meta.put(KEY_READ, true); + meta.put(KEY_RSS_FEED, b.isRssFeed()); clientHelper.addLocalMessage(txn, p.getMessage(), meta, true); // broadcast event about new post - GroupId groupId = p.getMessage().getGroupId(); MessageId postId = p.getMessage().getId(); BlogPostHeader h = getPostHeaderFromMetadata(txn, groupId, postId, meta); @@ -350,6 +354,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, wMessage = blogPostFactory .wrapPost(groupId, wDescriptor, wTimestamp, body); meta.put(KEY_TYPE, WRAPPED_POST.getInt()); + meta.put(KEY_RSS_FEED, pOriginalHeader.isRssFeed()); } else if (type == COMMENT) { Group wGroup = db.getGroup(txn, pOriginalHeader.getGroupId()); byte[] wDescriptor = wGroup.getDescriptor(); @@ -598,8 +603,11 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, String name = d.getString(KEY_AUTHOR_NAME); byte[] publicKey = d.getRaw(KEY_PUBLIC_KEY); Author author = new Author(authorId, name, publicKey); + boolean isFeedPost = meta.getBoolean(KEY_RSS_FEED, false); Status authorStatus; - if (authorStatuses.containsKey(authorId)) { + if (isFeedPost) { + authorStatus = Status.UNKNOWN; + } else if (authorStatuses.containsKey(authorId)) { authorStatus = authorStatuses.get(authorId); } else { authorStatus = identityManager.getAuthorStatus(txn, authorId); @@ -616,7 +624,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, timestamp, timeReceived, author, authorStatus, read); } else { return new BlogPostHeader(type, groupId, id, timestamp, - timeReceived, author, authorStatus, read); + timeReceived, author, authorStatus, isFeedPost, read); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java index 33fb0bddf76a4736df6bff337c7892f65520afca..5e74400c52ade433c2a175789d3e50648be6fbe7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogPostValidator.java @@ -39,6 +39,7 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_ORIGINAL_PARENT_ import static org.briarproject.briar.api.blog.BlogConstants.KEY_PARENT_MSG_ID; import static org.briarproject.briar.api.blog.BlogConstants.KEY_PUBLIC_KEY; import static org.briarproject.briar.api.blog.BlogConstants.KEY_READ; +import static org.briarproject.briar.api.blog.BlogConstants.KEY_RSS_FEED; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIMESTAMP; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED; import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE; @@ -123,6 +124,7 @@ class BlogPostValidator extends BdfMessageValidator { BdfDictionary meta = new BdfDictionary(); meta.put(KEY_ORIGINAL_MSG_ID, m.getId()); meta.put(KEY_AUTHOR, authorToBdfDictionary(a)); + meta.put(KEY_RSS_FEED, b.isRssFeed()); return new BdfMessageContext(meta); } diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java index 643fe482c3b939047029731aecce9773324221c7..c2c00ea571bbeb23559d162fae843435d454b53c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java @@ -1,5 +1,6 @@ package org.briarproject.briar.blog; +import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.TestDatabaseModule; import org.briarproject.briar.api.blog.Blog; @@ -32,7 +33,7 @@ public class BlogManagerIntegrationTest extends BriarIntegrationTest<BriarIntegrationTestComponent> { private BlogManager blogManager0, blogManager1; - private Blog blog0, blog1; + private Blog blog0, blog1, rssBlog; @Rule public ExpectedException thrown = ExpectedException.none(); @@ -50,6 +51,12 @@ public class BlogManagerIntegrationTest blog0 = blogFactory.createBlog(author0); blog1 = blogFactory.createBlog(author1); + + rssBlog = blogFactory.createFeedBlog(author0); + Transaction txn = db0.startTransaction(false); + blogManager0.addBlog(txn, rssBlog); + db0.commitTransaction(txn); + db0.endTransaction(txn); } @Override @@ -393,4 +400,62 @@ public class BlogManagerIntegrationTest assertEquals(2, headers0.size()); } + @Test + public void testFeedPost() throws Exception { + assertTrue(rssBlog.isRssFeed()); + + // add a feed post to rssBlog + final String body = getRandomString(42); + BlogPost p = blogPostFactory + .createBlogPost(rssBlog.getId(), clock.currentTimeMillis(), + null, author0, body); + blogManager0.addLocalPost(p); + + // make sure it got saved as an RSS feed post + Collection<BlogPostHeader> headers = + blogManager0.getPostHeaders(rssBlog.getId()); + assertEquals(1, headers.size()); + BlogPostHeader header = headers.iterator().next(); + assertEquals(POST, header.getType()); + assertTrue(header.isRssFeed()); + } + + @Test + public void testFeedReblog() throws Exception { + // add a feed post to rssBlog + final String body = getRandomString(42); + BlogPost p = blogPostFactory + .createBlogPost(rssBlog.getId(), clock.currentTimeMillis(), + null, author0, body); + blogManager0.addLocalPost(p); + + // reblog feed post to own blog + Collection<BlogPostHeader> headers = + blogManager0.getPostHeaders(rssBlog.getId()); + assertEquals(1, headers.size()); + BlogPostHeader header = headers.iterator().next(); + blogManager0.addLocalComment(author0, blog0.getId(), null, header); + + // make sure it got saved as an RSS feed post + headers = blogManager0.getPostHeaders(blog0.getId()); + assertEquals(1, headers.size()); + BlogCommentHeader commentHeader = + (BlogCommentHeader) headers.iterator().next(); + assertEquals(COMMENT, commentHeader.getType()); + assertTrue(commentHeader.getParent().isRssFeed()); + + // reblog reblogged post again to own blog + blogManager0 + .addLocalComment(author0, blog0.getId(), null, commentHeader); + + // make sure it got saved as an RSS feed post + headers = blogManager0.getPostHeaders(blog0.getId()); + assertEquals(2, headers.size()); + for (BlogPostHeader h: headers) { + assertTrue(h instanceof BlogCommentHeader); + assertEquals(COMMENT, h.getType()); + assertTrue(((BlogCommentHeader) h).getParent().isRssFeed()); + } + } + } diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java index 25d4992c41a4b03f012e5467cbff2afd22cb959b..2fc24aae58f3f082491e5ca6011ca7ca05d9100a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java @@ -12,6 +12,7 @@ import org.briarproject.bramble.test.TestUtils; import org.briarproject.bramble.transport.TransportModule; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogManager; +import org.briarproject.briar.api.blog.BlogPostHeader; import org.briarproject.briar.api.feed.Feed; import org.briarproject.briar.api.feed.FeedManager; import org.briarproject.briar.blog.BlogModule; @@ -88,6 +89,13 @@ public class FeedManagerIntegrationTest extends BriarTestCase { assertEquals(feed.getTitle(), feed.getBlog().getName()); assertEquals(feed.getTitle(), feed.getLocalAuthor().getName()); + // check the feed entries have been added to the blog as expected + Collection<BlogPostHeader> headers = + blogManager.getPostHeaders(feedBlog.getId()); + for (BlogPostHeader header : headers) { + assertTrue(header.isRssFeed()); + } + // now let's remove the feed's blog again blogManager.removeBlog(feedBlog); blogs = blogManager.getBlogs();