App saves/displays draft messages

This commit is contained in:
Sylvain Berfini 2012-09-20 14:32:43 +02:00
parent fa376612ed
commit 4ff6ae2d5f
8 changed files with 178 additions and 58 deletions

View file

@ -48,7 +48,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/new_fast_chat" android:hint="@string/new_fast_chat"
android:textColor="@color/text_default" android:textColor="@android:color/black"
android:inputType="textEmailAddress"/> android:inputType="textEmailAddress"/>
<ListView <ListView

View file

@ -1,37 +1,56 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingTop="10dp" android:paddingTop="10dp"
android:paddingBottom="10dp" android:paddingBottom="10dp"
android:background="@drawable/list_selector" android:background="@drawable/list_selector">
android:orientation="horizontal" >
<TextView
android:id="@+id/sipUri"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.1"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/black"
android:layout_marginLeft="10dp" />
<ImageView
android:contentDescription="@string/content_description_detail"
android:id="@+id/detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.9"
android:src="@drawable/list_detail" />
<ImageView <ImageView
android:contentDescription="@string/content_description_delete" android:contentDescription="@string/content_description_delete"
android:id="@+id/delete" android:id="@+id/delete"
android:layout_width="match_parent" android:paddingRight="5dp"
android:layout_height="match_parent" android:layout_width="wrap_content"
android:layout_weight="0.9" android:layout_height="wrap_content"
android:visibility="gone" android:adjustViewBounds="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:visibility="invisible"
android:src="@drawable/list_delete" /> android:src="@drawable/list_delete" />
<ImageView
android:contentDescription="@string/content_description_detail"
android:id="@+id/detail"
android:paddingRight="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:src="@drawable/list_detail" />
<TextView
android:id="@+id/draft"
android:visibility="gone"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/text_selected"
android:layout_toLeftOf="@id/detail"
android:text="@string/draft"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" />
</LinearLayout> <TextView
android:id="@+id/sipUri"
android:layout_centerVertical="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/black"
android:layout_toLeftOf="@id/draft"
android:layout_marginLeft="10dp" />
</RelativeLayout>

View file

@ -201,6 +201,7 @@
<string name="addressHint">Numéro ou adresse</string> <string name="addressHint">Numéro ou adresse</string>
<string name="conference">Conférence</string> <string name="conference">Conférence</string>
<string name="draft">Brouillon</string>
<string name="new_fast_chat">Entrez une adresse SIP avec qui discuter&#8230;</string> <string name="new_fast_chat">Entrez une adresse SIP avec qui discuter&#8230;</string>
<!-- Used by Android to help blind people by describing them images --> <!-- Used by Android to help blind people by describing them images -->

View file

@ -251,6 +251,7 @@
<string name="addressHint">Number or address</string> <string name="addressHint">Number or address</string>
<string name="conference">Conference</string> <string name="conference">Conference</string>
<string name="draft">Draft</string>
<string name="new_fast_chat">Enter a SIP address to chat with&#8230;</string> <string name="new_fast_chat">Enter a SIP address to chat with&#8230;</string>
<!-- Used by Android to help blind people by describing them images --> <!-- Used by Android to help blind people by describing them images -->

View file

@ -322,6 +322,17 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
latestImageMessages = null; latestImageMessages = null;
if (!message.getText().toString().equals("") && LinphoneActivity.isInstanciated()) {
ChatStorage chatStorage = LinphoneActivity.instance().getChatStorage();
if (chatStorage.getDraft(sipUri) == null) {
chatStorage.saveDraft(sipUri, message.getText().toString());
} else {
chatStorage.updateDraft(sipUri, message.getText().toString());
}
} else if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().getChatStorage().deleteDraft(sipUri);
}
} }
@SuppressLint("UseSparseArrays") @SuppressLint("UseSparseArrays")
@ -336,6 +347,11 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
LinphoneActivity.instance().updateChatFragment(this); LinphoneActivity.instance().updateChatFragment(this);
} }
scrollToEnd(); scrollToEnd();
if (LinphoneActivity.isInstanciated()) {
String draft = LinphoneActivity.instance().getChatStorage().getDraft(sipUri);
message.setText(draft);
}
} }
@Override @Override

View file

@ -24,8 +24,6 @@ import org.linphone.core.LinphoneCoreFactory;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -47,9 +45,9 @@ import android.widget.TextView;
*/ */
public class ChatListFragment extends Fragment implements OnClickListener, OnItemClickListener { public class ChatListFragment extends Fragment implements OnClickListener, OnItemClickListener {
private LayoutInflater mInflater; private LayoutInflater mInflater;
private List<String> mConversations; private List<String> mConversations, mDrafts;
private ListView chatList; private ListView chatList;
private ImageView edit, ok, newDiscussion, isFastNewChatAddressOk; private ImageView edit, ok, newDiscussion;
private EditText fastNewChat; private EditText fastNewChat;
private boolean isEditMode = false; private boolean isEditMode = false;
@ -78,10 +76,13 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
if (LinphoneActivity.isInstanciated()) if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHATLIST); LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHATLIST);
}
mConversations = LinphoneActivity.instance().getChatList(); mConversations = LinphoneActivity.instance().getChatList();
mDrafts = LinphoneActivity.instance().getDraftChatList();
mConversations.removeAll(mDrafts);
chatList.setAdapter(new ChatListAdapter()); chatList.setAdapter(new ChatListAdapter());
} }
@ -101,6 +102,8 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
LinphoneActivity.instance().removeFromChatList(sipUri); LinphoneActivity.instance().removeFromChatList(sipUri);
mConversations = LinphoneActivity.instance().getChatList(); mConversations = LinphoneActivity.instance().getChatList();
mDrafts = LinphoneActivity.instance().getDraftChatList();
mConversations.removeAll(mDrafts);
chatList.setAdapter(new ChatListAdapter()); chatList.setAdapter(new ChatListAdapter());
return true; return true;
} }
@ -145,8 +148,13 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
LinphoneActivity.instance().displayChat(sipUri); LinphoneActivity.instance().displayChat(sipUri);
} else if (LinphoneActivity.isInstanciated()) { } else if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().removeFromChatList(sipUri); LinphoneActivity.instance().removeFromChatList(sipUri);
LinphoneActivity.instance().removeFromDrafts(sipUri);
mConversations = LinphoneActivity.instance().getChatList(); mConversations = LinphoneActivity.instance().getChatList();
mDrafts = LinphoneActivity.instance().getDraftChatList();
mConversations.removeAll(mDrafts);
chatList.setAdapter(new ChatListAdapter()); chatList.setAdapter(new ChatListAdapter());
LinphoneActivity.instance().updateMissedChatCount(); LinphoneActivity.instance().updateMissedChatCount();
} }
} }
@ -156,7 +164,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
} }
public int getCount() { public int getCount() {
return mConversations.size(); return mConversations.size() + mDrafts.size();
} }
public Object getItem(int position) { public Object getItem(int position) {
@ -176,7 +184,14 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
view = mInflater.inflate(R.layout.chatlist_cell, parent, false); view = mInflater.inflate(R.layout.chatlist_cell, parent, false);
} }
String contact = mConversations.get(position); String contact;
boolean isDraft = false;
if (position >= mDrafts.size()) {
contact = mConversations.get(position - mDrafts.size());
} else {
contact = mDrafts.get(position);
isDraft = true;
}
view.setTag(contact); view.setTag(contact);
LinphoneAddress address = LinphoneCoreFactory.instance().createLinphoneAddress(contact); LinphoneAddress address = LinphoneCoreFactory.instance().createLinphoneAddress(contact);
@ -191,6 +206,9 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
} }
sipUri.setText(address.getDisplayName() == null ? contact : address.getDisplayName()); sipUri.setText(address.getDisplayName() == null ? contact : address.getDisplayName());
if (isDraft) {
view.findViewById(R.id.draft).setVisibility(View.VISIBLE);
}
ImageView delete, detail; ImageView delete, detail;
delete = (ImageView) view.findViewById(R.id.delete); delete = (ImageView) view.findViewById(R.id.delete);
@ -198,9 +216,9 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
if (isEditMode) { if (isEditMode) {
delete.setVisibility(View.VISIBLE); delete.setVisibility(View.VISIBLE);
detail.setVisibility(View.GONE); detail.setVisibility(View.INVISIBLE);
} else { } else {
delete.setVisibility(View.GONE); delete.setVisibility(View.INVISIBLE);
detail.setVisibility(View.VISIBLE); detail.setVisibility(View.VISIBLE);
} }

View file

@ -42,6 +42,7 @@ public class ChatStorage {
private Context context; private Context context;
private SQLiteDatabase db; private SQLiteDatabase db;
private static final String TABLE_NAME = "chat"; private static final String TABLE_NAME = "chat";
private static final String DRAFT_TABLE_NAME = "chat_draft";
public ChatStorage(Context c) { public ChatStorage(Context c) {
context = c; context = c;
@ -110,6 +111,57 @@ public class ChatStorage {
return (int) db.insert(TABLE_NAME, null, values); return (int) db.insert(TABLE_NAME, null, values);
} }
public int saveDraft(String to, String message) {
ContentValues values = new ContentValues();
values.put("remoteContact", to);
values.put("message", message);
return (int) db.insert(DRAFT_TABLE_NAME, null, values);
}
public void updateDraft(String to, String message) {
ContentValues values = new ContentValues();
values.put("message", message);
db.update(DRAFT_TABLE_NAME, values, "remoteContact LIKE \"" + to + "\"", null);
}
public void deleteDraft(String to) {
db.delete(DRAFT_TABLE_NAME, "remoteContact LIKE \"" + to + "\"", null);
}
public String getDraft(String to) {
Cursor c = db.query(DRAFT_TABLE_NAME, null, "remoteContact LIKE \"" + to + "\"", null, null, null, "id ASC");
String message = null;
while (c.moveToNext()) {
try {
message = c.getString(c.getColumnIndex("message"));
} catch (Exception e) {
e.printStackTrace();
}
}
c.close();
return message;
}
public List<String> getDrafts() {
List<String> drafts = new ArrayList<String>();
Cursor c = db.query(DRAFT_TABLE_NAME, null, null, null, null, null, "id ASC");
while (c.moveToNext()) {
try {
String to = c.getString(c.getColumnIndex("remoteContact"));
drafts.add(to);
} catch (Exception e) {
e.printStackTrace();
}
}
c.close();
return drafts;
}
public List<ChatMessage> getMessages(String correspondent) { public List<ChatMessage> getMessages(String correspondent) {
List<ChatMessage> chatMessages = new ArrayList<ChatMessage>(); List<ChatMessage> chatMessages = new ArrayList<ChatMessage>();
@ -167,27 +219,6 @@ public class ChatStorage {
return db.query(TABLE_NAME, null, "read LIKE " + NOT_READ, null, null, null, null).getCount(); return db.query(TABLE_NAME, null, "read LIKE " + NOT_READ, null, null, null, null).getCount();
} }
class ChatHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 13;
private static final String DATABASE_NAME = "linphone-android";
ChatHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, localContact TEXT NOT NULL, remoteContact TEXT NOT NULL, direction INTEGER, message TEXT, image BLOB, time NUMERIC, read INTEGER, status INTEGER);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME + ";");
onCreate(db);
}
}
public byte[] getRawImageFromMessage(int id) { public byte[] getRawImageFromMessage(int id) {
String[] columns = { "image" }; String[] columns = { "image" };
Cursor c = db.query(TABLE_NAME, columns, "id LIKE " + id + "", null, null, null, null); Cursor c = db.query(TABLE_NAME, columns, "id LIKE " + id + "", null, null, null, null);
@ -200,4 +231,27 @@ public class ChatStorage {
return null; return null;
} }
class ChatHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 14;
private static final String DATABASE_NAME = "linphone-android";
ChatHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, localContact TEXT NOT NULL, remoteContact TEXT NOT NULL, direction INTEGER, message TEXT, image BLOB, time NUMERIC, read INTEGER, status INTEGER);");
db.execSQL("CREATE TABLE " + DRAFT_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, remoteContact TEXT NOT NULL, message TEXT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME + ";");
db.execSQL("DROP TABLE IF EXISTS " + DRAFT_TABLE_NAME + ";");
onCreate(db);
}
}
} }

View file

@ -204,8 +204,9 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
statusFragment.getView().setVisibility(View.GONE); statusFragment.getView().setVisibility(View.GONE);
findViewById(R.id.fragmentContainer).setPadding(0, 0, 0, 0); findViewById(R.id.fragmentContainer).setPadding(0, 0, 0, 0);
} }
private void showStatusBar() { private void showStatusBar() {
if (statusFragment == null) { if (statusFragment == null || statusFragment.isVisible()) {
return; return;
} }
@ -624,9 +625,13 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
return statusFragment; return statusFragment;
} }
public ArrayList<String> getChatList() { public List<String> getChatList() {
return getChatStorage().getChatList(); return getChatStorage().getChatList();
} }
public List<String> getDraftChatList() {
return getChatStorage().getDrafts();
}
public List<ChatMessage> getChatMessages(String correspondent) { public List<ChatMessage> getChatMessages(String correspondent) {
return getChatStorage().getMessages(correspondent); return getChatStorage().getMessages(correspondent);
@ -636,6 +641,10 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
getChatStorage().removeDiscussion(sipUri); getChatStorage().removeDiscussion(sipUri);
} }
public void removeFromDrafts(String sipUri) {
getChatStorage().deleteDraft(sipUri);
}
@Override @Override
public void onMessageReceived(LinphoneAddress from, LinphoneChatMessage message) { public void onMessageReceived(LinphoneAddress from, LinphoneChatMessage message) {
String textMessage = message.getMessage(); String textMessage = message.getMessage();
@ -667,10 +676,12 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
} }
public int onMessageSent(String to, String message) { public int onMessageSent(String to, String message) {
getChatStorage().deleteDraft(to);
return getChatStorage().saveMessage("", to, message); return getChatStorage().saveMessage("", to, message);
} }
public int onMessageSent(String to, Bitmap image, String imageURL) { public int onMessageSent(String to, Bitmap image, String imageURL) {
getChatStorage().deleteDraft(to);
return getChatStorage().saveMessage("", to, image); return getChatStorage().saveMessage("", to, image);
} }