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.
@ -13,6 +13,7 @@
|
|||||||
<activity android:name=".SecureSMS"
|
<activity android:name=".SecureSMS"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
|
android:uiOptions="splitActionBarWhenNarrow"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout"
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout"
|
||||||
>
|
>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
BIN
res/drawable-hdpi/ic_menu_msg_compose_holo_dark.png
Normal file
After Width: | Height: | Size: 844 B |
BIN
res/drawable-hdpi/ic_menu_search_holo_dark.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
res/drawable-hdpi/ic_menu_trash_holo_dark.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
res/drawable-mdpi/ic_menu_msg_compose_holo_dark.png
Normal file
After Width: | Height: | Size: 669 B |
BIN
res/drawable-mdpi/ic_menu_search_holo_dark.png
Normal file
After Width: | Height: | Size: 881 B |
BIN
res/drawable-mdpi/ic_menu_trash_holo_dark.png
Normal file
After Width: | Height: | Size: 790 B |
BIN
res/drawable-xhdpi/ic_menu_msg_compose_holo_dark.png
Normal file
After Width: | Height: | Size: 961 B |
BIN
res/drawable-xhdpi/ic_menu_search_holo_dark.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
res/drawable-xhdpi/ic_menu_trash_holo_dark.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 265 B |
@ -5,21 +5,10 @@
|
|||||||
android:paddingRight="10dip"
|
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"
|
<QuickContactBadge android:id="@+id/contact_photo"
|
||||||
android:layout_width="60dp"
|
style="?android:attr/quickContactBadgeStyleWindowLarge"
|
||||||
android:layout_height="60dp"
|
android:layout_centerVertical="true"
|
||||||
android:cropToPadding="true"
|
android:layout_alignParentLeft="true" />
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:layout_toRightOf="@id/unread_indicator"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView android:id="@+id/key_indicator"
|
<ImageView android:id="@+id/key_indicator"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -43,7 +32,7 @@
|
|||||||
android:layout_marginTop="6dip"
|
android:layout_marginTop="6dip"
|
||||||
android:layout_marginRight="5dip"
|
android:layout_marginRight="5dip"
|
||||||
android:layout_marginLeft="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_toRightOf="@id/contact_photo"
|
||||||
android:layout_toLeftOf="@id/checkbox"
|
android:layout_toLeftOf="@id/checkbox"
|
||||||
android:layout_alignWithParentIfMissing="true"
|
android:layout_alignWithParentIfMissing="true"
|
||||||
@ -87,7 +76,7 @@
|
|||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:layout_marginBottom="10dip"
|
android:layout_marginBottom="10dip"
|
||||||
android:layout_marginLeft="5dip"
|
android:layout_marginLeft="5dip"
|
||||||
android:layout_alignBottom="@id/unread_indicator"
|
android:layout_alignBottom="@id/contact_photo"
|
||||||
android:layout_toRightOf="@id/contact_photo"
|
android:layout_toRightOf="@id/contact_photo"
|
||||||
android:layout_toLeftOf="@id/date"
|
android:layout_toLeftOf="@id/date"
|
||||||
android:ellipsize="end" />
|
android:ellipsize="end" />
|
||||||
|
@ -17,8 +17,12 @@
|
|||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -43,16 +47,13 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class ConversationHeaderView extends RelativeLayout {
|
public class ConversationHeaderView extends RelativeLayout {
|
||||||
|
|
||||||
private final Context context;
|
private Set<Long> selectedThreads;
|
||||||
private Set<Long> selectedThreads;
|
|
||||||
|
|
||||||
private Recipients recipients;
|
private Recipients recipients;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
private boolean first;
|
private boolean first;
|
||||||
private TextView subjectView;
|
private TextView subjectView;
|
||||||
private TextView fromView;
|
private TextView fromView;
|
||||||
private TextView dateView;
|
private TextView dateView;
|
||||||
private View unreadIndicator;
|
|
||||||
private View keyIndicator;
|
private View keyIndicator;
|
||||||
private CheckBox checkbox;
|
private CheckBox checkbox;
|
||||||
private QuickContactBadge contactPhoto;
|
private QuickContactBadge contactPhoto;
|
||||||
@ -70,12 +71,10 @@ public class ConversationHeaderView extends RelativeLayout {
|
|||||||
LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
li.inflate(R.layout.conversation_header_view, this, true);
|
li.inflate(R.layout.conversation_header_view, this, true);
|
||||||
|
|
||||||
this.context = context;
|
|
||||||
this.selectedThreads = selectedThreads;
|
this.selectedThreads = selectedThreads;
|
||||||
this.subjectView = (TextView)findViewById(R.id.subject);
|
this.subjectView = (TextView)findViewById(R.id.subject);
|
||||||
this.fromView = (TextView)findViewById(R.id.from);
|
this.fromView = (TextView)findViewById(R.id.from);
|
||||||
this.dateView = (TextView)findViewById(R.id.date);
|
this.dateView = (TextView)findViewById(R.id.date);
|
||||||
this.unreadIndicator = findViewById(R.id.unread_indicator);
|
|
||||||
this.keyIndicator = findViewById(R.id.key_indicator);
|
this.keyIndicator = findViewById(R.id.key_indicator);
|
||||||
this.contactPhoto = (QuickContactBadge)findViewById(R.id.contact_photo);
|
this.contactPhoto = (QuickContactBadge)findViewById(R.id.contact_photo);
|
||||||
this.checkbox = (CheckBox)findViewById(R.id.checkbox);
|
this.checkbox = (CheckBox)findViewById(R.id.checkbox);
|
||||||
@ -85,13 +84,12 @@ public class ConversationHeaderView extends RelativeLayout {
|
|||||||
|
|
||||||
public ConversationHeaderView(Context context, AttributeSet attrs) {
|
public ConversationHeaderView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
this.context = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(MessageRecord message, boolean batchMode) {
|
public void set(MessageRecord message, boolean batchMode) {
|
||||||
this.recipients = message.getRecipients();
|
this.recipients = message.getRecipients();
|
||||||
this.threadId = message.getThreadId();
|
this.threadId = message.getThreadId();
|
||||||
this.fromView.setText(formatFrom(recipients, message.getCount()));
|
this.fromView.setText(formatFrom(recipients, message.getCount(), message.getRead()));
|
||||||
|
|
||||||
if (message.isKeyExchange())
|
if (message.isKeyExchange())
|
||||||
this.subjectView.setText("Key exchange message...", TextView.BufferType.SPANNABLE);
|
this.subjectView.setText("Key exchange message...", TextView.BufferType.SPANNABLE);
|
||||||
@ -108,7 +106,7 @@ public class ConversationHeaderView extends RelativeLayout {
|
|||||||
this.checkbox.setChecked(selectedThreads.contains(threadId));
|
this.checkbox.setChecked(selectedThreads.contains(threadId));
|
||||||
|
|
||||||
clearIndicators();
|
clearIndicators();
|
||||||
setIndicators(message.getRead(), message.isKeyExchange());
|
setIndicators(message.isKeyExchange());
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
if (batchMode) checkbox.setVisibility(View.VISIBLE);
|
if (batchMode) checkbox.setVisibility(View.VISIBLE);
|
||||||
@ -126,16 +124,28 @@ public class ConversationHeaderView extends RelativeLayout {
|
|||||||
|
|
||||||
private void clearIndicators() {
|
private void clearIndicators() {
|
||||||
this.keyIndicator.setVisibility(View.INVISIBLE);
|
this.keyIndicator.setVisibility(View.INVISIBLE);
|
||||||
this.unreadIndicator.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIndicators(boolean read, boolean key) {
|
private void setIndicators(boolean key) {
|
||||||
if (!read && key) this.keyIndicator.setVisibility(View.VISIBLE);
|
if (key) this.keyIndicator.setVisibility(View.VISIBLE);
|
||||||
else if (!read) this.unreadIndicator.setVisibility(View.VISIBLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatFrom(Recipients from, long count) {
|
private CharSequence formatFrom(Recipients from, long count, boolean read) {
|
||||||
return from.toShortString() + (count > 0 ? " (" + count + ")" : "");
|
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() {
|
public Recipients getRecipients() {
|
||||||
|
@ -61,7 +61,6 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||||
import org.thoughtcrime.securesms.database.ApplicationExporter;
|
import org.thoughtcrime.securesms.database.ApplicationExporter;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessageRecord;
|
|
||||||
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
||||||
import org.thoughtcrime.securesms.database.SmsMigrator;
|
import org.thoughtcrime.securesms.database.SmsMigrator;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
@ -75,7 +74,6 @@ import org.thoughtcrime.securesms.util.Eula;
|
|||||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -89,6 +87,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class SecureSMS extends SherlockListActivity {
|
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_SEND_KEY = 1;
|
||||||
private static final int MENU_PASSPHRASE_KEY = 2;
|
private static final int MENU_PASSPHRASE_KEY = 2;
|
||||||
private static final int MENU_PREFERENCES_KEY = 3;
|
private static final int MENU_PREFERENCES_KEY = 3;
|
||||||
@ -187,30 +186,54 @@ public class SecureSMS extends SherlockListActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void prepareNormalMenu(Menu menu) {
|
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);
|
if (masterSecret != null) {
|
||||||
else menu.add(0, MENU_PASSPHRASE_KEY, Menu.NONE, "Enter passphrase").setIcon(R.drawable.ic_lock_message_sms);
|
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_NEW_MESSAGE, Menu.NONE, "New Message")
|
||||||
menu.add(0, MENU_PREFERENCES_KEY, Menu.NONE, "Settings").setIcon(android.R.drawable.ic_menu_preferences);
|
.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);
|
menu.add(0, MENU_SEARCH, Menu.NONE, "Search")
|
||||||
importExportMenu.add(0, MENU_EXPORT, Menu.NONE, "Export To SD Card").setIcon(android.R.drawable.ic_menu_save);
|
.setIcon(R.drawable.ic_menu_search_holo_dark)
|
||||||
importExportMenu.add(0, MENU_IMPORT, Menu.NONE, "Import From SD Card").setIcon(android.R.drawable.ic_menu_revert);
|
.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)
|
SubMenu importExportMenu = menu.addSubMenu("Import/Export")
|
||||||
moreMenu.add(0, MENU_CLEAR_PASSPHRASE, Menu.NONE, "Clear Passphrase").setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
.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) {
|
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_EXIT_BATCH, Menu.NONE, "Normal Mode")
|
||||||
menu.add(0, MENU_DELETE_SELECTED_THREADS, Menu.NONE, "Delete Selected").setIcon(android.R.drawable.ic_menu_delete);
|
.setIcon(android.R.drawable.ic_menu_set_as);
|
||||||
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_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
|
@Override
|
||||||
@ -218,6 +241,9 @@ public class SecureSMS extends SherlockListActivity {
|
|||||||
super.onOptionsItemSelected(item);
|
super.onOptionsItemSelected(item);
|
||||||
|
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
case MENU_NEW_MESSAGE:
|
||||||
|
createConversation(-1, null);
|
||||||
|
return true;
|
||||||
case MENU_SEND_KEY:
|
case MENU_SEND_KEY:
|
||||||
Intent intent = new Intent(this, SendKeyActivity.class);
|
Intent intent = new Intent(this, SendKeyActivity.class);
|
||||||
intent.putExtra("master_secret", masterSecret);
|
intent.putExtra("master_secret", masterSecret);
|
||||||
@ -435,7 +461,6 @@ public class SecureSMS extends SherlockListActivity {
|
|||||||
else DecryptingQueue.schedulePendingDecrypts(this, masterSecret);
|
else DecryptingQueue.schedulePendingDecrypts(this, masterSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
addNewMessageItem();
|
|
||||||
addConversationItems();
|
addConversationItems();
|
||||||
createConversationIfNecessary(this.getIntent());
|
createConversationIfNecessary(this.getIntent());
|
||||||
}
|
}
|
||||||
@ -465,9 +490,7 @@ public class SecureSMS extends SherlockListActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
if (position == 0) {
|
if (v instanceof ConversationHeaderView) {
|
||||||
createConversation(-1, null);
|
|
||||||
} else if (v instanceof ConversationHeaderView) {
|
|
||||||
ConversationHeaderView headerView = (ConversationHeaderView) v;
|
ConversationHeaderView headerView = (ConversationHeaderView) v;
|
||||||
createConversation(headerView.getThreadId(), headerView.getRecipients());
|
createConversation(headerView.getThreadId(), headerView.getRecipients());
|
||||||
}
|
}
|
||||||
@ -509,23 +532,6 @@ public class SecureSMS extends SherlockListActivity {
|
|||||||
startActivity(intent);
|
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() {
|
private void addConversationItems() {
|
||||||
Cursor cursor = DatabaseFactory.getThreadDatabase(this).getConversationList();
|
Cursor cursor = DatabaseFactory.getThreadDatabase(this).getConversationList();
|
||||||
startManagingCursor(cursor);
|
startManagingCursor(cursor);
|
||||||
|