mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Show which contacts subscribe to each forum. Dev task #79.
This commit is contained in:
@@ -53,6 +53,14 @@
|
||||
</plurals>
|
||||
<string name="no_posts">No posts</string>
|
||||
<string name="subscribe_to_this_forum">Subscribe to this forum</string>
|
||||
<string name="no_subscribers">No contacts subscribe to this forum</string>
|
||||
<plurals name="subscribers">
|
||||
<item quantity="one">%d contact subscribes to this forum:</item>
|
||||
<item quantity="other">%d contacts subscribe to this forum:</item>
|
||||
</plurals>
|
||||
<string name="public_space_warning">Forums are public spaces. There may be other subscribers who are not your contacts.</string>
|
||||
<string name="subscribe_button">Subscribe</string>
|
||||
<string name="unsubscribe_button">Unsubscribe</string>
|
||||
<string name="create_forum_title">New Forum</string>
|
||||
<string name="choose_forum_name">Choose a name for your forum:</string>
|
||||
<string name="forum_visible_to_all">Share this forum with all contacts</string>
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
package org.briarproject.android.groups;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
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.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.util.CommonLayoutParams.MATCH_MATCH;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
|
||||
|
||||
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;
|
||||
@@ -25,22 +29,29 @@ import org.briarproject.api.Contact;
|
||||
import org.briarproject.api.ContactId;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.messaging.Group;
|
||||
import org.briarproject.api.messaging.GroupId;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class ConfigureGroupActivity extends BriarActivity
|
||||
implements OnClickListener, NoContactsDialog.Listener,
|
||||
implements OnClickListener, EventListener, NoContactsDialog.Listener,
|
||||
SelectContactsDialog.Listener {
|
||||
|
||||
private static final Logger LOG =
|
||||
@@ -51,6 +62,8 @@ SelectContactsDialog.Listener {
|
||||
private RadioGroup radioGroup = null;
|
||||
private RadioButton visibleToAll = null, visibleToSome = null;
|
||||
private Button doneButton = null;
|
||||
private TextView subscribers = null;
|
||||
private TextView subscriberNames = null;
|
||||
private ProgressBar progress = null;
|
||||
private boolean changed = false;
|
||||
|
||||
@@ -86,6 +99,32 @@ SelectContactsDialog.Listener {
|
||||
int pad = LayoutUtils.getPadding(this);
|
||||
layout.setPadding(pad, pad, pad, pad);
|
||||
|
||||
subscribers = new TextView(this);
|
||||
subscribers.setGravity(CENTER);
|
||||
subscribers.setTextSize(18);
|
||||
subscribers.setText("\u2026");
|
||||
layout.addView(subscribers);
|
||||
|
||||
subscriberNames = new TextView(this);
|
||||
subscriberNames.setGravity(CENTER);
|
||||
subscriberNames.setTextSize(18);
|
||||
subscriberNames.setVisibility(GONE);
|
||||
layout.addView(subscriberNames);
|
||||
|
||||
LinearLayout warning = new LinearLayout(this);
|
||||
warning.setOrientation(HORIZONTAL);
|
||||
warning.setPadding(pad, pad, pad, pad);
|
||||
|
||||
ImageView icon = new ImageView(this);
|
||||
icon.setImageResource(R.drawable.action_about);
|
||||
warning.addView(icon);
|
||||
|
||||
TextView publicSpace = new TextView(this);
|
||||
publicSpace.setPadding(pad, 0, 0, 0);
|
||||
publicSpace.setText(R.string.public_space_warning);
|
||||
warning.addView(publicSpace);
|
||||
layout.addView(warning);
|
||||
|
||||
subscribeCheckBox = new CheckBox(this);
|
||||
subscribeCheckBox.setId(1);
|
||||
subscribeCheckBox.setText(R.string.subscribe_to_this_forum);
|
||||
@@ -129,6 +168,65 @@ SelectContactsDialog.Listener {
|
||||
setContentView(layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
db.addListener(this);
|
||||
loadSubscribers();
|
||||
}
|
||||
|
||||
private void loadSubscribers() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
Collection<Contact> contacts = db.getSubscribers(groupId);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displaySubscribers(contacts);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displaySubscribers(final Collection<Contact> contacts) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(contacts.isEmpty()) {
|
||||
subscribers.setText(R.string.no_subscribers);
|
||||
subscriberNames.setVisibility(GONE);
|
||||
} else {
|
||||
int count = contacts.size();
|
||||
Resources res = getResources();
|
||||
String title = res.getQuantityString(R.plurals.subscribers,
|
||||
count, count);
|
||||
subscribers.setText(title);
|
||||
List<String> names = new ArrayList<String>();
|
||||
for(Contact c : contacts)
|
||||
names.add(c.getAuthor().getName());
|
||||
Collections.sort(names, String.CASE_INSENSITIVE_ORDER);
|
||||
StringBuilder s = new StringBuilder();
|
||||
for(int i = 0; i < count; i++) {
|
||||
s.append(names.get(i));
|
||||
if(i + 1 < count) s.append(", ");
|
||||
}
|
||||
subscriberNames.setText(s.toString());
|
||||
subscriberNames.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
db.removeListener(this);
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if(view == subscribeCheckBox) {
|
||||
changed = true;
|
||||
@@ -139,24 +237,24 @@ SelectContactsDialog.Listener {
|
||||
changed = true;
|
||||
} else if(view == visibleToSome) {
|
||||
changed = true;
|
||||
if(contacts == null) loadContacts();
|
||||
else displayContacts();
|
||||
if(contacts == null) loadVisibleContacts();
|
||||
else displayVisibleContacts();
|
||||
} else if(view == doneButton) {
|
||||
if(changed) {
|
||||
boolean subscribe = subscribeCheckBox.isChecked();
|
||||
boolean all = visibleToAll.isChecked();
|
||||
// Replace the button with a progress bar
|
||||
doneButton.setVisibility(GONE);
|
||||
progress.setVisibility(VISIBLE);
|
||||
// Update the blog in a background thread
|
||||
if(subscribe || subscribed) updateGroup(subscribe, all);
|
||||
// Update the group in a background thread
|
||||
boolean subscribe = subscribeCheckBox.isChecked();
|
||||
boolean all = visibleToAll.isChecked();
|
||||
updateGroup(subscribe, all);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadContacts() {
|
||||
private void loadVisibleContacts() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
@@ -166,7 +264,7 @@ SelectContactsDialog.Listener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayContacts();
|
||||
displayVisibleContacts();
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
@@ -175,7 +273,7 @@ SelectContactsDialog.Listener {
|
||||
});
|
||||
}
|
||||
|
||||
private void displayContacts() {
|
||||
private void displayVisibleContacts() {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(contacts.isEmpty()) {
|
||||
@@ -232,6 +330,16 @@ SelectContactsDialog.Listener {
|
||||
});
|
||||
}
|
||||
|
||||
public void eventOccurred(Event e) {
|
||||
if(e instanceof LocalSubscriptionsUpdatedEvent) {
|
||||
LOG.info("Local subscriptions updated, reloading");
|
||||
loadSubscribers();
|
||||
} else if(e instanceof RemoteSubscriptionsUpdatedEvent) {
|
||||
LOG.info("Remote subscriptions updated, reloading");
|
||||
loadSubscribers();
|
||||
}
|
||||
}
|
||||
|
||||
public void contactCreationSelected() {
|
||||
startActivity(new Intent(this, AddContactActivity.class));
|
||||
}
|
||||
|
||||
@@ -231,6 +231,9 @@ public interface DatabaseComponent {
|
||||
/** Returns all settings. */
|
||||
Settings getSettings() throws DbException;
|
||||
|
||||
/** Returns all contacts who subscribe to the given group. */
|
||||
Collection<Contact> getSubscribers(GroupId g) throws DbException;
|
||||
|
||||
/** Returns the maximum latencies of all local transports. */
|
||||
Map<TransportId, Long> getTransportLatencies() throws DbException;
|
||||
|
||||
|
||||
@@ -486,6 +486,13 @@ interface Database<T> {
|
||||
*/
|
||||
Settings getSettings(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts who subscribe to the given group.
|
||||
* <p>
|
||||
* Locking: subscription read.
|
||||
*/
|
||||
Collection<Contact> getSubscribers(T txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns a subscription ack for the given contact, or null if no ack is
|
||||
* due.
|
||||
|
||||
@@ -1154,6 +1154,23 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Contact> getSubscribers(GroupId g) throws DbException {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<Contact> contacts = db.getSubscribers(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
return contacts;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
subscriptionLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TransportId, Long> getTransportLatencies() throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
|
||||
@@ -2154,6 +2154,40 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Contact> getSubscribers(Connection txn, GroupId g)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT c.contactId, authorId, c.name, publicKey,"
|
||||
+ " localAuthorId"
|
||||
+ " FROM contacts AS c"
|
||||
+ " JOIN contactGroups AS cg"
|
||||
+ " ON c.contactId = cg.contactId"
|
||||
+ " WHERE groupId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, g.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
List<Contact> contacts = new ArrayList<Contact>();
|
||||
while(rs.next()) {
|
||||
ContactId contactId = new ContactId(rs.getInt(1));
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(2));
|
||||
String name = rs.getString(3);
|
||||
byte[] publicKey = rs.getBytes(4);
|
||||
Author author = new Author(authorId, name, publicKey);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
|
||||
contacts.add(new Contact(contactId, author, localAuthorId));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return Collections.unmodifiableList(contacts);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SubscriptionAck getSubscriptionAck(Connection txn, ContactId c)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
|
||||
Reference in New Issue
Block a user