mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Removed forums for beta release.
This commit is contained in:
@@ -3,14 +3,6 @@ package org.briarproject.android;
|
||||
import android.app.Activity;
|
||||
|
||||
import org.briarproject.android.contact.ConversationActivity;
|
||||
import org.briarproject.android.forum.AvailableForumsActivity;
|
||||
import org.briarproject.android.forum.ContactSelectorFragment;
|
||||
import org.briarproject.android.forum.CreateForumActivity;
|
||||
import org.briarproject.android.forum.ForumActivity;
|
||||
import org.briarproject.android.forum.ReadForumPostActivity;
|
||||
import org.briarproject.android.forum.ShareForumActivity;
|
||||
import org.briarproject.android.forum.ShareForumMessageFragment;
|
||||
import org.briarproject.android.forum.WriteForumPostActivity;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.identity.CreateIdentityActivity;
|
||||
import org.briarproject.android.introduction.IntroductionActivity;
|
||||
@@ -51,18 +43,6 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(CreateIdentityActivity activity);
|
||||
|
||||
void inject(AvailableForumsActivity activity);
|
||||
|
||||
void inject(WriteForumPostActivity activity);
|
||||
|
||||
void inject(CreateForumActivity activity);
|
||||
|
||||
void inject(ShareForumActivity activity);
|
||||
|
||||
void inject(ReadForumPostActivity activity);
|
||||
|
||||
void inject(ForumActivity activity);
|
||||
|
||||
void inject(SettingsActivity activity);
|
||||
|
||||
void inject(IntroductionActivity activity);
|
||||
@@ -70,9 +50,6 @@ public interface ActivityComponent {
|
||||
@Named("ContactListFragment")
|
||||
BaseFragment newContactListFragment();
|
||||
|
||||
@Named("ForumListFragment")
|
||||
BaseFragment newForumListFragment();
|
||||
|
||||
@Named("ChooseIdentityFragment")
|
||||
BaseFragment newChooseIdentityFragment();
|
||||
|
||||
@@ -82,12 +59,6 @@ public interface ActivityComponent {
|
||||
@Named("ContactChooserFragment")
|
||||
BaseFragment newContactChooserFragment();
|
||||
|
||||
@Named("ContactSelectorFragment")
|
||||
ContactSelectorFragment newContactSelectorFragment();
|
||||
|
||||
@Named("ShareForumMessageFragment")
|
||||
ShareForumMessageFragment newShareForumMessageFragment();
|
||||
|
||||
@Named("IntroductionMessageFragment")
|
||||
IntroductionMessageFragment newIntroductionMessageFragment();
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@ import org.briarproject.android.controller.PasswordControllerImpl;
|
||||
import org.briarproject.android.controller.SetupController;
|
||||
import org.briarproject.android.controller.SetupControllerImpl;
|
||||
import org.briarproject.android.controller.TransportStateListener;
|
||||
import org.briarproject.android.forum.ContactSelectorFragment;
|
||||
import org.briarproject.android.forum.ForumListFragment;
|
||||
import org.briarproject.android.forum.ShareForumMessageFragment;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.introduction.ContactChooserFragment;
|
||||
import org.briarproject.android.introduction.IntroductionMessageFragment;
|
||||
@@ -116,13 +113,6 @@ public class ActivityModule {
|
||||
return new BriarServiceConnection();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("ForumListFragment")
|
||||
BaseFragment provideForumListFragment(ForumListFragment fragment) {
|
||||
fragment.setArguments(new Bundle());
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("ContactListFragment")
|
||||
BaseFragment provideContactListFragment(ContactListFragment fragment) {
|
||||
@@ -153,22 +143,6 @@ public class ActivityModule {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("ContactSelectorFragment")
|
||||
ContactSelectorFragment provideContactSelectorFragment(
|
||||
ContactSelectorFragment fragment) {
|
||||
fragment.setArguments(new Bundle());
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("ShareForumMessageFragment")
|
||||
ShareForumMessageFragment provideShareForumMessageFragment(
|
||||
ShareForumMessageFragment fragment) {
|
||||
fragment.setArguments(new Bundle());
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("IntroductionMessageFragment")
|
||||
IntroductionMessageFragment provideIntroductionMessageFragment(
|
||||
|
||||
@@ -14,9 +14,6 @@ import org.briarproject.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.api.db.DatabaseConfig;
|
||||
import org.briarproject.api.db.DatabaseExecutor;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumPostFactory;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.AuthorFactory;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.introduction.IntroductionManager;
|
||||
@@ -89,12 +86,6 @@ public interface AndroidComponent extends CoreEagerSingletons {
|
||||
|
||||
TransportPropertyManager transportPropertyManager();
|
||||
|
||||
ForumManager forumManager();
|
||||
|
||||
ForumSharingManager forumSharingManager();
|
||||
|
||||
ForumPostFactory forumPostFactory();
|
||||
|
||||
SettingsManager settingsManager();
|
||||
|
||||
ContactExchangeTask contactExchangeTask();
|
||||
|
||||
@@ -13,20 +13,17 @@ import org.briarproject.R;
|
||||
import org.briarproject.android.api.AndroidExecutor;
|
||||
import org.briarproject.android.api.AndroidNotificationManager;
|
||||
import org.briarproject.android.contact.ConversationActivity;
|
||||
import org.briarproject.android.forum.ForumActivity;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DatabaseExecutor;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionSucceededEvent;
|
||||
import org.briarproject.api.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.lifecycle.ServiceException;
|
||||
import org.briarproject.api.messaging.MessagingManager;
|
||||
@@ -54,7 +51,6 @@ import static android.content.Context.NOTIFICATION_SERVICE;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
|
||||
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.BriarActivity.GROUP_ID;
|
||||
@@ -64,12 +60,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
Service, EventListener {
|
||||
|
||||
private static final int PRIVATE_MESSAGE_NOTIFICATION_ID = 3;
|
||||
private static final int FORUM_POST_NOTIFICATION_ID = 4;
|
||||
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 5;
|
||||
private static final String CONTACT_URI =
|
||||
"content://org.briarproject/contact";
|
||||
private static final String FORUM_URI =
|
||||
"content://org.briarproject/forum";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidNotificationManagerImpl.class.getName());
|
||||
@@ -77,16 +70,14 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
private final Executor dbExecutor;
|
||||
private final SettingsManager settingsManager;
|
||||
private final MessagingManager messagingManager;
|
||||
private final ForumManager forumManager;
|
||||
private final AndroidExecutor androidExecutor;
|
||||
private final Context appContext;
|
||||
|
||||
// The following must only be accessed on the main UI thread
|
||||
private final Map<GroupId, Integer> contactCounts = new HashMap<>();
|
||||
private final Map<GroupId, Integer> forumCounts = new HashMap<>();
|
||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||
|
||||
private int contactTotal = 0, forumTotal = 0;
|
||||
private int contactTotal = 0;
|
||||
private int nextRequestId = 0;
|
||||
private GroupId visibleGroup = null;
|
||||
|
||||
@@ -95,12 +86,10 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
@Inject
|
||||
public AndroidNotificationManagerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||
SettingsManager settingsManager, MessagingManager messagingManager,
|
||||
ForumManager forumManager, AndroidExecutor androidExecutor,
|
||||
Application app) {
|
||||
AndroidExecutor androidExecutor, Application app) {
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.settingsManager = settingsManager;
|
||||
this.messagingManager = messagingManager;
|
||||
this.forumManager = forumManager;
|
||||
this.androidExecutor = androidExecutor;
|
||||
appContext = app.getApplicationContext();
|
||||
}
|
||||
@@ -121,7 +110,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
@Override
|
||||
public Void call() {
|
||||
clearPrivateMessageNotification();
|
||||
clearForumPostNotification();
|
||||
clearIntroductionSuccessNotification();
|
||||
return null;
|
||||
}
|
||||
@@ -139,12 +127,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
private void clearForumPostNotification() {
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.cancel(FORUM_POST_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
private void clearIntroductionSuccessNotification() {
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
@@ -162,8 +144,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
ClientId c = m.getClientId();
|
||||
if (c.equals(messagingManager.getClientId()))
|
||||
showPrivateMessageNotification(m.getMessage().getGroupId());
|
||||
else if (c.equals(forumManager.getClientId()))
|
||||
showForumPostNotification(m.getMessage().getGroupId());
|
||||
}
|
||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
||||
ContactId c = ((IntroductionRequestReceivedEvent) e).getContactId();
|
||||
@@ -174,9 +154,6 @@ 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();
|
||||
showNotificationForPrivateConversation(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,82 +259,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
return defaults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showForumPostNotification(final GroupId g) {
|
||||
androidExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Integer count = forumCounts.get(g);
|
||||
if (count == null) forumCounts.put(g, 1);
|
||||
else forumCounts.put(g, count + 1);
|
||||
forumTotal++;
|
||||
if (!g.equals(visibleGroup))
|
||||
updateForumPostNotification();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearForumPostNotification(final GroupId g) {
|
||||
androidExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Integer count = forumCounts.remove(g);
|
||||
if (count == null) return; // Already cleared
|
||||
forumTotal -= count;
|
||||
// FIXME: If the notification isn't showing, this may show it
|
||||
updateForumPostNotification();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateForumPostNotification() {
|
||||
if (forumTotal == 0) {
|
||||
clearForumPostNotification();
|
||||
} else if (settings.getBoolean("notifyForumPosts", true)) {
|
||||
NotificationCompat.Builder b =
|
||||
new NotificationCompat.Builder(appContext);
|
||||
b.setSmallIcon(R.drawable.message_notification_icon);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
b.setContentText(appContext.getResources().getQuantityString(
|
||||
R.plurals.forum_post_notification_text, forumTotal,
|
||||
forumTotal));
|
||||
String ringtoneUri = settings.get("notifyRingtoneUri");
|
||||
if (!StringUtils.isNullOrEmpty(ringtoneUri))
|
||||
b.setSound(Uri.parse(ringtoneUri));
|
||||
b.setDefaults(getDefaults());
|
||||
b.setOnlyAlertOnce(true);
|
||||
b.setAutoCancel(true);
|
||||
if (forumCounts.size() == 1) {
|
||||
Intent i = new Intent(appContext, ForumActivity.class);
|
||||
GroupId g = forumCounts.keySet().iterator().next();
|
||||
i.putExtra(GROUP_ID, g.getBytes());
|
||||
String idHex = StringUtils.toHexString(g.getBytes());
|
||||
i.setData(Uri.parse(FORUM_URI + "/" + idHex));
|
||||
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
TaskStackBuilder t = TaskStackBuilder.create(appContext);
|
||||
t.addParentStack(ForumActivity.class);
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
} else {
|
||||
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
||||
i.putExtra(NavDrawerActivity.INTENT_FORUMS, true);
|
||||
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
TaskStackBuilder t = TaskStackBuilder.create(appContext);
|
||||
t.addParentStack(NavDrawerActivity.class);
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
b.setCategory(CATEGORY_SOCIAL);
|
||||
b.setVisibility(VISIBILITY_SECRET);
|
||||
}
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(FORUM_POST_NOTIFICATION_ID, b.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockNotification(final GroupId g) {
|
||||
androidExecutor.execute(new Runnable() {
|
||||
@@ -423,5 +324,4 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.support.v7.app.AlertDialog;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.contact.ContactListFragment;
|
||||
import org.briarproject.android.forum.ForumListFragment;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
|
||||
/**
|
||||
@@ -24,8 +23,6 @@ public abstract class BriarFragmentActivity extends BriarActivity {
|
||||
|
||||
if (fragmentTag.equals(ContactListFragment.TAG)) {
|
||||
actionBar.setTitle(R.string.contacts_toolbar_header);
|
||||
} else if (fragmentTag.equals(ForumListFragment.TAG)) {
|
||||
actionBar.setTitle(R.string.forums_toolbar_header);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
||||
public final static String PREF_SEEN_WELCOME_MESSAGE = "welcome_message";
|
||||
|
||||
public static final String INTENT_CONTACTS = "intent_contacts";
|
||||
public static final String INTENT_FORUMS = "intent_forums";
|
||||
|
||||
private static final String KEY_CURRENT_FRAGMENT_ID = "key_current_id";
|
||||
|
||||
@@ -70,9 +69,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
||||
exitIfStartupFailed(intent);
|
||||
checkAuthorHandle(intent);
|
||||
clearBackStack();
|
||||
if (intent.getBooleanExtra(INTENT_FORUMS, false))
|
||||
startFragment(activityComponent.newForumListFragment());
|
||||
else if (intent.getBooleanExtra(INTENT_CONTACTS, false))
|
||||
if (intent.getBooleanExtra(INTENT_CONTACTS, false))
|
||||
startFragment(activityComponent.newContactListFragment());
|
||||
}
|
||||
|
||||
@@ -171,9 +168,6 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
||||
case R.id.nav_btn_contacts:
|
||||
startFragment(activityComponent.newContactListFragment());
|
||||
break;
|
||||
case R.id.nav_btn_forums:
|
||||
startFragment(activityComponent.newForumListFragment());
|
||||
break;
|
||||
case R.id.nav_btn_settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
break;
|
||||
|
||||
@@ -2,17 +2,13 @@ package org.briarproject.android.api;
|
||||
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
/** Manages notifications for private messages and forum posts. */
|
||||
/** Manages notifications for private messages and introductions. */
|
||||
public interface AndroidNotificationManager {
|
||||
|
||||
void showPrivateMessageNotification(GroupId g);
|
||||
|
||||
void clearPrivateMessageNotification(GroupId g);
|
||||
|
||||
void showForumPostNotification(GroupId g);
|
||||
|
||||
void clearForumPostNotification(GroupId g);
|
||||
|
||||
void blockNotification(GroupId g);
|
||||
|
||||
void unblockNotification(GroupId g);
|
||||
|
||||
@@ -29,8 +29,6 @@ import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.introduction.IntroductionManager;
|
||||
@@ -76,8 +74,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
protected volatile MessagingManager messagingManager;
|
||||
@Inject
|
||||
protected volatile IntroductionManager introductionManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
@Inject
|
||||
public ContactListFragment() {
|
||||
@@ -225,8 +221,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
MessageValidatedEvent m = (MessageValidatedEvent) e;
|
||||
ClientId c = m.getClientId();
|
||||
if (m.isValid() && (c.equals(messagingManager.getClientId()) ||
|
||||
c.equals(introductionManager.getClientId()) ||
|
||||
c.equals(forumSharingManager.getClientId()))) {
|
||||
c.equals(introductionManager.getClientId()))) {
|
||||
LOG.info("Message added, reloading");
|
||||
reloadConversation(m.getMessage().getGroupId());
|
||||
}
|
||||
@@ -320,16 +315,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading introduction messages took " + duration + " ms");
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
Collection<ForumInvitationMessage> invitations =
|
||||
forumSharingManager.getForumInvitationMessages(id);
|
||||
for (ForumInvitationMessage i : invitations) {
|
||||
messages.add(ConversationItem.from(i));
|
||||
}
|
||||
duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading forum invitations took " + duration + " ms");
|
||||
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,14 +43,11 @@ 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.IntroductionRequestReceivedEvent;
|
||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
||||
import org.briarproject.api.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.event.MessagesAckedEvent;
|
||||
import org.briarproject.api.event.MessagesSentEvent;
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.introduction.IntroductionManager;
|
||||
import org.briarproject.api.introduction.IntroductionMessage;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
@@ -122,8 +119,6 @@ public class ConversationActivity extends BriarActivity
|
||||
protected volatile PrivateMessageFactory privateMessageFactory;
|
||||
@Inject
|
||||
protected volatile IntroductionManager introductionManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
private volatile GroupId groupId = null;
|
||||
private volatile ContactId contactId = null;
|
||||
@@ -297,13 +292,10 @@ public class ConversationActivity extends BriarActivity
|
||||
Collection<IntroductionMessage> introductions =
|
||||
introductionManager
|
||||
.getIntroductionMessages(contactId);
|
||||
Collection<ForumInvitationMessage> invitations =
|
||||
forumSharingManager
|
||||
.getForumInvitationMessages(contactId);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading headers took " + duration + " ms");
|
||||
displayMessages(headers, introductions, invitations);
|
||||
displayMessages(headers, introductions);
|
||||
} catch (NoSuchContactException e) {
|
||||
finishOnUiThread();
|
||||
} catch (DbException e) {
|
||||
@@ -315,14 +307,12 @@ public class ConversationActivity extends BriarActivity
|
||||
}
|
||||
|
||||
private void displayMessages(final Collection<PrivateMessageHeader> headers,
|
||||
final Collection<IntroductionMessage> introductions,
|
||||
final Collection<ForumInvitationMessage> invitations) {
|
||||
final Collection<IntroductionMessage> introductions) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sendButton.setEnabled(true);
|
||||
if (headers.isEmpty() && introductions.isEmpty() &&
|
||||
invitations.isEmpty()) {
|
||||
if (headers.isEmpty() && introductions.isEmpty()) {
|
||||
// we have no messages,
|
||||
// so let the list know to hide progress bar
|
||||
list.showData();
|
||||
@@ -350,10 +340,6 @@ public class ConversationActivity extends BriarActivity
|
||||
}
|
||||
items.add(item);
|
||||
}
|
||||
for (ForumInvitationMessage i : invitations) {
|
||||
ConversationItem item = ConversationItem.from(i);
|
||||
items.add(item);
|
||||
}
|
||||
adapter.addAll(items);
|
||||
// Scroll to the bottom
|
||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||
@@ -507,12 +493,6 @@ public class ConversationActivity extends BriarActivity
|
||||
ConversationItem.from(this, contactName, ir);
|
||||
addIntroduction(item);
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
ForumInvitationReceivedEvent event =
|
||||
(ForumInvitationReceivedEvent) e;
|
||||
if (event.getContactId().equals(contactId)) {
|
||||
loadMessages();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.format.DateUtils;
|
||||
@@ -14,9 +13,7 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.forum.AvailableForumsActivity;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||
import org.briarproject.util.StringUtils;
|
||||
@@ -25,8 +22,6 @@ import java.util.List;
|
||||
|
||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||
import static android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
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;
|
||||
import static org.briarproject.android.contact.ConversationItem.INTRODUCTION_OUT;
|
||||
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
|
||||
@@ -87,14 +82,6 @@ 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) {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_forum_invitation_in, viewGroup, false);
|
||||
return new InvitationHolder(v, type);
|
||||
} else if (type == FORUM_INVITATION_OUT) {
|
||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||
R.layout.list_item_forum_invitation_out, viewGroup, false);
|
||||
return new InvitationHolder(v, type);
|
||||
}
|
||||
// incoming message (non-local)
|
||||
else {
|
||||
@@ -119,12 +106,6 @@ 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) {
|
||||
bindInvitation((InvitationHolder) ui,
|
||||
(ConversationForumInvitationOutItem) item);
|
||||
} else if (item instanceof ConversationForumInvitationInItem) {
|
||||
bindInvitation((InvitationHolder) ui,
|
||||
(ConversationForumInvitationInItem) item);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unhandled Conversation Item");
|
||||
}
|
||||
@@ -276,65 +257,6 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void bindInvitation(InvitationHolder ui,
|
||||
final ConversationForumInvitationItem item) {
|
||||
|
||||
ForumInvitationMessage fim = item.getForumInvitationMessage();
|
||||
|
||||
String message = fim.getMessage();
|
||||
if (StringUtils.isNullOrEmpty(message)) {
|
||||
ui.messageLayout.setVisibility(View.GONE);
|
||||
} else {
|
||||
ui.messageLayout.setVisibility(View.VISIBLE);
|
||||
ui.message.body.setText(message);
|
||||
ui.message.date.setText(
|
||||
DateUtils.getRelativeTimeSpanString(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 (i.isSeen()) {
|
||||
ui.status.setImageResource(R.drawable.message_delivered);
|
||||
ui.message.status.setImageResource(
|
||||
R.drawable.message_delivered_white);
|
||||
} else if (i.isSent()) {
|
||||
ui.status.setImageResource(R.drawable.message_sent);
|
||||
ui.message.status.setImageResource(
|
||||
R.drawable.message_sent_white);
|
||||
} else {
|
||||
ui.status.setImageResource(R.drawable.message_stored);
|
||||
ui.message.status.setImageResource(
|
||||
R.drawable.message_stored_white);
|
||||
}
|
||||
}
|
||||
// Incoming Invitation
|
||||
else {
|
||||
ui.text.setText(ctx.getString(R.string.forum_invitation_received,
|
||||
contactName, fim.getForumName()));
|
||||
|
||||
if (fim.isAvailable()) {
|
||||
ui.showForumsButton.setVisibility(View.VISIBLE);
|
||||
ui.showForumsButton
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(ctx,
|
||||
AvailableForumsActivity.class);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ui.showForumsButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
ui.date.setText(
|
||||
DateUtils.getRelativeTimeSpanString(ctx, item.getTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
@@ -473,33 +395,6 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
private static class InvitationHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final View messageLayout;
|
||||
private final MessageHolder message;
|
||||
private final TextView text;
|
||||
private final Button showForumsButton;
|
||||
private final TextView date;
|
||||
private final ImageView status;
|
||||
|
||||
public 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);
|
||||
date = (TextView) v.findViewById(R.id.introductionTime);
|
||||
|
||||
if (type == FORUM_INVITATION_OUT) {
|
||||
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
||||
} else {
|
||||
status = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ListCallbacks extends SortedList.Callback<ConversationItem> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
|
||||
// This class is not thread-safe
|
||||
public class ConversationForumInvitationInItem
|
||||
extends ConversationForumInvitationItem
|
||||
implements ConversationItem.IncomingItem {
|
||||
|
||||
private boolean read;
|
||||
|
||||
public ConversationForumInvitationInItem(ForumInvitationMessage 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.ForumInvitationMessage;
|
||||
|
||||
abstract class ConversationForumInvitationItem extends ConversationItem {
|
||||
|
||||
private final ForumInvitationMessage fim;
|
||||
|
||||
public ConversationForumInvitationItem(ForumInvitationMessage fim) {
|
||||
super(fim.getId(), fim.getTimestamp());
|
||||
|
||||
this.fim = fim;
|
||||
}
|
||||
|
||||
public ForumInvitationMessage getForumInvitationMessage() {
|
||||
return fim;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package org.briarproject.android.contact;
|
||||
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
|
||||
/**
|
||||
* This class is needed and can not be replaced by an ConversationNoticeOutItem,
|
||||
* because it carries the optional invitation message
|
||||
* to be displayed as a regular private message.
|
||||
* <p/>
|
||||
* This class is not thread-safe
|
||||
*/
|
||||
public class ConversationForumInvitationOutItem
|
||||
extends ConversationForumInvitationItem
|
||||
implements ConversationItem.OutgoingItem {
|
||||
|
||||
private boolean sent, seen;
|
||||
|
||||
public ConversationForumInvitationOutItem(ForumInvitationMessage fim) {
|
||||
super(fim);
|
||||
this.sent = fim.isSent();
|
||||
this.seen = fim.isSeen();
|
||||
}
|
||||
|
||||
@Override
|
||||
int getType() {
|
||||
return FORUM_INVITATION_OUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSent(boolean sent) {
|
||||
this.sent = sent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSeen() {
|
||||
return seen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeen(boolean seen) {
|
||||
this.seen = seen;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package org.briarproject.android.contact;
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||
import org.briarproject.api.introduction.IntroductionMessage;
|
||||
import org.briarproject.api.introduction.IntroductionRequest;
|
||||
import org.briarproject.api.introduction.IntroductionResponse;
|
||||
@@ -21,8 +20,6 @@ public abstract class ConversationItem {
|
||||
final static int INTRODUCTION_OUT = 4;
|
||||
final static int NOTICE_IN = 5;
|
||||
final static int NOTICE_OUT = 6;
|
||||
final static int FORUM_INVITATION_IN = 7;
|
||||
final static int FORUM_INVITATION_OUT = 8;
|
||||
|
||||
private MessageId id;
|
||||
private long time;
|
||||
@@ -95,14 +92,6 @@ public abstract class ConversationItem {
|
||||
}
|
||||
}
|
||||
|
||||
public static ConversationItem from(ForumInvitationMessage fim) {
|
||||
if (fim.isLocal()) {
|
||||
return new ConversationForumInvitationOutItem(fim);
|
||||
} else {
|
||||
return new ConversationForumInvitationInItem(fim);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should not be used to get user-facing objects,
|
||||
* Its purpose is to provider data for the contact list.
|
||||
|
||||
@@ -1,178 +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.List;
|
||||
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.AvailableForumsAdapter.AvailableForumClickListener;
|
||||
|
||||
public class AvailableForumsActivity extends BriarActivity
|
||||
implements EventListener, AvailableForumClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AvailableForumsActivity.class.getName());
|
||||
|
||||
private AvailableForumsAdapter 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 AvailableForumsAdapter(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();
|
||||
}
|
||||
|
||||
private void loadForums() {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Collection<ForumContacts> available = new ArrayList<>();
|
||||
long now = System.currentTimeMillis();
|
||||
for (Forum f : forumSharingManager.getAvailableForums()) {
|
||||
try {
|
||||
Collection<Contact> c =
|
||||
forumSharingManager.getSharedBy(f.getId());
|
||||
available.add(new ForumContacts(f, c));
|
||||
} catch (NoSuchGroupException e) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayForums(available);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayForums(final Collection<ForumContacts> available) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (available.isEmpty()) {
|
||||
LOG.info("No forums available, finishing");
|
||||
finish();
|
||||
} else {
|
||||
adapter.clear();
|
||||
List<AvailableForumsItem> list =
|
||||
new ArrayList<>(available.size());
|
||||
for (ForumContacts f : available)
|
||||
list.add(new AvailableForumsItem(f));
|
||||
adapter.addAll(list);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactRemovedEvent) {
|
||||
LOG.info("Contact removed, reloading");
|
||||
loadForums();
|
||||
} else if (e instanceof GroupAddedEvent) {
|
||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum added, reloading");
|
||||
loadForums();
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum removed, reloading");
|
||||
loadForums();
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
LOG.info("Available forums updated, reloading");
|
||||
loadForums();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AvailableForumsItem item, boolean accept) {
|
||||
respondToInvitation(item.getForum(), 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();
|
||||
}
|
||||
|
||||
private void respondToInvitation(final Forum f, final boolean accept) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
forumSharingManager.respondToInvitation(f, accept);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
loadForums();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.util.TextAvatarView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
class AvailableForumsAdapter extends
|
||||
RecyclerView.Adapter<AvailableForumsAdapter.AvailableForumViewHolder> {
|
||||
|
||||
private final Context ctx;
|
||||
private final AvailableForumClickListener listener;
|
||||
private final SortedList<AvailableForumsItem> forums =
|
||||
new SortedList<>(AvailableForumsItem.class,
|
||||
new SortedListCallBacks());
|
||||
|
||||
AvailableForumsAdapter(Context ctx, AvailableForumClickListener listener) {
|
||||
this.ctx = ctx;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AvailableForumViewHolder onCreateViewHolder(ViewGroup parent,
|
||||
int viewType) {
|
||||
|
||||
View v = LayoutInflater.from(ctx)
|
||||
.inflate(R.layout.list_item_available_forum, parent, false);
|
||||
return new AvailableForumViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(AvailableForumViewHolder ui, int position) {
|
||||
final AvailableForumsItem 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());
|
||||
|
||||
Collection<String> names = new ArrayList<>();
|
||||
for (Contact c : item.getContacts()) names.add(c.getAuthor().getName());
|
||||
ui.sharedBy.setText(ctx.getString(R.string.shared_by_format,
|
||||
StringUtils.join(names, ", ")));
|
||||
|
||||
ui.accept.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listener.onItemClick(item, true);
|
||||
}
|
||||
});
|
||||
ui.decline.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listener.onItemClick(item, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return forums.size();
|
||||
}
|
||||
|
||||
public AvailableForumsItem getItem(int position) {
|
||||
return forums.get(position);
|
||||
}
|
||||
|
||||
public void add(AvailableForumsItem item) {
|
||||
forums.add(item);
|
||||
}
|
||||
|
||||
public void addAll(Collection<AvailableForumsItem> list) {
|
||||
forums.addAll(list);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
forums.clear();
|
||||
}
|
||||
|
||||
protected static class AvailableForumViewHolder
|
||||
extends RecyclerView.ViewHolder {
|
||||
|
||||
private final TextAvatarView avatar;
|
||||
private final TextView name;
|
||||
private final TextView sharedBy;
|
||||
private final Button accept;
|
||||
private final Button decline;
|
||||
|
||||
public AvailableForumViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
avatar = (TextAvatarView) v.findViewById(R.id.avatarView);
|
||||
name = (TextView) v.findViewById(R.id.forumNameView);
|
||||
sharedBy = (TextView) v.findViewById(R.id.sharedByView);
|
||||
accept = (Button) v.findViewById(R.id.acceptButton);
|
||||
decline = (Button) v.findViewById(R.id.declineButton);
|
||||
}
|
||||
}
|
||||
|
||||
private class SortedListCallBacks
|
||||
extends SortedList.Callback<AvailableForumsItem> {
|
||||
|
||||
@Override
|
||||
public int compare(AvailableForumsItem o1,
|
||||
AvailableForumsItem o2) {
|
||||
return String.CASE_INSENSITIVE_ORDER
|
||||
.compare(o1.getForum().getName(),
|
||||
o2.getForum().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInserted(int position, int count) {
|
||||
notifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(int position, int count) {
|
||||
notifyItemRangeRemoved(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(int fromPosition, int toPosition) {
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(int position, int count) {
|
||||
notifyItemRangeChanged(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(AvailableForumsItem oldItem,
|
||||
AvailableForumsItem newItem) {
|
||||
return oldItem.getForum().equals(newItem.getForum()) &&
|
||||
oldItem.getContacts().equals(newItem.getContacts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(AvailableForumsItem oldItem,
|
||||
AvailableForumsItem newItem) {
|
||||
return oldItem.getForum().equals(newItem.getForum());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface AvailableForumClickListener {
|
||||
void onItemClick(AvailableForumsItem item, boolean accept);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
class AvailableForumsItem {
|
||||
|
||||
private final ForumContacts forumContacts;
|
||||
|
||||
AvailableForumsItem(ForumContacts forumContacts) {
|
||||
this.forumContacts = forumContacts;
|
||||
}
|
||||
|
||||
Forum getForum() {
|
||||
return forumContacts.getForum();
|
||||
}
|
||||
|
||||
Collection<Contact> getContacts() {
|
||||
return forumContacts.getContacts();
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.os.Build;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.contact.BaseContactListAdapter;
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ContactSelectorAdapter
|
||||
extends BaseContactListAdapter<ContactSelectorAdapter.SelectableContactHolder> {
|
||||
|
||||
public ContactSelectorAdapter(Context context,
|
||||
OnItemClickListener listener) {
|
||||
|
||||
super(context, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectableContactHolder onCreateViewHolder(ViewGroup viewGroup,
|
||||
int i) {
|
||||
View v = LayoutInflater.from(ctx).inflate(
|
||||
R.layout.list_item_selectable_contact, viewGroup, false);
|
||||
|
||||
return new SelectableContactHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(SelectableContactHolder ui, int position) {
|
||||
super.onBindViewHolder(ui, position);
|
||||
|
||||
SelectableContactListItem item =
|
||||
(SelectableContactListItem) getItem(position);
|
||||
|
||||
if (item.isSelected()) {
|
||||
ui.checkBox.setChecked(true);
|
||||
} else {
|
||||
ui.checkBox.setChecked(false);
|
||||
}
|
||||
|
||||
if (item.isDisabled()) {
|
||||
// we share this forum already with that contact
|
||||
ui.layout.setEnabled(false);
|
||||
grayOutItem(ui);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<ContactId> getSelectedContactIds() {
|
||||
Collection<ContactId> selected = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < contacts.size(); i++) {
|
||||
SelectableContactListItem item =
|
||||
(SelectableContactListItem) contacts.get(i);
|
||||
if (item.isSelected()) selected.add(item.getContact().getId());
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
protected static class SelectableContactHolder
|
||||
extends BaseContactListAdapter.BaseContactHolder {
|
||||
|
||||
private final CheckBox checkBox;
|
||||
|
||||
public SelectableContactHolder(View v) {
|
||||
super(v);
|
||||
|
||||
checkBox = (CheckBox) v.findViewById(R.id.checkBox);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareContactListItems(ContactListItem c1, ContactListItem c2) {
|
||||
return compareByName(c1, c2);
|
||||
}
|
||||
|
||||
private void grayOutItem(final SelectableContactHolder ui) {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
float alpha = 0.25f;
|
||||
ui.avatar.setAlpha(alpha);
|
||||
ui.name.setAlpha(alpha);
|
||||
ui.checkBox.setAlpha(alpha);
|
||||
} else {
|
||||
ColorFilter colorFilter = new PorterDuffColorFilter(Color.GRAY,
|
||||
PorterDuff.Mode.MULTIPLY);
|
||||
ui.avatar.setColorFilter(colorFilter);
|
||||
ui.name.setEnabled(false);
|
||||
ui.checkBox.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.transition.Fade;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.contact.BaseContactListAdapter;
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
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.api.forum.ForumConstants.GROUP_ID;
|
||||
|
||||
public class ContactSelectorFragment extends BaseFragment implements
|
||||
BaseContactListAdapter.OnItemClickListener {
|
||||
|
||||
public final static String TAG = "ContactSelectorFragment";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ContactSelectorFragment.class.getName());
|
||||
|
||||
private ShareForumActivity shareForumActivity;
|
||||
private Menu menu;
|
||||
private BriarRecyclerView list;
|
||||
private ContactSelectorAdapter adapter;
|
||||
private Collection<ContactId> selectedContacts;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ContactManager contactManager;
|
||||
@Inject
|
||||
protected volatile IdentityManager identityManager;
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
protected volatile GroupId groupId;
|
||||
|
||||
public void initBundle(GroupId groupId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putByteArray(GROUP_ID, groupId.getBytes());
|
||||
setArguments(bundle);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public ContactSelectorFragment() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
shareForumActivity = (ShareForumActivity) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InstantiationError(
|
||||
"This fragment is only meant to be attached to the ShareForumActivity");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
groupId = new GroupId(getArguments().getByteArray(GROUP_ID));
|
||||
if (groupId == null) throw new IllegalStateException("No GroupId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View contentView = inflater.inflate(
|
||||
R.layout.introduction_contact_chooser, container, false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
setExitTransition(new Fade());
|
||||
}
|
||||
|
||||
adapter = new ContactSelectorAdapter(getActivity(), this);
|
||||
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.contactList);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_contacts));
|
||||
|
||||
// restore selected contacts if available
|
||||
if (savedInstanceState != null) {
|
||||
ArrayList<Integer> intContacts =
|
||||
savedInstanceState.getIntegerArrayList(CONTACTS);
|
||||
selectedContacts = ShareForumActivity.getContactsFromIntegers(
|
||||
intContacts);
|
||||
}
|
||||
|
||||
return contentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (selectedContacts != null)
|
||||
loadContacts(Collections.unmodifiableCollection(selectedContacts));
|
||||
else loadContacts(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
if (adapter != null) {
|
||||
selectedContacts = adapter.getSelectedContactIds();
|
||||
outState.putIntegerArrayList(CONTACTS,
|
||||
getContactsFromIds(selectedContacts));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.forum_share_actions, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
this.menu = menu;
|
||||
// hide sharing action initially, if no contact is selected
|
||||
updateMenuItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
// Handle presses on the action bar items
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
shareForumActivity.onBackPressed();
|
||||
return true;
|
||||
case R.id.action_share_forum:
|
||||
selectedContacts = adapter.getSelectedContactIds();
|
||||
shareForumActivity.showMessageScreen(groupId, selectedContacts);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(View view, ContactListItem item) {
|
||||
((SelectableContactListItem) item).toggleSelected();
|
||||
adapter.notifyItemChanged(adapter.findItemPosition(item), item);
|
||||
|
||||
updateMenuItem();
|
||||
}
|
||||
|
||||
private void loadContacts(final Collection<ContactId> selection) {
|
||||
shareForumActivity.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
List<ContactListItem> contacts = new ArrayList<>();
|
||||
|
||||
for (Contact c : contactManager.getActiveContacts()) {
|
||||
LocalAuthor localAuthor = identityManager
|
||||
.getLocalAuthor(c.getLocalAuthorId());
|
||||
// was this contact already selected?
|
||||
boolean selected = selection != null &&
|
||||
selection.contains(c.getId());
|
||||
// do we have already some sharing with that contact?
|
||||
boolean disabled =
|
||||
!forumSharingManager.canBeShared(groupId, c);
|
||||
contacts.add(new SelectableContactListItem(c,
|
||||
localAuthor, groupId, selected, disabled));
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayContacts(Collections.unmodifiableList(contacts));
|
||||
} catch (DbException e) {
|
||||
displayContacts(Collections.<ContactListItem>emptyList());
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayContacts(final List<ContactListItem> contacts) {
|
||||
shareForumActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!contacts.isEmpty()) adapter.addAll(contacts);
|
||||
else list.showData();
|
||||
updateMenuItem();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateMenuItem() {
|
||||
if (menu == null) return;
|
||||
MenuItem item = menu.findItem(R.id.action_share_forum);
|
||||
if (item == null) return;
|
||||
|
||||
selectedContacts = adapter.getSelectedContactIds();
|
||||
if (selectedContacts.size() > 0) {
|
||||
item.setVisible(true);
|
||||
} else {
|
||||
item.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
|
||||
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
|
||||
|
||||
public class CreateForumActivity extends BriarActivity
|
||||
implements OnEditorActionListener, OnClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(CreateForumActivity.class.getName());
|
||||
|
||||
private EditText nameEntry;
|
||||
private Button createForumButton;
|
||||
private ProgressBar progress;
|
||||
private TextView feedback;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumManager forumManager;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
setContentView(R.layout.activity_create_forum);
|
||||
|
||||
nameEntry = (EditText) findViewById(R.id.createForumNameEntry);
|
||||
TextWatcher nameEntryWatcher = new TextWatcher() {
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||
int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence text, int start,
|
||||
int lengthBefore, int lengthAfter) {
|
||||
enableOrDisableCreateButton();
|
||||
}
|
||||
};
|
||||
nameEntry.setOnEditorActionListener(this);
|
||||
nameEntry.addTextChangedListener(nameEntryWatcher);
|
||||
|
||||
feedback = (TextView) findViewById(R.id.createForumFeedback);
|
||||
|
||||
createForumButton = (Button) findViewById(R.id.createForumButton);
|
||||
createForumButton.setOnClickListener(this);
|
||||
|
||||
progress = (ProgressBar) findViewById(R.id.createForumProgressBar);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
private void enableOrDisableCreateButton() {
|
||||
if (progress == null) return; // Not created yet
|
||||
createForumButton.setEnabled(validateName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
|
||||
hideSoftKeyboard(textView);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean validateName() {
|
||||
String name = nameEntry.getText().toString();
|
||||
int length = StringUtils.toUtf8(name).length;
|
||||
if (length > MAX_FORUM_NAME_LENGTH) {
|
||||
feedback.setText(R.string.name_too_long);
|
||||
return false;
|
||||
}
|
||||
feedback.setText("");
|
||||
return length > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (view == createForumButton) {
|
||||
hideSoftKeyboard(view);
|
||||
if (!validateName()) return;
|
||||
createForumButton.setVisibility(GONE);
|
||||
progress.setVisibility(VISIBLE);
|
||||
storeForum(nameEntry.getText().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void storeForum(final String name) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
Forum f = forumManager.createForum(name);
|
||||
forumManager.addForum(f);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Storing forum took " + duration + " ms");
|
||||
displayForum(f);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
finishOnUiThread();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayForum(final Forum f) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent i = new Intent(CreateForumActivity.this,
|
||||
ForumActivity.class);
|
||||
i.putExtra(GROUP_ID, f.getId().getBytes());
|
||||
i.putExtra(FORUM_NAME, f.getName());
|
||||
startActivity(i);
|
||||
Toast.makeText(CreateForumActivity.this,
|
||||
R.string.forum_created_toast, LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,442 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.AndroidComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.api.AndroidNotificationManager;
|
||||
import org.briarproject.android.util.ListLoadingProgressBar;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchGroupException;
|
||||
import org.briarproject.api.db.NoSuchMessageException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.GroupRemovedEvent;
|
||||
import org.briarproject.api.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumPostHeader;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
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.view.Gravity.CENTER;
|
||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
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.ReadForumPostActivity.RESULT_PREV_NEXT;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP_1;
|
||||
|
||||
public class ForumActivity extends BriarActivity implements EventListener,
|
||||
OnItemClickListener {
|
||||
|
||||
public static final String FORUM_NAME = "briar.FORUM_NAME";
|
||||
public static final String MIN_TIMESTAMP = "briar.MIN_TIMESTAMP";
|
||||
|
||||
private static final int REQUEST_READ = 2;
|
||||
private static final int REQUEST_FORUM_SHARED = 3;
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ForumActivity.class.getName());
|
||||
|
||||
@Inject protected AndroidNotificationManager notificationManager;
|
||||
private Map<MessageId, byte[]> bodyCache = new HashMap<>();
|
||||
private TextView empty = null;
|
||||
private ForumAdapter adapter = null;
|
||||
private ListView list = null;
|
||||
private ListLoadingProgressBar loading = null;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject protected volatile ForumManager forumManager;
|
||||
@Inject protected volatile EventBus eventBus;
|
||||
private volatile GroupId groupId = null;
|
||||
private volatile Forum forum = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
if (b == null) throw new IllegalStateException();
|
||||
groupId = new GroupId(b);
|
||||
String forumName = i.getStringExtra(FORUM_NAME);
|
||||
if (forumName != null) setTitle(forumName);
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setLayoutParams(MATCH_MATCH);
|
||||
layout.setOrientation(VERTICAL);
|
||||
layout.setGravity(CENTER_HORIZONTAL);
|
||||
|
||||
empty = new TextView(this);
|
||||
empty.setLayoutParams(MATCH_WRAP_1);
|
||||
empty.setGravity(CENTER);
|
||||
empty.setTextSize(18);
|
||||
empty.setText(R.string.no_forum_posts);
|
||||
empty.setVisibility(GONE);
|
||||
layout.addView(empty);
|
||||
|
||||
adapter = new ForumAdapter(this);
|
||||
list = new ListView(this);
|
||||
list.setLayoutParams(MATCH_WRAP_1);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
list.setVisibility(GONE);
|
||||
layout.addView(list);
|
||||
|
||||
// Show a progress bar while the list is loading
|
||||
loading = new ListLoadingProgressBar(this);
|
||||
layout.addView(loading);
|
||||
|
||||
setContentView(layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
eventBus.addListener(this);
|
||||
notificationManager.blockNotification(groupId);
|
||||
notificationManager.clearForumPostNotification(groupId);
|
||||
loadForum();
|
||||
loadHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu items for use in the action bar
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.forum_actions, menu);
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
// Handle presses on the action bar items
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_forum_compose_post:
|
||||
Intent i = new Intent(this, WriteForumPostActivity.class);
|
||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
||||
i.putExtra(FORUM_NAME, forum.getName());
|
||||
i.putExtra(MIN_TIMESTAMP, getMinTimestampForNewPost());
|
||||
startActivity(i);
|
||||
return true;
|
||||
case R.id.action_forum_share:
|
||||
Intent i2 = new Intent(this, ShareForumActivity.class);
|
||||
i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
i2.putExtra(GROUP_ID, groupId.getBytes());
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat
|
||||
.makeCustomAnimation(this, android.R.anim.slide_in_left,
|
||||
android.R.anim.slide_out_right);
|
||||
ActivityCompat
|
||||
.startActivityForResult(this, i2, REQUEST_FORUM_SHARED,
|
||||
options.toBundle());
|
||||
return true;
|
||||
case R.id.action_forum_delete:
|
||||
showUnsubscribeDialog();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadForum() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
forum = forumManager.getForum(groupId);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading forum " + duration + " ms");
|
||||
displayForumName();
|
||||
} catch (NoSuchGroupException e) {
|
||||
finishOnUiThread();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayForumName() {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
setTitle(forum.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadHeaders() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
Collection<ForumPostHeader> headers =
|
||||
forumManager.getPostHeaders(groupId);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayHeaders(headers);
|
||||
} catch (NoSuchGroupException e) {
|
||||
finishOnUiThread();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayHeaders(final Collection<ForumPostHeader> headers) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
loading.setVisibility(GONE);
|
||||
adapter.clear();
|
||||
if (headers.isEmpty()) {
|
||||
empty.setVisibility(VISIBLE);
|
||||
list.setVisibility(GONE);
|
||||
} else {
|
||||
empty.setVisibility(GONE);
|
||||
list.setVisibility(VISIBLE);
|
||||
for (ForumPostHeader h : headers) {
|
||||
ForumItem item = new ForumItem(h);
|
||||
byte[] body = bodyCache.get(h.getId());
|
||||
if (body == null) loadPostBody(h);
|
||||
else item.setBody(body);
|
||||
adapter.add(item);
|
||||
}
|
||||
adapter.sort(ForumItemComparator.INSTANCE);
|
||||
// Scroll to the bottom
|
||||
list.setSelection(adapter.getCount() - 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadPostBody(final ForumPostHeader h) {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
byte[] body = forumManager.getPostBody(h.getId());
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading message took " + duration + " ms");
|
||||
displayPost(h.getId(), body);
|
||||
} catch (NoSuchMessageException e) {
|
||||
// The item will be removed when we get the event
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayPost(final MessageId m, final byte[] body) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
bodyCache.put(m, body);
|
||||
int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
ForumItem item = adapter.getItem(i);
|
||||
if (item.getHeader().getId().equals(m)) {
|
||||
item.setBody(body);
|
||||
adapter.notifyDataSetChanged();
|
||||
// Scroll to the bottom
|
||||
list.setSelection(count - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int request, int result, Intent data) {
|
||||
super.onActivityResult(request, result, data);
|
||||
if (request == REQUEST_READ && result == RESULT_PREV_NEXT) {
|
||||
int position = data.getIntExtra("briar.POSITION", -1);
|
||||
if (position >= 0 && position < adapter.getCount())
|
||||
displayPost(position);
|
||||
}
|
||||
else if (request == REQUEST_FORUM_SHARED && result == RESULT_OK) {
|
||||
Snackbar s = Snackbar.make(list, R.string.forum_shared_snackbar,
|
||||
LENGTH_LONG);
|
||||
s.getView().setBackgroundResource(R.color.briar_primary);
|
||||
s.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
eventBus.removeListener(this);
|
||||
notificationManager.unblockNotification(groupId);
|
||||
if (isFinishing()) markPostsRead();
|
||||
}
|
||||
|
||||
private void markPostsRead() {
|
||||
List<MessageId> unread = new ArrayList<>();
|
||||
int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
ForumPostHeader h = adapter.getItem(i).getHeader();
|
||||
if (!h.isRead()) unread.add(h.getId());
|
||||
}
|
||||
if (unread.isEmpty()) return;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Marking " + unread.size() + " posts read");
|
||||
markPostsRead(Collections.unmodifiableList(unread));
|
||||
}
|
||||
|
||||
private void markPostsRead(final Collection<MessageId> unread) {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
for (MessageId m : unread)
|
||||
forumManager.setReadFlag(m, true);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Marking read took " + duration + " ms");
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof MessageValidatedEvent) {
|
||||
MessageValidatedEvent m = (MessageValidatedEvent) e;
|
||||
if (m.isValid() && m.getMessage().getGroupId().equals(groupId)) {
|
||||
LOG.info("Message added, reloading");
|
||||
loadHeaders();
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent s = (GroupRemovedEvent) e;
|
||||
if (s.getGroup().getId().equals(groupId)) {
|
||||
LOG.info("Forum removed");
|
||||
finishOnUiThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long getMinTimestampForNewPost() {
|
||||
// Don't use an earlier timestamp than the newest post
|
||||
long timestamp = 0;
|
||||
int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
long t = adapter.getItem(i).getHeader().getTimestamp();
|
||||
if (t > timestamp) timestamp = t;
|
||||
}
|
||||
return timestamp + 1;
|
||||
}
|
||||
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
displayPost(position);
|
||||
}
|
||||
|
||||
private void displayPost(int position) {
|
||||
ForumPostHeader header = adapter.getItem(position).getHeader();
|
||||
Intent i = new Intent(this, ReadForumPostActivity.class);
|
||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
||||
i.putExtra(FORUM_NAME, forum.getName());
|
||||
i.putExtra("briar.MESSAGE_ID", header.getId().getBytes());
|
||||
Author author = header.getAuthor();
|
||||
if (author != null) {
|
||||
i.putExtra("briar.AUTHOR_NAME", author.getName());
|
||||
i.putExtra("briar.AUTHOR_ID", author.getId().getBytes());
|
||||
}
|
||||
i.putExtra("briar.AUTHOR_STATUS", header.getAuthorStatus().name());
|
||||
i.putExtra("briar.CONTENT_TYPE", header.getContentType());
|
||||
i.putExtra("briar.TIMESTAMP", header.getTimestamp());
|
||||
i.putExtra(MIN_TIMESTAMP, getMinTimestampForNewPost());
|
||||
i.putExtra("briar.POSITION", position);
|
||||
startActivityForResult(i, REQUEST_READ);
|
||||
}
|
||||
|
||||
private void showUnsubscribeDialog() {
|
||||
DialogInterface.OnClickListener okListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
unsubscribe(forum);
|
||||
Toast.makeText(ForumActivity.this,
|
||||
R.string.forum_left_toast, LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
};
|
||||
AlertDialog.Builder builder =
|
||||
new AlertDialog.Builder(ForumActivity.this,
|
||||
R.style.BriarDialogTheme);
|
||||
builder.setTitle(getString(R.string.dialog_title_leave_forum));
|
||||
builder.setMessage(getString(R.string.dialog_message_leave_forum));
|
||||
builder.setPositiveButton(R.string.dialog_button_leave, okListener);
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void unsubscribe(final Forum f) {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
forumManager.removeForum(f);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Removing forum took " + duration + " ms");
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.util.AuthorView;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.api.forum.ForumPostHeader;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||
import static android.view.Gravity.CENTER_VERTICAL;
|
||||
import static android.widget.LinearLayout.HORIZONTAL;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1;
|
||||
|
||||
class ForumAdapter extends ArrayAdapter<ForumItem> {
|
||||
|
||||
private final int pad;
|
||||
|
||||
ForumAdapter(Context ctx) {
|
||||
super(ctx, android.R.layout.simple_expandable_list_item_1,
|
||||
new ArrayList<ForumItem>());
|
||||
pad = LayoutUtils.getPadding(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ForumItem item = getItem(position);
|
||||
ForumPostHeader header = item.getHeader();
|
||||
Context ctx = getContext();
|
||||
Resources res = ctx.getResources();
|
||||
|
||||
LinearLayout layout = new LinearLayout(ctx);
|
||||
layout.setOrientation(VERTICAL);
|
||||
layout.setGravity(CENTER_HORIZONTAL);
|
||||
if (!header.isRead())
|
||||
layout.setBackgroundColor(res.getColor(R.color.unread_background));
|
||||
|
||||
LinearLayout headerLayout = new LinearLayout(ctx);
|
||||
headerLayout.setOrientation(HORIZONTAL);
|
||||
headerLayout.setGravity(CENTER_VERTICAL);
|
||||
|
||||
AuthorView authorView = new AuthorView(ctx);
|
||||
authorView.setLayoutParams(WRAP_WRAP_1);
|
||||
authorView.setPadding(0, pad, pad, pad);
|
||||
Author author = header.getAuthor();
|
||||
if (author == null) {
|
||||
authorView.init(null, null, header.getAuthorStatus());
|
||||
} else {
|
||||
authorView.init(author.getName(), author.getId(),
|
||||
header.getAuthorStatus());
|
||||
}
|
||||
headerLayout.addView(authorView);
|
||||
|
||||
TextView date = new TextView(ctx);
|
||||
date.setPadding(pad, pad, pad, pad);
|
||||
long timestamp = header.getTimestamp();
|
||||
date.setText(DateUtils.getRelativeTimeSpanString(ctx, timestamp));
|
||||
headerLayout.addView(date);
|
||||
layout.addView(headerLayout);
|
||||
|
||||
if (item.getBody() == null) {
|
||||
TextView ellipsis = new TextView(ctx);
|
||||
ellipsis.setPadding(pad, 0, pad, pad);
|
||||
ellipsis.setText("\u2026");
|
||||
layout.addView(ellipsis);
|
||||
} else if (header.getContentType().equals("text/plain")) {
|
||||
TextView text = new TextView(ctx);
|
||||
text.setPadding(pad, 0, pad, pad);
|
||||
text.setText(StringUtils.fromUtf8(item.getBody()));
|
||||
layout.addView(text);
|
||||
} else {
|
||||
ImageButton attachment = new ImageButton(ctx);
|
||||
attachment.setPadding(pad, 0, pad, pad);
|
||||
attachment.setImageResource(R.drawable.content_attachment);
|
||||
layout.addView(attachment);
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
class ForumContacts {
|
||||
|
||||
private final Forum forum;
|
||||
private final Collection<Contact> contacts;
|
||||
|
||||
ForumContacts(Forum forum, Collection<Contact> contacts) {
|
||||
this.forum = forum;
|
||||
this.contacts = contacts;
|
||||
}
|
||||
|
||||
Forum getForum() {
|
||||
return forum;
|
||||
}
|
||||
|
||||
Collection<Contact> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import org.briarproject.api.forum.ForumPostHeader;
|
||||
|
||||
// This class is not thread-safe
|
||||
class ForumItem {
|
||||
|
||||
private final ForumPostHeader header;
|
||||
private byte[] body;
|
||||
|
||||
ForumItem(ForumPostHeader header) {
|
||||
this.header = header;
|
||||
body = null;
|
||||
}
|
||||
|
||||
ForumPostHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
void setBody(byte[] body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
class ForumItemComparator implements Comparator<ForumItem> {
|
||||
|
||||
static final ForumItemComparator INSTANCE = new ForumItemComparator();
|
||||
|
||||
public int compare(ForumItem a, ForumItem b) {
|
||||
// The oldest message comes first
|
||||
long aTime = a.getHeader().getTimestamp();
|
||||
long bTime = b.getHeader().getTimestamp();
|
||||
if (aTime < bTime) return -1;
|
||||
if (aTime > bTime) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.util.TextAvatarView;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.briarproject.android.BriarActivity.GROUP_ID;
|
||||
import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
|
||||
|
||||
public class ForumListAdapter extends
|
||||
RecyclerView.Adapter<ForumListAdapter.ForumViewHolder> {
|
||||
|
||||
private SortedList<ForumListItem> forums = new SortedList<>(
|
||||
ForumListItem.class, new SortedList.Callback<ForumListItem>() {
|
||||
|
||||
@Override
|
||||
public int compare(ForumListItem a, ForumListItem b) {
|
||||
if (a == b) return 0;
|
||||
// The forum with the newest message comes first
|
||||
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
||||
if (aTime > bTime) return -1;
|
||||
if (aTime < bTime) return 1;
|
||||
// Break ties by forum name
|
||||
String aName = a.getForum().getName();
|
||||
String bName = b.getForum().getName();
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInserted(int position, int count) {
|
||||
notifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(int position, int count) {
|
||||
notifyItemRangeRemoved(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(int fromPosition, int toPosition) {
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(int position, int count) {
|
||||
notifyItemRangeChanged(position, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(ForumListItem a, ForumListItem b) {
|
||||
return a.getForum().equals(b.getForum()) &&
|
||||
a.getTimestamp() == b.getTimestamp() &&
|
||||
a.getUnreadCount() == b.getUnreadCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(ForumListItem a, ForumListItem b) {
|
||||
return a.getForum().equals(b.getForum());
|
||||
}
|
||||
});
|
||||
|
||||
private final Context ctx;
|
||||
|
||||
public ForumListAdapter(Context ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForumViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(ctx).inflate(
|
||||
R.layout.list_item_forum, parent, false);
|
||||
return new ForumViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ForumViewHolder ui, int position) {
|
||||
final ForumListItem item = getItem(position);
|
||||
|
||||
// Avatar
|
||||
ui.avatar.setText(item.getForum().getName().substring(0, 1));
|
||||
ui.avatar.setBackgroundBytes(item.getForum().getId().getBytes());
|
||||
|
||||
// Forum Name
|
||||
ui.name.setText(item.getForum().getName());
|
||||
|
||||
// Unread Count
|
||||
int unread = item.getUnreadCount();
|
||||
if (unread > 0) {
|
||||
ui.unread.setText(ctx.getResources()
|
||||
.getQuantityString(R.plurals.unread_posts, unread, unread));
|
||||
ui.unread.setTextColor(
|
||||
ContextCompat.getColor(ctx, R.color.briar_button_positive));
|
||||
} else {
|
||||
ui.unread.setText(ctx.getString(R.string.no_unread_posts));
|
||||
ui.unread.setTextColor(
|
||||
ContextCompat.getColor(ctx, R.color.briar_text_secondary));
|
||||
}
|
||||
|
||||
// Date or "No Posts"
|
||||
if (item.isEmpty()) {
|
||||
ui.date.setVisibility(View.GONE);
|
||||
} else {
|
||||
long timestamp = item.getTimestamp();
|
||||
ui.date.setText(
|
||||
DateUtils.getRelativeTimeSpanString(ctx, timestamp));
|
||||
ui.date.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// Open Forum on Click
|
||||
ui.layout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent i = new Intent(ctx, ForumActivity.class);
|
||||
Forum f = item.getForum();
|
||||
i.putExtra(GROUP_ID, f.getId().getBytes());
|
||||
i.putExtra(FORUM_NAME, f.getName());
|
||||
ctx.startActivity(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return forums.size();
|
||||
}
|
||||
|
||||
public ForumListItem getItem(int position) {
|
||||
return forums.get(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ForumListItem getItem(GroupId g) {
|
||||
for (int i = 0; i < forums.size(); i++) {
|
||||
ForumListItem item = forums.get(i);
|
||||
if (item.getForum().getGroup().getId().equals(g)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addAll(Collection<ForumListItem> items) {
|
||||
forums.addAll(items);
|
||||
}
|
||||
|
||||
public void updateItem(ForumListItem item) {
|
||||
ForumListItem oldItem = getItem(item.getForum().getGroup().getId());
|
||||
int position = forums.indexOf(oldItem);
|
||||
forums.updateItemAt(position, item);
|
||||
}
|
||||
|
||||
public void remove(ForumListItem item) {
|
||||
forums.remove(item);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
forums.clear();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return forums.size() == 0;
|
||||
}
|
||||
|
||||
protected static class ForumViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ViewGroup layout;
|
||||
private final TextAvatarView avatar;
|
||||
private final TextView name;
|
||||
private final TextView unread;
|
||||
private final TextView date;
|
||||
|
||||
public ForumViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
layout = (ViewGroup) v;
|
||||
avatar = (TextAvatarView) v.findViewById(R.id.avatarView);
|
||||
name = (TextView) v.findViewById(R.id.forumNameView);
|
||||
unread = (TextView) v.findViewById(R.id.unreadView);
|
||||
date = (TextView) v.findViewById(R.id.dateView);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.AndroidComponent;
|
||||
import org.briarproject.android.fragment.BaseEventFragment;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
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.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.event.GroupAddedEvent;
|
||||
import org.briarproject.api.event.GroupRemovedEvent;
|
||||
import org.briarproject.api.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumPostHeader;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
public class ForumListFragment extends BaseEventFragment implements
|
||||
View.OnClickListener {
|
||||
|
||||
public final static String TAG = "ForumListFragment";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ForumListFragment.class.getName());
|
||||
|
||||
|
||||
private BriarRecyclerView list;
|
||||
private ForumListAdapter adapter;
|
||||
private Snackbar snackbar;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject protected volatile ForumManager forumManager;
|
||||
@Inject protected volatile ForumSharingManager forumSharingManager;
|
||||
|
||||
@Inject
|
||||
public ForumListFragment() {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View contentView =
|
||||
inflater.inflate(R.layout.fragment_forum_list, container,
|
||||
false);
|
||||
|
||||
adapter = new ForumListAdapter(getActivity());
|
||||
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.forumList);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_forums));
|
||||
|
||||
snackbar = Snackbar.make(list, "", LENGTH_INDEFINITE);
|
||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
||||
snackbar.setAction(R.string.show_forums, this);
|
||||
snackbar.setActionTextColor(ContextCompat
|
||||
.getColor(getContext(), R.color.briar_button_positive));
|
||||
|
||||
return contentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
loadForumHeaders();
|
||||
loadAvailableForums();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.forum_list_actions, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
// Handle presses on the action bar items
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_create_forum:
|
||||
Intent intent =
|
||||
new Intent(getContext(), CreateForumActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadForumHeaders() {
|
||||
listener.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// load forums
|
||||
long now = System.currentTimeMillis();
|
||||
Collection<ForumListItem> forums = new ArrayList<>();
|
||||
for (Forum f : forumManager.getForums()) {
|
||||
try {
|
||||
Collection<ForumPostHeader> headers =
|
||||
forumManager.getPostHeaders(f.getId());
|
||||
forums.add(new ForumListItem(f, headers));
|
||||
} catch (NoSuchGroupException e) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
displayForumHeaders(forums);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Full load took " + duration + " ms");
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayForumHeaders(final Collection<ForumListItem> forums) {
|
||||
listener.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (forums.size() > 0) adapter.addAll(forums);
|
||||
else list.showData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadAvailableForums() {
|
||||
listener.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
int available =
|
||||
forumSharingManager.getAvailableForums().size();
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading available took " + duration + " ms");
|
||||
displayAvailableForums(available);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayAvailableForums(final int availableCount) {
|
||||
listener.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (availableCount == 0) {
|
||||
snackbar.dismiss();
|
||||
} else {
|
||||
snackbar.show();
|
||||
snackbar.setText(getResources().getQuantityString(
|
||||
R.plurals.forums_shared, availableCount,
|
||||
availableCount));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactRemovedEvent) {
|
||||
LOG.info("Contact removed, reloading available forums");
|
||||
loadAvailableForums();
|
||||
} else if (e instanceof GroupAddedEvent) {
|
||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum added, reloading forums");
|
||||
loadForumHeaders();
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum removed, removing from list");
|
||||
removeForum(g.getGroup().getId());
|
||||
}
|
||||
} else if (e instanceof MessageValidatedEvent) {
|
||||
MessageValidatedEvent m = (MessageValidatedEvent) e;
|
||||
if (m.isValid()) {
|
||||
ClientId c = m.getClientId();
|
||||
if (c.equals(forumManager.getClientId())) {
|
||||
LOG.info("Forum post added, reloading");
|
||||
loadForumHeaders(m.getMessage().getGroupId());
|
||||
}
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
loadAvailableForums();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadForumHeaders(final GroupId g) {
|
||||
listener.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
Forum f = forumManager.getForum(g);
|
||||
Collection<ForumPostHeader> headers =
|
||||
forumManager.getPostHeaders(g);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Partial load took " + duration + " ms");
|
||||
updateForum(new ForumListItem(f, headers));
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateForum(final ForumListItem item) {
|
||||
listener.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.updateItem(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeForum(final GroupId g) {
|
||||
listener.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ForumListItem item = adapter.getItem(g);
|
||||
if (item != null) adapter.remove(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// snackbar click
|
||||
startActivity(new Intent(getContext(), AvailableForumsActivity.class));
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumPostHeader;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
class ForumListItem {
|
||||
|
||||
private final Forum forum;
|
||||
private final boolean empty;
|
||||
private final long timestamp;
|
||||
private final int unread;
|
||||
|
||||
ForumListItem(Forum forum, Collection<ForumPostHeader> headers) {
|
||||
this.forum = forum;
|
||||
empty = headers.isEmpty();
|
||||
if (empty) {
|
||||
timestamp = 0;
|
||||
unread = 0;
|
||||
} else {
|
||||
ForumPostHeader newest = null;
|
||||
long timestamp = -1;
|
||||
int unread = 0;
|
||||
for (ForumPostHeader h : headers) {
|
||||
if (h.getTimestamp() > timestamp) {
|
||||
timestamp = h.getTimestamp();
|
||||
newest = h;
|
||||
}
|
||||
if (!h.isRead()) unread++;
|
||||
}
|
||||
this.timestamp = newest.getTimestamp();
|
||||
this.unread = unread;
|
||||
}
|
||||
}
|
||||
|
||||
Forum getForum() {
|
||||
return forum;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return empty;
|
||||
}
|
||||
|
||||
long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
int getUnreadCount() {
|
||||
return unread;
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.AndroidComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.util.AuthorView;
|
||||
import org.briarproject.android.util.ElasticHorizontalSpace;
|
||||
import org.briarproject.android.util.HorizontalBorder;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.NoSuchMessageException;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.view.Gravity.CENTER;
|
||||
import static android.view.Gravity.CENTER_VERTICAL;
|
||||
import static android.widget.LinearLayout.HORIZONTAL;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
|
||||
import static org.briarproject.android.forum.ForumActivity.MIN_TIMESTAMP;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP_1;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1;
|
||||
|
||||
public class ReadForumPostActivity extends BriarActivity
|
||||
implements OnClickListener {
|
||||
|
||||
static final int RESULT_REPLY = RESULT_FIRST_USER;
|
||||
static final int RESULT_PREV_NEXT = RESULT_FIRST_USER + 1;
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ReadForumPostActivity.class.getName());
|
||||
|
||||
private GroupId groupId = null;
|
||||
private String forumName = null;
|
||||
private long minTimestamp = -1;
|
||||
private ImageButton prevButton = null, nextButton = null;
|
||||
private ImageButton replyButton = null;
|
||||
private TextView content = null;
|
||||
private int position = -1;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject protected volatile ForumManager forumManager;
|
||||
private volatile MessageId messageId = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
if (b == null) throw new IllegalStateException();
|
||||
groupId = new GroupId(b);
|
||||
forumName = i.getStringExtra(FORUM_NAME);
|
||||
if (forumName == null) throw new IllegalStateException();
|
||||
setTitle(forumName);
|
||||
b = i.getByteArrayExtra("briar.MESSAGE_ID");
|
||||
if (b == null) throw new IllegalStateException();
|
||||
messageId = new MessageId(b);
|
||||
String contentType = i.getStringExtra("briar.CONTENT_TYPE");
|
||||
if (contentType == null) throw new IllegalStateException();
|
||||
long timestamp = i.getLongExtra("briar.TIMESTAMP", -1);
|
||||
if (timestamp == -1) throw new IllegalStateException();
|
||||
minTimestamp = i.getLongExtra(MIN_TIMESTAMP, -1);
|
||||
if (minTimestamp == -1) throw new IllegalStateException();
|
||||
position = i.getIntExtra("briar.POSITION", -1);
|
||||
if (position == -1) throw new IllegalStateException();
|
||||
String authorName = i.getStringExtra("briar.AUTHOR_NAME");
|
||||
AuthorId authorId = null;
|
||||
b = i.getByteArrayExtra("briar.AUTHOR_ID");
|
||||
if (b != null) authorId = new AuthorId(b);
|
||||
String s = i.getStringExtra("briar.AUTHOR_STATUS");
|
||||
if (s == null) throw new IllegalStateException();
|
||||
Author.Status authorStatus = Author.Status.valueOf(s);
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setLayoutParams(MATCH_MATCH);
|
||||
layout.setOrientation(VERTICAL);
|
||||
|
||||
ScrollView scrollView = new ScrollView(this);
|
||||
scrollView.setLayoutParams(MATCH_WRAP_1);
|
||||
|
||||
LinearLayout message = new LinearLayout(this);
|
||||
message.setOrientation(VERTICAL);
|
||||
|
||||
LinearLayout header = new LinearLayout(this);
|
||||
header.setLayoutParams(MATCH_WRAP);
|
||||
header.setOrientation(HORIZONTAL);
|
||||
header.setGravity(CENTER_VERTICAL);
|
||||
|
||||
int pad = LayoutUtils.getPadding(this);
|
||||
|
||||
AuthorView authorView = new AuthorView(this);
|
||||
authorView.setPadding(0, pad, pad, pad);
|
||||
authorView.setLayoutParams(WRAP_WRAP_1);
|
||||
authorView.init(authorName, authorId, authorStatus);
|
||||
header.addView(authorView);
|
||||
|
||||
TextView date = new TextView(this);
|
||||
date.setPadding(pad, pad, pad, pad);
|
||||
date.setText(DateUtils.getRelativeTimeSpanString(this, timestamp));
|
||||
header.addView(date);
|
||||
message.addView(header);
|
||||
|
||||
if (contentType.equals("text/plain")) {
|
||||
// Load and display the message body
|
||||
content = new TextView(this);
|
||||
content.setPadding(pad, 0, pad, pad);
|
||||
message.addView(content);
|
||||
loadPostBody();
|
||||
}
|
||||
scrollView.addView(message);
|
||||
layout.addView(scrollView);
|
||||
|
||||
layout.addView(new HorizontalBorder(this));
|
||||
|
||||
LinearLayout footer = new LinearLayout(this);
|
||||
footer.setLayoutParams(MATCH_WRAP);
|
||||
footer.setOrientation(HORIZONTAL);
|
||||
footer.setGravity(CENTER);
|
||||
Resources res = getResources();
|
||||
footer.setBackgroundColor(res.getColor(R.color.button_bar_background));
|
||||
|
||||
prevButton = new ImageButton(this);
|
||||
prevButton.setBackgroundResource(0);
|
||||
prevButton.setImageResource(R.drawable.navigation_previous_item);
|
||||
prevButton.setOnClickListener(this);
|
||||
footer.addView(prevButton);
|
||||
footer.addView(new ElasticHorizontalSpace(this));
|
||||
|
||||
nextButton = new ImageButton(this);
|
||||
nextButton.setBackgroundResource(0);
|
||||
nextButton.setImageResource(R.drawable.navigation_next_item);
|
||||
nextButton.setOnClickListener(this);
|
||||
footer.addView(nextButton);
|
||||
footer.addView(new ElasticHorizontalSpace(this));
|
||||
|
||||
replyButton = new ImageButton(this);
|
||||
replyButton.setBackgroundResource(0);
|
||||
replyButton.setImageResource(R.drawable.social_reply_all);
|
||||
replyButton.setOnClickListener(this);
|
||||
footer.addView(replyButton);
|
||||
layout.addView(footer);
|
||||
|
||||
setContentView(layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (isFinishing()) markPostRead();
|
||||
}
|
||||
|
||||
private void markPostRead() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
forumManager.setReadFlag(messageId, true);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Marking read took " + duration + " ms");
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadPostBody() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
byte[] body = forumManager.getPostBody(messageId);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Loading post took " + duration + " ms");
|
||||
displayPostBody(StringUtils.fromUtf8(body));
|
||||
} catch (NoSuchMessageException e) {
|
||||
finishOnUiThread();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayPostBody(final String body) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
content.setText(body);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if (view == prevButton) {
|
||||
Intent i = new Intent();
|
||||
i.putExtra("briar.POSITION", position - 1);
|
||||
setResult(RESULT_PREV_NEXT, i);
|
||||
finish();
|
||||
} else if (view == nextButton) {
|
||||
Intent i = new Intent();
|
||||
i.putExtra("briar.POSITION", position + 1);
|
||||
setResult(RESULT_PREV_NEXT, i);
|
||||
finish();
|
||||
} else if (view == replyButton) {
|
||||
Intent i = new Intent(this, WriteForumPostActivity.class);
|
||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
||||
i.putExtra(FORUM_NAME, forumName);
|
||||
i.putExtra("briar.PARENT_ID", messageId.getBytes());
|
||||
i.putExtra(MIN_TIMESTAMP, minTimestamp);
|
||||
startActivity(i);
|
||||
setResult(RESULT_REPLY);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.android.contact.ConversationItem;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
// This class is not thread-safe
|
||||
public class SelectableContactListItem extends ContactListItem {
|
||||
|
||||
private boolean selected, disabled;
|
||||
|
||||
public SelectableContactListItem(Contact contact, LocalAuthor localAuthor,
|
||||
GroupId groupId, boolean selected, boolean disabled) {
|
||||
|
||||
super(contact, localAuthor, false, groupId,
|
||||
Collections.<ConversationItem>emptyList());
|
||||
|
||||
this.selected = selected;
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void toggleSelected() {
|
||||
selected = !selected;
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
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.ContactId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ShareForumActivity extends BriarActivity implements
|
||||
BaseFragment.BaseFragmentListener {
|
||||
|
||||
public final static String CONTACTS = "contacts";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_share_forum);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
if (b == null) throw new IllegalStateException("No GroupId");
|
||||
GroupId groupId = new GroupId(b);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
ContactSelectorFragment contactSelectorFragment =
|
||||
activityComponent.newContactSelectorFragment();
|
||||
contactSelectorFragment.initBundle(groupId);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.shareForumContainer, contactSelectorFragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
public void showMessageScreen(GroupId groupId,
|
||||
Collection<ContactId> contacts) {
|
||||
|
||||
ShareForumMessageFragment messageFragment =
|
||||
activityComponent.newShareForumMessageFragment();
|
||||
messageFragment.initBundle(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,
|
||||
ContactSelectorFragment.TAG)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static ArrayList<Integer> getContactsFromIds(
|
||||
Collection<ContactId> contacts) {
|
||||
|
||||
// transform ContactIds to Integers so they can be added to a bundle
|
||||
ArrayList<Integer> intContacts = new ArrayList<>(contacts.size());
|
||||
for (ContactId contactId : contacts) {
|
||||
intContacts.add(contactId.getInt());
|
||||
}
|
||||
return intContacts;
|
||||
}
|
||||
|
||||
public void sharingSuccessful(View v) {
|
||||
setResult(RESULT_OK);
|
||||
hideSoftKeyboard(v);
|
||||
supportFinishAfterTransition();
|
||||
}
|
||||
|
||||
protected static Collection<ContactId> getContactsFromIntegers(
|
||||
ArrayList<Integer> intContacts) {
|
||||
|
||||
// turn contact integers from a bundle back to ContactIds
|
||||
List<ContactId> contacts = new ArrayList<>(intContacts.size());
|
||||
for(Integer c : intContacts) {
|
||||
contacts.add(new ContactId(c));
|
||||
}
|
||||
return contacts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showLoadingScreen(boolean isBlocking, int stringId) {
|
||||
// this is handled by the recycler view in ContactSelectorFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideLoadingScreen() {
|
||||
// this is handled by the recycler view in ContactSelectorFragment
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
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.fragment.BaseFragment;
|
||||
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.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.WARNING;
|
||||
import static org.briarproject.android.forum.ShareForumActivity.CONTACTS;
|
||||
import static org.briarproject.android.forum.ShareForumActivity.getContactsFromIds;
|
||||
import static org.briarproject.api.forum.ForumConstants.GROUP_ID;
|
||||
|
||||
public class ShareForumMessageFragment extends BaseFragment {
|
||||
|
||||
public final static String TAG = "IntroductionMessageFragment";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ShareForumMessageFragment.class.getName());
|
||||
|
||||
private ShareForumActivity shareForumActivity;
|
||||
private ViewHolder ui;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
protected volatile ForumSharingManager forumSharingManager;
|
||||
private volatile GroupId groupId;
|
||||
private volatile Collection<ContactId> contacts;
|
||||
|
||||
public void initBundle(GroupId groupId, Collection<ContactId> contacts) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putByteArray(GROUP_ID, groupId.getBytes());
|
||||
bundle.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts));
|
||||
setArguments(bundle);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public ShareForumMessageFragment() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
shareForumActivity = (ShareForumActivity) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InstantiationError(
|
||||
"This fragment is only meant to be attached to the ShareForumActivity");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
// inflate view
|
||||
View v = inflater.inflate(R.layout.share_forum_message, container,
|
||||
false);
|
||||
ui = new ViewHolder(v);
|
||||
ui.button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onButtonClick();
|
||||
}
|
||||
});
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
shareForumActivity.onBackPressed();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
public void onButtonClick() {
|
||||
// disable button to prevent accidental double invitations
|
||||
ui.button.setEnabled(false);
|
||||
|
||||
String msg = ui.message.getText().toString();
|
||||
shareForum(msg);
|
||||
|
||||
// don't wait for the introduction to be made before finishing activity
|
||||
shareForumActivity.sharingSuccessful(ui.message);
|
||||
}
|
||||
|
||||
private void shareForum(final String msg) {
|
||||
shareForumActivity.runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (ContactId c : contacts) {
|
||||
forumSharingManager.sendForumInvitation(groupId, c,
|
||||
msg);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
sharingError();
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sharingError() {
|
||||
shareForumActivity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(shareForumActivity,
|
||||
R.string.introduction_error, LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
|
||||
private final EditText message;
|
||||
private final Button button;
|
||||
|
||||
ViewHolder(View v) {
|
||||
message = (EditText) v.findViewById(R.id.invitationMessageView);
|
||||
button = (Button) v.findViewById(R.id.shareForumButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.ActivityComponent;
|
||||
import org.briarproject.android.AndroidComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.identity.CreateIdentityActivity;
|
||||
import org.briarproject.android.identity.LocalAuthorItem;
|
||||
import org.briarproject.android.identity.LocalAuthorItemComparator;
|
||||
import org.briarproject.android.identity.LocalAuthorSpinnerAdapter;
|
||||
import org.briarproject.android.util.CommonLayoutParams;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.api.crypto.KeyParser;
|
||||
import org.briarproject.api.crypto.PrivateKey;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumPost;
|
||||
import org.briarproject.api.forum.ForumPostFactory;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.text.InputType.TYPE_CLASS_TEXT;
|
||||
import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static android.widget.RelativeLayout.ALIGN_PARENT_LEFT;
|
||||
import static android.widget.RelativeLayout.ALIGN_PARENT_RIGHT;
|
||||
import static android.widget.RelativeLayout.CENTER_VERTICAL;
|
||||
import static android.widget.RelativeLayout.LEFT_OF;
|
||||
import static android.widget.RelativeLayout.RIGHT_OF;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
|
||||
import static org.briarproject.android.forum.ForumActivity.MIN_TIMESTAMP;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP;
|
||||
|
||||
public class WriteForumPostActivity extends BriarActivity
|
||||
implements OnItemSelectedListener, OnClickListener {
|
||||
|
||||
private static final int REQUEST_CREATE_IDENTITY = 2;
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(WriteForumPostActivity.class.getName());
|
||||
|
||||
@Inject @CryptoExecutor protected Executor cryptoExecutor;
|
||||
private LocalAuthorSpinnerAdapter adapter = null;
|
||||
private Spinner spinner = null;
|
||||
private ImageButton sendButton = null;
|
||||
private EditText content = null;
|
||||
private AuthorId localAuthorId = null;
|
||||
private GroupId groupId = null;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject protected volatile IdentityManager identityManager;
|
||||
@Inject protected volatile ForumManager forumManager;
|
||||
@Inject protected volatile ForumPostFactory forumPostFactory;
|
||||
@Inject protected volatile CryptoComponent crypto;
|
||||
private volatile MessageId parentId = null;
|
||||
private volatile long minTimestamp = -1;
|
||||
private volatile LocalAuthor localAuthor = null;
|
||||
private volatile Forum forum = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
if (b == null) throw new IllegalStateException();
|
||||
groupId = new GroupId(b);
|
||||
String forumName = i.getStringExtra(FORUM_NAME);
|
||||
if (forumName == null) throw new IllegalStateException();
|
||||
setTitle(forumName);
|
||||
minTimestamp = i.getLongExtra(MIN_TIMESTAMP, -1);
|
||||
if (minTimestamp == -1) throw new IllegalStateException();
|
||||
b = i.getByteArrayExtra("briar.PARENT_ID");
|
||||
if (b != null) parentId = new MessageId(b);
|
||||
|
||||
if (state != null) {
|
||||
b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
|
||||
if (b != null) localAuthorId = new AuthorId(b);
|
||||
}
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setLayoutParams(MATCH_WRAP);
|
||||
layout.setOrientation(VERTICAL);
|
||||
int pad = LayoutUtils.getPadding(this);
|
||||
layout.setPadding(pad, 0, pad, pad);
|
||||
|
||||
RelativeLayout header = new RelativeLayout(this);
|
||||
|
||||
TextView from = new TextView(this);
|
||||
from.setId(1);
|
||||
from.setTextSize(18);
|
||||
from.setText(R.string.from);
|
||||
RelativeLayout.LayoutParams left = CommonLayoutParams.relative();
|
||||
left.addRule(ALIGN_PARENT_LEFT);
|
||||
left.addRule(CENTER_VERTICAL);
|
||||
header.addView(from, left);
|
||||
|
||||
adapter = new LocalAuthorSpinnerAdapter(this, true);
|
||||
spinner = new Spinner(this);
|
||||
spinner.setId(2);
|
||||
spinner.setAdapter(adapter);
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
RelativeLayout.LayoutParams between = CommonLayoutParams.relative();
|
||||
between.addRule(CENTER_VERTICAL);
|
||||
between.addRule(RIGHT_OF, 1);
|
||||
between.addRule(LEFT_OF, 3);
|
||||
header.addView(spinner, between);
|
||||
|
||||
sendButton = new ImageButton(this);
|
||||
sendButton.setId(3);
|
||||
sendButton.setBackgroundResource(0);
|
||||
sendButton.setImageResource(R.drawable.social_send_now);
|
||||
sendButton.setEnabled(false); // Enabled after loading the forum
|
||||
sendButton.setOnClickListener(this);
|
||||
RelativeLayout.LayoutParams right = CommonLayoutParams.relative();
|
||||
right.addRule(ALIGN_PARENT_RIGHT);
|
||||
right.addRule(CENTER_VERTICAL);
|
||||
header.addView(sendButton, right);
|
||||
layout.addView(header);
|
||||
|
||||
content = new EditText(this);
|
||||
content.setId(4);
|
||||
int inputType = TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE
|
||||
| TYPE_TEXT_FLAG_CAP_SENTENCES;
|
||||
content.setInputType(inputType);
|
||||
content.setHint(R.string.forum_post_hint);
|
||||
layout.addView(content);
|
||||
|
||||
setContentView(layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
loadAuthorsAndForum();
|
||||
}
|
||||
|
||||
private void loadAuthorsAndForum() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
Collection<LocalAuthor> localAuthors =
|
||||
identityManager.getLocalAuthors();
|
||||
forum = forumManager.getForum(groupId);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayAuthorsAndForum(localAuthors);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayAuthorsAndForum(
|
||||
final Collection<LocalAuthor> localAuthors) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (localAuthors.isEmpty()) throw new IllegalStateException();
|
||||
adapter.clear();
|
||||
for (LocalAuthor a : localAuthors)
|
||||
adapter.add(new LocalAuthorItem(a));
|
||||
adapter.sort(LocalAuthorItemComparator.INSTANCE);
|
||||
int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
LocalAuthorItem item = adapter.getItem(i);
|
||||
if (item == LocalAuthorItem.ANONYMOUS) continue;
|
||||
if (item == LocalAuthorItem.NEW) continue;
|
||||
if (item.getLocalAuthor().getId().equals(localAuthorId)) {
|
||||
localAuthor = item.getLocalAuthor();
|
||||
spinner.setSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
setTitle(forum.getName());
|
||||
sendButton.setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle state) {
|
||||
super.onSaveInstanceState(state);
|
||||
if (localAuthorId != null) {
|
||||
byte[] b = localAuthorId.getBytes();
|
||||
state.putByteArray("briar.LOCAL_AUTHOR_ID", b);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int request, int result, Intent data) {
|
||||
super.onActivityResult(request, result, data);
|
||||
if (request == REQUEST_CREATE_IDENTITY && result == RESULT_OK) {
|
||||
byte[] b = data.getByteArrayExtra("briar.LOCAL_AUTHOR_ID");
|
||||
if (b == null) throw new IllegalStateException();
|
||||
localAuthorId = new AuthorId(b);
|
||||
loadAuthorsAndForum();
|
||||
}
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
LocalAuthorItem item = adapter.getItem(position);
|
||||
if (item == LocalAuthorItem.ANONYMOUS) {
|
||||
localAuthor = null;
|
||||
localAuthorId = null;
|
||||
} else if (item == LocalAuthorItem.NEW) {
|
||||
localAuthor = null;
|
||||
localAuthorId = null;
|
||||
Intent i = new Intent(this, CreateIdentityActivity.class);
|
||||
startActivityForResult(i, REQUEST_CREATE_IDENTITY);
|
||||
} else {
|
||||
localAuthor = item.getLocalAuthor();
|
||||
localAuthorId = localAuthor.getId();
|
||||
}
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
localAuthor = null;
|
||||
localAuthorId = null;
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if (forum == null) throw new IllegalStateException();
|
||||
String body = content.getText().toString();
|
||||
if (body.equals("")) return;
|
||||
createPost(StringUtils.toUtf8(body));
|
||||
Toast.makeText(this, R.string.post_sent_toast, LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
|
||||
private void createPost(final byte[] body) {
|
||||
cryptoExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
// Don't use an earlier timestamp than the newest post
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.max(timestamp, minTimestamp);
|
||||
ForumPost p;
|
||||
try {
|
||||
if (localAuthor == null) {
|
||||
p = forumPostFactory.createAnonymousPost(groupId,
|
||||
timestamp, parentId, "text/plain", body);
|
||||
} else {
|
||||
KeyParser keyParser = crypto.getSignatureKeyParser();
|
||||
byte[] b = localAuthor.getPrivateKey();
|
||||
PrivateKey authorKey = keyParser.parsePrivateKey(b);
|
||||
p = forumPostFactory.createPseudonymousPost(groupId,
|
||||
timestamp, parentId, localAuthor, "text/plain",
|
||||
body, authorKey);
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
storePost(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void storePost(final ForumPost p) {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
forumManager.addLocalPost(p);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Storing message took " + duration + " ms");
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
private ListPreference enableBluetooth;
|
||||
private ListPreference torOverMobile;
|
||||
private CheckBoxPreference notifyPrivateMessages;
|
||||
private CheckBoxPreference notifyForumPosts;
|
||||
private CheckBoxPreference notifyVibration;
|
||||
private Preference notifySound;
|
||||
|
||||
@@ -94,8 +93,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
(ListPreference) findPreference("pref_key_tor_mobile");
|
||||
notifyPrivateMessages = (CheckBoxPreference) findPreference(
|
||||
"pref_key_notify_private_messages");
|
||||
notifyForumPosts = (CheckBoxPreference) findPreference(
|
||||
"pref_key_notify_forum_posts");
|
||||
notifyVibration = (CheckBoxPreference) findPreference(
|
||||
"pref_key_notify_vibration");
|
||||
notifySound = findPreference("pref_key_notify_sound");
|
||||
@@ -103,7 +100,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
enableBluetooth.setOnPreferenceChangeListener(this);
|
||||
torOverMobile.setOnPreferenceChangeListener(this);
|
||||
notifyPrivateMessages.setOnPreferenceChangeListener(this);
|
||||
notifyForumPosts.setOnPreferenceChangeListener(this);
|
||||
notifyVibration.setOnPreferenceChangeListener(this);
|
||||
|
||||
notifySound.setOnPreferenceClickListener(
|
||||
@@ -197,9 +193,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
notifyPrivateMessages.setChecked(settings.getBoolean(
|
||||
"notifyPrivateMessages", true));
|
||||
|
||||
notifyForumPosts.setChecked(settings.getBoolean(
|
||||
"notifyForumPosts", true));
|
||||
|
||||
notifyVibration.setChecked(settings.getBoolean(
|
||||
"notifyVibration", true));
|
||||
|
||||
@@ -241,10 +234,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
Settings s = new Settings();
|
||||
s.putBoolean("notifyPrivateMessages", (Boolean) o);
|
||||
storeSettings(s);
|
||||
} else if (preference == notifyForumPosts) {
|
||||
Settings s = new Settings();
|
||||
s.putBoolean("notifyForumPosts", (Boolean) o);
|
||||
storeSettings(s);
|
||||
} else if (preference == notifyVibration) {
|
||||
Settings s = new Settings();
|
||||
s.putBoolean("notifyVibration", (Boolean) o);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package org.briarproject.android.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.briarproject.R;
|
||||
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
public class TextAvatarView extends FrameLayout {
|
||||
|
||||
final private AppCompatTextView textView;
|
||||
final private CircleImageView backgroundView;
|
||||
|
||||
public TextAvatarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater
|
||||
.inflate(R.layout.text_avatar_view, this, true);
|
||||
textView = (AppCompatTextView) findViewById(R.id.textAvatarView);
|
||||
backgroundView = (CircleImageView) findViewById(R.id.avatarBackground);
|
||||
}
|
||||
|
||||
public TextAvatarView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
public void setBackgroundBytes(byte[] bytes) {
|
||||
int r = getByte(bytes, 0) * 3 / 4 + 96;
|
||||
int g = getByte(bytes, 1) * 3 / 4 + 96;
|
||||
int b = getByte(bytes, 2) * 3 / 4 + 96;
|
||||
int color = Color.rgb(r, g, b);
|
||||
|
||||
backgroundView.setFillColor(color);
|
||||
}
|
||||
|
||||
private byte getByte(byte[] bytes, int index) {
|
||||
if (bytes == null) {
|
||||
return -128;
|
||||
} else {
|
||||
return bytes[index % bytes.length];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user