mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Merge branch '121-new-available-forums-ui' into 'master'
Modernize AvailableForumsActivity Turn list of available forums into a `BriarRecyclerView` with XML layout. Allow to respond to forum invitations from the list of available forums. The user can either accept or decline an invitation.  See merge request !172
This commit is contained in:
6
briar-android/res/layout/activity_available_forums.xml
Normal file
6
briar-android/res/layout/activity_available_forums.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.briarproject.android.util.BriarRecyclerView
|
||||
android:id="@+id/availableForumsView"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
60
briar-android/res/layout/list_item_available_forum.xml
Normal file
60
briar-android/res/layout/list_item_available_forum.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/listitem_horizontal_margin"
|
||||
android:paddingTop="@dimen/listitem_horizontal_margin"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/forumNameView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
tools:text="This is a name of a forum that is available"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sharedByView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/forumNameView"
|
||||
android:layout_marginBottom="-8dp"
|
||||
android:paddingTop="@dimen/margin_medium"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textSize="@dimen/text_size_small"
|
||||
tools:text="Shared by Megalox"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/acceptButton"
|
||||
style="@style/BriarButtonFlat.Positive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_button_accept"
|
||||
android:layout_below="@+id/sharedByView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/declineButton"
|
||||
style="@style/BriarButtonFlat.Negative"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_button_decline"
|
||||
android:layout_below="@+id/sharedByView"
|
||||
android:layout_toLeftOf="@+id/acceptButton"
|
||||
android:layout_toStartOf="@+id/acceptButton"/>
|
||||
|
||||
<View style="@style/Divider.ForumList"
|
||||
android:layout_below="@+id/acceptButton"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
<string name="forum_post_hint">Type forum post</string>
|
||||
<string name="available_forums_title">Available Forums</string>
|
||||
<string name="forum_joined_toast">Joined Forum</string>
|
||||
<string name="forum_declined_toast">Forum Invitation Declined</string>
|
||||
<string name="shared_by_format">Shared by %s</string>
|
||||
<string name="no_contacts_prompt">You don\'t have any contacts. Add a contact now?</string>
|
||||
<string name="add_button">Add</string>
|
||||
|
||||
@@ -21,14 +21,14 @@ import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||
public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.BaseContactHolder>
|
||||
extends RecyclerView.Adapter<VH> {
|
||||
|
||||
protected SortedList<ContactListItem> contacts;
|
||||
protected final SortedList<ContactListItem> contacts;
|
||||
protected final OnItemClickListener listener;
|
||||
protected Context ctx;
|
||||
|
||||
public BaseContactListAdapter(Context context, OnItemClickListener listener) {
|
||||
this.ctx = context;
|
||||
this.listener = listener;
|
||||
this.contacts = new SortedList<ContactListItem>(ContactListItem.class,
|
||||
this.contacts = new SortedList<>(ContactListItem.class,
|
||||
new SortedListCallBacks());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,30 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListView;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.AndroidComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.util.ListLoadingProgressBar;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
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.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -36,16 +32,15 @@ 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.util.CommonLayoutParams.MATCH_MATCH;
|
||||
import static org.briarproject.android.forum.AvailableForumsAdapter.AvailableForumClickListener;
|
||||
|
||||
public class AvailableForumsActivity extends BriarActivity
|
||||
implements EventListener, OnItemClickListener {
|
||||
implements EventListener, AvailableForumClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AvailableForumsActivity.class.getName());
|
||||
|
||||
private AvailableForumsAdapter adapter = null;
|
||||
private ListView list = null;
|
||||
private AvailableForumsAdapter adapter;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject protected volatile ForumManager forumManager;
|
||||
@@ -56,15 +51,13 @@ implements EventListener, OnItemClickListener {
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
adapter = new AvailableForumsAdapter(this);
|
||||
list = new ListView(this);
|
||||
list.setLayoutParams(MATCH_MATCH);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
setContentView(R.layout.activity_available_forums);
|
||||
|
||||
// Show a progress bar while the list is loading
|
||||
ListLoadingProgressBar loading = new ListLoadingProgressBar(this);
|
||||
setContentView(loading);
|
||||
adapter = new AvailableForumsAdapter(this, this);
|
||||
BriarRecyclerView list =
|
||||
(BriarRecyclerView) findViewById(R.id.availableForumsView);
|
||||
list.setLayoutManager(new LinearLayoutManager(this));
|
||||
list.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,11 +106,12 @@ implements EventListener, OnItemClickListener {
|
||||
LOG.info("No forums available, finishing");
|
||||
finish();
|
||||
} else {
|
||||
setContentView(list);
|
||||
adapter.clear();
|
||||
List<AvailableForumsItem> list =
|
||||
new ArrayList<>(available.size());
|
||||
for (ForumContacts f : available)
|
||||
adapter.add(new AvailableForumsItem(f));
|
||||
adapter.sort(AvailableForumsItemComparator.INSTANCE);
|
||||
list.add(new AvailableForumsItem(f));
|
||||
adapter.addAll(list);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -145,37 +139,33 @@ implements EventListener, OnItemClickListener {
|
||||
LOG.info("Forum removed, reloading");
|
||||
loadForums();
|
||||
}
|
||||
} else if (e instanceof MessageValidatedEvent) {
|
||||
MessageValidatedEvent m = (MessageValidatedEvent) e;
|
||||
ClientId c = m.getClientId();
|
||||
if (m.isValid() && !m.isLocal()
|
||||
&& c.equals(forumSharingManager.getClientId())) {
|
||||
LOG.info("Available forums updated, reloading");
|
||||
loadForums();
|
||||
}
|
||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||
LOG.info("Available forums updated, reloading");
|
||||
loadForums();
|
||||
}
|
||||
}
|
||||
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
AvailableForumsItem item = adapter.getItem(position);
|
||||
Collection<ContactId> shared = new ArrayList<>();
|
||||
for (Contact c : item.getContacts()) shared.add(c.getId());
|
||||
subscribe(item.getForum(), shared);
|
||||
String joined = getString(R.string.forum_joined_toast);
|
||||
Toast.makeText(this, joined, LENGTH_SHORT).show();
|
||||
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 subscribe(final Forum f, final Collection<ContactId> shared) {
|
||||
private void respondToInvitation(final Forum f, final boolean accept) {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
forumManager.addForum(f);
|
||||
forumSharingManager.respondToInvitation(f, accept);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
loadForums();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,57 +1,160 @@
|
||||
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.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import static android.text.TextUtils.TruncateAt.END;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
class AvailableForumsAdapter extends
|
||||
RecyclerView.Adapter<AvailableForumsAdapter.AvailableForumViewHolder> {
|
||||
|
||||
class AvailableForumsAdapter extends ArrayAdapter<AvailableForumsItem> {
|
||||
private final Context ctx;
|
||||
private final AvailableForumClickListener listener;
|
||||
private final SortedList<AvailableForumsItem> forums =
|
||||
new SortedList<>(AvailableForumsItem.class,
|
||||
new SortedListCallBacks());
|
||||
|
||||
private final int pad;
|
||||
AvailableForumsAdapter(Context ctx,
|
||||
AvailableForumClickListener listener) {
|
||||
|
||||
AvailableForumsAdapter(Context ctx) {
|
||||
super(ctx, android.R.layout.simple_expandable_list_item_1,
|
||||
new ArrayList<AvailableForumsItem>());
|
||||
pad = LayoutUtils.getPadding(ctx);
|
||||
this.ctx = ctx;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
AvailableForumsItem item = getItem(position);
|
||||
Context ctx = getContext();
|
||||
public AvailableForumViewHolder onCreateViewHolder(ViewGroup parent,
|
||||
int viewType) {
|
||||
|
||||
LinearLayout layout = new LinearLayout(ctx);
|
||||
layout.setOrientation(VERTICAL);
|
||||
|
||||
TextView name = new TextView(ctx);
|
||||
name.setTextSize(18);
|
||||
name.setSingleLine();
|
||||
name.setEllipsize(END);
|
||||
name.setPadding(pad, pad, pad, pad);
|
||||
name.setText(item.getForum().getName());
|
||||
layout.addView(name);
|
||||
|
||||
TextView status = new TextView(ctx);
|
||||
status.setPadding(pad, 0, pad, pad);
|
||||
Collection<String> names = new ArrayList<String>();
|
||||
for (Contact c : item.getContacts()) names.add(c.getAuthor().getName());
|
||||
String format = ctx.getString(R.string.shared_by_format);
|
||||
status.setText(String.format(format, StringUtils.join(names, ", ")));
|
||||
layout.addView(status);
|
||||
|
||||
return layout;
|
||||
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.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 {
|
||||
|
||||
public final ViewGroup layout;
|
||||
public final TextView name;
|
||||
public final TextView sharedBy;
|
||||
public final Button accept;
|
||||
public final Button decline;
|
||||
|
||||
public AvailableForumViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
layout = (ViewGroup) v;
|
||||
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,16 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
class AvailableForumsItemComparator implements Comparator<AvailableForumsItem> {
|
||||
|
||||
static final AvailableForumsItemComparator INSTANCE =
|
||||
new AvailableForumsItemComparator();
|
||||
|
||||
public int compare(AvailableForumsItem a, AvailableForumsItem b) {
|
||||
if (a == b) return 0;
|
||||
String aName = a.getForum().getName();
|
||||
String bName = b.getForum().getName();
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user