mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Private Group List
This commit is contained in:
@@ -28,6 +28,7 @@ import org.briarproject.android.keyagreement.KeyAgreementActivity;
|
||||
import org.briarproject.android.keyagreement.ShowQrCodeFragment;
|
||||
import org.briarproject.android.panic.PanicPreferencesActivity;
|
||||
import org.briarproject.android.panic.PanicResponderActivity;
|
||||
import org.briarproject.android.privategroup.list.GroupListFragment;
|
||||
import org.briarproject.android.sharing.ContactSelectorFragment;
|
||||
import org.briarproject.android.sharing.InvitationsBlogActivity;
|
||||
import org.briarproject.android.sharing.InvitationsForumActivity;
|
||||
@@ -114,6 +115,7 @@ public interface ActivityComponent {
|
||||
|
||||
// Fragments
|
||||
void inject(ContactListFragment fragment);
|
||||
void inject(GroupListFragment fragment);
|
||||
void inject(ForumListFragment fragment);
|
||||
void inject(FeedFragment fragment);
|
||||
void inject(IntroFragment fragment);
|
||||
|
||||
@@ -22,6 +22,8 @@ import org.briarproject.android.controller.SetupController;
|
||||
import org.briarproject.android.controller.SetupControllerImpl;
|
||||
import org.briarproject.android.forum.ForumController;
|
||||
import org.briarproject.android.forum.ForumControllerImpl;
|
||||
import org.briarproject.android.privategroup.list.GroupListController;
|
||||
import org.briarproject.android.privategroup.list.GroupListControllerImpl;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
@@ -90,6 +92,13 @@ public class ActivityModule {
|
||||
return dbController;
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Provides
|
||||
protected GroupListController provideGroupListController(
|
||||
GroupListControllerImpl groupListController) {
|
||||
return groupListController;
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Provides
|
||||
protected ForumController provideForumController(
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.briarproject.api.messaging.MessagingManager;
|
||||
import org.briarproject.api.messaging.PrivateMessageFactory;
|
||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.api.settings.SettingsManager;
|
||||
import org.briarproject.plugins.AndroidPluginsModule;
|
||||
import org.briarproject.system.AndroidSystemModule;
|
||||
@@ -93,6 +94,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
|
||||
|
||||
PrivateMessageFactory privateMessageFactory();
|
||||
|
||||
PrivateGroupManager privateGroupManager();
|
||||
|
||||
ForumManager forumManager();
|
||||
|
||||
ForumSharingManager forumSharingManager();
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.briarproject.android.blogs.FeedFragment;
|
||||
import org.briarproject.android.contact.ContactListFragment;
|
||||
import org.briarproject.android.forum.ForumListFragment;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.privategroup.list.GroupListFragment;
|
||||
|
||||
import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
||||
|
||||
@@ -26,6 +27,8 @@ public abstract class BriarFragmentActivity extends BriarActivity {
|
||||
|
||||
if (fragmentTag.equals(ContactListFragment.TAG)) {
|
||||
actionBar.setTitle(R.string.contact_list_button);
|
||||
} else if (fragmentTag.equals(GroupListFragment.TAG)) {
|
||||
actionBar.setTitle(R.string.groups_button);
|
||||
} else if (fragmentTag.equals(ForumListFragment.TAG)) {
|
||||
actionBar.setTitle(R.string.forums_button);
|
||||
} else if (fragmentTag.equals(FeedFragment.TAG)) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.briarproject.android.controller.TransportStateListener;
|
||||
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||
import org.briarproject.android.forum.ForumListFragment;
|
||||
import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
|
||||
import org.briarproject.android.privategroup.list.GroupListFragment;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
|
||||
@@ -180,6 +181,9 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
||||
case R.id.nav_btn_contacts:
|
||||
startFragment(ContactListFragment.newInstance());
|
||||
break;
|
||||
case R.id.nav_btn_groups:
|
||||
startFragment(GroupListFragment.newInstance());
|
||||
break;
|
||||
case R.id.nav_btn_forums:
|
||||
startFragment(ForumListFragment.newInstance());
|
||||
break;
|
||||
|
||||
@@ -109,7 +109,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View contentView =
|
||||
inflater.inflate(R.layout.fragment_contact_list, container,
|
||||
inflater.inflate(R.layout.list, container,
|
||||
false);
|
||||
|
||||
BaseContactListAdapter.OnItemClickListener onItemClickListener =
|
||||
@@ -141,7 +141,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
||||
};
|
||||
|
||||
adapter = new ContactListAdapter(getContext(), onItemClickListener);
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.contactList);
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.list);
|
||||
list.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_contacts));
|
||||
|
||||
@@ -77,10 +77,7 @@ public class ContactChooserFragment extends BaseFragment {
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View contentView =
|
||||
inflater.inflate(R.layout.introduction_contact_chooser,
|
||||
container, false);
|
||||
|
||||
View contentView = inflater.inflate(R.layout.list, container, false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
setExitTransition(new Fade());
|
||||
@@ -105,7 +102,7 @@ public class ContactChooserFragment extends BaseFragment {
|
||||
};
|
||||
adapter = new ContactChooserAdapter(getActivity(), onItemClickListener);
|
||||
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.contactList);
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.list);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_contacts));
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.briarproject.android.privategroup.list;
|
||||
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||
import org.briarproject.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// This class is not thread-safe
|
||||
class GroupItem {
|
||||
|
||||
private final PrivateGroup privateGroup;
|
||||
private int messageCount;
|
||||
private long lastUpdate;
|
||||
private int unreadCount;
|
||||
private boolean dissolved;
|
||||
|
||||
GroupItem(@NotNull PrivateGroup privateGroup, int messageCount,
|
||||
long lastUpdate, int unreadCount, boolean dissolved) {
|
||||
|
||||
this.privateGroup = privateGroup;
|
||||
this.messageCount = messageCount;
|
||||
this.lastUpdate = lastUpdate;
|
||||
this.unreadCount = unreadCount;
|
||||
this.dissolved = dissolved;
|
||||
}
|
||||
|
||||
void addMessageHeader(GroupMessageHeader header) {
|
||||
messageCount++;
|
||||
if (header.getTimestamp() > lastUpdate) {
|
||||
lastUpdate = header.getTimestamp();
|
||||
}
|
||||
if (!header.isRead()) {
|
||||
unreadCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
PrivateGroup getPrivateGroup() {
|
||||
return privateGroup;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
GroupId getId() {
|
||||
return privateGroup.getId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Author getCreator() {
|
||||
return privateGroup.getAuthor();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
String getName() {
|
||||
return privateGroup.getName();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return messageCount == 0;
|
||||
}
|
||||
|
||||
int getMessageCount() {
|
||||
return messageCount;
|
||||
}
|
||||
|
||||
long getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
|
||||
int getUnreadCount() {
|
||||
return unreadCount;
|
||||
}
|
||||
|
||||
boolean isDissolved() {
|
||||
return dissolved;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.briarproject.android.privategroup.list;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener;
|
||||
import org.briarproject.android.util.BriarAdapter;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||
|
||||
class GroupListAdapter extends BriarAdapter<GroupItem, GroupViewHolder> {
|
||||
|
||||
private final OnGroupRemoveClickListener listener;
|
||||
|
||||
GroupListAdapter(Context ctx, OnGroupRemoveClickListener listener) {
|
||||
super(ctx, GroupItem.class);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(ctx).inflate(
|
||||
R.layout.list_item_group, parent, false);
|
||||
return new GroupViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(GroupViewHolder ui, int position) {
|
||||
ui.bindView(ctx, getItemAt(position), listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(GroupItem a, GroupItem b) {
|
||||
if (a == b) return 0;
|
||||
// The group with the latest message comes first
|
||||
long aTime = a.getLastUpdate(), bTime = b.getLastUpdate();
|
||||
if (aTime > bTime) return -1;
|
||||
if (aTime < bTime) return 1;
|
||||
// Break ties by group name
|
||||
String aName = a.getName();
|
||||
String bName = b.getName();
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(GroupItem a, GroupItem b) {
|
||||
return a.getMessageCount() == b.getMessageCount() &&
|
||||
a.getLastUpdate() == b.getLastUpdate() &&
|
||||
a.getUnreadCount() == b.getUnreadCount() &&
|
||||
a.isDissolved() == b.isDissolved();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(GroupItem a, GroupItem b) {
|
||||
return a.getId().equals(b.getId());
|
||||
}
|
||||
|
||||
int findItemPosition(@NotNull GroupId g) {
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
GroupItem item = items.get(i);
|
||||
if (item.getId().equals(g)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return INVALID_POSITION;
|
||||
}
|
||||
|
||||
void removeItem(GroupId groupId) {
|
||||
int pos = findItemPosition(groupId);
|
||||
if (pos != INVALID_POSITION) items.removeItemAt(pos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.briarproject.android.privategroup.list;
|
||||
|
||||
import android.support.annotation.UiThread;
|
||||
|
||||
import org.briarproject.android.DestroyableContext;
|
||||
import org.briarproject.android.controller.DbController;
|
||||
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface GroupListController extends DbController {
|
||||
|
||||
/**
|
||||
* The listener must be set right after the controller was injected
|
||||
*/
|
||||
void setGroupListListener(GroupListListener listener);
|
||||
|
||||
@UiThread
|
||||
void onStart();
|
||||
|
||||
@UiThread
|
||||
void onStop();
|
||||
|
||||
void loadGroups(
|
||||
ResultExceptionHandler<Collection<GroupItem>, DbException> result);
|
||||
|
||||
void removeGroup(GroupId g,
|
||||
ResultExceptionHandler<Void, DbException> result);
|
||||
|
||||
interface GroupListListener extends DestroyableContext {
|
||||
@UiThread
|
||||
void onGroupMessageAdded(GroupMessageHeader header);
|
||||
|
||||
@UiThread
|
||||
void onGroupAdded(GroupId groupId);
|
||||
|
||||
@UiThread
|
||||
void onGroupRemoved(GroupId groupId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package org.briarproject.android.privategroup.list;
|
||||
|
||||
import android.support.annotation.CallSuper;
|
||||
|
||||
import org.briarproject.android.api.AndroidNotificationManager;
|
||||
import org.briarproject.android.controller.DbControllerImpl;
|
||||
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
||||
import org.briarproject.api.clients.MessageTracker.GroupCount;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.GroupAddedEvent;
|
||||
import org.briarproject.api.event.GroupMessageAddedEvent;
|
||||
import org.briarproject.api.event.GroupRemovedEvent;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
public class GroupListControllerImpl extends DbControllerImpl
|
||||
implements GroupListController, EventListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(GroupListControllerImpl.class.getName());
|
||||
|
||||
@Inject
|
||||
PrivateGroupManager groupManager;
|
||||
@Inject
|
||||
EventBus eventBus;
|
||||
@Inject
|
||||
AndroidNotificationManager notificationManager;
|
||||
@Inject
|
||||
IdentityManager identityManager;
|
||||
|
||||
protected volatile GroupListListener listener;
|
||||
|
||||
@Inject
|
||||
GroupListControllerImpl() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupListListener(GroupListListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public void onStart() {
|
||||
if (listener == null)
|
||||
throw new IllegalStateException(
|
||||
"GroupListListener needs to be attached");
|
||||
eventBus.addListener(this);
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public void onStop() {
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CallSuper
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof GroupMessageAddedEvent) {
|
||||
final GroupMessageAddedEvent m = (GroupMessageAddedEvent) e;
|
||||
LOG.info("New group message added");
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onGroupMessageAdded(m.getHeader());
|
||||
}
|
||||
});
|
||||
} else if (e instanceof GroupAddedEvent) {
|
||||
final GroupAddedEvent gae = (GroupAddedEvent) e;
|
||||
ClientId id = gae.getGroup().getClientId();
|
||||
if (id.equals(groupManager.getClientId())) {
|
||||
LOG.info("Private group added");
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onGroupAdded(gae.getGroup().getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
final GroupRemovedEvent gre = (GroupRemovedEvent) e;
|
||||
ClientId id = gre.getGroup().getClientId();
|
||||
if (id.equals(groupManager.getClientId())) {
|
||||
LOG.info("Private group removed");
|
||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onGroupRemoved(gre.getGroup().getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadGroups(
|
||||
final ResultExceptionHandler<Collection<GroupItem>, DbException> handler) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Loading groups from database...");
|
||||
try {
|
||||
Collection<PrivateGroup> groups =
|
||||
groupManager.getPrivateGroups();
|
||||
List<GroupItem> items = new ArrayList<>(groups.size());
|
||||
for (PrivateGroup g : groups) {
|
||||
GroupCount c = groupManager.getGroupCount(g.getId());
|
||||
boolean dissolved = groupManager.isDissolved(g.getId());
|
||||
items.add(new GroupItem(g, c.getMsgCount(),
|
||||
c.getLatestMsgTime(), c.getUnreadCount(),
|
||||
dissolved));
|
||||
}
|
||||
handler.onResult(items);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
handler.onException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(final GroupId g,
|
||||
final ResultExceptionHandler<Void, DbException> handler) {
|
||||
runOnDbThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Removing group from database...");
|
||||
try {
|
||||
groupManager.removePrivateGroup(g);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
handler.onException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package org.briarproject.android.privategroup.list;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
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.controller.handler.UiResultExceptionHandler;
|
||||
import org.briarproject.android.fragment.BaseFragment;
|
||||
import org.briarproject.android.invitation.AddContactActivity;
|
||||
import org.briarproject.android.privategroup.list.GroupListController.GroupListListener;
|
||||
import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener;
|
||||
import org.briarproject.android.view.BriarRecyclerView;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class GroupListFragment extends BaseFragment implements
|
||||
GroupListListener, OnGroupRemoveClickListener {
|
||||
|
||||
public final static String TAG = GroupListFragment.class.getName();
|
||||
|
||||
public static GroupListFragment newInstance() {
|
||||
return new GroupListFragment();
|
||||
}
|
||||
|
||||
@Inject
|
||||
GroupListController controller;
|
||||
|
||||
private BriarRecyclerView list;
|
||||
private GroupListAdapter adapter;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View v = inflater.inflate(R.layout.list, container, false);
|
||||
|
||||
adapter = new GroupListAdapter(getContext(), this);
|
||||
list = (BriarRecyclerView) v.findViewById(R.id.list);
|
||||
list.setEmptyText(R.string.groups_list_empty);
|
||||
list.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
list.setAdapter(adapter);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
controller.setGroupListListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
controller.onStart();
|
||||
list.startPeriodicUpdate();
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
controller.onStop();
|
||||
list.stopPeriodicUpdate();
|
||||
adapter.clear();
|
||||
list.showProgressBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.groups_list_actions, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_add_group:
|
||||
// TODO
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void onGroupRemoveClick(GroupItem item) {
|
||||
controller.removeGroup(item.getId(),
|
||||
new UiResultExceptionHandler<Void, DbException>(listener) {
|
||||
@Override
|
||||
public void onResultUi(Void result) {
|
||||
// handled by GroupRemovedEvent and onGroupRemoved()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExceptionUi(DbException exception) {
|
||||
// TODO handle error
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void onGroupMessageAdded(GroupMessageHeader header) {
|
||||
int position = adapter.findItemPosition(header.getGroupId());
|
||||
GroupItem item = adapter.getItemAt(position);
|
||||
if (item != null) {
|
||||
item.addMessageHeader(header);
|
||||
adapter.updateItemAt(position, item);
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void onGroupAdded(GroupId groupId) {
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void onGroupRemoved(GroupId groupId) {
|
||||
adapter.removeItem(groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
private void loadGroups() {
|
||||
controller.loadGroups(
|
||||
new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
|
||||
listener) {
|
||||
@Override
|
||||
public void onResultUi(Collection<GroupItem> result) {
|
||||
if (result.isEmpty()) {
|
||||
list.showData();
|
||||
} else {
|
||||
adapter.addAll(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExceptionUi(DbException exception) {
|
||||
// TODO handle this error
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.briarproject.android.privategroup.list;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.util.AndroidUtils;
|
||||
import org.briarproject.android.view.TextAvatarView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static android.support.v4.content.ContextCompat.getColor;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
class GroupViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final static float ALPHA = 0.42f;
|
||||
|
||||
private final ViewGroup layout;
|
||||
private final TextAvatarView avatar;
|
||||
private final TextView name;
|
||||
private final TextView creator;
|
||||
private final TextView postCount;
|
||||
private final TextView date;
|
||||
private final TextView status;
|
||||
private final Button remove;
|
||||
|
||||
GroupViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
layout = (ViewGroup) v;
|
||||
avatar = (TextAvatarView) v.findViewById(R.id.avatarView);
|
||||
name = (TextView) v.findViewById(R.id.nameView);
|
||||
creator = (TextView) v.findViewById(R.id.creatorView);
|
||||
postCount = (TextView) v.findViewById(R.id.messageCountView);
|
||||
date = (TextView) v.findViewById(R.id.dateView);
|
||||
status = (TextView) v.findViewById(R.id.statusView);
|
||||
remove = (Button) v.findViewById(R.id.removeButton);
|
||||
}
|
||||
|
||||
void bindView(Context ctx, @Nullable final GroupItem group,
|
||||
@NotNull final OnGroupRemoveClickListener listener) {
|
||||
if (group == null) return;
|
||||
|
||||
// Avatar
|
||||
avatar.setText(group.getName().substring(0, 1));
|
||||
avatar.setBackgroundBytes(group.getId().getBytes());
|
||||
avatar.setUnreadCount(group.getUnreadCount());
|
||||
|
||||
// Group Name
|
||||
name.setText(group.getName());
|
||||
|
||||
// Creator
|
||||
creator.setText(ctx.getString(R.string.groups_created_by,
|
||||
group.getCreator().getName()));
|
||||
|
||||
if (!group.isDissolved()) {
|
||||
// full visibility
|
||||
avatar.setAlpha(1);
|
||||
name.setAlpha(1);
|
||||
creator.setAlpha(1);
|
||||
|
||||
// Date and Status
|
||||
if (group.isEmpty()) {
|
||||
postCount.setVisibility(GONE);
|
||||
date.setVisibility(GONE);
|
||||
avatar.setProblem(true);
|
||||
status
|
||||
.setText(ctx.getString(R.string.groups_group_is_empty));
|
||||
status.setVisibility(VISIBLE);
|
||||
} else {
|
||||
// Message Count
|
||||
int messageCount = group.getMessageCount();
|
||||
postCount.setVisibility(VISIBLE);
|
||||
postCount.setText(ctx.getResources()
|
||||
.getQuantityString(R.plurals.messages, messageCount,
|
||||
messageCount));
|
||||
postCount.setTextColor(
|
||||
getColor(ctx, R.color.briar_text_secondary));
|
||||
|
||||
long lastUpdate = group.getLastUpdate();
|
||||
date.setText(AndroidUtils.formatDate(ctx, lastUpdate));
|
||||
date.setVisibility(VISIBLE);
|
||||
avatar.setProblem(false);
|
||||
status.setVisibility(GONE);
|
||||
}
|
||||
remove.setVisibility(GONE);
|
||||
} else {
|
||||
// grey out
|
||||
avatar.setAlpha(ALPHA);
|
||||
name.setAlpha(ALPHA);
|
||||
creator.setAlpha(ALPHA);
|
||||
|
||||
postCount.setVisibility(GONE);
|
||||
date.setVisibility(GONE);
|
||||
status
|
||||
.setText(ctx.getString(R.string.groups_group_is_dissolved));
|
||||
status.setVisibility(VISIBLE);
|
||||
remove.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listener.onGroupRemoveClick(group);
|
||||
}
|
||||
});
|
||||
remove.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
// Open Group on Click
|
||||
layout.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
/*
|
||||
Intent i = new Intent(ctx, GroupActivity.class);
|
||||
GroupId id = item.getId();
|
||||
i.putExtra(GROUP_ID, id.getBytes());
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat
|
||||
.makeCustomAnimation(ctx, android.R.anim.fade_in,
|
||||
android.R.anim.fade_out);
|
||||
ActivityCompat.startActivity(ctx, i, options.toBundle());
|
||||
*/
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
interface OnGroupRemoveClickListener {
|
||||
void onGroupRemoveClick(GroupItem item);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,8 +99,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View contentView = inflater.inflate(
|
||||
R.layout.introduction_contact_chooser, container, false);
|
||||
View contentView = inflater.inflate(R.layout.list, container, false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
setExitTransition(new Fade());
|
||||
@@ -108,7 +107,7 @@ public class ContactSelectorFragment extends BaseFragment implements
|
||||
|
||||
adapter = new ContactSelectorAdapter(getActivity(), this);
|
||||
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.contactList);
|
||||
list = (BriarRecyclerView) contentView.findViewById(R.id.list);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_contacts_selector));
|
||||
|
||||
@@ -38,12 +38,12 @@ abstract class InvitationsActivity extends BriarActivity
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
setContentView(R.layout.activity_invitations);
|
||||
setContentView(R.layout.list);
|
||||
|
||||
adapter = getAdapter(this, this);
|
||||
|
||||
|
||||
list = (BriarRecyclerView) findViewById(R.id.invitationsView);
|
||||
list = (BriarRecyclerView) findViewById(R.id.list);
|
||||
if (list != null) {
|
||||
list.setLayoutManager(new LinearLayoutManager(this));
|
||||
list.setAdapter(adapter);
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.android.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
@@ -78,7 +79,7 @@ public class TextAvatarView extends FrameLayout {
|
||||
int b = getByte(bytes, 2) * 3 / 4 + 96;
|
||||
int color = Color.rgb(r, g, b);
|
||||
|
||||
background.setFillColor(color);
|
||||
background.setImageDrawable(new ColorDrawable(color));
|
||||
}
|
||||
|
||||
private byte getByte(byte[] bytes, int index) {
|
||||
|
||||
Reference in New Issue
Block a user