Hooked up star/unstar and read/unread buttons. Tinkered with layouts.

This commit is contained in:
akwizgran
2013-03-05 14:28:09 +00:00
parent 792d8cb071
commit 86925ef402
14 changed files with 237 additions and 159 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LightTheme" parent="android:Theme.Holo.Light" />
<style name="LightThemeNoActionBar"
parent="android:Theme.Holo.Light.NoActionBar" />
</resources>

View File

@@ -12,7 +12,6 @@
<string name="contact_list_title">Contacts</string>
<string name="contact_connected">Connected</string>
<string name="contact_last_connected">Last connected &lt;br /&gt; %1$s</string>
<string name="add_contact_button">New Contact</string>
<string name="search_button">Search</string>
<string name="add_contact_title">Add a Contact</string>
<string name="same_network">Briar can add contacts via Wi-Fi or Bluetooth. For security reasons, you must be face-to-face to add someone as a contact. To use Wi-Fi you must both be connected to the same network.</string>
@@ -42,6 +41,7 @@
<string name="enter_nickname">Please enter a nickname for this contact:</string>
<string name="done_button">Done</string>
<string name="messages_title">Messages</string>
<string name="compose_button">New Message</string>
<string name="message_from">From: %1$s</string>
<string name="compose_title">New Message</string>
<string name="message_to">To: %1$s</string>
</resources>

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LightTheme" parent="android:Theme.Light" />
<style name="LightThemeNoActionBar" parent="android:Theme.Light" />
</resources>

View File

@@ -31,7 +31,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
@@ -69,13 +69,10 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
list.setOnItemClickListener(adapter);
layout.addView(list);
Button addContactButton = new Button(this);
ImageButton addContactButton = new ImageButton(this);
addContactButton.setPadding(5, 5, 5, 5);
addContactButton.setBackgroundResource(0);
addContactButton.setLayoutParams(new LayoutParams(MATCH_PARENT,
WRAP_CONTENT));
addContactButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.social_add_person, 0, 0);
addContactButton.setText(R.string.add_contact_button);
addContactButton.setImageResource(R.drawable.social_add_person);
addContactButton.setOnClickListener(this);
layout.addView(addContactButton);

View File

@@ -7,7 +7,10 @@ import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -30,7 +33,7 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
@@ -49,22 +52,21 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
@Inject private DatabaseComponent db;
@Inject @DatabaseExecutor private Executor dbExecutor;
private ContactId contactId = null;
private String contactName = null;
private ConversationAdapter adapter = null;
private ListView list = null;
private String contactName = null;
private volatile ContactId contactId = null;
@Override
public void onCreate(Bundle state) {
super.onCreate(null);
Intent i = getIntent();
contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
int id = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
if(id == -1) throw new IllegalStateException();
contactId = new ContactId(id);
contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
@@ -79,13 +81,10 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
list.setOnItemClickListener(this);
layout.addView(list);
Button composeButton = new Button(this);
ImageButton composeButton = new ImageButton(this);
composeButton.setPadding(5, 5, 5, 5);
composeButton.setBackgroundResource(0);
composeButton.setLayoutParams(new LayoutParams(MATCH_PARENT,
WRAP_CONTENT));
composeButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.content_new_email, 0, 0);
composeButton.setText(R.string.compose_button);
composeButton.setImageResource(R.drawable.content_new_email);
composeButton.setOnClickListener(this);
layout.addView(composeButton);
@@ -122,6 +121,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
}
private void reloadMessageHeaders() {
final ContactId contactId = this.contactId;
dbExecutor.execute(new Runnable() {
public void run() {
try {
@@ -146,18 +146,19 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
});
}
private void updateConversation(
final Collection<PrivateMessageHeader> headers) {
private void updateConversation(Collection<PrivateMessageHeader> headers) {
final List<PrivateMessageHeader> sort =
new ArrayList<PrivateMessageHeader>(headers);
Collections.sort(sort, AscendingHeaderComparator.INSTANCE);
runOnUiThread(new Runnable() {
public void run() {
int firstUnread = -1;
adapter.clear();
for(PrivateMessageHeader h : headers) {
for(PrivateMessageHeader h : sort) {
if(firstUnread == -1 && !h.isRead())
firstUnread = adapter.getCount();
adapter.add(h);
}
adapter.sort(AscendingHeaderComparator.INSTANCE);
if(firstUnread == -1) list.setSelection(adapter.getCount() - 1);
else list.setSelection(firstUnread);
}

View File

@@ -37,7 +37,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
@@ -75,13 +75,10 @@ implements OnClickListener, DatabaseListener {
list.setOnItemClickListener(adapter);
layout.addView(list);
Button composeButton = new Button(this);
ImageButton composeButton = new ImageButton(this);
composeButton.setPadding(5, 5, 5, 5);
composeButton.setBackgroundResource(0);
composeButton.setLayoutParams(new LayoutParams(MATCH_PARENT,
WRAP_CONTENT));
composeButton.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.content_new_email, 0, 0);
composeButton.setText(R.string.compose_button);
composeButton.setImageResource(R.drawable.content_new_email);
composeButton.setOnClickListener(this);
layout.addView(composeButton);
@@ -110,7 +107,14 @@ implements OnClickListener, DatabaseListener {
ContactId contactId = db.addContact("Carol");
// Insert some text messages to and from the contact
for(int i = 0; i < 20; i++) {
String body = "Message " + i + " is short";
String body;
if(i % 3 == 0) {
body = "Message " + i + " is short.";
} else {
body = "Message " + i + " is long enough to"
+ " wrap onto a second line on some"
+ " screens.";
}
Message m = messageFactory.createPrivateMessage(
null, "text/plain", body.getBytes("UTF-8"));
if(Math.random() < 0.5)

View File

@@ -1,7 +1,7 @@
package net.sf.briar.android.messages;
import static android.view.Gravity.CENTER;
import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.RIGHT;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.widget.LinearLayout.HORIZONTAL;
@@ -19,6 +19,7 @@ import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.android.BundleEncrypter;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DatabaseExecutor;
import net.sf.briar.api.db.DbException;
@@ -45,14 +46,16 @@ implements OnClickListener {
private final BriarServiceConnection serviceConnection =
new BriarServiceConnection();
@Inject private BundleEncrypter bundleEncrypter;
@Inject private DatabaseComponent db;
@Inject @DatabaseExecutor private Executor dbExecutor;
private ContactId contactId = null;
private String contactName = null;
private MessageId messageId = null;
private boolean starred = false;
private ImageButton starButton = null, replyButton = null;
private boolean starred, read;
private ImageButton replyButton = null, starButton = null;
private ImageButton readButton = null;
private TextView content = null;
@Override
@@ -65,7 +68,6 @@ implements OnClickListener {
contactId = new ContactId(cid);
contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
byte[] mid = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(mid == null) throw new IllegalStateException();
messageId = new MessageId(mid);
@@ -73,52 +75,108 @@ implements OnClickListener {
if(contentType == null) throw new IllegalStateException();
long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
if(timestamp == -1) throw new IllegalStateException();
starred = i.getBooleanExtra("net.sf.briar.STARRED", false);
if(state != null && bundleEncrypter.decrypt(state)) {
starred = state.getBoolean("net.sf.briar.STARRED");
read = state.getBoolean("net.sf.briar.READ");
} else {
starred = i.getBooleanExtra("net.sf.briar.STARRED", false);
read = false;
final MessageId id = messageId;
dbExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
db.setReadFlag(id, true);
runOnUiThread(new Runnable() {
public void run() {
setRead(true);
}
});
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
}
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
layout.setOrientation(VERTICAL);
ScrollView scrollView = new ScrollView(this);
// Give me all the width and all the unused height
scrollView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT,
1));
LinearLayout message = new LinearLayout(this);
message.setOrientation(VERTICAL);
LinearLayout header = new LinearLayout(this);
header.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
TextView name = new TextView(this);
// Give me all the unused width
name.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1));
name.setTextSize(18);
name.setPadding(10, 0, 0, 0);
String format = getResources().getString(R.string.message_from);
name.setText(String.format(format, contactName));
header.addView(name);
TextView date = new TextView(this);
date.setTextSize(14);
date.setPadding(0, 0, 10, 0);
long now = System.currentTimeMillis();
date.setText(DateUtils.formatSameDayTime(timestamp, now, SHORT, SHORT));
header.addView(date);
message.addView(header);
if(contentType.equals("text/plain")) {
// Load and display the message body
content = new TextView(this);
content.setPadding(10, 10, 10, 10);
message.addView(content);
loadMessageBody();
}
scrollView.addView(message);
layout.addView(scrollView);
LinearLayout footer = new LinearLayout(this);
footer.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
footer.setOrientation(HORIZONTAL);
footer.setGravity(CENTER);
replyButton = new ImageButton(this);
replyButton.setPadding(5, 5, 5, 5);
replyButton.setBackgroundResource(0);
replyButton.setImageResource(R.drawable.social_reply);
replyButton.setOnClickListener(this);
footer.addView(replyButton);
layout.addView(footer);
starButton = new ImageButton(this);
starButton.setPadding(5, 5, 5, 5);
starButton.setBackgroundResource(0);
if(starred) starButton.setImageResource(R.drawable.rating_important);
else starButton.setImageResource(R.drawable.rating_not_important);
starButton.setOnClickListener(this);
header.addView(starButton);
footer.addView(starButton);
replyButton = new ImageButton(this);
replyButton.setPadding(5, 5, 5, 5);
replyButton.setBackgroundResource(0);
replyButton.setImageResource(R.drawable.social_reply);
replyButton.setOnClickListener(this);
header.addView(replyButton);
TextView date = new TextView(this);
// Give me all the unused width
date.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1));
date.setTextSize(14);
date.setPadding(10, 0, 10, 0);
date.setGravity(RIGHT);
long now = System.currentTimeMillis();
date.setText(DateUtils.formatSameDayTime(timestamp, now, SHORT, SHORT));
header.addView(date);
layout.addView(header);
if(contentType.equals("text/plain")) {
// Load and display the message body
ScrollView scrollView = new ScrollView(this);
content = new TextView(this);
content.setPadding(10, 10, 10, 10);
scrollView.addView(content);
layout.addView(scrollView);
loadMessageBody();
}
readButton = new ImageButton(this);
readButton.setPadding(5, 5, 5, 5);
readButton.setBackgroundResource(0);
if(read) readButton.setImageResource(R.drawable.content_unread);
else readButton.setImageResource(R.drawable.content_read);
readButton.setOnClickListener(this);
footer.addView(readButton);
setContentView(layout);
@@ -133,12 +191,9 @@ implements OnClickListener {
dbExecutor.execute(new Runnable() {
public void run() {
try {
// Wait for the service to be bound and started
serviceConnection.waitForStartup();
// Load the message body from the database
byte[] body = db.getMessageBody(messageId);
final String text = new String(body, "UTF-8");
// Display the message body
runOnUiThread(new Runnable() {
public void run() {
content.setText(text);
@@ -159,26 +214,10 @@ implements OnClickListener {
}
@Override
public void onResume() {
super.onResume();
final MessageId id = messageId;
dbExecutor.execute(new Runnable() {
public void run() {
try {
// Wait for the service to be bound and started
serviceConnection.waitForStartup();
// Mark the message as read
db.setReadFlag(id, true);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
public void onSaveInstanceState(Bundle state) {
state.putBoolean("net.sf.briar.STARRED", starred);
state.putBoolean("net.sf.briar.READ", read);
bundleEncrypter.encrypt(state);
}
@Override
@@ -188,29 +227,71 @@ implements OnClickListener {
}
public void onClick(View view) {
if(view == starButton) {
final MessageId id = messageId;
final boolean starredNow = !starred;
dbExecutor.execute(new Runnable() {
public void run() {
try {
db.setStarredFlag(id, starredNow);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
starred = starredNow;
if(starred)
starButton.setImageResource(R.drawable.rating_important);
else starButton.setImageResource(R.drawable.rating_not_important);
} else if(view == replyButton) {
if(view == replyButton) {
Intent i = new Intent(this, WriteMessageActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes());
startActivity(i);
finish();
} else if(view == starButton) {
final MessageId messageId = this.messageId;
final boolean starred = !this.starred;
dbExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
db.setStarredFlag(messageId, starred);
runOnUiThread(new Runnable() {
public void run() {
setStarred(starred);
}
});
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
} else if(view == readButton) {
final MessageId messageId = this.messageId;
final boolean read = !this.read;
dbExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
db.setReadFlag(messageId, read);
runOnUiThread(new Runnable() {
public void run() {
setRead(read);
}
});
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
}
}
private void setStarred(boolean starred) {
this.starred = starred;
if(starred) starButton.setImageResource(R.drawable.rating_important);
else starButton.setImageResource(R.drawable.rating_not_important);
}
private void setRead(boolean read) {
this.read = read;
if(read) readButton.setImageResource(R.drawable.content_unread);
else readButton.setImageResource(R.drawable.content_read);
}
}

View File

@@ -9,7 +9,6 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -35,7 +34,7 @@ import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;
import com.google.inject.Inject;
@@ -56,7 +55,6 @@ implements OnClickListener {
private ContactId contactId = null;
private String contactName = null;
private MessageId parentId = null;
private ImageButton cancelButton = null, sendButton = null;
private EditText content = null;
@Override
@@ -69,42 +67,42 @@ implements OnClickListener {
contactId = new ContactId(cid);
contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
byte[] pid = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
byte[] pid = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
if(pid != null) parentId = new MessageId(pid);
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
layout.setOrientation(VERTICAL);
LinearLayout header = new LinearLayout(this);
header.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
header.setOrientation(HORIZONTAL);
header.setGravity(CENTER_VERTICAL);
LinearLayout actionBar = new LinearLayout(this);
actionBar.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
actionBar.setOrientation(HORIZONTAL);
actionBar.setGravity(CENTER_VERTICAL);
cancelButton = new ImageButton(this);
cancelButton.setPadding(5, 5, 5, 5);
cancelButton.setBackgroundResource(0);
cancelButton.setImageResource(R.drawable.navigation_cancel);
cancelButton.setOnClickListener(this);
header.addView(cancelButton);
TextView to = new TextView(this);
// Give me all the unused width
to.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1));
to.setPadding(10, 0, 0, 0);
to.setTextSize(18);
String format = getResources().getString(R.string.message_to);
to.setText(String.format(format, contactName));
actionBar.addView(to);
sendButton = new ImageButton(this);
ImageButton sendButton = new ImageButton(this);
sendButton.setPadding(5, 5, 5, 5);
sendButton.setBackgroundResource(0);
sendButton.setImageResource(R.drawable.social_send_now);
sendButton.setOnClickListener(this);
header.addView(sendButton);
layout.addView(header);
actionBar.addView(sendButton);
layout.addView(actionBar);
ScrollView scrollView = new ScrollView(this);
content = new EditText(this);
content.setPadding(10, 10, 10, 10);
if(state != null && bundleEncrypter.decrypt(state)) {
Parcelable p = state.getParcelable("net.sf.briar.CONTENT");
if(p != null) content.onRestoreInstanceState(p);
}
scrollView.addView(content);
layout.addView(scrollView);
layout.addView(content);
setContentView(layout);
@@ -127,38 +125,32 @@ implements OnClickListener {
}
public void onClick(View view) {
if(view == cancelButton) {
finish();
} else if(view == sendButton) {
final Message m;
try {
byte[] body = content.getText().toString().getBytes("UTF-8");
m = messageFactory.createPrivateMessage(parentId,
"text/plain", body);
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch(IOException e) {
throw new RuntimeException(e);
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
}
final ContactId contactId = this.contactId;
dbExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
db.addLocalPrivateMessage(m, contactId);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
finish();
final Message m;
try {
byte[] body = content.getText().toString().getBytes("UTF-8");
m = messageFactory.createPrivateMessage(parentId, "text/plain",
body);
} catch(IOException e) {
throw new RuntimeException(e);
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
}
final ContactId contactId = this.contactId;
dbExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
db.addLocalPrivateMessage(m, contactId);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
finish();
}
}