Restyle conversation list view.

1. New look for quick contact badges.
2. No more unread indicator, replace with bolded text.
3. Style message count with color rather than parens.
4. Remove "New Message" item, add as item in action bar instead.
This commit is contained in:
Moxie Marlinspike 2012-07-16 21:35:32 -07:00
parent 63250b33a8
commit b93bb69c28
14 changed files with 75 additions and 69 deletions

View File

@ -13,6 +13,7 @@
<activity android:name=".SecureSMS"
android:label="@string/app_name"
android:launchMode="singleTask"
android:uiOptions="splitActionBarWhenNarrow"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout"
>
<intent-filter>

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

View File

@ -5,21 +5,10 @@
android:paddingRight="10dip"
>
<ImageView android:id="@+id/unread_indicator"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:visibility="invisible"
android:src="@drawable/ic_sms_unread_msg_indicator" />
<QuickContactBadge android:id="@+id/contact_photo"
android:layout_width="60dp"
android:layout_height="60dp"
android:cropToPadding="true"
android:scaleType="centerCrop"
android:layout_toRightOf="@id/unread_indicator"
android:visibility="gone" />
style="?android:attr/quickContactBadgeStyleWindowLarge"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true" />
<ImageView android:id="@+id/key_indicator"
android:layout_width="wrap_content"
@ -43,7 +32,7 @@
android:layout_marginTop="6dip"
android:layout_marginRight="5dip"
android:layout_marginLeft="5dip"
android:layout_alignTop="@id/unread_indicator"
android:layout_alignTop="@id/contact_photo"
android:layout_toRightOf="@id/contact_photo"
android:layout_toLeftOf="@id/checkbox"
android:layout_alignWithParentIfMissing="true"
@ -87,7 +76,7 @@
android:singleLine="true"
android:layout_marginBottom="10dip"
android:layout_marginLeft="5dip"
android:layout_alignBottom="@id/unread_indicator"
android:layout_alignBottom="@id/contact_photo"
android:layout_toRightOf="@id/contact_photo"
android:layout_toLeftOf="@id/date"
android:ellipsize="end" />

View File

@ -17,8 +17,12 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.format.DateUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@ -43,16 +47,13 @@ import java.util.Set;
public class ConversationHeaderView extends RelativeLayout {
private final Context context;
private Set<Long> selectedThreads;
private Set<Long> selectedThreads;
private Recipients recipients;
private long threadId;
private boolean first;
private TextView subjectView;
private TextView fromView;
private TextView dateView;
private View unreadIndicator;
private View keyIndicator;
private CheckBox checkbox;
private QuickContactBadge contactPhoto;
@ -70,12 +71,10 @@ public class ConversationHeaderView extends RelativeLayout {
LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.conversation_header_view, this, true);
this.context = context;
this.selectedThreads = selectedThreads;
this.subjectView = (TextView)findViewById(R.id.subject);
this.fromView = (TextView)findViewById(R.id.from);
this.dateView = (TextView)findViewById(R.id.date);
this.unreadIndicator = findViewById(R.id.unread_indicator);
this.keyIndicator = findViewById(R.id.key_indicator);
this.contactPhoto = (QuickContactBadge)findViewById(R.id.contact_photo);
this.checkbox = (CheckBox)findViewById(R.id.checkbox);
@ -85,13 +84,12 @@ public class ConversationHeaderView extends RelativeLayout {
public ConversationHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public void set(MessageRecord message, boolean batchMode) {
this.recipients = message.getRecipients();
this.threadId = message.getThreadId();
this.fromView.setText(formatFrom(recipients, message.getCount()));
this.fromView.setText(formatFrom(recipients, message.getCount(), message.getRead()));
if (message.isKeyExchange())
this.subjectView.setText("Key exchange message...", TextView.BufferType.SPANNABLE);
@ -108,7 +106,7 @@ public class ConversationHeaderView extends RelativeLayout {
this.checkbox.setChecked(selectedThreads.contains(threadId));
clearIndicators();
setIndicators(message.getRead(), message.isKeyExchange());
setIndicators(message.isKeyExchange());
if (!first) {
if (batchMode) checkbox.setVisibility(View.VISIBLE);
@ -126,16 +124,28 @@ public class ConversationHeaderView extends RelativeLayout {
private void clearIndicators() {
this.keyIndicator.setVisibility(View.INVISIBLE);
this.unreadIndicator.setVisibility(View.INVISIBLE);
}
private void setIndicators(boolean read, boolean key) {
if (!read && key) this.keyIndicator.setVisibility(View.VISIBLE);
else if (!read) this.unreadIndicator.setVisibility(View.VISIBLE);
private void setIndicators(boolean key) {
if (key) this.keyIndicator.setVisibility(View.VISIBLE);
}
private String formatFrom(Recipients from, long count) {
return from.toShortString() + (count > 0 ? " (" + count + ")" : "");
private CharSequence formatFrom(Recipients from, long count, boolean read) {
SpannableStringBuilder builder = new SpannableStringBuilder(from.toShortString());
if (count > 0) {
builder.append(" " + count);
builder.setSpan(new ForegroundColorSpan(Color.parseColor("#66333333")),
from.toShortString().length(), builder.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
if (!read) {
builder.setSpan(new StyleSpan(Typeface.BOLD), 0, builder.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
return builder;
}
public Recipients getRecipients() {

View File

@ -61,7 +61,6 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.database.ApplicationExporter;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessageRecord;
import org.thoughtcrime.securesms.database.NoExternalStorageException;
import org.thoughtcrime.securesms.database.SmsMigrator;
import org.thoughtcrime.securesms.database.ThreadDatabase;
@ -75,7 +74,6 @@ import org.thoughtcrime.securesms.util.Eula;
import org.thoughtcrime.securesms.util.MemoryCleaner;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -89,6 +87,7 @@ import java.util.Set;
public class SecureSMS extends SherlockListActivity {
private static final int MENU_NEW_MESSAGE = 0;
private static final int MENU_SEND_KEY = 1;
private static final int MENU_PASSPHRASE_KEY = 2;
private static final int MENU_PREFERENCES_KEY = 3;
@ -187,30 +186,54 @@ public class SecureSMS extends SherlockListActivity {
}
private void prepareNormalMenu(Menu menu) {
menu.add(0, MENU_BATCH_MODE, Menu.NONE, "Batch Mode").setIcon(android.R.drawable.ic_menu_share);
menu.add(0, MENU_BATCH_MODE, Menu.NONE, "Batch Mode")
.setIcon(android.R.drawable.ic_menu_share);
if (masterSecret != null) menu.add(0, MENU_SEND_KEY, Menu.NONE, "Secure Session").setIcon(R.drawable.ic_lock_message_sms);
else menu.add(0, MENU_PASSPHRASE_KEY, Menu.NONE, "Enter passphrase").setIcon(R.drawable.ic_lock_message_sms);
if (masterSecret != null) {
menu.add(0, MENU_SEND_KEY, Menu.NONE, "Secure Session")
.setIcon(R.drawable.ic_lock_message_sms);
} else {
menu.add(0, MENU_PASSPHRASE_KEY, Menu.NONE, "Enter passphrase")
.setIcon(R.drawable.ic_lock_message_sms);
}
menu.add(0, MENU_SEARCH, Menu.NONE, "Search").setIcon(android.R.drawable.ic_menu_search);
menu.add(0, MENU_PREFERENCES_KEY, Menu.NONE, "Settings").setIcon(android.R.drawable.ic_menu_preferences);
menu.add(0, MENU_NEW_MESSAGE, Menu.NONE, "New Message")
.setIcon(R.drawable.ic_menu_msg_compose_holo_dark)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SubMenu importExportMenu = menu.addSubMenu("Import/Export").setIcon(android.R.drawable.ic_menu_save);
importExportMenu.add(0, MENU_EXPORT, Menu.NONE, "Export To SD Card").setIcon(android.R.drawable.ic_menu_save);
importExportMenu.add(0, MENU_IMPORT, Menu.NONE, "Import From SD Card").setIcon(android.R.drawable.ic_menu_revert);
menu.add(0, MENU_SEARCH, Menu.NONE, "Search")
.setIcon(R.drawable.ic_menu_search_holo_dark)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SubMenu moreMenu = menu.addSubMenu("More").setIcon(android.R.drawable.ic_menu_more);
menu.add(0, MENU_PREFERENCES_KEY, Menu.NONE, "Settings")
.setIcon(android.R.drawable.ic_menu_preferences);
if (masterSecret != null)
moreMenu.add(0, MENU_CLEAR_PASSPHRASE, Menu.NONE, "Clear Passphrase").setIcon(android.R.drawable.ic_menu_close_clear_cancel);
SubMenu importExportMenu = menu.addSubMenu("Import/Export")
.setIcon(android.R.drawable.ic_menu_save);
importExportMenu.add(0, MENU_EXPORT, Menu.NONE, "Export To SD Card")
.setIcon(android.R.drawable.ic_menu_save);
importExportMenu.add(0, MENU_IMPORT, Menu.NONE, "Import From SD Card")
.setIcon(android.R.drawable.ic_menu_revert);
if (masterSecret != null) {
menu.add(0, MENU_CLEAR_PASSPHRASE, Menu.NONE, "Clear Passphrase")
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
}
}
private void prepareBatchModeMenu(Menu menu) {
menu.add(0, MENU_EXIT_BATCH, Menu.NONE, "Normal Mode").setIcon(android.R.drawable.ic_menu_set_as);
menu.add(0, MENU_DELETE_SELECTED_THREADS, Menu.NONE, "Delete Selected").setIcon(android.R.drawable.ic_menu_delete);
menu.add(0, MENU_SELECT_ALL_THREADS, Menu.NONE, "Select All").setIcon(android.R.drawable.ic_menu_add);
menu.add(0, MENU_CLEAR_SELECTION, Menu.NONE, "Unselect All").setIcon(android.R.drawable.ic_menu_revert);
menu.add(0, MENU_EXIT_BATCH, Menu.NONE, "Normal Mode")
.setIcon(android.R.drawable.ic_menu_set_as);
menu.add(0, MENU_DELETE_SELECTED_THREADS, Menu.NONE, "Delete Selected")
.setIcon(R.drawable.ic_menu_trash_holo_dark)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(0, MENU_SELECT_ALL_THREADS, Menu.NONE, "Select All")
.setIcon(android.R.drawable.ic_menu_add);
menu.add(0, MENU_CLEAR_SELECTION, Menu.NONE, "Unselect All")
.setIcon(android.R.drawable.ic_menu_revert);
}
@Override
@ -218,6 +241,9 @@ public class SecureSMS extends SherlockListActivity {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case MENU_NEW_MESSAGE:
createConversation(-1, null);
return true;
case MENU_SEND_KEY:
Intent intent = new Intent(this, SendKeyActivity.class);
intent.putExtra("master_secret", masterSecret);
@ -435,7 +461,6 @@ public class SecureSMS extends SherlockListActivity {
else DecryptingQueue.schedulePendingDecrypts(this, masterSecret);
}
addNewMessageItem();
addConversationItems();
createConversationIfNecessary(this.getIntent());
}
@ -465,9 +490,7 @@ public class SecureSMS extends SherlockListActivity {
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if (position == 0) {
createConversation(-1, null);
} else if (v instanceof ConversationHeaderView) {
if (v instanceof ConversationHeaderView) {
ConversationHeaderView headerView = (ConversationHeaderView) v;
createConversation(headerView.getThreadId(), headerView.getRecipients());
}
@ -509,23 +532,6 @@ public class SecureSMS extends SherlockListActivity {
startActivity(intent);
}
private void addNewMessageItem() {
ListView listView = getListView();
if (listView.getHeaderViewsCount() > 0) return;
ArrayList<Recipient> dummyList = new ArrayList<Recipient>();
dummyList.add(new Recipient("New Message", null, null));
Recipients recipients = new Recipients(dummyList);
headerView = new ConversationHeaderView(this, true);
MessageRecord messageRecord = new MessageRecord(-1, recipients, 0, 0, true, -1);
messageRecord.setBody("Compose new message.");
headerView.set(messageRecord, false);
// headerView.setBackgroundColor(Color.TRANSPARENT);
listView.addHeaderView(headerView, null, true);
}
private void addConversationItems() {
Cursor cursor = DatabaseFactory.getThreadDatabase(this).getConversationList();
startManagingCursor(cursor);