mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
Merge branch '498-implement-ui-for-sharing-blogs' into 'master'
UI for sharing blogs Not posting any screenshots, because the UI is the same as for forums. This does not yet offer the possibility to unsubscribe from blogs again. Should be done in a different MR as this one is big enough already. Closes #498, #497 See merge request !263
This commit is contained in:
@@ -0,0 +1,658 @@
|
||||
package org.briarproject;
|
||||
|
||||
import net.jodah.concurrentunit.Waiter;
|
||||
|
||||
import org.briarproject.api.blogs.Blog;
|
||||
import org.briarproject.api.blogs.BlogInvitationRequest;
|
||||
import org.briarproject.api.blogs.BlogInvitationResponse;
|
||||
import org.briarproject.api.blogs.BlogManager;
|
||||
import org.briarproject.api.blogs.BlogPostFactory;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyPair;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.BlogInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.BlogInvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.MessageStateChangedEvent;
|
||||
import org.briarproject.api.identity.AuthorFactory;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.SyncSession;
|
||||
import org.briarproject.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.api.sync.ValidationManager.State;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.blogs.BlogsModule;
|
||||
import org.briarproject.contact.ContactModule;
|
||||
import org.briarproject.crypto.CryptoModule;
|
||||
import org.briarproject.lifecycle.LifecycleModule;
|
||||
import org.briarproject.properties.PropertiesModule;
|
||||
import org.briarproject.sharing.SharingModule;
|
||||
import org.briarproject.sync.SyncModule;
|
||||
import org.briarproject.transport.TransportModule;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.TestPluginsModule.MAX_LATENCY;
|
||||
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
|
||||
import static org.briarproject.api.sync.ValidationManager.State.INVALID;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BlogSharingIntegrationTest extends BriarTestCase {
|
||||
|
||||
private LifecycleManager lifecycleManager0, lifecycleManager1,
|
||||
lifecycleManager2;
|
||||
private SyncSessionFactory sync0, sync1, sync2;
|
||||
private BlogManager blogManager0, blogManager1;
|
||||
private ContactManager contactManager0, contactManager1, contactManager2;
|
||||
private Contact contact1, contact2, contact01, contact02;
|
||||
private ContactId contactId1, contactId2, contactId01, contactId02;
|
||||
private IdentityManager identityManager0, identityManager1,
|
||||
identityManager2;
|
||||
private LocalAuthor author0, author1, author2;
|
||||
private Blog blog0, blog1, blog2;
|
||||
private SharerListener listener0, listener2;
|
||||
private InviteeListener listener1;
|
||||
|
||||
@Inject
|
||||
Clock clock;
|
||||
@Inject
|
||||
AuthorFactory authorFactory;
|
||||
@Inject
|
||||
BlogPostFactory blogPostFactory;
|
||||
@Inject
|
||||
CryptoComponent cryptoComponent;
|
||||
|
||||
// objects accessed from background threads need to be volatile
|
||||
private volatile BlogSharingManager blogSharingManager0;
|
||||
private volatile BlogSharingManager blogSharingManager1;
|
||||
private volatile BlogSharingManager blogSharingManager2;
|
||||
private volatile Waiter eventWaiter;
|
||||
private volatile Waiter msgWaiter;
|
||||
|
||||
private final File testDir = TestUtils.getTestDirectory();
|
||||
private final SecretKey master = TestUtils.getSecretKey();
|
||||
private final int TIMEOUT = 15000;
|
||||
private final String SHARER = "Sharer";
|
||||
private final String INVITEE = "Invitee";
|
||||
private final String CONTACT2 = "Contact2";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BlogSharingIntegrationTest.class.getName());
|
||||
|
||||
private BlogSharingIntegrationTestComponent t0, t1, t2;
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
BlogSharingIntegrationTestComponent component =
|
||||
DaggerBlogSharingIntegrationTestComponent.builder().build();
|
||||
component.inject(this);
|
||||
injectEagerSingletons(component);
|
||||
|
||||
assertTrue(testDir.mkdirs());
|
||||
File t0Dir = new File(testDir, SHARER);
|
||||
t0 = DaggerBlogSharingIntegrationTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(t0Dir)).build();
|
||||
injectEagerSingletons(t0);
|
||||
File t1Dir = new File(testDir, INVITEE);
|
||||
t1 = DaggerBlogSharingIntegrationTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(t1Dir)).build();
|
||||
injectEagerSingletons(t1);
|
||||
File t2Dir = new File(testDir, CONTACT2);
|
||||
t2 = DaggerBlogSharingIntegrationTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(t2Dir)).build();
|
||||
injectEagerSingletons(t2);
|
||||
|
||||
identityManager0 = t0.getIdentityManager();
|
||||
identityManager1 = t1.getIdentityManager();
|
||||
identityManager2 = t2.getIdentityManager();
|
||||
contactManager0 = t0.getContactManager();
|
||||
contactManager1 = t1.getContactManager();
|
||||
contactManager2 = t2.getContactManager();
|
||||
blogManager0 = t0.getBlogManager();
|
||||
blogManager1 = t1.getBlogManager();
|
||||
blogSharingManager0 = t0.getBlogSharingManager();
|
||||
blogSharingManager1 = t1.getBlogSharingManager();
|
||||
blogSharingManager2 = t2.getBlogSharingManager();
|
||||
sync0 = t0.getSyncSessionFactory();
|
||||
sync1 = t1.getSyncSessionFactory();
|
||||
sync2 = t2.getSyncSessionFactory();
|
||||
|
||||
// initialize waiters fresh for each test
|
||||
eventWaiter = new Waiter();
|
||||
msgWaiter = new Waiter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersonalBlogCannotBeSharedWithOwner() throws Exception {
|
||||
startLifecycles();
|
||||
defaultInit(true);
|
||||
|
||||
assertFalse(blogSharingManager0.canBeShared(blog1.getId(), contact1));
|
||||
assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact2));
|
||||
assertFalse(blogSharingManager1.canBeShared(blog0.getId(), contact01));
|
||||
assertFalse(blogSharingManager2.canBeShared(blog0.getId(), contact02));
|
||||
|
||||
// create invitation
|
||||
blogSharingManager0
|
||||
.sendInvitation(blog1.getId(), contactId1, "Hi!");
|
||||
|
||||
// sync invitation
|
||||
sync0To1();
|
||||
// make sure the invitee ignored the request for their own blog
|
||||
assertFalse(listener1.requestReceived);
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulSharing() throws Exception {
|
||||
startLifecycles();
|
||||
|
||||
// initialize and let invitee accept all requests
|
||||
defaultInit(true);
|
||||
|
||||
// send invitation
|
||||
blogSharingManager0
|
||||
.sendInvitation(blog2.getId(), contactId1, "Hi!");
|
||||
|
||||
// invitee has own blog and that of the sharer
|
||||
assertEquals(2, blogManager1.getBlogs().size());
|
||||
|
||||
// sync first request message
|
||||
sync0To1();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener1.requestReceived);
|
||||
|
||||
// sync response back
|
||||
sync1To0();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.responseReceived);
|
||||
|
||||
// blog was added successfully
|
||||
assertEquals(0, blogSharingManager0.getInvited().size());
|
||||
assertEquals(3, blogManager1.getBlogs().size());
|
||||
|
||||
// invitee has one invitation message from sharer
|
||||
List<InvitationMessage> list =
|
||||
new ArrayList<>(blogSharingManager1
|
||||
.getInvitationMessages(contactId01));
|
||||
assertEquals(2, list.size());
|
||||
// check other things are alright with the message
|
||||
for (InvitationMessage m : list) {
|
||||
if (m instanceof BlogInvitationRequest) {
|
||||
BlogInvitationRequest invitation =
|
||||
(BlogInvitationRequest) m;
|
||||
assertFalse(invitation.isAvailable());
|
||||
assertEquals(blog2.getAuthor().getName(),
|
||||
invitation.getBlogAuthorName());
|
||||
assertEquals(contactId1, invitation.getContactId());
|
||||
assertEquals("Hi!", invitation.getMessage());
|
||||
} else {
|
||||
BlogInvitationResponse response =
|
||||
(BlogInvitationResponse) m;
|
||||
assertEquals(contactId01, response.getContactId());
|
||||
assertTrue(response.wasAccepted());
|
||||
assertTrue(response.isLocal());
|
||||
}
|
||||
}
|
||||
// sharer has own invitation message and response
|
||||
assertEquals(2,
|
||||
blogSharingManager0.getInvitationMessages(contactId1)
|
||||
.size());
|
||||
// blog can not be shared again
|
||||
assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1));
|
||||
assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01));
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeclinedSharing() throws Exception {
|
||||
startLifecycles();
|
||||
|
||||
// initialize and let invitee deny all requests
|
||||
defaultInit(false);
|
||||
|
||||
// send invitation
|
||||
blogSharingManager0
|
||||
.sendInvitation(blog2.getId(), contactId1, null);
|
||||
|
||||
// sync first request message
|
||||
sync0To1();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener1.requestReceived);
|
||||
|
||||
// sync response back
|
||||
sync1To0();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.responseReceived);
|
||||
|
||||
// blog was not added
|
||||
assertEquals(0, blogSharingManager0.getInvited().size());
|
||||
assertEquals(2, blogManager1.getBlogs().size());
|
||||
// blog is no longer available to invitee who declined
|
||||
assertEquals(0, blogSharingManager1.getInvited().size());
|
||||
|
||||
// invitee has one invitation message from sharer and one response
|
||||
List<InvitationMessage> list =
|
||||
new ArrayList<>(blogSharingManager1
|
||||
.getInvitationMessages(contactId01));
|
||||
assertEquals(2, list.size());
|
||||
// check things are alright with the message
|
||||
for (InvitationMessage m : list) {
|
||||
if (m instanceof BlogInvitationRequest) {
|
||||
BlogInvitationRequest invitation =
|
||||
(BlogInvitationRequest) m;
|
||||
assertFalse(invitation.isAvailable());
|
||||
assertEquals(blog2.getAuthor().getName(),
|
||||
invitation.getBlogAuthorName());
|
||||
assertEquals(contactId1, invitation.getContactId());
|
||||
assertEquals(null, invitation.getMessage());
|
||||
} else {
|
||||
BlogInvitationResponse response =
|
||||
(BlogInvitationResponse) m;
|
||||
assertEquals(contactId01, response.getContactId());
|
||||
assertFalse(response.wasAccepted());
|
||||
assertTrue(response.isLocal());
|
||||
}
|
||||
}
|
||||
// sharer has own invitation message and response
|
||||
assertEquals(2,
|
||||
blogSharingManager0.getInvitationMessages(contactId1)
|
||||
.size());
|
||||
// blog can be shared again
|
||||
assertTrue(blogSharingManager0.canBeShared(blog2.getId(), contact1));
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInviteeLeavesAfterFinished() throws Exception {
|
||||
startLifecycles();
|
||||
|
||||
// initialize and let invitee accept all requests
|
||||
defaultInit(true);
|
||||
|
||||
// send invitation
|
||||
blogSharingManager0
|
||||
.sendInvitation(blog2.getId(), contactId1, "Hi!");
|
||||
|
||||
// sync first request message
|
||||
sync0To1();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener1.requestReceived);
|
||||
|
||||
// sync response back
|
||||
sync1To0();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.responseReceived);
|
||||
|
||||
// blog was added successfully
|
||||
assertEquals(0, blogSharingManager0.getInvited().size());
|
||||
assertEquals(3, blogManager1.getBlogs().size());
|
||||
assertTrue(blogManager1.getBlogs().contains(blog2));
|
||||
|
||||
// sharer shares blog with invitee
|
||||
assertTrue(blogSharingManager0.getSharedWith(blog2.getId())
|
||||
.contains(contact1));
|
||||
// invitee gets blog shared by sharer
|
||||
assertTrue(blogSharingManager1.getSharedBy(blog2.getId())
|
||||
.contains(contact01));
|
||||
|
||||
// invitee un-subscribes from blog
|
||||
blogManager1.removeBlog(blog2);
|
||||
|
||||
// send leave message to sharer
|
||||
sync1To0();
|
||||
|
||||
// blog is gone
|
||||
assertEquals(0, blogSharingManager0.getInvited().size());
|
||||
assertEquals(2, blogManager1.getBlogs().size());
|
||||
|
||||
// sharer no longer shares blog with invitee
|
||||
assertFalse(blogSharingManager0.getSharedWith(blog2.getId())
|
||||
.contains(contact1));
|
||||
// invitee no longer gets blog shared by sharer
|
||||
assertFalse(blogSharingManager1.getSharedBy(blog2.getId())
|
||||
.contains(contact01));
|
||||
// blog can be shared again
|
||||
assertTrue(blogSharingManager0.canBeShared(blog2.getId(), contact1));
|
||||
assertTrue(blogSharingManager1.canBeShared(blog2.getId(), contact01));
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvitationForExistingBlog() throws Exception {
|
||||
startLifecycles();
|
||||
|
||||
// initialize and let invitee accept all requests
|
||||
defaultInit(true);
|
||||
|
||||
// 1 and 2 are adding each other
|
||||
contactManager1.addContact(author2,
|
||||
author1.getId(), master, clock.currentTimeMillis(), true,
|
||||
true
|
||||
);
|
||||
contactManager2.addContact(author1,
|
||||
author2.getId(), master, clock.currentTimeMillis(), true,
|
||||
true
|
||||
);
|
||||
assertEquals(3, blogManager1.getBlogs().size());
|
||||
|
||||
// sharer sends invitation for 2's blog to 1
|
||||
blogSharingManager0
|
||||
.sendInvitation(blog2.getId(), contactId1, "Hi!");
|
||||
|
||||
// sync first request message
|
||||
sync0To1();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener1.requestReceived);
|
||||
|
||||
// make sure blog2 is shared by 0
|
||||
Collection<Contact> contacts =
|
||||
blogSharingManager1.getSharedBy(blog2.getId());
|
||||
assertEquals(1, contacts.size());
|
||||
assertTrue(contacts.contains(contact01));
|
||||
|
||||
// make sure 1 knows that they have blog2 already
|
||||
Collection<InvitationMessage> messages =
|
||||
blogSharingManager1.getInvitationMessages(contactId01);
|
||||
assertEquals(2, messages.size());
|
||||
assertEquals(blog2, blogManager1.getBlog(blog2.getId()));
|
||||
|
||||
// sync response back
|
||||
sync1To0();
|
||||
eventWaiter.await(TIMEOUT, 1);
|
||||
assertTrue(listener0.responseReceived);
|
||||
|
||||
// blog was not added, because it was there already
|
||||
assertEquals(0, blogSharingManager0.getInvited().size());
|
||||
assertEquals(3, blogManager1.getBlogs().size());
|
||||
|
||||
stopLifecycles();
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void tearDown() throws InterruptedException {
|
||||
TestUtils.deleteTestDirectory(testDir);
|
||||
}
|
||||
|
||||
private class SharerListener implements EventListener {
|
||||
|
||||
volatile boolean requestReceived = false;
|
||||
volatile boolean responseReceived = false;
|
||||
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof MessageStateChangedEvent) {
|
||||
MessageStateChangedEvent event = (MessageStateChangedEvent) e;
|
||||
State s = event.getState();
|
||||
ClientId c = event.getClientId();
|
||||
if ((s == DELIVERED || s == INVALID) &&
|
||||
c.equals(blogSharingManager0.getClientId()) &&
|
||||
!event.isLocal()) {
|
||||
LOG.info("TEST: Sharer received message in group " +
|
||||
event.getMessage().getGroupId().hashCode());
|
||||
msgWaiter.resume();
|
||||
} else if (s == DELIVERED && !event.isLocal() &&
|
||||
c.equals(blogManager0.getClientId())) {
|
||||
LOG.info("TEST: Sharer received blog post");
|
||||
msgWaiter.resume();
|
||||
}
|
||||
} else if (e instanceof BlogInvitationResponseReceivedEvent) {
|
||||
BlogInvitationResponseReceivedEvent event =
|
||||
(BlogInvitationResponseReceivedEvent) e;
|
||||
eventWaiter.assertEquals(contactId1, event.getContactId());
|
||||
responseReceived = true;
|
||||
eventWaiter.resume();
|
||||
}
|
||||
// this is only needed for tests where a blog is re-shared
|
||||
else if (e instanceof BlogInvitationReceivedEvent) {
|
||||
BlogInvitationReceivedEvent event =
|
||||
(BlogInvitationReceivedEvent) e;
|
||||
eventWaiter.assertEquals(contactId1, event.getContactId());
|
||||
requestReceived = true;
|
||||
Blog b = event.getBlog();
|
||||
try {
|
||||
Contact c = contactManager0.getContact(contactId1);
|
||||
blogSharingManager0.respondToInvitation(b, c, true);
|
||||
} catch (DbException ex) {
|
||||
eventWaiter.rethrow(ex);
|
||||
} finally {
|
||||
eventWaiter.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InviteeListener implements EventListener {
|
||||
|
||||
volatile boolean requestReceived = false;
|
||||
volatile boolean responseReceived = false;
|
||||
|
||||
private final boolean accept, answer;
|
||||
|
||||
InviteeListener(boolean accept, boolean answer) {
|
||||
this.accept = accept;
|
||||
this.answer = answer;
|
||||
}
|
||||
|
||||
InviteeListener(boolean accept) {
|
||||
this(accept, true);
|
||||
}
|
||||
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof MessageStateChangedEvent) {
|
||||
MessageStateChangedEvent event = (MessageStateChangedEvent) e;
|
||||
State s = event.getState();
|
||||
ClientId c = event.getClientId();
|
||||
if ((s == DELIVERED || s == INVALID) &&
|
||||
c.equals(blogSharingManager0.getClientId()) &&
|
||||
!event.isLocal()) {
|
||||
LOG.info("TEST: Invitee received message in group " +
|
||||
event.getMessage().getGroupId().hashCode());
|
||||
msgWaiter.resume();
|
||||
} else if (s == DELIVERED && !event.isLocal() &&
|
||||
c.equals(blogManager0.getClientId())) {
|
||||
LOG.info("TEST: Invitee received blog post");
|
||||
msgWaiter.resume();
|
||||
}
|
||||
} else if (e instanceof BlogInvitationReceivedEvent) {
|
||||
BlogInvitationReceivedEvent event =
|
||||
(BlogInvitationReceivedEvent) e;
|
||||
requestReceived = true;
|
||||
if (!answer) return;
|
||||
Blog b = event.getBlog();
|
||||
try {
|
||||
eventWaiter.assertEquals(1,
|
||||
blogSharingManager1.getInvited().size());
|
||||
Contact c =
|
||||
contactManager1.getContact(event.getContactId());
|
||||
blogSharingManager1.respondToInvitation(b, c, accept);
|
||||
} catch (DbException ex) {
|
||||
eventWaiter.rethrow(ex);
|
||||
} finally {
|
||||
eventWaiter.resume();
|
||||
}
|
||||
}
|
||||
// this is only needed for tests where a blog is re-shared
|
||||
else if (e instanceof BlogInvitationResponseReceivedEvent) {
|
||||
BlogInvitationResponseReceivedEvent event =
|
||||
(BlogInvitationResponseReceivedEvent) e;
|
||||
eventWaiter.assertEquals(contactId01, event.getContactId());
|
||||
responseReceived = true;
|
||||
eventWaiter.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startLifecycles() throws InterruptedException {
|
||||
// Start the lifecycle manager and wait for it to finish
|
||||
lifecycleManager0 = t0.getLifecycleManager();
|
||||
lifecycleManager1 = t1.getLifecycleManager();
|
||||
lifecycleManager2 = t2.getLifecycleManager();
|
||||
lifecycleManager0.startServices();
|
||||
lifecycleManager1.startServices();
|
||||
lifecycleManager2.startServices();
|
||||
lifecycleManager0.waitForStartup();
|
||||
lifecycleManager1.waitForStartup();
|
||||
lifecycleManager2.waitForStartup();
|
||||
}
|
||||
|
||||
private void stopLifecycles() throws InterruptedException {
|
||||
// Clean up
|
||||
lifecycleManager0.stopServices();
|
||||
lifecycleManager1.stopServices();
|
||||
lifecycleManager2.stopServices();
|
||||
lifecycleManager0.waitForShutdown();
|
||||
lifecycleManager1.waitForShutdown();
|
||||
lifecycleManager2.waitForShutdown();
|
||||
}
|
||||
|
||||
private void defaultInit(boolean accept) throws DbException {
|
||||
addDefaultIdentities();
|
||||
addDefaultContacts();
|
||||
getPersonalBlogOfSharer();
|
||||
listenToEvents(accept);
|
||||
}
|
||||
|
||||
private void addDefaultIdentities() throws DbException {
|
||||
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair();
|
||||
author0 = authorFactory.createLocalAuthor(SHARER,
|
||||
keyPair.getPublic().getEncoded(),
|
||||
keyPair.getPrivate().getEncoded());
|
||||
identityManager0.addLocalAuthor(author0);
|
||||
|
||||
keyPair = cryptoComponent.generateSignatureKeyPair();
|
||||
author1 = authorFactory.createLocalAuthor(INVITEE,
|
||||
keyPair.getPublic().getEncoded(),
|
||||
keyPair.getPrivate().getEncoded());
|
||||
identityManager1.addLocalAuthor(author1);
|
||||
|
||||
keyPair = cryptoComponent.generateSignatureKeyPair();
|
||||
author2 = authorFactory.createLocalAuthor(CONTACT2,
|
||||
keyPair.getPublic().getEncoded(),
|
||||
keyPair.getPrivate().getEncoded());
|
||||
identityManager2.addLocalAuthor(author2);
|
||||
}
|
||||
|
||||
private void addDefaultContacts() throws DbException {
|
||||
// sharer adds invitee as contact
|
||||
contactId1 = contactManager0.addContact(author1,
|
||||
author0.getId(), master, clock.currentTimeMillis(), true,
|
||||
true
|
||||
);
|
||||
contact1 = contactManager0.getContact(contactId1);
|
||||
// sharer adds second contact
|
||||
contactId2 = contactManager0.addContact(author2,
|
||||
author0.getId(), master, clock.currentTimeMillis(), true,
|
||||
true
|
||||
);
|
||||
contact2 = contactManager0.getContact(contactId2);
|
||||
// contacts add sharer back
|
||||
contactId01 = contactManager1.addContact(author0,
|
||||
author1.getId(), master, clock.currentTimeMillis(), true,
|
||||
true
|
||||
);
|
||||
contact01 = contactManager1.getContact(contactId01);
|
||||
contactId02 = contactManager2.addContact(author0,
|
||||
author2.getId(), master, clock.currentTimeMillis(), true,
|
||||
true
|
||||
);
|
||||
contact02 = contactManager2.getContact(contactId02);
|
||||
}
|
||||
|
||||
private void getPersonalBlogOfSharer() throws DbException {
|
||||
blog0 = blogManager0.getPersonalBlog(author0);
|
||||
blog1 = blogManager0.getPersonalBlog(author1);
|
||||
blog2 = blogManager0.getPersonalBlog(author2);
|
||||
}
|
||||
|
||||
private void listenToEvents(boolean accept) {
|
||||
listener0 = new SharerListener();
|
||||
t0.getEventBus().addListener(listener0);
|
||||
listener1 = new InviteeListener(accept);
|
||||
t1.getEventBus().addListener(listener1);
|
||||
listener2 = new SharerListener();
|
||||
t2.getEventBus().addListener(listener2);
|
||||
}
|
||||
|
||||
private void sync0To1() throws IOException, TimeoutException {
|
||||
deliverMessage(sync0, contactId01, sync1, contactId1,
|
||||
"Sharer to Invitee");
|
||||
}
|
||||
|
||||
private void sync1To0() throws IOException, TimeoutException {
|
||||
deliverMessage(sync1, contactId1, sync0, contactId01,
|
||||
"Invitee to Sharer");
|
||||
}
|
||||
|
||||
private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId,
|
||||
SyncSessionFactory toSync, ContactId toId, String debug)
|
||||
throws IOException, TimeoutException {
|
||||
|
||||
if (debug != null) LOG.info("TEST: Sending message from " + debug);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Create an outgoing sync session
|
||||
SyncSession sessionFrom =
|
||||
fromSync.createSimplexOutgoingSession(toId, MAX_LATENCY, out);
|
||||
// Write whatever needs to be written
|
||||
sessionFrom.run();
|
||||
out.close();
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
// Create an incoming sync session
|
||||
SyncSession sessionTo = toSync.createIncomingSession(fromId, in);
|
||||
// Read whatever needs to be read
|
||||
sessionTo.run();
|
||||
in.close();
|
||||
|
||||
// wait for message to actually arrive
|
||||
msgWaiter.await(TIMEOUT, 1);
|
||||
}
|
||||
|
||||
private void injectEagerSingletons(
|
||||
BlogSharingIntegrationTestComponent component) {
|
||||
|
||||
component.inject(new LifecycleModule.EagerSingletons());
|
||||
component.inject(new BlogsModule.EagerSingletons());
|
||||
component.inject(new CryptoModule.EagerSingletons());
|
||||
component.inject(new ContactModule.EagerSingletons());
|
||||
component.inject(new TransportModule.EagerSingletons());
|
||||
component.inject(new SharingModule.EagerSingletons());
|
||||
component.inject(new SyncModule.EagerSingletons());
|
||||
component.inject(new PropertiesModule.EagerSingletons());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.briarproject;
|
||||
|
||||
import org.briarproject.api.blogs.BlogManager;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.clients.MessageQueueManager;
|
||||
import org.briarproject.api.clients.PrivateGroupFactory;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.blogs.BlogsModule;
|
||||
import org.briarproject.clients.ClientsModule;
|
||||
import org.briarproject.contact.ContactModule;
|
||||
import org.briarproject.crypto.CryptoModule;
|
||||
import org.briarproject.data.DataModule;
|
||||
import org.briarproject.db.DatabaseModule;
|
||||
import org.briarproject.event.EventModule;
|
||||
import org.briarproject.forum.ForumModule;
|
||||
import org.briarproject.identity.IdentityModule;
|
||||
import org.briarproject.lifecycle.LifecycleModule;
|
||||
import org.briarproject.properties.PropertiesModule;
|
||||
import org.briarproject.sharing.SharingModule;
|
||||
import org.briarproject.sync.SyncModule;
|
||||
import org.briarproject.system.SystemModule;
|
||||
import org.briarproject.transport.TransportModule;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@Singleton
|
||||
@Component(modules = {
|
||||
TestDatabaseModule.class,
|
||||
TestPluginsModule.class,
|
||||
TestSeedProviderModule.class,
|
||||
ClientsModule.class,
|
||||
ContactModule.class,
|
||||
CryptoModule.class,
|
||||
DataModule.class,
|
||||
DatabaseModule.class,
|
||||
EventModule.class,
|
||||
BlogsModule.class,
|
||||
ForumModule.class,
|
||||
IdentityModule.class,
|
||||
LifecycleModule.class,
|
||||
PropertiesModule.class,
|
||||
SharingModule.class,
|
||||
SyncModule.class,
|
||||
SystemModule.class,
|
||||
TransportModule.class
|
||||
})
|
||||
interface BlogSharingIntegrationTestComponent {
|
||||
|
||||
void inject(BlogSharingIntegrationTest testCase);
|
||||
|
||||
void inject(ContactModule.EagerSingletons init);
|
||||
|
||||
void inject(CryptoModule.EagerSingletons init);
|
||||
|
||||
void inject(BlogsModule.EagerSingletons init);
|
||||
|
||||
void inject(LifecycleModule.EagerSingletons init);
|
||||
|
||||
void inject(PropertiesModule.EagerSingletons init);
|
||||
|
||||
void inject(SharingModule.EagerSingletons init);
|
||||
|
||||
void inject(SyncModule.EagerSingletons init);
|
||||
|
||||
void inject(TransportModule.EagerSingletons init);
|
||||
|
||||
LifecycleManager getLifecycleManager();
|
||||
|
||||
EventBus getEventBus();
|
||||
|
||||
IdentityManager getIdentityManager();
|
||||
|
||||
ContactManager getContactManager();
|
||||
|
||||
BlogSharingManager getBlogSharingManager();
|
||||
|
||||
BlogManager getBlogManager();
|
||||
|
||||
SyncSessionFactory getSyncSessionFactory();
|
||||
|
||||
/* the following methods are only needed to manually construct messages */
|
||||
|
||||
DatabaseComponent getDatabaseComponent();
|
||||
|
||||
PrivateGroupFactory getPrivateGroupFactory();
|
||||
|
||||
ClientHelper getClientHelper();
|
||||
|
||||
MessageQueueManager getMessageQueueManager();
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.blogs.BlogsModule;
|
||||
import org.briarproject.clients.ClientsModule;
|
||||
import org.briarproject.contact.ContactModule;
|
||||
import org.briarproject.crypto.CryptoModule;
|
||||
@@ -38,6 +39,7 @@ import dagger.Component;
|
||||
DatabaseModule.class,
|
||||
EventModule.class,
|
||||
ForumModule.class,
|
||||
BlogsModule.class,
|
||||
IdentityModule.class,
|
||||
LifecycleModule.class,
|
||||
PropertiesModule.class,
|
||||
@@ -46,7 +48,7 @@ import dagger.Component;
|
||||
SystemModule.class,
|
||||
TransportModule.class
|
||||
})
|
||||
public interface ForumManagerTestComponent {
|
||||
interface ForumManagerTestComponent {
|
||||
|
||||
void inject(ForumManagerTest testCase);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.blogs.BlogsModule;
|
||||
import org.briarproject.clients.ClientsModule;
|
||||
import org.briarproject.contact.ContactModule;
|
||||
import org.briarproject.crypto.CryptoModule;
|
||||
@@ -42,6 +43,7 @@ import dagger.Component;
|
||||
DatabaseModule.class,
|
||||
EventModule.class,
|
||||
ForumModule.class,
|
||||
BlogsModule.class,
|
||||
IdentityModule.class,
|
||||
LifecycleModule.class,
|
||||
PropertiesModule.class,
|
||||
@@ -50,7 +52,7 @@ import dagger.Component;
|
||||
SystemModule.class,
|
||||
TransportModule.class
|
||||
})
|
||||
public interface ForumSharingIntegrationTestComponent {
|
||||
interface ForumSharingIntegrationTestComponent {
|
||||
|
||||
void inject(ForumSharingIntegrationTest testCase);
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.forum.ForumInvitationsActivity"
|
||||
android:name=".android.sharing.InvitationsForumActivity"
|
||||
android:label="@string/forum_invitations_title"
|
||||
android:parentActivityName=".android.NavDrawerActivity">
|
||||
<meta-data
|
||||
@@ -111,6 +111,16 @@
|
||||
/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.sharing.InvitationsBlogActivity"
|
||||
android:label="@string/blogs_sharing_invitations_title"
|
||||
android:parentActivityName=".android.contact.ConversationActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".android.contact.ConversationActivity"
|
||||
/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.forum.CreateForumActivity"
|
||||
android:label="@string/create_forum_title"
|
||||
@@ -133,8 +143,8 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.forum.ShareForumActivity"
|
||||
android:label="@string/forums_share_toolbar_header"
|
||||
android:name=".android.sharing.ShareForumActivity"
|
||||
android:label="@string/activity_share_toolbar_header"
|
||||
android:parentActivityName=".android.forum.ForumActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
@@ -143,8 +153,18 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.forum.ForumSharingStatusActivity"
|
||||
android:label="@string/forum_sharing_status"
|
||||
android:name=".android.sharing.ShareBlogActivity"
|
||||
android:label="@string/activity_share_toolbar_header"
|
||||
android:parentActivityName=".android.blogs.BlogActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".android.blogs.BlogActivity"
|
||||
/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.sharing.SharingStatusForumActivity"
|
||||
android:label="@string/sharing_status"
|
||||
android:parentActivityName=".android.forum.ForumActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
@@ -152,6 +172,16 @@
|
||||
/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.sharing.SharingStatusBlogActivity"
|
||||
android:label="@string/sharing_status"
|
||||
android:parentActivityName=".android.blogs.BlogActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".android.blogs.BlogActivity"
|
||||
/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.blogs.CreateBlogActivity"
|
||||
android:label="@string/blogs_my_blogs_label"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.briarproject.android.util.BriarRecyclerView
|
||||
android:id="@+id/availableForumsView"
|
||||
android:id="@+id/invitationsView"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
android:id="@+id/shareForumContainer"
|
||||
android:id="@+id/shareContainer"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/messageLayout"
|
||||
layout="@layout/list_item_msg_out"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/introductionLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right|end"
|
||||
android:background="@drawable/notice_out"
|
||||
android:layout_marginLeft="@dimen/message_bubble_margin_non_tail"
|
||||
android:layout_marginRight="@dimen/message_bubble_margin_tail">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/introductionText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/briar_text_secondary"
|
||||
tools:text="@string/introduction_request_received"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/introductionTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/introductionText"
|
||||
android:textColor="@color/private_message_date"
|
||||
android:textSize="@dimen/text_size_tiny"
|
||||
tools:text="Dec 24, 13:37"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/introductionStatus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/introductionTime"
|
||||
android:layout_toRightOf="@+id/introductionTime"
|
||||
android:layout_alignBottom="@+id/introductionTime"
|
||||
android:layout_marginLeft="@dimen/margin_medium"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/message_delivered"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -37,13 +37,13 @@
|
||||
android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
|
||||
android:layout_alignEnd="@+id/introductionText"
|
||||
android:layout_alignRight="@+id/introductionText"
|
||||
android:layout_below="@+id/showForumsButton"
|
||||
android:layout_below="@+id/showInvitationsButton"
|
||||
android:textColor="@color/private_message_date"
|
||||
android:textSize="@dimen/text_size_tiny"
|
||||
tools:text="Dec 24, 13:37"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/showForumsButton"
|
||||
android:id="@+id/showInvitationsButton"
|
||||
style="@style/BriarButtonFlat.Positive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -51,7 +51,7 @@
|
||||
android:layout_alignEnd="@+id/introductionText"
|
||||
android:layout_alignRight="@+id/introductionText"
|
||||
android:layout_below="@+id/introductionText"
|
||||
android:text="@string/forum_show_invitations"/>
|
||||
tools:text="@string/forum_show_invitations"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
17
briar-android/res/menu/blogs_blog_actions.xml
Normal file
17
briar-android/res/menu/blogs_blog_actions.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_blog_share"
|
||||
android:icon="@drawable/social_share_white"
|
||||
android:title="@string/blogs_sharing_share"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_blog_sharing_status"
|
||||
android:title="@string/sharing_status"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<item
|
||||
android:id="@+id/action_forum_sharing_status"
|
||||
android:title="@string/forum_sharing_status"
|
||||
android:title="@string/sharing_status"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<string name="show_forums">Mostrar</string>
|
||||
<string name="forum_leave">Sair do fórum</string>
|
||||
<string name="forum_left_toast">Saiu do fórum</string>
|
||||
<string name="forum_sharing_status">Status de compartilhamento</string>
|
||||
<string name="sharing_status">Status de compartilhamento</string>
|
||||
<string name="no_posts">Sem Posts</string>
|
||||
<plurals name="unread_posts">
|
||||
<item quantity="one">%d post não lido</item>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="now">now</string>
|
||||
<string name="contact_list_title">Contacts</string>
|
||||
<string name="no_contacts">It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future.</string>
|
||||
<string name="no_contacts_selector">It seems that you are new here and have no contacts yet.\n\nPlease come back here after you added your first contact.</string>
|
||||
<string name="add_contact_title">Add a Contact</string>
|
||||
<string name="your_nickname">Choose the identity you want to use:</string>
|
||||
<string name="face_to_face">You must be face-to-face with the person you want to add as a contact. This will prevent anyone from impersonating you or reading your messages in future.</string>
|
||||
@@ -95,7 +96,7 @@
|
||||
<string name="show_forums">Show</string>
|
||||
<string name="forum_leave">Leave Forum</string>
|
||||
<string name="forum_left_toast">Left Forum</string>
|
||||
<string name="forum_sharing_status">Sharing Status</string>
|
||||
<string name="sharing_status">Sharing Status</string>
|
||||
<string name="no_posts">No posts</string>
|
||||
<plurals name="unread_posts">
|
||||
<item quantity="one">%d unread post</item>
|
||||
@@ -113,6 +114,7 @@
|
||||
<string name="forum_share_button">Share Forum</string>
|
||||
<string name="forum_shared_snackbar">Forum shared with chosen contacts</string>
|
||||
<string name="forum_share_message">You may compose an optional invitation message that will be sent to the selected contacts.</string>
|
||||
<string name="forum_share_error">There was an error sharing this forum.</string>
|
||||
<string name="forum_invitation_received">%1$s has shared the forum \"%2$s\" with you.</string>
|
||||
<string name="forum_invitation_sent">You have shared the forum \"%1$s\" with %2$s.</string>
|
||||
<string name="forum_show_invitations">Show Forum Invitations</string>
|
||||
@@ -265,7 +267,7 @@
|
||||
<string name="settings_toolbar_header">Settings</string>
|
||||
<string name="contacts_toolbar_header">Contacts</string>
|
||||
<string name="forums_toolbar_header">Forums</string>
|
||||
<string name="forums_share_toolbar_header">Choose Contacts</string>
|
||||
<string name="activity_share_toolbar_header">Choose Contacts</string>
|
||||
<!-- Progress titles -->
|
||||
<string name="progress_title_logout">Signing out of Briar..</string>
|
||||
<string name="progress_title_please_wait">Please wait..</string>
|
||||
@@ -304,6 +306,21 @@
|
||||
<string name="blogs_delete_blog_cancel">Keep</string>
|
||||
<string name="blogs_blog_deleted">Blog Deleted</string>
|
||||
<string name="blogs_remove_blog">Remove Blog</string>
|
||||
<string name="blogs_sharing_share">Share Blog</string>
|
||||
<string name="blogs_sharing_error">There was an error sharing this blog.</string>
|
||||
<string name="blogs_sharing_button">Share Blog</string>
|
||||
<string name="blogs_sharing_snackbar">Blog shared with chosen contacts</string>
|
||||
<string name="blogs_sharing_response_accepted_sent">You accepted the blog invitation from %s.</string>
|
||||
<string name="blogs_sharing_response_declined_sent">You declined the blog invitation from %s.</string>
|
||||
<string name="blogs_sharing_response_accepted_received">%s accepted the blog invitation.</string>
|
||||
<string name="blogs_sharing_response_declined_received">%s declined the blog invitation.</string>
|
||||
<string name="blogs_sharing_invitation_received">%1$s has shared the personal blog of %2$s with you.</string>
|
||||
<string name="blogs_sharing_invitation_sent">You have shared the personal blog of %1$s with %2$s.</string>
|
||||
<string name="blogs_sharing_show_invitations">Show Blog Invitations</string>
|
||||
<string name="blogs_sharing_invitations_title">Blog Invitations</string>
|
||||
<string name="blogs_sharing_exists">You are subscribed to this blog already. Accepting again can lead to faster blog post delivery.</string>
|
||||
<string name="blogs_sharing_joined_toast">Subscribed to Blog</string>
|
||||
<string name="blogs_sharing_declined_toast">Blog Invitation Declined</string>
|
||||
|
||||
<string name="blogs_blog_list">Blog List</string>
|
||||
<string name="blogs_available_blogs">Available Blogs</string>
|
||||
|
||||
@@ -15,14 +15,9 @@ import org.briarproject.android.blogs.RssFeedManageActivity;
|
||||
import org.briarproject.android.blogs.WriteBlogPostActivity;
|
||||
import org.briarproject.android.contact.ContactListFragment;
|
||||
import org.briarproject.android.contact.ConversationActivity;
|
||||
import org.briarproject.android.forum.ForumInvitationsActivity;
|
||||
import org.briarproject.android.forum.ContactSelectorFragment;
|
||||
import org.briarproject.android.forum.CreateForumActivity;
|
||||
import org.briarproject.android.forum.ForumActivity;
|
||||
import org.briarproject.android.forum.ForumListFragment;
|
||||
import org.briarproject.android.forum.ForumSharingStatusActivity;
|
||||
import org.briarproject.android.forum.ShareForumActivity;
|
||||
import org.briarproject.android.forum.ShareForumMessageFragment;
|
||||
import org.briarproject.android.identity.CreateIdentityActivity;
|
||||
import org.briarproject.android.introduction.ContactChooserFragment;
|
||||
import org.briarproject.android.introduction.IntroductionActivity;
|
||||
@@ -33,6 +28,15 @@ import org.briarproject.android.keyagreement.KeyAgreementActivity;
|
||||
import org.briarproject.android.keyagreement.ShowQrCodeFragment;
|
||||
import org.briarproject.android.panic.PanicPreferencesActivity;
|
||||
import org.briarproject.android.panic.PanicResponderActivity;
|
||||
import org.briarproject.android.sharing.ContactSelectorFragment;
|
||||
import org.briarproject.android.sharing.InvitationsBlogActivity;
|
||||
import org.briarproject.android.sharing.InvitationsForumActivity;
|
||||
import org.briarproject.android.sharing.ShareBlogActivity;
|
||||
import org.briarproject.android.sharing.ShareBlogMessageFragment;
|
||||
import org.briarproject.android.sharing.ShareForumActivity;
|
||||
import org.briarproject.android.sharing.ShareForumMessageFragment;
|
||||
import org.briarproject.android.sharing.SharingStatusBlogActivity;
|
||||
import org.briarproject.android.sharing.SharingStatusForumActivity;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@@ -63,13 +67,19 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(CreateIdentityActivity activity);
|
||||
|
||||
void inject(ForumInvitationsActivity activity);
|
||||
void inject(InvitationsForumActivity activity);
|
||||
|
||||
void inject(InvitationsBlogActivity activity);
|
||||
|
||||
void inject(CreateForumActivity activity);
|
||||
|
||||
void inject(ShareForumActivity activity);
|
||||
|
||||
void inject(ForumSharingStatusActivity activity);
|
||||
void inject(ShareBlogActivity activity);
|
||||
|
||||
void inject(SharingStatusForumActivity activity);
|
||||
|
||||
void inject(SharingStatusBlogActivity activity);
|
||||
|
||||
void inject(ForumActivity activity);
|
||||
|
||||
@@ -105,6 +115,7 @@ public interface ActivityComponent {
|
||||
void inject(ContactChooserFragment fragment);
|
||||
void inject(ContactSelectorFragment fragment);
|
||||
void inject(ShareForumMessageFragment fragment);
|
||||
void inject(ShareBlogMessageFragment fragment);
|
||||
void inject(IntroductionMessageFragment fragment);
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.briarproject.android.api.ReferenceManager;
|
||||
import org.briarproject.android.report.BriarReportSender;
|
||||
import org.briarproject.api.blogs.BlogManager;
|
||||
import org.briarproject.api.blogs.BlogPostFactory;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.ContactExchangeTask;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
@@ -93,6 +94,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
|
||||
|
||||
ForumSharingManager forumSharingManager();
|
||||
|
||||
BlogSharingManager blogSharingManager();
|
||||
|
||||
ForumPostFactory forumPostFactory();
|
||||
|
||||
BlogManager blogManager();
|
||||
|
||||
@@ -21,11 +21,12 @@ import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.BlogPostAddedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.ForumPostReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionSucceededEvent;
|
||||
import org.briarproject.api.event.InvitationReceivedEvent;
|
||||
import org.briarproject.api.event.InvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.event.PrivateMessageReceivedEvent;
|
||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
@@ -174,8 +175,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
} else if (e instanceof IntroductionSucceededEvent) {
|
||||
Contact c = ((IntroductionSucceededEvent) e).getContact();
|
||||
showIntroductionSucceededNotification(c);
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
ContactId c = ((ForumInvitationReceivedEvent) e).getContactId();
|
||||
} else if (e instanceof InvitationReceivedEvent) {
|
||||
ContactId c = ((InvitationReceivedEvent) e).getContactId();
|
||||
showNotificationForPrivateConversation(c);
|
||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
||||
ContactId c = ((InvitationResponseReceivedEvent) e).getContactId();
|
||||
showNotificationForPrivateConversation(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public class BlogActivity extends BriarActivity implements BlogPostListener,
|
||||
OnBlogPostClickListener, BaseFragmentListener {
|
||||
|
||||
static final int REQUEST_WRITE_POST = 1;
|
||||
static final int REQUEST_SHARE = 2;
|
||||
static final String BLOG_NAME = "briar.BLOG_NAME";
|
||||
static final String IS_MY_BLOG = "briar.IS_MY_BLOG";
|
||||
static final String IS_NEW_BLOG = "briar.IS_NEW_BLOG";
|
||||
@@ -185,6 +186,7 @@ public class BlogActivity extends BriarActivity implements BlogPostListener,
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
// The BlogPostAddedEvent arrives when the controller is not listening,
|
||||
// so we need to manually reload the blog posts :(
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.briarproject.android.blogs.BlogController.BlogPostListener;
|
||||
import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
|
||||
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.sharing.ShareBlogActivity;
|
||||
import org.briarproject.android.sharing.SharingStatusBlogActivity;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
@@ -30,6 +32,9 @@ import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
|
||||
import static android.support.design.widget.Snackbar.LENGTH_LONG;
|
||||
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
@@ -37,6 +42,7 @@ import static org.briarproject.android.BriarActivity.GROUP_ID;
|
||||
import static org.briarproject.android.blogs.BlogActivity.BLOG_NAME;
|
||||
import static org.briarproject.android.blogs.BlogActivity.IS_MY_BLOG;
|
||||
import static org.briarproject.android.blogs.BlogActivity.IS_NEW_BLOG;
|
||||
import static org.briarproject.android.blogs.BlogActivity.REQUEST_SHARE;
|
||||
import static org.briarproject.android.blogs.BlogActivity.REQUEST_WRITE_POST;
|
||||
|
||||
public class BlogFragment extends BaseFragment implements BlogPostListener {
|
||||
@@ -136,12 +142,18 @@ public class BlogFragment extends BaseFragment implements BlogPostListener {
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
if (myBlog) {
|
||||
inflater.inflate(R.menu.blogs_my_blog_actions, menu);
|
||||
} else {
|
||||
inflater.inflate(R.menu.blogs_blog_actions, menu);
|
||||
}
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
ActivityOptionsCompat options =
|
||||
makeCustomAnimation(getActivity(),
|
||||
android.R.anim.slide_in_left,
|
||||
android.R.anim.slide_out_right);
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
getActivity().onBackPressed();
|
||||
@@ -151,18 +163,36 @@ public class BlogFragment extends BaseFragment implements BlogPostListener {
|
||||
new Intent(getActivity(), WriteBlogPostActivity.class);
|
||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
||||
i.putExtra(BLOG_NAME, blogName);
|
||||
ActivityOptionsCompat options =
|
||||
makeCustomAnimation(getActivity(),
|
||||
android.R.anim.slide_in_left,
|
||||
android.R.anim.slide_out_right);
|
||||
ActivityCompat.startActivityForResult(getActivity(), i,
|
||||
REQUEST_WRITE_POST, options.toBundle());
|
||||
return true;
|
||||
case R.id.action_blog_share:
|
||||
Intent i2 = new Intent(getActivity(), ShareBlogActivity.class);
|
||||
i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
i2.putExtra(GROUP_ID, groupId.getBytes());
|
||||
startActivityForResult(i2, REQUEST_SHARE, options.toBundle());
|
||||
return true;
|
||||
case R.id.action_blog_sharing_status:
|
||||
Intent i3 = new Intent(getActivity(),
|
||||
SharingStatusBlogActivity.class);
|
||||
i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
i3.putExtra(GROUP_ID, groupId.getBytes());
|
||||
startActivity(i3, options.toBundle());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int request, int result, Intent data) {
|
||||
super.onActivityResult(request, result, data);
|
||||
|
||||
if (request == REQUEST_SHARE && result == RESULT_OK) {
|
||||
displaySnackbar(R.string.blogs_sharing_snackbar);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
@@ -202,6 +232,13 @@ public class BlogFragment extends BaseFragment implements BlogPostListener {
|
||||
loadData(true);
|
||||
}
|
||||
|
||||
private void displaySnackbar(int stringId) {
|
||||
Snackbar snackbar =
|
||||
Snackbar.make(list, stringId, Snackbar.LENGTH_SHORT);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
snackbar.show();
|
||||
}
|
||||
|
||||
private void showDeleteDialog() {
|
||||
DialogInterface.OnClickListener okListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.keyagreement.KeyAgreementActivity;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
@@ -33,13 +34,11 @@ import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.ForumInvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
||||
import org.briarproject.api.event.InvitationReceivedEvent;
|
||||
import org.briarproject.api.event.InvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.event.PrivateMessageReceivedEvent;
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.api.forum.ForumInvitationResponse;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
@@ -91,6 +90,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
protected volatile IntroductionManager introductionManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
@Inject
|
||||
protected volatile BlogSharingManager blogSharingManager;
|
||||
|
||||
public static ContactListFragment newInstance() {
|
||||
|
||||
@@ -277,14 +278,14 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
(IntroductionResponseReceivedEvent) e;
|
||||
IntroductionResponse ir = m.getIntroductionResponse();
|
||||
updateItem(m.getContactId(), ConversationItem.from(ir));
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
LOG.info("Forum Invitation received, reloading conversation...");
|
||||
ForumInvitationReceivedEvent m = (ForumInvitationReceivedEvent) e;
|
||||
} else if (e instanceof InvitationReceivedEvent) {
|
||||
LOG.info("Invitation received, reloading conversation...");
|
||||
InvitationReceivedEvent m = (InvitationReceivedEvent) e;
|
||||
reloadConversation(m.getContactId());
|
||||
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
|
||||
LOG.info("Forum Invitation Response received, reloading ...");
|
||||
ForumInvitationResponseReceivedEvent m =
|
||||
(ForumInvitationResponseReceivedEvent) e;
|
||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
||||
LOG.info("Invitation Response received, reloading ...");
|
||||
InvitationResponseReceivedEvent m =
|
||||
(InvitationResponseReceivedEvent) e;
|
||||
reloadConversation(m.getContactId());
|
||||
}
|
||||
}
|
||||
@@ -404,14 +405,19 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
LOG.info("Loading introduction messages took " + duration + " ms");
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
Collection<InvitationMessage> invitations =
|
||||
Collection<InvitationMessage> forumInvitations =
|
||||
forumSharingManager.getInvitationMessages(id);
|
||||
for (InvitationMessage i : invitations) {
|
||||
for (InvitationMessage i : forumInvitations) {
|
||||
messages.add(ConversationItem.from(i));
|
||||
}
|
||||
Collection<InvitationMessage> blogInvitations =
|
||||
blogSharingManager.getInvitationMessages(id);
|
||||
for (InvitationMessage i : blogInvitations) {
|
||||
messages.add(ConversationItem.from(i));
|
||||
}
|
||||
duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading forum invitations took " + duration + " ms");
|
||||
LOG.info("Loading invitations took " + duration + " ms");
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.briarproject.android.api.AndroidNotificationManager;
|
||||
import org.briarproject.android.introduction.IntroductionActivity;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
@@ -44,15 +45,13 @@ import org.briarproject.api.event.ContactRemovedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.ForumInvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
||||
import org.briarproject.api.event.InvitationReceivedEvent;
|
||||
import org.briarproject.api.event.InvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.event.MessagesAckedEvent;
|
||||
import org.briarproject.api.event.MessagesSentEvent;
|
||||
import org.briarproject.api.event.PrivateMessageReceivedEvent;
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.api.forum.ForumInvitationResponse;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.introduction.IntroductionManager;
|
||||
import org.briarproject.api.introduction.IntroductionMessage;
|
||||
@@ -64,6 +63,8 @@ import org.briarproject.api.messaging.PrivateMessageFactory;
|
||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sharing.InvitationRequest;
|
||||
import org.briarproject.api.sharing.InvitationResponse;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.briarproject.util.StringUtils;
|
||||
@@ -128,6 +129,8 @@ public class ConversationActivity extends BriarActivity
|
||||
protected volatile IntroductionManager introductionManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
@Inject
|
||||
protected volatile BlogSharingManager blogSharingManager;
|
||||
|
||||
private volatile GroupId groupId = null;
|
||||
private volatile ContactId contactId = null;
|
||||
@@ -334,9 +337,16 @@ public class ConversationActivity extends BriarActivity
|
||||
Collection<IntroductionMessage> introductions =
|
||||
introductionManager
|
||||
.getIntroductionMessages(contactId);
|
||||
Collection<InvitationMessage> invitations =
|
||||
Collection<InvitationMessage> forumInvitations =
|
||||
forumSharingManager
|
||||
.getInvitationMessages(contactId);
|
||||
Collection<InvitationMessage> blogInvitations =
|
||||
blogSharingManager
|
||||
.getInvitationMessages(contactId);
|
||||
List<InvitationMessage> invitations = new ArrayList<>(
|
||||
forumInvitations.size() + blogInvitations.size());
|
||||
invitations.addAll(forumInvitations);
|
||||
invitations.addAll(blogInvitations);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading headers took " + duration + " ms");
|
||||
@@ -388,13 +398,13 @@ public class ConversationActivity extends BriarActivity
|
||||
items.add(item);
|
||||
}
|
||||
for (InvitationMessage i : invitations) {
|
||||
if (i instanceof ForumInvitationRequest) {
|
||||
ForumInvitationRequest r =
|
||||
(ForumInvitationRequest) i;
|
||||
if (i instanceof InvitationRequest) {
|
||||
InvitationRequest r =
|
||||
(InvitationRequest) i;
|
||||
items.add(ConversationItem.from(r));
|
||||
} else if (i instanceof ForumInvitationResponse) {
|
||||
ForumInvitationResponse r =
|
||||
(ForumInvitationResponse) i;
|
||||
} else if (i instanceof InvitationResponse) {
|
||||
InvitationResponse r =
|
||||
(InvitationResponse) i;
|
||||
items.add(ConversationItem
|
||||
.from(ConversationActivity.this,
|
||||
contactName, r));
|
||||
@@ -541,6 +551,7 @@ public class ConversationActivity extends BriarActivity
|
||||
IntroductionRequestReceivedEvent event =
|
||||
(IntroductionRequestReceivedEvent) e;
|
||||
if (event.getContactId().equals(contactId)) {
|
||||
LOG.info("Introduction request received, adding...");
|
||||
IntroductionRequest ir = event.getIntroductionRequest();
|
||||
ConversationItem item = new ConversationIntroductionInItem(ir);
|
||||
addConversationItem(item);
|
||||
@@ -549,21 +560,24 @@ public class ConversationActivity extends BriarActivity
|
||||
IntroductionResponseReceivedEvent event =
|
||||
(IntroductionResponseReceivedEvent) e;
|
||||
if (event.getContactId().equals(contactId)) {
|
||||
LOG.info("Introduction response received, adding...");
|
||||
IntroductionResponse ir = event.getIntroductionResponse();
|
||||
ConversationItem item =
|
||||
ConversationItem.from(this, contactName, ir);
|
||||
addConversationItem(item);
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
ForumInvitationReceivedEvent event =
|
||||
(ForumInvitationReceivedEvent) e;
|
||||
} else if (e instanceof InvitationReceivedEvent) {
|
||||
InvitationReceivedEvent event =
|
||||
(InvitationReceivedEvent) e;
|
||||
if (event.getContactId().equals(contactId)) {
|
||||
LOG.info("Invitation received, reloading...");
|
||||
loadMessages();
|
||||
}
|
||||
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
|
||||
ForumInvitationResponseReceivedEvent event =
|
||||
(ForumInvitationResponseReceivedEvent) e;
|
||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
||||
InvitationResponseReceivedEvent event =
|
||||
(InvitationResponseReceivedEvent) e;
|
||||
if (event.getContactId().equals(contactId)) {
|
||||
LOG.info("Invitation response received, reloading...");
|
||||
loadMessages();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,18 +13,25 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.forum.ForumInvitationsActivity;
|
||||
import org.briarproject.android.sharing.InvitationsBlogActivity;
|
||||
import org.briarproject.android.sharing.InvitationsForumActivity;
|
||||
import org.briarproject.android.util.AndroidUtils;
|
||||
import org.briarproject.api.blogs.BlogInvitationRequest;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||
import org.briarproject.api.sharing.InvitationRequest;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||
import static android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.android.contact.ConversationItem.BLOG_INVITATION_IN;
|
||||
import static org.briarproject.android.contact.ConversationItem.BLOG_INVITATION_OUT;
|
||||
import static org.briarproject.android.contact.ConversationItem.FORUM_INVITATION_IN;
|
||||
import static org.briarproject.android.contact.ConversationItem.FORUM_INVITATION_OUT;
|
||||
import static org.briarproject.android.contact.ConversationItem.INTRODUCTION_IN;
|
||||
@@ -46,13 +53,13 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
private IntroductionHandler intro;
|
||||
private String contactName;
|
||||
|
||||
public ConversationAdapter(Context context,
|
||||
ConversationAdapter(Context context,
|
||||
IntroductionHandler introductionHandler) {
|
||||
ctx = context;
|
||||
intro = introductionHandler;
|
||||
}
|
||||
|
||||
public void setContactName(String contactName) {
|
||||
void setContactName(String contactName) {
|
||||
this.contactName = contactName;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
@@ -77,7 +84,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
return new IntroductionHolder(v, type);
|
||||
} else if (type == INTRODUCTION_OUT) {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_introduction_out, viewGroup, false);
|
||||
R.layout.list_item_msg_notice_out, viewGroup, false);
|
||||
return new IntroductionHolder(v, type);
|
||||
} else if (type == NOTICE_IN) {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
@@ -87,13 +94,15 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_notice_out, viewGroup, false);
|
||||
return new NoticeHolder(v, type);
|
||||
} else if (type == FORUM_INVITATION_IN) {
|
||||
} else if (type == FORUM_INVITATION_IN || type == BLOG_INVITATION_IN) {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_forum_invitation_in, viewGroup, false);
|
||||
R.layout.list_item_shareable_invitation_in, viewGroup,
|
||||
false);
|
||||
return new InvitationHolder(v, type);
|
||||
} else if (type == FORUM_INVITATION_OUT) {
|
||||
} else if (type == FORUM_INVITATION_OUT ||
|
||||
type == BLOG_INVITATION_OUT) {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_forum_invitation_out, viewGroup, false);
|
||||
R.layout.list_item_msg_notice_out, viewGroup, false);
|
||||
return new InvitationHolder(v, type);
|
||||
}
|
||||
// incoming message (non-local)
|
||||
@@ -119,12 +128,12 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
bindNotice((NoticeHolder) ui, (ConversationNoticeOutItem) item);
|
||||
} else if (item instanceof ConversationNoticeInItem) {
|
||||
bindNotice((NoticeHolder) ui, (ConversationNoticeInItem) item);
|
||||
} else if (item instanceof ConversationForumInvitationOutItem) {
|
||||
} else if (item instanceof ConversationShareableInvitationOutItem) {
|
||||
bindInvitation((InvitationHolder) ui,
|
||||
(ConversationForumInvitationOutItem) item);
|
||||
} else if (item instanceof ConversationForumInvitationInItem) {
|
||||
(ConversationShareableInvitationOutItem) item);
|
||||
} else if (item instanceof ConversationShareableInvitationInItem) {
|
||||
bindInvitation((InvitationHolder) ui,
|
||||
(ConversationForumInvitationInItem) item);
|
||||
(ConversationShareableInvitationInItem) item);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unhandled Conversation Item");
|
||||
}
|
||||
@@ -180,9 +189,9 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
String message = ir.getMessage();
|
||||
if (StringUtils.isNullOrEmpty(message)) {
|
||||
ui.messageLayout.setVisibility(View.GONE);
|
||||
ui.messageLayout.setVisibility(GONE);
|
||||
} else {
|
||||
ui.messageLayout.setVisibility(View.VISIBLE);
|
||||
ui.messageLayout.setVisibility(VISIBLE);
|
||||
ui.message.body.setText(StringUtils.trim(message));
|
||||
ui.message.date
|
||||
.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
||||
@@ -213,8 +222,8 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
ui.text.setText(ctx.getString(
|
||||
R.string.introduction_request_answered_received,
|
||||
contactName, ir.getName()));
|
||||
ui.acceptButton.setVisibility(View.GONE);
|
||||
ui.declineButton.setVisibility(View.GONE);
|
||||
ui.acceptButton.setVisibility(GONE);
|
||||
ui.declineButton.setVisibility(GONE);
|
||||
}
|
||||
// Incoming Introduction Request (Not Answered)
|
||||
else {
|
||||
@@ -230,12 +239,12 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
|
||||
if (item.getIntroductionRequest().doesIntroduceOtherIdentity()) {
|
||||
// don't allow accept when one of our identities is introduced
|
||||
ui.acceptButton.setVisibility(View.GONE);
|
||||
ui.acceptButton.setVisibility(GONE);
|
||||
ui.text.setText(ctx.getString(
|
||||
R.string.introduction_request_for_our_identity_received,
|
||||
contactName, ir.getName()));
|
||||
} else {
|
||||
ui.acceptButton.setVisibility(View.VISIBLE);
|
||||
ui.acceptButton.setVisibility(VISIBLE);
|
||||
ui.acceptButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -245,7 +254,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
});
|
||||
}
|
||||
ui.declineButton.setVisibility(View.VISIBLE);
|
||||
ui.declineButton.setVisibility(VISIBLE);
|
||||
ui.declineButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -276,26 +285,38 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
|
||||
private void bindInvitation(InvitationHolder ui,
|
||||
final ConversationForumInvitationItem item) {
|
||||
final ConversationShareableInvitationItem item) {
|
||||
|
||||
ForumInvitationRequest fim = item.getForumInvitationMessage();
|
||||
final InvitationRequest ir = item.getInvitationRequest();
|
||||
String name = "";
|
||||
int receivedRes = 0, sentRes = 0, buttonRes = 0;
|
||||
if (ir instanceof ForumInvitationRequest) {
|
||||
name = ((ForumInvitationRequest) ir).getForumName();
|
||||
receivedRes = R.string.forum_invitation_received;
|
||||
sentRes = R.string.forum_invitation_sent;
|
||||
buttonRes = R.string.forum_show_invitations;
|
||||
} else if (ir instanceof BlogInvitationRequest) {
|
||||
name = ((BlogInvitationRequest) ir).getBlogAuthorName();
|
||||
receivedRes = R.string.blogs_sharing_invitation_received;
|
||||
sentRes = R.string.blogs_sharing_invitation_sent;
|
||||
buttonRes = R.string.blogs_sharing_show_invitations;
|
||||
}
|
||||
|
||||
String message = fim.getMessage();
|
||||
String message = ir.getMessage();
|
||||
if (StringUtils.isNullOrEmpty(message)) {
|
||||
ui.messageLayout.setVisibility(View.GONE);
|
||||
ui.messageLayout.setVisibility(GONE);
|
||||
} else {
|
||||
ui.messageLayout.setVisibility(View.VISIBLE);
|
||||
ui.messageLayout.setVisibility(VISIBLE);
|
||||
ui.message.body.setText(StringUtils.trim(message));
|
||||
ui.message.date
|
||||
.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
||||
}
|
||||
|
||||
// Outgoing Invitation
|
||||
if (item instanceof ConversationForumInvitationOutItem) {
|
||||
ui.text.setText(ctx.getString(R.string.forum_invitation_sent,
|
||||
fim.getForumName(), contactName));
|
||||
ConversationForumInvitationOutItem i =
|
||||
(ConversationForumInvitationOutItem) item;
|
||||
if (item instanceof ConversationShareableInvitationOutItem) {
|
||||
ui.text.setText(ctx.getString(sentRes, name, contactName));
|
||||
ConversationShareableInvitationOutItem i =
|
||||
(ConversationShareableInvitationOutItem) item;
|
||||
if (i.isSeen()) {
|
||||
ui.status.setImageResource(R.drawable.message_delivered);
|
||||
ui.message.status.setImageResource(
|
||||
@@ -312,22 +333,24 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
// Incoming Invitation
|
||||
else {
|
||||
ui.text.setText(ctx.getString(R.string.forum_invitation_received,
|
||||
contactName, fim.getForumName()));
|
||||
ui.text.setText(ctx.getString(receivedRes, contactName, name));
|
||||
|
||||
if (fim.isAvailable()) {
|
||||
ui.showForumsButton.setVisibility(View.VISIBLE);
|
||||
ui.showForumsButton
|
||||
if (ir.isAvailable()) {
|
||||
final Class c = ir instanceof ForumInvitationRequest ?
|
||||
InvitationsForumActivity.class :
|
||||
InvitationsBlogActivity.class;
|
||||
ui.showInvitationsButton.setText(ctx.getString(buttonRes));
|
||||
ui.showInvitationsButton.setVisibility(VISIBLE);
|
||||
ui.showInvitationsButton
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(ctx,
|
||||
ForumInvitationsActivity.class);
|
||||
ctx.startActivity(intent);
|
||||
Intent i = new Intent(ctx, c);
|
||||
ctx.startActivity(i);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ui.showForumsButton.setVisibility(View.GONE);
|
||||
ui.showInvitationsButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
ui.date.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
||||
@@ -345,7 +368,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
public ConversationItem getLastItem() {
|
||||
ConversationItem getLastItem() {
|
||||
if (items.size() > 0) {
|
||||
return items.get(items.size() - 1);
|
||||
} else {
|
||||
@@ -353,7 +376,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
public SparseArray<IncomingItem> getIncomingMessages() {
|
||||
SparseArray<IncomingItem> getIncomingMessages() {
|
||||
SparseArray<IncomingItem> messages = new SparseArray<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
@@ -365,7 +388,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public SparseArray<OutgoingItem> getOutgoingMessages() {
|
||||
SparseArray<OutgoingItem> getOutgoingMessages() {
|
||||
SparseArray<OutgoingItem> messages = new SparseArray<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
@@ -377,7 +400,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public SparseArray<ConversationMessageItem> getPrivateMessages() {
|
||||
SparseArray<ConversationMessageItem> getPrivateMessages() {
|
||||
SparseArray<ConversationMessageItem> messages = new SparseArray<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
@@ -408,7 +431,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
public TextView date;
|
||||
public ImageView status;
|
||||
|
||||
public MessageHolder(View v, int type) {
|
||||
MessageHolder(View v, int type) {
|
||||
super(v);
|
||||
|
||||
layout = (ViewGroup) v.findViewById(R.id.msgLayout);
|
||||
@@ -432,7 +455,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
private final TextView date;
|
||||
private final ImageView status;
|
||||
|
||||
public IntroductionHolder(View v, int type) {
|
||||
IntroductionHolder(View v, int type) {
|
||||
super(v);
|
||||
|
||||
messageLayout = v.findViewById(R.id.messageLayout);
|
||||
@@ -457,7 +480,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
private final TextView date;
|
||||
private final ImageView status;
|
||||
|
||||
public NoticeHolder(View v, int type) {
|
||||
NoticeHolder(View v, int type) {
|
||||
super(v);
|
||||
|
||||
text = (TextView) v.findViewById(R.id.noticeText);
|
||||
@@ -476,21 +499,21 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
private final View messageLayout;
|
||||
private final MessageHolder message;
|
||||
private final TextView text;
|
||||
private final Button showForumsButton;
|
||||
private final Button showInvitationsButton;
|
||||
private final TextView date;
|
||||
private final ImageView status;
|
||||
|
||||
public InvitationHolder(View v, int type) {
|
||||
InvitationHolder(View v, int type) {
|
||||
super(v);
|
||||
|
||||
messageLayout = v.findViewById(R.id.messageLayout);
|
||||
message = new MessageHolder(messageLayout,
|
||||
type == FORUM_INVITATION_IN ? MSG_IN : MSG_OUT);
|
||||
text = (TextView) v.findViewById(R.id.introductionText);
|
||||
showForumsButton = (Button) v.findViewById(R.id.showForumsButton);
|
||||
showInvitationsButton = (Button) v.findViewById(R.id.showInvitationsButton);
|
||||
date = (TextView) v.findViewById(R.id.introductionTime);
|
||||
|
||||
if (type == FORUM_INVITATION_OUT) {
|
||||
if (type == FORUM_INVITATION_OUT || type == BLOG_INVITATION_OUT) {
|
||||
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
||||
} else {
|
||||
status = null;
|
||||
@@ -543,7 +566,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
public interface IntroductionHandler {
|
||||
interface IntroductionHandler {
|
||||
void respondToIntroduction(SessionId sessionId, boolean accept);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
|
||||
// This class is not thread-safe
|
||||
public class ConversationForumInvitationInItem
|
||||
extends ConversationForumInvitationItem
|
||||
implements ConversationItem.IncomingItem {
|
||||
|
||||
private boolean read;
|
||||
|
||||
public ConversationForumInvitationInItem(ForumInvitationRequest fim) {
|
||||
super(fim);
|
||||
|
||||
this.read = fim.isRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
int getType() {
|
||||
return FORUM_INVITATION_IN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRead(boolean read) {
|
||||
this.read = read;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
|
||||
abstract class ConversationForumInvitationItem extends ConversationItem {
|
||||
|
||||
private final ForumInvitationRequest fim;
|
||||
|
||||
public ConversationForumInvitationItem(ForumInvitationRequest fim) {
|
||||
super(fim.getId(), fim.getTimestamp());
|
||||
|
||||
this.fim = fim;
|
||||
}
|
||||
|
||||
public ForumInvitationRequest getForumInvitationMessage() {
|
||||
return fim;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,15 @@ package org.briarproject.android.contact;
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.api.blogs.BlogInvitationResponse;
|
||||
import org.briarproject.api.forum.ForumInvitationResponse;
|
||||
import org.briarproject.api.introduction.IntroductionMessage;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.api.introduction.IntroductionResponse;
|
||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sharing.InvitationRequest;
|
||||
import org.briarproject.api.sharing.InvitationResponse;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
// This class is not thread-safe
|
||||
@@ -25,6 +27,8 @@ public abstract class ConversationItem {
|
||||
final static int NOTICE_OUT = 6;
|
||||
final static int FORUM_INVITATION_IN = 7;
|
||||
final static int FORUM_INVITATION_OUT = 8;
|
||||
final static int BLOG_INVITATION_IN = 9;
|
||||
final static int BLOG_INVITATION_OUT = 10;
|
||||
|
||||
private MessageId id;
|
||||
private long time;
|
||||
@@ -97,15 +101,27 @@ public abstract class ConversationItem {
|
||||
}
|
||||
}
|
||||
|
||||
public static ConversationItem from(ForumInvitationRequest fim) {
|
||||
public static ConversationItem from(InvitationRequest fim) {
|
||||
if (fim.isLocal()) {
|
||||
return new ConversationForumInvitationOutItem(fim);
|
||||
return new ConversationShareableInvitationOutItem(fim);
|
||||
} else {
|
||||
return new ConversationForumInvitationInItem(fim);
|
||||
return new ConversationShareableInvitationInItem(fim);
|
||||
}
|
||||
}
|
||||
|
||||
public static ConversationItem from(Context ctx, String contactName,
|
||||
InvitationResponse ir) {
|
||||
|
||||
if (ir instanceof ForumInvitationResponse) {
|
||||
return from(ctx, contactName, (ForumInvitationResponse) ir);
|
||||
} else if (ir instanceof BlogInvitationResponse) {
|
||||
return from(ctx, contactName, (BlogInvitationResponse) ir);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown Invitation Response.");
|
||||
}
|
||||
}
|
||||
|
||||
private static ConversationItem from(Context ctx, String contactName,
|
||||
ForumInvitationResponse fir) {
|
||||
|
||||
if (fir.isLocal()) {
|
||||
@@ -137,6 +153,38 @@ public abstract class ConversationItem {
|
||||
}
|
||||
}
|
||||
|
||||
private static ConversationItem from(Context ctx, String contactName,
|
||||
BlogInvitationResponse fir) {
|
||||
|
||||
if (fir.isLocal()) {
|
||||
String text;
|
||||
if (fir.wasAccepted()) {
|
||||
text = ctx.getString(
|
||||
R.string.blogs_sharing_response_accepted_sent,
|
||||
contactName);
|
||||
} else {
|
||||
text = ctx.getString(
|
||||
R.string.blogs_sharing_response_declined_sent,
|
||||
contactName);
|
||||
}
|
||||
return new ConversationNoticeOutItem(fir.getId(), text,
|
||||
fir.getTimestamp(), fir.isSent(), fir.isSeen());
|
||||
} else {
|
||||
String text;
|
||||
if (fir.wasAccepted()) {
|
||||
text = ctx.getString(
|
||||
R.string.blogs_sharing_response_accepted_received,
|
||||
contactName);
|
||||
} else {
|
||||
text = ctx.getString(
|
||||
R.string.blogs_sharing_response_declined_received,
|
||||
contactName);
|
||||
}
|
||||
return new ConversationNoticeInItem(fir.getId(), text,
|
||||
fir.getTimestamp(), fir.isRead());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should not be used to get user-facing objects,
|
||||
* Its purpose is only to provide data for the contact list.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.blogs.BlogInvitationRequest;
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.api.sharing.InvitationRequest;
|
||||
|
||||
// This class is not thread-safe
|
||||
class ConversationShareableInvitationInItem
|
||||
extends ConversationShareableInvitationItem
|
||||
implements ConversationItem.IncomingItem {
|
||||
|
||||
private final int type;
|
||||
private boolean read;
|
||||
|
||||
ConversationShareableInvitationInItem(InvitationRequest ir) {
|
||||
super(ir);
|
||||
|
||||
if (ir instanceof ForumInvitationRequest) {
|
||||
this.type = FORUM_INVITATION_IN;
|
||||
} else if (ir instanceof BlogInvitationRequest) {
|
||||
this.type = BLOG_INVITATION_IN;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown Invitation Type.");
|
||||
}
|
||||
|
||||
this.read = ir.isRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRead(boolean read) {
|
||||
this.read = read;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.sharing.InvitationRequest;
|
||||
|
||||
abstract class ConversationShareableInvitationItem extends ConversationItem {
|
||||
|
||||
private final InvitationRequest fim;
|
||||
|
||||
ConversationShareableInvitationItem(InvitationRequest fim) {
|
||||
super(fim.getId(), fim.getTimestamp());
|
||||
|
||||
this.fim = fim;
|
||||
}
|
||||
|
||||
InvitationRequest getInvitationRequest() {
|
||||
return fim;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.blogs.BlogInvitationRequest;
|
||||
import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
import org.briarproject.api.sharing.InvitationRequest;
|
||||
|
||||
/**
|
||||
* This class is needed and can not be replaced by an ConversationNoticeOutItem,
|
||||
@@ -9,21 +11,31 @@ import org.briarproject.api.forum.ForumInvitationRequest;
|
||||
* <p/>
|
||||
* This class is not thread-safe
|
||||
*/
|
||||
public class ConversationForumInvitationOutItem
|
||||
extends ConversationForumInvitationItem
|
||||
class ConversationShareableInvitationOutItem
|
||||
extends ConversationShareableInvitationItem
|
||||
implements ConversationItem.OutgoingItem {
|
||||
|
||||
private final int type;
|
||||
private boolean sent, seen;
|
||||
|
||||
public ConversationForumInvitationOutItem(ForumInvitationRequest fim) {
|
||||
super(fim);
|
||||
this.sent = fim.isSent();
|
||||
this.seen = fim.isSeen();
|
||||
ConversationShareableInvitationOutItem(InvitationRequest ir) {
|
||||
super(ir);
|
||||
|
||||
if (ir instanceof ForumInvitationRequest) {
|
||||
this.type = FORUM_INVITATION_OUT;
|
||||
} else if (ir instanceof BlogInvitationRequest) {
|
||||
this.type = BLOG_INVITATION_OUT;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown Invitation Type.");
|
||||
}
|
||||
|
||||
this.sent = ir.isSent();
|
||||
this.seen = ir.isSeen();
|
||||
}
|
||||
|
||||
@Override
|
||||
int getType() {
|
||||
return FORUM_INVITATION_OUT;
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,6 +33,8 @@ import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.api.AndroidNotificationManager;
|
||||
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||
import org.briarproject.android.sharing.ShareForumActivity;
|
||||
import org.briarproject.android.sharing.SharingStatusForumActivity;
|
||||
import org.briarproject.android.util.AndroidUtils;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.android.util.TrustIndicatorView;
|
||||
@@ -228,7 +230,7 @@ public class ForumActivity extends BriarActivity implements
|
||||
options.toBundle());
|
||||
return true;
|
||||
case R.id.action_forum_sharing_status:
|
||||
Intent i3 = new Intent(this, ForumSharingStatusActivity.class);
|
||||
Intent i3 = new Intent(this, SharingStatusForumActivity.class);
|
||||
i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
i3.putExtra(GROUP_ID, groupId.getBytes());
|
||||
ActivityCompat.startActivity(this, i3, options.toBundle());
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchGroupException;
|
||||
import org.briarproject.api.event.ContactRemovedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.GroupAddedEvent;
|
||||
import org.briarproject.api.event.GroupRemovedEvent;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ForumInvitationAdapter.AvailableForumClickListener;
|
||||
|
||||
public class ForumInvitationsActivity extends BriarActivity
|
||||
implements EventListener, AvailableForumClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ForumInvitationsActivity.class.getName());
|
||||
|
||||
private ForumInvitationAdapter adapter;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumManager forumManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
@Inject
|
||||
protected volatile EventBus eventBus;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
setContentView(R.layout.activity_available_forums);
|
||||
|
||||
adapter = new ForumInvitationAdapter(this, this);
|
||||
BriarRecyclerView list =
|
||||
(BriarRecyclerView) findViewById(R.id.availableForumsView);
|
||||
list.setLayoutManager(new LinearLayoutManager(this));
|
||||
list.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
eventBus.addListener(this);
|
||||
loadForums(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
eventBus.removeListener(this);
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
private void loadForums(final boolean clear) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Collection<ForumInvitationItem> forums = new ArrayList<>();
|
||||
long now = System.currentTimeMillis();
|
||||
for (Forum f : forumSharingManager.getInvited()) {
|
||||
boolean subscribed;
|
||||
try {
|
||||
forumManager.getForum(f.getId());
|
||||
subscribed = true;
|
||||
} catch (NoSuchGroupException e) {
|
||||
subscribed = false;
|
||||
}
|
||||
Collection<Contact> c =
|
||||
forumSharingManager.getSharedBy(f.getId());
|
||||
forums.add(
|
||||
new ForumInvitationItem(f, subscribed, c));
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayForums(forums, clear);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayForums(final Collection<ForumInvitationItem> forums,
|
||||
final boolean clear) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (forums.isEmpty()) {
|
||||
LOG.info("No forums available, finishing");
|
||||
finish();
|
||||
} else {
|
||||
if (clear) adapter.clear();
|
||||
adapter.addAll(forums);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactRemovedEvent) {
|
||||
LOG.info("Contact removed, reloading");
|
||||
loadForums(true);
|
||||
} else if (e instanceof GroupAddedEvent) {
|
||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum added, reloading");
|
||||
loadForums(false);
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum removed, reloading");
|
||||
loadForums(true);
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
LOG.info("Available forums updated, reloading");
|
||||
loadForums(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(ForumInvitationItem item, boolean accept) {
|
||||
respondToInvitation(item, accept);
|
||||
|
||||
// show toast
|
||||
int res = R.string.forum_declined_toast;
|
||||
if (accept) res = R.string.forum_joined_toast;
|
||||
Toast.makeText(this, res, LENGTH_SHORT).show();
|
||||
|
||||
// remove item and finish if it was the last
|
||||
adapter.remove(item);
|
||||
if (adapter.getItemCount() == 0) {
|
||||
supportFinishAfterTransition();
|
||||
}
|
||||
}
|
||||
|
||||
private void respondToInvitation(final ForumInvitationItem item,
|
||||
final boolean accept) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Forum f = item.getForum();
|
||||
for (Contact c : item.getContacts()) {
|
||||
forumSharingManager.respondToInvitation(f, c, accept);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import android.view.ViewGroup;
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.fragment.BaseEventFragment;
|
||||
import org.briarproject.android.sharing.InvitationsForumActivity;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchGroupException;
|
||||
@@ -285,6 +286,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// snackbar click
|
||||
startActivity(new Intent(getContext(), ForumInvitationsActivity.class));
|
||||
Intent i = new Intent(getContext(), InvitationsForumActivity.class);
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.api.blogs.Blog;
|
||||
|
||||
class BlogInvitationAdapter extends InvitationAdapter {
|
||||
|
||||
BlogInvitationAdapter(Context ctx, AvailableForumClickListener listener) {
|
||||
super(ctx, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(InvitationsViewHolder ui, int position) {
|
||||
super.onBindViewHolder(ui, position);
|
||||
InvitationItem item = getItem(position);
|
||||
Blog blog = (Blog) item.getShareable();
|
||||
|
||||
ui.avatar.setAuthorAvatar(blog.getAuthor());
|
||||
|
||||
ui.name.setText(ctx.getString(R.string.blogs_personal_blog,
|
||||
blog.getAuthor().getName()));
|
||||
|
||||
if (item.isSubscribed()) {
|
||||
ui.subscribed.setText(ctx.getString(R.string.blogs_sharing_exists,
|
||||
blog.getAuthor().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
int compareInvitations(InvitationItem o1, InvitationItem o2) {
|
||||
return String.CASE_INSENSITIVE_ORDER
|
||||
.compare(((Blog) o1.getShareable()).getAuthor().getName(),
|
||||
((Blog) o2.getShareable()).getAuthor().getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
@@ -37,8 +37,8 @@ import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ShareForumActivity.CONTACTS;
|
||||
import static org.briarproject.android.forum.ShareForumActivity.getContactsFromIds;
|
||||
import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
|
||||
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
|
||||
import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
|
||||
|
||||
public class ContactSelectorFragment extends BaseFragment implements
|
||||
@@ -49,7 +49,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ContactSelectorFragment.class.getName());
|
||||
|
||||
private ShareForumActivity shareForumActivity;
|
||||
private ShareActivity shareActivity;
|
||||
private Menu menu;
|
||||
private BriarRecyclerView list;
|
||||
private ContactSelectorAdapter adapter;
|
||||
@@ -63,7 +63,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
protected volatile GroupId groupId;
|
||||
private volatile GroupId groupId;
|
||||
|
||||
public static ContactSelectorFragment newInstance(GroupId groupId) {
|
||||
|
||||
@@ -83,10 +83,10 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
shareForumActivity = (ShareForumActivity) context;
|
||||
shareActivity = (ShareActivity) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InstantiationError(
|
||||
"This fragment is only meant to be attached to the ShareForumActivity");
|
||||
"This fragment is only meant to be attached to a subclass of ShareActivity");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
groupId = new GroupId(getArguments().getByteArray(GROUP_ID));
|
||||
Bundle args = getArguments();
|
||||
groupId = new GroupId(args.getByteArray(GROUP_ID));
|
||||
if (groupId == null) throw new IllegalStateException("No GroupId");
|
||||
}
|
||||
|
||||
@@ -115,13 +116,13 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.contactList);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_contacts));
|
||||
list.setEmptyText(getString(R.string.no_contacts_selector));
|
||||
|
||||
// restore selected contacts if available
|
||||
if (savedInstanceState != null) {
|
||||
ArrayList<Integer> intContacts =
|
||||
savedInstanceState.getIntegerArrayList(CONTACTS);
|
||||
selectedContacts = ShareForumActivity.getContactsFromIntegers(
|
||||
selectedContacts = ShareActivity.getContactsFromIntegers(
|
||||
intContacts);
|
||||
}
|
||||
|
||||
@@ -160,11 +161,11 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
// Handle presses on the action bar items
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
shareForumActivity.onBackPressed();
|
||||
shareActivity.onBackPressed();
|
||||
return true;
|
||||
case R.id.action_share_forum:
|
||||
selectedContacts = adapter.getSelectedContactIds();
|
||||
shareForumActivity.showMessageScreen(groupId, selectedContacts);
|
||||
shareActivity.showMessageScreen(groupId, selectedContacts);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -185,7 +186,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
}
|
||||
|
||||
private void loadContacts(final Collection<ContactId> selection) {
|
||||
shareForumActivity.runOnDbThread(new Runnable() {
|
||||
shareActivity.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@@ -199,8 +200,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
boolean selected = selection != null &&
|
||||
selection.contains(c.getId());
|
||||
// do we have already some sharing with that contact?
|
||||
boolean disabled =
|
||||
!forumSharingManager.canBeShared(groupId, c);
|
||||
boolean disabled = shareActivity.isDisabled(groupId, c);
|
||||
contacts.add(new SelectableContactListItem(c,
|
||||
localAuthor, groupId, selected, disabled));
|
||||
}
|
||||
@@ -218,7 +218,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
}
|
||||
|
||||
private void displayContacts(final List<ContactListItem> contacts) {
|
||||
shareForumActivity.runOnUiThread(new Runnable() {
|
||||
shareActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!contacts.isEmpty()) adapter.addAll(contacts);
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.api.forum.Forum;
|
||||
|
||||
class ForumInvitationAdapter extends InvitationAdapter {
|
||||
|
||||
ForumInvitationAdapter(Context ctx, AvailableForumClickListener listener) {
|
||||
super(ctx, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(InvitationsViewHolder ui, int position) {
|
||||
super.onBindViewHolder(ui, position);
|
||||
InvitationItem item = getItem(position);
|
||||
Forum forum = (Forum) item.getShareable();
|
||||
|
||||
ui.avatar.setText(forum.getName().substring(0, 1));
|
||||
ui.avatar.setBackgroundBytes(item.getShareable().getId().getBytes());
|
||||
|
||||
ui.name.setText(forum.getName());
|
||||
}
|
||||
|
||||
int compareInvitations(InvitationItem o1, InvitationItem o2) {
|
||||
return String.CASE_INSENSITIVE_ORDER
|
||||
.compare(((Forum) o1.getShareable()).getName(),
|
||||
((Forum) o2.getShareable()).getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.util.SortedList;
|
||||
@@ -12,7 +12,6 @@ import android.widget.TextView;
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.util.TextAvatarView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.forum.ForumSharingMessage;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -21,37 +20,32 @@ import java.util.Collection;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
class ForumInvitationAdapter extends
|
||||
RecyclerView.Adapter<ForumInvitationAdapter.AvailableForumViewHolder> {
|
||||
abstract class InvitationAdapter extends
|
||||
RecyclerView.Adapter<InvitationAdapter.InvitationsViewHolder> {
|
||||
|
||||
private final Context ctx;
|
||||
protected final Context ctx;
|
||||
private final AvailableForumClickListener listener;
|
||||
private final SortedList<ForumInvitationItem> forums =
|
||||
new SortedList<>(ForumInvitationItem.class,
|
||||
private final SortedList<InvitationItem> invitations =
|
||||
new SortedList<>(InvitationItem.class,
|
||||
new SortedListCallBacks());
|
||||
|
||||
ForumInvitationAdapter(Context ctx, AvailableForumClickListener listener) {
|
||||
InvitationAdapter(Context ctx, AvailableForumClickListener listener) {
|
||||
this.ctx = ctx;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AvailableForumViewHolder onCreateViewHolder(ViewGroup parent,
|
||||
public InvitationsViewHolder onCreateViewHolder(ViewGroup parent,
|
||||
int viewType) {
|
||||
|
||||
View v = LayoutInflater.from(ctx)
|
||||
.inflate(R.layout.list_item_available_forum, parent, false);
|
||||
return new AvailableForumViewHolder(v);
|
||||
.inflate(R.layout.list_item_invitations, parent, false);
|
||||
return new InvitationsViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(AvailableForumViewHolder ui, int position) {
|
||||
final ForumInvitationItem item = getItem(position);
|
||||
|
||||
ui.avatar.setText(item.getForum().getName().substring(0, 1));
|
||||
ui.avatar.setBackgroundBytes(item.getForum().getId().getBytes());
|
||||
|
||||
ui.name.setText(item.getForum().getName());
|
||||
public void onBindViewHolder(InvitationsViewHolder ui, int position) {
|
||||
final InvitationItem item = getItem(position);
|
||||
|
||||
Collection<String> names = new ArrayList<>();
|
||||
for (Contact c : item.getContacts()) names.add(c.getAuthor().getName());
|
||||
@@ -80,40 +74,39 @@ class ForumInvitationAdapter extends
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return forums.size();
|
||||
return invitations.size();
|
||||
}
|
||||
|
||||
public ForumInvitationItem getItem(int position) {
|
||||
return forums.get(position);
|
||||
public InvitationItem getItem(int position) {
|
||||
return invitations.get(position);
|
||||
}
|
||||
|
||||
public void add(ForumInvitationItem item) {
|
||||
forums.add(item);
|
||||
public void add(InvitationItem item) {
|
||||
invitations.add(item);
|
||||
}
|
||||
|
||||
public void addAll(Collection<ForumInvitationItem> list) {
|
||||
forums.addAll(list);
|
||||
public void addAll(Collection<InvitationItem> list) {
|
||||
invitations.addAll(list);
|
||||
}
|
||||
|
||||
public void remove(ForumInvitationItem item) {
|
||||
forums.remove(item);
|
||||
public void remove(InvitationItem item) {
|
||||
invitations.remove(item);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
forums.clear();
|
||||
invitations.clear();
|
||||
}
|
||||
|
||||
static class AvailableForumViewHolder
|
||||
extends RecyclerView.ViewHolder {
|
||||
static class InvitationsViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final TextAvatarView avatar;
|
||||
private final TextView name;
|
||||
private final TextView sharedBy;
|
||||
private final TextView subscribed;
|
||||
private final Button accept;
|
||||
private final Button decline;
|
||||
final TextAvatarView avatar;
|
||||
final TextView name;
|
||||
final TextView sharedBy;
|
||||
final TextView subscribed;
|
||||
final Button accept;
|
||||
final Button decline;
|
||||
|
||||
AvailableForumViewHolder(View v) {
|
||||
InvitationsViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
avatar = (TextAvatarView) v.findViewById(R.id.avatarView);
|
||||
@@ -125,15 +118,15 @@ class ForumInvitationAdapter extends
|
||||
}
|
||||
}
|
||||
|
||||
abstract int compareInvitations(InvitationItem o1, InvitationItem o2);
|
||||
|
||||
private class SortedListCallBacks
|
||||
extends SortedList.Callback<ForumInvitationItem> {
|
||||
extends SortedList.Callback<InvitationItem> {
|
||||
|
||||
@Override
|
||||
public int compare(ForumInvitationItem o1,
|
||||
ForumInvitationItem o2) {
|
||||
return String.CASE_INSENSITIVE_ORDER
|
||||
.compare(o1.getForum().getName(),
|
||||
o2.getForum().getName());
|
||||
public int compare(InvitationItem o1,
|
||||
InvitationItem o2) {
|
||||
return compareInvitations(o1, o2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,21 +150,21 @@ class ForumInvitationAdapter extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(ForumInvitationItem oldItem,
|
||||
ForumInvitationItem newItem) {
|
||||
public boolean areContentsTheSame(InvitationItem oldItem,
|
||||
InvitationItem newItem) {
|
||||
return oldItem.isSubscribed() == newItem.isSubscribed() &&
|
||||
oldItem.getContacts().equals(newItem.getContacts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(ForumInvitationItem oldItem,
|
||||
ForumInvitationItem newItem) {
|
||||
return oldItem.getForum().equals(newItem.getForum());
|
||||
public boolean areItemsTheSame(InvitationItem oldItem,
|
||||
InvitationItem newItem) {
|
||||
return oldItem.getShareable().equals(newItem.getShareable());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface AvailableForumClickListener {
|
||||
void onItemClick(ForumInvitationItem item, boolean accept);
|
||||
void onItemClick(InvitationItem item, boolean accept);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.sharing.Shareable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
class ForumInvitationItem {
|
||||
class InvitationItem {
|
||||
|
||||
private final Forum forum;
|
||||
private final Shareable shareable;
|
||||
private final boolean subscribed;
|
||||
private final Collection<Contact> contacts;
|
||||
|
||||
ForumInvitationItem(Forum forum, boolean subscribed,
|
||||
InvitationItem(Shareable shareable, boolean subscribed,
|
||||
Collection<Contact> contacts) {
|
||||
|
||||
this.forum = forum;
|
||||
this.shareable = shareable;
|
||||
this.subscribed = subscribed;
|
||||
this.contacts = contacts;
|
||||
}
|
||||
|
||||
Forum getForum() {
|
||||
return forum;
|
||||
Shareable getShareable() {
|
||||
return shareable;
|
||||
}
|
||||
|
||||
public boolean isSubscribed() {
|
||||
boolean isSubscribed() {
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.event.ContactRemovedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static org.briarproject.android.sharing.InvitationAdapter.AvailableForumClickListener;
|
||||
|
||||
abstract class InvitationsActivity extends BriarActivity
|
||||
implements EventListener, AvailableForumClickListener {
|
||||
|
||||
protected static final Logger LOG =
|
||||
Logger.getLogger(InvitationsActivity.class.getName());
|
||||
|
||||
private InvitationAdapter adapter;
|
||||
|
||||
@Inject
|
||||
protected EventBus eventBus;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
setContentView(R.layout.activity_invitations);
|
||||
|
||||
adapter = getAdapter(this, this);
|
||||
|
||||
BriarRecyclerView list =
|
||||
(BriarRecyclerView) findViewById(R.id.invitationsView);
|
||||
if (list != null) {
|
||||
list.setLayoutManager(new LinearLayoutManager(this));
|
||||
list.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
eventBus.addListener(this);
|
||||
loadInvitations(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
eventBus.removeListener(this);
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactRemovedEvent) {
|
||||
LOG.info("Contact removed, reloading...");
|
||||
loadInvitations(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(InvitationItem item, boolean accept) {
|
||||
respondToInvitation(item, accept);
|
||||
|
||||
// show toast
|
||||
int res = getDeclineRes();
|
||||
if (accept) res = getAcceptRes();
|
||||
Toast.makeText(this, res, LENGTH_SHORT).show();
|
||||
|
||||
// remove item and finish if it was the last
|
||||
adapter.remove(item);
|
||||
if (adapter.getItemCount() == 0) {
|
||||
supportFinishAfterTransition();
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected InvitationAdapter getAdapter(Context ctx,
|
||||
AvailableForumClickListener listener);
|
||||
|
||||
abstract protected void loadInvitations(boolean clear);
|
||||
|
||||
abstract protected void respondToInvitation(final InvitationItem item,
|
||||
final boolean accept);
|
||||
|
||||
abstract protected int getAcceptRes();
|
||||
|
||||
abstract protected int getDeclineRes();
|
||||
|
||||
protected void displayInvitations(
|
||||
final Collection<InvitationItem> invitations, final boolean clear) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (invitations.isEmpty()) {
|
||||
LOG.info("No more invitations available, finishing");
|
||||
finish();
|
||||
} else {
|
||||
if (clear) adapter.clear();
|
||||
adapter.addAll(invitations);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.blogs.Blog;
|
||||
import org.briarproject.api.blogs.BlogManager;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchGroupException;
|
||||
import org.briarproject.api.event.BlogInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.GroupAddedEvent;
|
||||
import org.briarproject.api.event.GroupRemovedEvent;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.sharing.InvitationAdapter.AvailableForumClickListener;
|
||||
|
||||
public class InvitationsBlogActivity extends InvitationsActivity {
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile BlogManager blogManager;
|
||||
@Inject
|
||||
protected volatile BlogSharingManager blogSharingManager;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
super.eventOccurred(e);
|
||||
|
||||
if (e instanceof GroupAddedEvent) {
|
||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||
ClientId cId = g.getGroup().getClientId();
|
||||
if (cId.equals(blogManager.getClientId())) {
|
||||
LOG.info("Blog added, reloading");
|
||||
loadInvitations(false);
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||
ClientId cId = g.getGroup().getClientId();
|
||||
if (cId.equals(blogManager.getClientId())) {
|
||||
LOG.info("Blog removed, reloading");
|
||||
loadInvitations(false);
|
||||
}
|
||||
} else if (e instanceof BlogInvitationReceivedEvent) {
|
||||
LOG.info("Blog invitation received, reloading");
|
||||
loadInvitations(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected InvitationAdapter getAdapter(Context ctx,
|
||||
AvailableForumClickListener listener) {
|
||||
return new BlogInvitationAdapter(ctx, listener);
|
||||
}
|
||||
|
||||
protected void loadInvitations(final boolean clear) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Collection<InvitationItem> invitations = new ArrayList<>();
|
||||
long now = System.currentTimeMillis();
|
||||
for (Blog b : blogSharingManager.getInvited()) {
|
||||
boolean subscribed;
|
||||
try {
|
||||
blogManager.getBlog(b.getId());
|
||||
subscribed = true;
|
||||
} catch (NoSuchGroupException e) {
|
||||
subscribed = false;
|
||||
}
|
||||
Collection<Contact> c =
|
||||
blogSharingManager.getSharedBy(b.getId());
|
||||
invitations.add(
|
||||
new InvitationItem(b, subscribed, c));
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayInvitations(invitations, clear);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void respondToInvitation(final InvitationItem item,
|
||||
final boolean accept) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Blog b = (Blog) item.getShareable();
|
||||
for (Contact c : item.getContacts()) {
|
||||
blogSharingManager.respondToInvitation(b, c, accept);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getAcceptRes() {
|
||||
return R.string.blogs_sharing_joined_toast;
|
||||
}
|
||||
|
||||
protected int getDeclineRes() {
|
||||
return R.string.blogs_sharing_declined_toast;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchGroupException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.GroupAddedEvent;
|
||||
import org.briarproject.api.event.GroupRemovedEvent;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.sharing.InvitationAdapter.AvailableForumClickListener;
|
||||
|
||||
public class InvitationsForumActivity extends InvitationsActivity {
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumManager forumManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
super.eventOccurred(e);
|
||||
|
||||
if (e instanceof GroupAddedEvent) {
|
||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||
ClientId cId = g.getGroup().getClientId();
|
||||
if (cId.equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum added, reloading");
|
||||
loadInvitations(false);
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||
ClientId cId = g.getGroup().getClientId();
|
||||
if (cId.equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum removed, reloading");
|
||||
loadInvitations(false);
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
LOG.info("Forum invitation received, reloading");
|
||||
loadInvitations(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected InvitationAdapter getAdapter(Context ctx,
|
||||
AvailableForumClickListener listener) {
|
||||
return new ForumInvitationAdapter(ctx, listener);
|
||||
}
|
||||
|
||||
protected void loadInvitations(final boolean clear) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Collection<InvitationItem> forums = new ArrayList<>();
|
||||
long now = System.currentTimeMillis();
|
||||
for (Forum f : forumSharingManager.getInvited()) {
|
||||
boolean subscribed;
|
||||
try {
|
||||
forumManager.getForum(f.getId());
|
||||
subscribed = true;
|
||||
} catch (NoSuchGroupException e) {
|
||||
subscribed = false;
|
||||
}
|
||||
Collection<Contact> c =
|
||||
forumSharingManager.getSharedBy(f.getId());
|
||||
forums.add(
|
||||
new InvitationItem(f, subscribed, c));
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayInvitations(forums, clear);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void respondToInvitation(final InvitationItem item,
|
||||
final boolean accept) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Forum f = (Forum) item.getShareable();
|
||||
for (Contact c : item.getContacts()) {
|
||||
forumSharingManager.respondToInvitation(f, c, accept);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getAcceptRes() {
|
||||
return R.string.forum_joined_toast;
|
||||
}
|
||||
|
||||
protected int getDeclineRes() {
|
||||
return R.string.forum_declined_toast;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.android.contact.ConversationItem;
|
||||
@@ -1,31 +1,31 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
// TODO extend the BriarFragmentActivity ?
|
||||
public class ShareForumActivity extends BriarActivity implements
|
||||
public abstract class ShareActivity extends BriarActivity implements
|
||||
BaseFragment.BaseFragmentListener {
|
||||
|
||||
public final static String CONTACTS = "contacts";
|
||||
final static String CONTACTS = "contacts";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_share_forum);
|
||||
setContentView(R.layout.activity_share);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
@@ -36,34 +36,32 @@ public class ShareForumActivity extends BriarActivity implements
|
||||
ContactSelectorFragment contactSelectorFragment =
|
||||
ContactSelectorFragment.newInstance(groupId);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.shareForumContainer, contactSelectorFragment)
|
||||
.add(R.id.shareContainer, contactSelectorFragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
abstract ShareMessageFragment getMessageFragment(GroupId groupId,
|
||||
Collection<ContactId> contacts);
|
||||
|
||||
public void showMessageScreen(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
abstract boolean isDisabled(GroupId groupId, Contact c) throws DbException;
|
||||
|
||||
ShareForumMessageFragment messageFragment =
|
||||
ShareForumMessageFragment.newInstance(groupId, contacts);
|
||||
void showMessageScreen(GroupId groupId, Collection<ContactId> contacts) {
|
||||
ShareMessageFragment messageFragment =
|
||||
getMessageFragment(groupId, contacts);
|
||||
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(android.R.anim.fade_in,
|
||||
android.R.anim.fade_out,
|
||||
android.R.anim.slide_in_left,
|
||||
android.R.anim.slide_out_right)
|
||||
.replace(R.id.shareForumContainer, messageFragment,
|
||||
.replace(R.id.shareContainer, messageFragment,
|
||||
ContactSelectorFragment.TAG)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static ArrayList<Integer> getContactsFromIds(
|
||||
static ArrayList<Integer> getContactsFromIds(
|
||||
Collection<ContactId> contacts) {
|
||||
|
||||
// transform ContactIds to Integers so they can be added to a bundle
|
||||
@@ -74,13 +72,13 @@ public class ShareForumActivity extends BriarActivity implements
|
||||
return intContacts;
|
||||
}
|
||||
|
||||
public void sharingSuccessful(View v) {
|
||||
void sharingSuccessful(View v) {
|
||||
setResult(RESULT_OK);
|
||||
hideSoftKeyboard(v);
|
||||
supportFinishAfterTransition();
|
||||
}
|
||||
|
||||
protected static Collection<ContactId> getContactsFromIntegers(
|
||||
static Collection<ContactId> getContactsFromIntegers(
|
||||
ArrayList<Integer> intContacts) {
|
||||
|
||||
// turn contact integers from a bundle back to ContactIds
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class ShareBlogActivity extends ShareActivity {
|
||||
|
||||
@Inject
|
||||
volatile BlogSharingManager blogSharingManager;
|
||||
|
||||
ShareMessageFragment getMessageFragment(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
return ShareBlogMessageFragment.newInstance(groupId, contacts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This must only be called from a DbThread
|
||||
*/
|
||||
boolean isDisabled(GroupId groupId, Contact c) throws DbException {
|
||||
return !blogSharingManager.canBeShared(groupId, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
public class ShareBlogMessageFragment extends ShareMessageFragment {
|
||||
|
||||
public final static String TAG = ShareBlogMessageFragment.class.getName();
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile BlogSharingManager blogSharingManager;
|
||||
|
||||
public static ShareBlogMessageFragment newInstance(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
|
||||
ShareBlogMessageFragment fragment = new ShareBlogMessageFragment();
|
||||
fragment.setArguments(getArguments(groupId, contacts));
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
setTitle(R.string.blogs_sharing_share);
|
||||
|
||||
View v = super.onCreateView(inflater, container, savedInstanceState);
|
||||
ui.button.setText(getString(R.string.blogs_sharing_button));
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
protected void share(final String msg) {
|
||||
listener.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (ContactId c : getContacts()) {
|
||||
blogSharingManager.sendInvitation(getGroupId(), c, msg);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
sharingError();
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void sharingError() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int res = R.string.blogs_sharing_error;
|
||||
Toast.makeText(getContext(), res, LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class ShareForumActivity extends ShareActivity {
|
||||
@Inject
|
||||
volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
ShareMessageFragment getMessageFragment(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
return ShareForumMessageFragment.newInstance(groupId, contacts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This must only be called from a DbThread
|
||||
*/
|
||||
boolean isDisabled(GroupId groupId, Contact c) throws DbException {
|
||||
return !forumSharingManager.canBeShared(groupId, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
public class ShareForumMessageFragment extends ShareMessageFragment {
|
||||
|
||||
public final static String TAG = ShareForumMessageFragment.class.getName();
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
public static ShareForumMessageFragment newInstance(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
|
||||
ShareForumMessageFragment fragment = new ShareForumMessageFragment();
|
||||
fragment.setArguments(getArguments(groupId, contacts));
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
setTitle(R.string.forum_share_button);
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
protected void share(final String msg) {
|
||||
listener.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (ContactId c : getContacts()) {
|
||||
forumSharingManager.
|
||||
sendInvitation(getGroupId(), c, msg);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
sharingError();
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void sharingError() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int res = R.string.forum_share_error;
|
||||
Toast.makeText(getContext(), res, LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,18 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
@@ -25,42 +22,41 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ShareForumActivity.CONTACTS;
|
||||
import static org.briarproject.android.forum.ShareForumActivity.getContactsFromIds;
|
||||
import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
|
||||
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
|
||||
import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
|
||||
|
||||
public class ShareForumMessageFragment extends BaseFragment {
|
||||
abstract class ShareMessageFragment extends BaseFragment {
|
||||
|
||||
public final static String TAG = "IntroductionMessageFragment";
|
||||
public final static String TAG = ShareMessageFragment.class.getName();
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ShareForumMessageFragment.class.getName());
|
||||
protected static final Logger LOG = Logger.getLogger(TAG);
|
||||
|
||||
private ShareForumActivity shareForumActivity;
|
||||
private ViewHolder ui;
|
||||
protected ViewHolder ui;
|
||||
private ShareActivity shareActivity;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
@Inject
|
||||
protected volatile BlogSharingManager blogSharingManager;
|
||||
private volatile GroupId groupId;
|
||||
private volatile Collection<ContactId> contacts;
|
||||
|
||||
public static ShareForumMessageFragment newInstance(GroupId groupId, Collection<ContactId> contacts) {
|
||||
protected static Bundle getArguments(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putByteArray(GROUP_ID, groupId.getBytes());
|
||||
args.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts));
|
||||
ShareForumMessageFragment fragment = new ShareForumMessageFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
return args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
shareForumActivity = (ShareForumActivity) context;
|
||||
shareActivity = (ShareActivity) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InstantiationError(
|
||||
"This fragment is only meant to be attached to the ShareForumActivity");
|
||||
@@ -71,17 +67,18 @@ public class ShareForumMessageFragment extends BaseFragment {
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
// change toolbar text
|
||||
ActionBar actionBar = shareForumActivity.getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(R.string.forum_share_button);
|
||||
}
|
||||
|
||||
// allow for home button to act as back button
|
||||
// allow for "up" button to act as back button
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
// get groupID and contactIDs from fragment arguments
|
||||
groupId = new GroupId(getArguments().getByteArray(GROUP_ID));
|
||||
ArrayList<Integer> intContacts =
|
||||
getArguments().getIntegerArrayList(CONTACTS);
|
||||
if (intContacts == null) throw new IllegalArgumentException();
|
||||
contacts = ShareActivity.getContactsFromIntegers(intContacts);
|
||||
|
||||
// inflate view
|
||||
View v = inflater.inflate(R.layout.share_forum_message, container,
|
||||
View v = inflater.inflate(R.layout.fragment_share_message, container,
|
||||
false);
|
||||
ui = new ViewHolder(v);
|
||||
ui.button.setOnClickListener(new View.OnClickListener() {
|
||||
@@ -91,13 +88,6 @@ public class ShareForumMessageFragment extends BaseFragment {
|
||||
}
|
||||
});
|
||||
|
||||
// get groupID and contactIDs from fragment arguments
|
||||
groupId = new GroupId(getArguments().getByteArray(GROUP_ID));
|
||||
ArrayList<Integer> intContacts =
|
||||
getArguments().getIntegerArrayList(CONTACTS);
|
||||
if (intContacts == null) throw new IllegalArgumentException();
|
||||
contacts = ShareForumActivity.getContactsFromIntegers(intContacts);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -105,7 +95,7 @@ public class ShareForumMessageFragment extends BaseFragment {
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
shareForumActivity.onBackPressed();
|
||||
shareActivity.onBackPressed();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -117,54 +107,40 @@ public class ShareForumMessageFragment extends BaseFragment {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
protected void setTitle(int res) {
|
||||
shareActivity.setTitle(res);
|
||||
}
|
||||
|
||||
public void onButtonClick() {
|
||||
private void onButtonClick() {
|
||||
// disable button to prevent accidental double invitations
|
||||
ui.button.setEnabled(false);
|
||||
|
||||
String msg = ui.message.getText().toString();
|
||||
shareForum(msg);
|
||||
share(msg);
|
||||
|
||||
// don't wait for the introduction to be made before finishing activity
|
||||
shareForumActivity.sharingSuccessful(ui.message);
|
||||
// don't wait for the invitation to be made before finishing activity
|
||||
shareActivity.sharingSuccessful(ui.message);
|
||||
}
|
||||
|
||||
private void shareForum(final String msg) {
|
||||
shareForumActivity.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (ContactId c : contacts) {
|
||||
forumSharingManager.sendInvitation(groupId, c,
|
||||
msg);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
sharingError();
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
abstract void share(final String msg);
|
||||
|
||||
abstract void sharingError();
|
||||
|
||||
protected Collection<ContactId> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
private void sharingError() {
|
||||
shareForumActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(shareForumActivity,
|
||||
R.string.introduction_error, LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
protected GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
protected void runOnUiThread(Runnable runnable) {
|
||||
listener.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
private final EditText message;
|
||||
private final Button button;
|
||||
protected static class ViewHolder {
|
||||
protected final EditText message;
|
||||
protected final Button button;
|
||||
|
||||
ViewHolder(View v) {
|
||||
message = (EditText) v.findViewById(R.id.invitationMessageView);
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
@@ -6,13 +6,11 @@ import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
@@ -26,26 +24,24 @@ import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
public class ForumSharingStatusActivity extends BriarActivity {
|
||||
abstract class SharingStatusActivity extends BriarActivity {
|
||||
|
||||
private GroupId groupId;
|
||||
private BriarRecyclerView sharedByList, sharedWithList;
|
||||
private ForumSharingStatusAdapter sharedByAdapter, sharedWithAdapter;
|
||||
private SharingStatusAdapter sharedByAdapter, sharedWithAdapter;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
@Inject
|
||||
protected volatile IdentityManager identityManager;
|
||||
|
||||
public final static String TAG = "ForumSharingStatusActivity";
|
||||
public final static String TAG = SharingStatusActivity.class.getName();
|
||||
private static final Logger LOG = Logger.getLogger(TAG);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_forum_sharing_status);
|
||||
setContentView(R.layout.activity_sharing_status);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
@@ -53,13 +49,13 @@ public class ForumSharingStatusActivity extends BriarActivity {
|
||||
groupId = new GroupId(b);
|
||||
|
||||
sharedByList = (BriarRecyclerView) findViewById(R.id.sharedByView);
|
||||
sharedByAdapter = new ForumSharingStatusAdapter(this);
|
||||
sharedByAdapter = new SharingStatusAdapter(this);
|
||||
sharedByList.setLayoutManager(new LinearLayoutManager(this));
|
||||
sharedByList.setAdapter(sharedByAdapter);
|
||||
sharedByList.setEmptyText(getString(R.string.nobody));
|
||||
|
||||
sharedWithList = (BriarRecyclerView) findViewById(R.id.sharedWithView);
|
||||
sharedWithAdapter = new ForumSharingStatusAdapter(this);
|
||||
sharedWithAdapter = new SharingStatusAdapter(this);
|
||||
sharedWithList.setLayoutManager(new LinearLayoutManager(this));
|
||||
sharedWithList.setAdapter(sharedWithAdapter);
|
||||
sharedWithList.setEmptyText(getString(R.string.nobody));
|
||||
@@ -85,9 +81,18 @@ public class ForumSharingStatusActivity extends BriarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
/**
|
||||
* This must only be called from the DbThread
|
||||
*/
|
||||
abstract protected Collection<Contact> getSharedWith() throws DbException;
|
||||
|
||||
/**
|
||||
* This must only be called from the DbThread
|
||||
*/
|
||||
abstract protected Collection<Contact> getSharedBy() throws DbException;
|
||||
|
||||
protected GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
private void loadSharedBy() {
|
||||
@@ -96,9 +101,7 @@ public class ForumSharingStatusActivity extends BriarActivity {
|
||||
public void run() {
|
||||
List<ContactListItem> contactItems = new ArrayList<>();
|
||||
try {
|
||||
Collection<Contact> contacts =
|
||||
forumSharingManager.getSharedBy(groupId);
|
||||
for (Contact c : contacts) {
|
||||
for (Contact c : getSharedBy()) {
|
||||
LocalAuthor localAuthor = identityManager
|
||||
.getLocalAuthor(c.getLocalAuthorId());
|
||||
ContactListItem item =
|
||||
@@ -134,9 +137,7 @@ public class ForumSharingStatusActivity extends BriarActivity {
|
||||
public void run() {
|
||||
List<ContactListItem> contactItems = new ArrayList<>();
|
||||
try {
|
||||
Collection<Contact> contacts =
|
||||
forumSharingManager.getSharedWith(groupId);
|
||||
for (Contact c : contacts) {
|
||||
for (Contact c : getSharedWith()) {
|
||||
LocalAuthor localAuthor = identityManager
|
||||
.getLocalAuthor(c.getLocalAuthorId());
|
||||
ContactListItem item =
|
||||
@@ -1,22 +1,18 @@
|
||||
package org.briarproject.android.forum;
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.contact.BaseContactListAdapter;
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
|
||||
public class ForumSharingStatusAdapter
|
||||
class SharingStatusAdapter
|
||||
extends BaseContactListAdapter<BaseContactListAdapter.BaseContactHolder> {
|
||||
|
||||
public ForumSharingStatusAdapter(Context context) {
|
||||
SharingStatusAdapter(Context context) {
|
||||
super(context, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.db.DbException;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class SharingStatusBlogActivity extends SharingStatusActivity {
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile BlogSharingManager blogSharingManager;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This must only be called from the DbThread
|
||||
*/
|
||||
protected Collection<Contact> getSharedWith() throws DbException {
|
||||
return blogSharingManager.getSharedWith(getGroupId());
|
||||
}
|
||||
|
||||
/**
|
||||
* This must only be called from the DbThread
|
||||
*/
|
||||
protected Collection<Contact> getSharedBy() throws DbException {
|
||||
return blogSharingManager.getSharedBy(getGroupId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.briarproject.android.sharing;
|
||||
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class SharingStatusForumActivity extends SharingStatusActivity {
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This must only be called from the DbThread
|
||||
*/
|
||||
protected Collection<Contact> getSharedWith() throws DbException {
|
||||
return forumSharingManager.getSharedWith(getGroupId());
|
||||
}
|
||||
|
||||
/**
|
||||
* This must only be called from the DbThread
|
||||
*/
|
||||
protected Collection<Contact> getSharedBy() throws DbException {
|
||||
return forumSharingManager.getSharedBy(getGroupId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.android.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.util.AttributeSet;
|
||||
@@ -10,8 +11,10 @@ import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.api.identity.Author;
|
||||
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
import im.delight.android.identicons.IdenticonDrawable;
|
||||
|
||||
public class TextAvatarView extends FrameLayout {
|
||||
|
||||
@@ -83,4 +86,10 @@ public class TextAvatarView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthorAvatar(Author author) {
|
||||
Drawable drawable = new IdenticonDrawable(author.getId().getBytes());
|
||||
background.setImageDrawable(drawable);
|
||||
character.setVisibility(GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,20 +8,20 @@ import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public class BlogInvitationRequest extends InvitationRequest {
|
||||
|
||||
private final String blogTitle;
|
||||
private final String blogAuthorName;
|
||||
|
||||
public BlogInvitationRequest(MessageId id, SessionId sessionId,
|
||||
ContactId contactId, String blogTitle, String message,
|
||||
ContactId contactId, String blogAuthorName, String message,
|
||||
boolean available, long time, boolean local, boolean sent,
|
||||
boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, contactId, message, available, time, local, sent,
|
||||
seen, read);
|
||||
this.blogTitle = blogTitle;
|
||||
this.blogAuthorName = blogAuthorName;
|
||||
}
|
||||
|
||||
public String getBlogTitle() {
|
||||
return blogTitle;
|
||||
public String getBlogAuthorName() {
|
||||
return blogAuthorName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.briarproject.api.blogs;
|
||||
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.sharing.InvitationResponse;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public class BlogInvitationResponse extends InvitationResponse {
|
||||
|
||||
public BlogInvitationResponse(MessageId id, SessionId sessionId,
|
||||
ContactId contactId, boolean accept, long time, boolean local,
|
||||
boolean sent, boolean seen, boolean read) {
|
||||
|
||||
super(id, sessionId, contactId, accept, time, local, sent, seen, read);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public interface BlogManager {
|
||||
Collection<Blog> getBlogs(LocalAuthor localAuthor) throws DbException;
|
||||
|
||||
/** Returns only the personal blog of the given author. */
|
||||
Blog getPersonalBlog(Author author) throws DbException;
|
||||
Blog getPersonalBlog(Author author);
|
||||
|
||||
/** Returns all blogs to which the user subscribes. */
|
||||
Collection<Blog> getBlogs() throws DbException;
|
||||
|
||||
@@ -3,14 +3,14 @@ package org.briarproject.api.blogs;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sharing.SharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface BlogSharingManager
|
||||
extends SharingManager<Blog, BlogInvitationRequest> {
|
||||
public interface BlogSharingManager extends SharingManager<Blog> {
|
||||
|
||||
/**
|
||||
* Returns the unique ID of the blog sharing client.
|
||||
@@ -34,7 +34,7 @@ public interface BlogSharingManager
|
||||
* Returns all blogs sharing messages sent by the Contact
|
||||
* identified by contactId.
|
||||
*/
|
||||
Collection<BlogInvitationRequest> getInvitationMessages(
|
||||
Collection<InvitationMessage> getInvitationMessages(
|
||||
ContactId contactId) throws DbException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ForumSharingManager extends SharingManager<Forum, InvitationMessage> {
|
||||
public interface ForumSharingManager extends SharingManager<Forum> {
|
||||
|
||||
/** Returns the unique ID of the forum sharing client. */
|
||||
ClientId getClientId();
|
||||
|
||||
@@ -20,6 +20,12 @@ public interface IdentityManager {
|
||||
/** Returns the local pseudonym with the given ID. */
|
||||
LocalAuthor getLocalAuthor(AuthorId a) throws DbException;
|
||||
|
||||
/** Returns the main local identity. */
|
||||
LocalAuthor getLocalAuthor() throws DbException;
|
||||
|
||||
/** Returns the main local identity within the given Transaction. */
|
||||
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
|
||||
|
||||
/** Returns all local pseudonyms. */
|
||||
Collection<LocalAuthor> getLocalAuthors() throws DbException;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface SharingManager<S extends Shareable, IM extends InvitationMessage> {
|
||||
public interface SharingManager<S extends Shareable> {
|
||||
|
||||
/** Returns the unique ID of the group sharing client. */
|
||||
ClientId getClientId();
|
||||
@@ -30,7 +30,7 @@ public interface SharingManager<S extends Shareable, IM extends InvitationMessag
|
||||
* Returns all group sharing messages sent by the Contact
|
||||
* identified by contactId.
|
||||
*/
|
||||
Collection<IM> getInvitationMessages(
|
||||
Collection<InvitationMessage> getInvitationMessages(
|
||||
ContactId contactId) throws DbException;
|
||||
|
||||
/** Returns all shareables to which the user has been invited. */
|
||||
|
||||
@@ -69,7 +69,7 @@ class BlogFactoryImpl implements BlogFactory {
|
||||
Author a =
|
||||
authorFactory.createAuthor(blog.getString(1), blog.getRaw(2));
|
||||
// TODO change permanent depending on how this will be used
|
||||
boolean permanent = false;
|
||||
boolean permanent = true;
|
||||
return new Blog(g, blog.getString(0), description, a, permanent);
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blog getPersonalBlog(Author author) throws DbException {
|
||||
public Blog getPersonalBlog(Author author) {
|
||||
return blogFactory.createPersonalBlog(author);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@ import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -69,12 +67,22 @@ class IdentityManagerImpl implements IdentityManager {
|
||||
return author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor() throws DbException {
|
||||
return getLocalAuthors().iterator().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor(Transaction txn) throws DbException {
|
||||
return getLocalAuthors(txn).iterator().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LocalAuthor> getLocalAuthors() throws DbException {
|
||||
Collection<LocalAuthor> authors;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
authors = db.getLocalAuthors(txn);
|
||||
authors = getLocalAuthors(txn);
|
||||
txn.setComplete();
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
@@ -82,6 +90,12 @@ class IdentityManagerImpl implements IdentityManager {
|
||||
return authors;
|
||||
}
|
||||
|
||||
private Collection<LocalAuthor> getLocalAuthors(Transaction txn)
|
||||
throws DbException {
|
||||
|
||||
return db.getLocalAuthors(txn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocalAuthor(AuthorId a) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.blogs.Blog;
|
||||
import org.briarproject.api.blogs.BlogFactory;
|
||||
import org.briarproject.api.blogs.BlogInvitationRequest;
|
||||
import org.briarproject.api.blogs.BlogInvitationResponse;
|
||||
import org.briarproject.api.blogs.BlogManager;
|
||||
import org.briarproject.api.blogs.BlogManager.RemoveBlogHook;
|
||||
import org.briarproject.api.blogs.BlogSharingManager;
|
||||
@@ -12,6 +13,7 @@ import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.clients.MessageQueueManager;
|
||||
import org.briarproject.api.clients.PrivateGroupFactory;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
@@ -24,6 +26,9 @@ import org.briarproject.api.event.BlogInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.BlogInvitationResponseReceivedEvent;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorFactory;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
@@ -40,13 +45,17 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
|
||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
|
||||
|
||||
class BlogSharingManagerImpl extends
|
||||
SharingManagerImpl<Blog, BlogInvitation, BlogInvitationRequest, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
|
||||
SharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
|
||||
implements BlogSharingManager, RemoveBlogHook {
|
||||
|
||||
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
|
||||
"bee438b5de0b3a685badc4e49d76e72d"
|
||||
+ "21e01c4b569a775112756bdae267a028"));
|
||||
|
||||
@Inject
|
||||
IdentityManager identityManager;
|
||||
private final BlogManager blogManager;
|
||||
|
||||
private final SFactory sFactory;
|
||||
private final IFactory iFactory;
|
||||
private final ISFactory isFactory;
|
||||
@@ -64,6 +73,7 @@ class BlogSharingManagerImpl extends
|
||||
super(db, messageQueueManager, clientHelper, metadataParser,
|
||||
metadataEncoder, random, privateGroupFactory, clock);
|
||||
|
||||
this.blogManager = blogManager;
|
||||
sFactory = new SFactory(authorFactory, blogFactory, blogManager);
|
||||
iFactory = new IFactory();
|
||||
isFactory = new ISFactory();
|
||||
@@ -78,21 +88,37 @@ class BlogSharingManagerImpl extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlogInvitationRequest createInvitationRequest(MessageId id,
|
||||
protected boolean canBeShared(Transaction txn, GroupId g, Contact c)
|
||||
throws DbException {
|
||||
|
||||
// check if g is our personal blog
|
||||
LocalAuthor author = identityManager.getLocalAuthor(txn);
|
||||
Blog b = blogManager.getPersonalBlog(author);
|
||||
if (b.getId().equals(g)) return false;
|
||||
|
||||
// check if g is c's personal blog
|
||||
b = blogManager.getPersonalBlog(c.getAuthor());
|
||||
if (b.getId().equals(g)) return false;
|
||||
|
||||
return super.canBeShared(txn, g, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InvitationMessage createInvitationRequest(MessageId id,
|
||||
BlogInvitation msg, ContactId contactId, boolean available,
|
||||
long time, boolean local, boolean sent, boolean seen,
|
||||
boolean read) {
|
||||
return new BlogInvitationRequest(id, msg.getSessionId(), contactId,
|
||||
msg.getBlogTitle(), msg.getMessage(), available, time, local,
|
||||
sent, seen, read);
|
||||
msg.getBlogAuthorName(), msg.getMessage(), available, time,
|
||||
local, sent, seen, read);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlogInvitationRequest createInvitationResponse(MessageId id,
|
||||
protected InvitationMessage createInvitationResponse(MessageId id,
|
||||
SessionId sessionId, ContactId contactId, boolean accept, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read) {
|
||||
// TODO implement when doing blog sharing
|
||||
return null;
|
||||
return new BlogInvitationResponse(id, sessionId, contactId, accept,
|
||||
time, local, sent, seen, read);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,7 +58,7 @@ class BlogSharingValidator extends BdfMessageValidator {
|
||||
checkLength(name, 1, MAX_BLOG_TITLE_LENGTH);
|
||||
|
||||
String desc = body.getString(3);
|
||||
checkLength(desc, 1, MAX_BLOG_DESC_LENGTH);
|
||||
checkLength(desc, 0, MAX_BLOG_DESC_LENGTH);
|
||||
|
||||
BdfList author = body.getList(4);
|
||||
checkSize(author, 2);
|
||||
|
||||
@@ -37,7 +37,7 @@ import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
||||
|
||||
class ForumSharingManagerImpl extends
|
||||
SharingManagerImpl<Forum, ForumInvitation, InvitationMessage, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent>
|
||||
SharingManagerImpl<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent>
|
||||
implements ForumSharingManager, ForumManager.RemoveForumHook {
|
||||
|
||||
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
|
||||
|
||||
@@ -83,9 +83,9 @@ import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
|
||||
import static org.briarproject.api.sharing.SharingMessage.Invitation;
|
||||
import static org.briarproject.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
|
||||
|
||||
abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM extends InvitationMessage, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent>
|
||||
abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent>
|
||||
extends BdfIncomingMessageHook
|
||||
implements SharingManager<S, IM>, Client, AddContactHook,
|
||||
implements SharingManager<S>, Client, AddContactHook,
|
||||
RemoveContactHook {
|
||||
|
||||
private static final Logger LOG =
|
||||
@@ -117,11 +117,11 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
||||
|
||||
public abstract ClientId getClientId();
|
||||
|
||||
protected abstract IM createInvitationRequest(MessageId id, I msg,
|
||||
protected abstract InvitationMessage createInvitationRequest(MessageId id, I msg,
|
||||
ContactId contactId, boolean available, long time, boolean local,
|
||||
boolean sent, boolean seen, boolean read);
|
||||
|
||||
protected abstract IM createInvitationResponse(MessageId id,
|
||||
protected abstract InvitationMessage createInvitationResponse(MessageId id,
|
||||
SessionId sessionId, ContactId contactId, boolean accept, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read);
|
||||
|
||||
@@ -326,7 +326,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<IM> getInvitationMessages(ContactId contactId)
|
||||
public Collection<InvitationMessage> getInvitationMessages(ContactId contactId)
|
||||
throws DbException {
|
||||
|
||||
Transaction txn = db.startTransaction(true);
|
||||
@@ -334,7 +334,8 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
||||
Contact contact = db.getContact(txn, contactId);
|
||||
Group group = getContactGroup(contact);
|
||||
|
||||
Collection<IM> list = new ArrayList<IM>();
|
||||
Collection<InvitationMessage> list =
|
||||
new ArrayList<InvitationMessage>();
|
||||
Map<MessageId, BdfDictionary> map = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, group.getId());
|
||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||
@@ -362,7 +363,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
||||
available = ((InviteeSessionState) s).getState() ==
|
||||
AWAIT_LOCAL_RESPONSE;
|
||||
}
|
||||
IM im = createInvitationRequest(m.getKey(), msg,
|
||||
InvitationMessage im = createInvitationRequest(m.getKey(), msg,
|
||||
contactId, available, time, local,
|
||||
status.isSent(), status.isSeen(), read);
|
||||
list.add(im);
|
||||
@@ -373,9 +374,9 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
||||
BaseMessage msg = BaseMessage
|
||||
.from(getIFactory(), group.getId(), d);
|
||||
SessionId sessionId = msg.getSessionId();
|
||||
IM im = createInvitationResponse(m.getKey(), sessionId,
|
||||
contactId, accept, time, local,
|
||||
status.isSent(), status.isSeen(), read);
|
||||
InvitationMessage im = createInvitationResponse(
|
||||
m.getKey(), sessionId, contactId, accept, time,
|
||||
local, status.isSent(), status.isSeen(), read);
|
||||
list.add(im);
|
||||
}
|
||||
else {
|
||||
@@ -499,7 +500,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
||||
return canBeShared;
|
||||
}
|
||||
|
||||
private boolean canBeShared(Transaction txn, GroupId g, Contact c)
|
||||
protected boolean canBeShared(Transaction txn, GroupId g, Contact c)
|
||||
throws DbException {
|
||||
|
||||
try {
|
||||
|
||||
@@ -27,6 +27,8 @@ public class SharingModule {
|
||||
ForumSharingValidator forumSharingValidator;
|
||||
@Inject
|
||||
ForumSharingManager forumSharingManager;
|
||||
@Inject
|
||||
BlogSharingManager blogSharingManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
Reference in New Issue
Block a user