diff options
author | Daniel Gultsch <daniel.gultsch@rwth-aachen.de> | 2014-01-26 03:27:55 +0100 |
---|---|---|
committer | Daniel Gultsch <daniel.gultsch@rwth-aachen.de> | 2014-01-26 03:27:55 +0100 |
commit | 898b0ca8c485888e06e2b5b1c798eebce1a6dabc (patch) | |
tree | f737883fd44da0270ed5ae0f76560d202d55ff24 | |
parent | 665ef7511f5dcccb349228baa2aa6f02281d3c07 (diff) |
chat bubbles. yeah
-rw-r--r-- | AndroidManifest.xml | 1 | ||||
-rw-r--r-- | gen/de/gultsch/chat/R.java | 30 | ||||
-rw-r--r-- | res/drawable/message_border.xml | 6 | ||||
-rw-r--r-- | res/layout/conversation_list_row.xml | 2 | ||||
-rw-r--r-- | res/layout/fragment_conversation.xml | 85 | ||||
-rw-r--r-- | res/layout/message_sent.xml | 53 | ||||
-rw-r--r-- | res/values/strings.xml | 2 | ||||
-rw-r--r-- | src/de/gultsch/chat/entities/Conversation.java | 11 | ||||
-rw-r--r-- | src/de/gultsch/chat/entities/Message.java | 2 | ||||
-rw-r--r-- | src/de/gultsch/chat/persistance/DatabaseBackend.java | 32 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/ConversationActivity.java | 3 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/ConversationFragment.java | 96 | ||||
-rw-r--r-- | src/de/gultsch/chat/ui/XmppActivity.java | 4 | ||||
-rw-r--r-- | src/de/gultsch/chat/utils/Beautifier.java | 25 |
14 files changed, 273 insertions, 79 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index be7addb5..e0ebee7f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -9,6 +9,7 @@ android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> + <uses-permission android:name="android.permission.READ_PROFILE"/> <application android:allowBackup="true" diff --git a/gen/de/gultsch/chat/R.java b/gen/de/gultsch/chat/R.java index 0e8cf1af..cdd36a90 100644 --- a/gen/de/gultsch/chat/R.java +++ b/gen/de/gultsch/chat/R.java @@ -32,29 +32,33 @@ public final class R { public static final int ic_action_unsecure=0x7f020004; public static final int ic_launcher=0x7f020005; public static final int ic_profile=0x7f020006; - public static final int section_header=0x7f020007; + public static final int message_border=0x7f020007; + public static final int profilemock=0x7f020008; + public static final int section_header=0x7f020009; } public static final class id { - public static final int action_accounts=0x7f0a001b; - public static final int action_add=0x7f0a0017; - public static final int action_archive=0x7f0a001a; - public static final int action_details=0x7f0a0019; - public static final int action_security=0x7f0a0018; - public static final int action_settings=0x7f0a001c; + public static final int action_accounts=0x7f0a001e; + public static final int action_add=0x7f0a001a; + public static final int action_archive=0x7f0a001d; + public static final int action_details=0x7f0a001c; + public static final int action_security=0x7f0a001b; + public static final int action_settings=0x7f0a001f; public static final int contact_display_name=0x7f0a0009; public static final int contact_divider=0x7f0a000b; public static final int contact_jid=0x7f0a000a; public static final int contact_photo=0x7f0a0008; public static final int conversation_image=0x7f0a000c; public static final int conversation_lastmsg=0x7f0a000e; + public static final int conversation_lastupdate=0x7f0a000f; public static final int conversation_name=0x7f0a000d; public static final int create_new_contact=0x7f0a0007; - public static final int duration=0x7f0a000f; - public static final int editText1=0x7f0a0011; - public static final int imageButton1=0x7f0a0012; public static final int jabber_contacts=0x7f0a0005; public static final int jabber_contacts_header=0x7f0a0004; public static final int list=0x7f0a0015; + public static final int message_body=0x7f0a0018; + public static final int message_photo=0x7f0a0017; + public static final int message_time=0x7f0a0019; + public static final int messages_view=0x7f0a0013; public static final int new_contact_header=0x7f0a0006; public static final int new_conversation_search=0x7f0a0000; public static final int phone_contacts=0x7f0a0003; @@ -62,7 +66,8 @@ public final class R { public static final int scrollView1=0x7f0a0001; public static final int selected_conversation=0x7f0a0016; public static final int slidingpanelayout=0x7f0a0014; - public static final int textView1=0x7f0a0013; + public static final int textSendButton=0x7f0a0012; + public static final int textinput=0x7f0a0011; public static final int textsend=0x7f0a0010; } public static final class layout { @@ -71,6 +76,7 @@ public final class R { public static final int conversation_list_row=0x7f030002; public static final int fragment_conversation=0x7f030003; public static final int fragment_conversations_overview=0x7f030004; + public static final int message_sent=0x7f030005; } public static final class menu { public static final int conversations=0x7f090000; @@ -84,6 +90,8 @@ public final class R { public static final int action_secure=0x7f070006; public static final int action_settings=0x7f070001; public static final int app_name=0x7f070000; + public static final int just_now=0x7f070008; + public static final int sending=0x7f070009; public static final int title_activity_new_conversation=0x7f070007; } public static final class style { diff --git a/res/drawable/message_border.xml b/res/drawable/message_border.xml new file mode 100644 index 00000000..1477fbe8 --- /dev/null +++ b/res/drawable/message_border.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> + <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + <corners android:radius="2dp"/> + <padding android:left="1.5dp" android:right="1.5dp" android:top="1.5dp" android:bottom="1.5dp"/> + <solid android:color="#cecece"/> +</shape>
\ No newline at end of file diff --git a/res/layout/conversation_list_row.xml b/res/layout/conversation_list_row.xml index cfac7175..303fdd1d 100644 --- a/res/layout/conversation_list_row.xml +++ b/res/layout/conversation_list_row.xml @@ -38,7 +38,7 @@ android:paddingTop="3dp"/> <TextView - android:id="@+id/duration" + android:id="@+id/conversation_lastupdate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/conversation_name" diff --git a/res/layout/fragment_conversation.xml b/res/layout/fragment_conversation.xml index 02fe1f90..11859573 100644 --- a/res/layout/fragment_conversation.xml +++ b/res/layout/fragment_conversation.xml @@ -1,64 +1,55 @@ <?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="match_parent" - android:background="#f9f9f9"> - + android:background="#e5e5e5" > + <RelativeLayout + android:background="#eee" android:id="@+id/textsend" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" > - - <EditText - android:id="@+id/editText1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_toLeftOf="@+id/imageButton1" - android:ems="10" - android:inputType="textMultiLine" - android:minLines="1" - android:background="#ffffff" - android:layout_marginTop="12dp" - android:layout_marginBottom="12dp" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp"> - </EditText> - <ImageButton - android:id="@+id/imageButton1" - android:layout_width="48dp" - android:layout_height="48dp" - android:layout_alignParentRight="true" - android:layout_centerVertical="true" - android:background="?android:selectableItemBackground" - android:src="@drawable/ic_action_send_now" /> + <EditText + android:id="@+id/textinput" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:layout_alignParentLeft="true" + android:paddingBottom="12dp" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:paddingTop="12dp" + android:layout_toLeftOf="@+id/textSendButton" + android:background="#eee" + android:ems="10" + android:inputType="textMultiLine" + android:minLines="1" > + </EditText> + <ImageButton + android:id="@+id/textSendButton" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:background="?android:selectableItemBackground" + android:src="@drawable/ic_action_send_now" /> </RelativeLayout> - - <ScrollView - android:id="@+id/scrollView1" + + <ListView + android:id="@+id/messages_view" android:layout_width="fill_parent" - android:layout_height="fill_parent" + android:layout_height="wrap_content" android:layout_above="@+id/textsend" android:layout_alignParentLeft="true" - android:layout_alignParentTop="true" - android:background="#e5e5e5" > - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:background="#e5e5e5" - android:orientation="vertical" > - - <TextView - android:id="@+id/textView1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="TextView" /> - </LinearLayout> - </ScrollView> + android:background="#e5e5e5" + tools:listitem="@layout/message_sent" + android:divider="@null" + android:dividerHeight="0dp"> + </ListView> -</RelativeLayout> +</RelativeLayout>
\ No newline at end of file diff --git a/res/layout/message_sent.xml b/res/layout/message_sent.xml new file mode 100644 index 00000000..c690c217 --- /dev/null +++ b/res/layout/message_sent.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="8dp"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/message_border" + android:layout_toLeftOf="@+id/message_photo" + android:layout_alignParentLeft="true" + android:layout_alignParentBottom="true" + android:minHeight="48dp" + > +<LinearLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" + android:background="#ededed" + android:padding="5dp"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hi, how are you?" + android:textSize="16sp" + android:id="@+id/message_body" + android:textColor="#333333"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="1dp" + android:text="@string/sending" + android:textColor="#8e8e8e" + android:textSize="12sp" + android:id="@+id/message_time"/> + + </LinearLayout> +</LinearLayout> + <ImageView + android:id="@+id/message_photo" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_alignParentBottom="true" + android:layout_alignParentRight="true" + android:layout_marginLeft="-1.5dp" + android:padding="0dp" + android:src="@drawable/ic_profile" + android:scaleType="fitXY"/> + +</RelativeLayout> diff --git a/res/values/strings.xml b/res/values/strings.xml index d6849e02..d48f23cd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9,4 +9,6 @@ <string name="action_details">Show details</string> <string name="action_secure">Secure conversation</string> <string name="title_activity_new_conversation">New Conversation</string> + <string name="just_now">just now</string> + <string name="sending">sending…</string> </resources> diff --git a/src/de/gultsch/chat/entities/Conversation.java b/src/de/gultsch/chat/entities/Conversation.java index 2dd8a049..413e3d62 100644 --- a/src/de/gultsch/chat/entities/Conversation.java +++ b/src/de/gultsch/chat/entities/Conversation.java @@ -1,5 +1,6 @@ package de.gultsch.chat.entities; +import java.util.ArrayList; import java.util.List; import android.content.ContentValues; @@ -9,6 +10,9 @@ import android.net.Uri; public class Conversation extends AbstractEntity { private static final long serialVersionUID = -6727528868973996739L; + + public static final String TABLENAME = "conversations"; + public static final int STATUS_AVAILABLE = 0; public static final int STATUS_ARCHIVED = 1; public static final int STATUS_DELETED = 2; @@ -27,7 +31,7 @@ public class Conversation extends AbstractEntity { private int status; private long created; - private transient List<Message> messages; + private transient List<Message> messages = null; public Conversation(String name, Uri profilePhoto, Account account, String contactJid) { @@ -48,6 +52,7 @@ public class Conversation extends AbstractEntity { } public List<Message> getMessages() { + if (messages == null) this.messages = new ArrayList<Message>(); //prevent null pointer return messages; } @@ -81,6 +86,10 @@ public class Conversation extends AbstractEntity { public int getStatus() { return this.status; } + + public long getCreated() { + return this.created; + } public ContentValues getContentValues() { ContentValues values = new ContentValues(); diff --git a/src/de/gultsch/chat/entities/Message.java b/src/de/gultsch/chat/entities/Message.java index 5e5cfbe4..26e646ff 100644 --- a/src/de/gultsch/chat/entities/Message.java +++ b/src/de/gultsch/chat/entities/Message.java @@ -6,6 +6,8 @@ import android.database.Cursor; public class Message extends AbstractEntity { private static final long serialVersionUID = 7222081895167103025L; + + public static final String TABLENAME = "messages"; public static final int STATUS_RECIEVED = 0; public static final int STATUS_UNSEND = 1; diff --git a/src/de/gultsch/chat/persistance/DatabaseBackend.java b/src/de/gultsch/chat/persistance/DatabaseBackend.java index dac83f58..06b9af16 100644 --- a/src/de/gultsch/chat/persistance/DatabaseBackend.java +++ b/src/de/gultsch/chat/persistance/DatabaseBackend.java @@ -4,15 +4,16 @@ import java.util.ArrayList; import java.util.List; import de.gultsch.chat.entities.Conversation; +import de.gultsch.chat.entities.Message; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DatabaseBackend extends SQLiteOpenHelper { - + private static DatabaseBackend instance = null; - + private static final String DATABASE_NAME = "history"; private static final int DATABASE_VERSION = 1; @@ -22,7 +23,13 @@ public class DatabaseBackend extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { - db.execSQL("create table conversations (uuid TEXT, name TEXT, profilePhotoUri TEXT, accountUuid TEXT, contactJid TEXT, created NUMBER, status NUMBER)"); + db.execSQL("create table " + Conversation.TABLENAME + " (" + + Conversation.UUID + " TEXT, " + Conversation.NAME + " TEXT, " + + Conversation.PHOTO_URI + " TEXT, " + Conversation.ACCOUNT + + " TEXT, " + Conversation.CONTACT + " TEXT, " + + Conversation.CREATED + " NUMBER, " + Conversation.STATUS + + " NUMBER)"); + db.execSQL("create table "+Message.TABLENAME+ "()"); } @Override @@ -30,23 +37,23 @@ public class DatabaseBackend extends SQLiteOpenHelper { // TODO Auto-generated method stub } - + public static synchronized DatabaseBackend getInstance(Context context) { if (instance == null) { instance = new DatabaseBackend(context); } return instance; } - + public void addConversation(Conversation conversation) { SQLiteDatabase db = this.getWritableDatabase(); db.insert("conversations", null, conversation.getContentValues()); } - - + public int getConversationCount() { SQLiteDatabase db = this.getReadableDatabase(); - Cursor cursor = db.rawQuery("select count(uuid) as count from conversations",null); + Cursor cursor = db.rawQuery( + "select count(uuid) as count from conversations", null); cursor.moveToFirst(); return cursor.getInt(0); } @@ -54,9 +61,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { public List<Conversation> getConversations(int status) { List<Conversation> list = new ArrayList<Conversation>(); SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = {""+status}; - Cursor cursor = db.rawQuery("select * from conversations where status = ? order by created desc", selectionArgs); - while(cursor.moveToNext()) { + String[] selectionArgs = { "" + status }; + Cursor cursor = db + .rawQuery( + "select * from conversations where status = ? order by created desc", + selectionArgs); + while (cursor.moveToNext()) { list.add(Conversation.fromCursor(cursor)); } return list; diff --git a/src/de/gultsch/chat/ui/ConversationActivity.java b/src/de/gultsch/chat/ui/ConversationActivity.java index 97b937c3..4f76e9c1 100644 --- a/src/de/gultsch/chat/ui/ConversationActivity.java +++ b/src/de/gultsch/chat/ui/ConversationActivity.java @@ -9,6 +9,7 @@ import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.persistance.DatabaseBackend; +import de.gultsch.chat.utils.Beautifier; import android.os.Bundle; import android.app.FragmentTransaction; import android.content.Context; @@ -60,6 +61,8 @@ public class ConversationActivity extends XmppActivity { } ((TextView) view.findViewById(R.id.conversation_name)) .setText(getItem(position).getName()); + ((TextView) view.findViewById(R.id.conversation_lastupdate)) + .setText(Beautifier.readableTimeDifference(getItem(position).getCreated())); ((ImageView) view.findViewById(R.id.conversation_image)) .setImageURI(getItem(position).getProfilePhotoUri()); return view; diff --git a/src/de/gultsch/chat/ui/ConversationFragment.java b/src/de/gultsch/chat/ui/ConversationFragment.java index 70ceb07c..fca5202a 100644 --- a/src/de/gultsch/chat/ui/ConversationFragment.java +++ b/src/de/gultsch/chat/ui/ConversationFragment.java @@ -2,24 +2,108 @@ package de.gultsch.chat.ui; import de.gultsch.chat.R; import de.gultsch.chat.entities.Conversation; +import de.gultsch.chat.entities.Message; +import de.gultsch.chat.utils.Beautifier; import android.app.Fragment; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Typeface; +import android.net.Uri; import android.os.Bundle; +import android.provider.ContactsContract.Profile; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; public class ConversationFragment extends Fragment { - + Conversation conversation; - + public void setConversation(Conversation conv) { this.conversation = conv; } - + @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_conversation, container, false); - } + public View onCreateView(final LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + String[] mProjection = new String[] + { + Profile._ID, + Profile.PHOTO_THUMBNAIL_URI + }; + Cursor mProfileCursor = getActivity().getContentResolver().query( + Profile.CONTENT_URI, + mProjection , + null, + null, + null); + + mProfileCursor.moveToFirst(); + final Uri profilePicture = Uri.parse(mProfileCursor.getString(1)); + + Log.d("gultsch","found user profile pic "+profilePicture.toString()); + + final View view = inflater.inflate(R.layout.fragment_conversation, container, + false); + ((ImageButton) view.findViewById(R.id.textSendButton)) + .setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + EditText chatMsg = (EditText) view.findViewById(R.id.textinput); + if (chatMsg.getText().length() < 1) return; + Message message = new Message(conversation,chatMsg.getText().toString(), + Message.ENCRYPTION_NONE); + XmppActivity activity = (XmppActivity) getActivity(); + activity.xmppConnectionService.sendMessage(message); + conversation.getMessages().add(message); + chatMsg.setText(""); + + ListView messagesView = (ListView) view.findViewById(R.id.messages_view); + ArrayAdapter<Message> adapter = (ArrayAdapter<Message>) messagesView.getAdapter(); + adapter.notifyDataSetChanged(); + + messagesView.setSelection(conversation.getMessages().size() -1); + } + }); + + ListView messagesView = (ListView) view + .findViewById(R.id.messages_view); + messagesView.setAdapter(new ArrayAdapter<Message>(this.getActivity() + .getApplicationContext(), R.layout.message_sent, + this.conversation.getMessages()) { + + @Override + public View getView(int position, View view, ViewGroup parent) { + Message item = getItem(position); + if ((item.getStatus() != Message.STATUS_RECIEVED) + || (item.getStatus() == Message.STATUS_SEND)) { + view = (View) inflater.inflate(R.layout.message_sent, null); + ((ImageView) view.findViewById(R.id.message_photo)).setImageURI(profilePicture); + } + ((TextView) view.findViewById(R.id.message_body)).setText(item.getBody()); + TextView time = (TextView) view.findViewById(R.id.message_time); + if (item.getStatus() == Message.STATUS_UNSEND) { + time.setTypeface(null, Typeface.ITALIC); + } else { + time.setText(Beautifier.readableTimeDifference(item.getTimeSent())); + } + return view; + } + }); + + return view; + } public Conversation getConversation() { return conversation; diff --git a/src/de/gultsch/chat/ui/XmppActivity.java b/src/de/gultsch/chat/ui/XmppActivity.java index 99173041..c15482ac 100644 --- a/src/de/gultsch/chat/ui/XmppActivity.java +++ b/src/de/gultsch/chat/ui/XmppActivity.java @@ -10,8 +10,8 @@ import android.content.ServiceConnection; import android.os.IBinder; public abstract class XmppActivity extends Activity { - protected XmppConnectionService xmppConnectionService; - protected boolean xmppConnectionServiceBound = false; + public XmppConnectionService xmppConnectionService; + public boolean xmppConnectionServiceBound = false; protected boolean handledViewIntent = false; protected ServiceConnection mConnection = new ServiceConnection() { diff --git a/src/de/gultsch/chat/utils/Beautifier.java b/src/de/gultsch/chat/utils/Beautifier.java new file mode 100644 index 00000000..43b7acc2 --- /dev/null +++ b/src/de/gultsch/chat/utils/Beautifier.java @@ -0,0 +1,25 @@ +package de.gultsch.chat.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Beautifier { + public static String readableTimeDifference(long time) { + if (time==0) { + return "just now"; + } + Date date = new Date(time); + long difference = (System.currentTimeMillis() - time) / 1000; + if (difference<60) { + return "just now"; + } else if (difference<60*10) { + return difference / 60 + " min ago"; + } else if (difference<60*60*24) { + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); + return sdf.format(date); + } else { + SimpleDateFormat sdf = new SimpleDateFormat("M/D"); + return sdf.format(date); + } + } +} |