Use CursorAdapter for messages so all messages can be viewed.
This commit is contained in:
parent
6ec9b949c5
commit
0aeb82553a
6 changed files with 76 additions and 55 deletions
|
@ -17,7 +17,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:stackFromBottom="true"
|
||||
android:transcriptMode="normal"
|
||||
android:transcriptMode="alwaysScroll"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="5dp"
|
||||
android:layout_marginBottom="2dip"/>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/root"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
|
|
|
@ -52,8 +52,8 @@ class ChatFragment extends ListFragment with OnClickListener {
|
|||
|
||||
database.getContact(address).foreach(c => getActivity.setTitle(c.name))
|
||||
|
||||
adapter = new DatesAdapter(getActivity, new MessagesAdapter(getActivity, address))
|
||||
database.getMessages(address, 15).foreach(adapter.add)
|
||||
adapter = new DatesAdapter(getActivity,
|
||||
new MessagesAdapter(getActivity, database.getMessagesCursor(address, None), address))
|
||||
|
||||
if (listView != null) {
|
||||
listView.setAdapter(adapter)
|
||||
|
@ -124,7 +124,8 @@ class ChatFragment extends ListFragment with OnClickListener {
|
|||
return
|
||||
|
||||
msg.body match {
|
||||
case _: Text => adapter.add(msg)
|
||||
case _: Text =>
|
||||
adapter.changeCursor(database.getMessagesCursor(address, None))
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.nutomic.ensichat.util
|
|||
import java.util.Date
|
||||
|
||||
import android.content.{Intent, ContentValues, Context}
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.{SQLiteDatabase, SQLiteOpenHelper}
|
||||
import android.support.v4.content.LocalBroadcastManager
|
||||
import com.nutomic.ensichat.protocol._
|
||||
|
@ -37,6 +38,18 @@ object Database {
|
|||
"name TEXT NOT NULL," +
|
||||
"status TEXT NOT NULL)"
|
||||
|
||||
def messageFromCursor(c: Cursor): Message = {
|
||||
val header = new ContentHeader(new Address(
|
||||
c.getString(c.getColumnIndex("origin"))),
|
||||
new Address(c.getString(c.getColumnIndex("target"))),
|
||||
-1,
|
||||
Text.Type,
|
||||
c.getLong(c.getColumnIndex("message_id")),
|
||||
new Date(c.getLong(c.getColumnIndex("date"))))
|
||||
val body = new Text(new String(c.getString(c.getColumnIndex ("text"))))
|
||||
new Message(header, body)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,25 +63,21 @@ class Database(context: Context)
|
|||
db.execSQL(Database.CreateMessagesTable)
|
||||
}
|
||||
|
||||
def getMessagesCursor(address: Address, count: Option[Int]): Cursor = {
|
||||
getReadableDatabase.query(true,
|
||||
"messages", Array("_id", "origin", "target", "message_id", "text", "date"),
|
||||
"origin = ? OR target = ?", Array(address.toString, address.toString),
|
||||
null, null, "date ASC", count.map(_.toString).orNull)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the count last messages for device.
|
||||
*/
|
||||
def getMessages(address: Address, count: Int): SortedSet[Message] = {
|
||||
val c = getReadableDatabase.query(true,
|
||||
"messages", Array("origin", "target", "message_id", "text", "date"),
|
||||
"origin = ? OR target = ?", Array(address.toString, address.toString),
|
||||
null, null, "date DESC", count.toString)
|
||||
val c = getMessagesCursor(address, Option(count))
|
||||
var messages = new TreeSet[Message]()(Message.Ordering)
|
||||
while (c.moveToNext()) {
|
||||
val header = new ContentHeader(new Address(
|
||||
c.getString(c.getColumnIndex("origin"))),
|
||||
new Address(c.getString(c.getColumnIndex("target"))),
|
||||
-1,
|
||||
Text.Type,
|
||||
c.getLong(c.getColumnIndex("message_id")),
|
||||
new Date(c.getLong(c.getColumnIndex("date"))))
|
||||
val body = new Text(new String(c.getString(c.getColumnIndex ("text"))))
|
||||
messages += new Message(header, body)
|
||||
messages += Database.messageFromCursor(c)
|
||||
}
|
||||
c.close()
|
||||
messages
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
package com.nutomic.ensichat.views
|
||||
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import com.mobsandgeeks.adapters.{Sectionizer, SimpleSectionAdapter}
|
||||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.protocol.Message
|
||||
import com.nutomic.ensichat.protocol.header.ContentHeader
|
||||
import com.nutomic.ensichat.util.Database
|
||||
|
||||
object DatesAdapter {
|
||||
|
||||
private val Sectionizer = new Sectionizer[Message]() {
|
||||
override def getSectionTitleForItem(item: Message): String = {
|
||||
private val Sectionizer = new Sectionizer[Cursor]() {
|
||||
override def getSectionTitleForItem(item: Cursor): String = {
|
||||
DateFormat
|
||||
.getDateInstance(DateFormat.MEDIUM)
|
||||
.format(item.header.asInstanceOf[ContentHeader].time)
|
||||
.format(Database.messageFromCursor(item).header.asInstanceOf[ContentHeader].time)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,11 +27,11 @@ object DatesAdapter {
|
|||
* Wraps [[MessagesAdapter]] and shows date between messages.
|
||||
*/
|
||||
class DatesAdapter(context: Context, messagesAdapter: MessagesAdapter)
|
||||
extends SimpleSectionAdapter[Message](context, messagesAdapter, R.layout.item_date, R.id.date,
|
||||
extends SimpleSectionAdapter[Cursor](context, messagesAdapter, R.layout.item_date, R.id.date,
|
||||
DatesAdapter.Sectionizer) {
|
||||
|
||||
def add(message: Message): Unit = {
|
||||
messagesAdapter.add(message)
|
||||
def changeCursor(cursor: Cursor): Unit = {
|
||||
messagesAdapter.changeCursor(cursor)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,57 +1,64 @@
|
|||
package com.nutomic.ensichat.views
|
||||
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
|
||||
import android.content.Context
|
||||
import android.view.{Gravity, LayoutInflater, View, ViewGroup}
|
||||
import android.widget.{ArrayAdapter, LinearLayout, TextView}
|
||||
import android.database.Cursor
|
||||
import android.view._
|
||||
import android.widget._
|
||||
import com.mobsandgeeks.adapters.{SimpleSectionAdapter, ViewHandler, InstantCursorAdapter}
|
||||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.protocol.body.Text
|
||||
import com.nutomic.ensichat.protocol.header.ContentHeader
|
||||
import com.nutomic.ensichat.protocol.{Address, Message}
|
||||
import com.nutomic.ensichat.util.Database
|
||||
|
||||
/**
|
||||
* Displays [[Message]]s in ListView.
|
||||
*
|
||||
* We just use the instant adapter for compatibility with [[SimpleSectionAdapter]], but don't use
|
||||
* the annotations (as it breaks separation of presentation and content).
|
||||
*/
|
||||
class MessagesAdapter(context: Context, remoteAddress: Address) extends
|
||||
ArrayAdapter[Message](context, 0, 0) {
|
||||
class MessagesAdapter(context: Context, cursor: Cursor, remoteAddress: Address) extends
|
||||
InstantCursorAdapter[Message](context, R.layout.item_message, classOf[Message], cursor) {
|
||||
|
||||
/**
|
||||
* Free space to the right/left to a message depending on who sent it, in dip.
|
||||
*/
|
||||
private val MessageMargin = 50
|
||||
|
||||
override def getView(position: Int, convertView: View, parent: ViewGroup): View = {
|
||||
val view =
|
||||
if (convertView != null)
|
||||
convertView.asInstanceOf[LinearLayout]
|
||||
else
|
||||
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
|
||||
.asInstanceOf[LayoutInflater]
|
||||
.inflate(R.layout.item_message, parent, false)
|
||||
.asInstanceOf[LinearLayout]
|
||||
val text = view.findViewById(R.id.text).asInstanceOf[TextView]
|
||||
val time = view.findViewById(R.id.time).asInstanceOf[TextView]
|
||||
setViewHandler(R.id.root, new ViewHandler[Message] {
|
||||
override def handleView(adapter: ListAdapter, parent: View, view: View, msg: Message,
|
||||
position: Int): Unit = {
|
||||
val root = view.asInstanceOf[LinearLayout]
|
||||
val container = view.findViewById(R.id.container).asInstanceOf[LinearLayout]
|
||||
val text = view.findViewById(R.id.text).asInstanceOf[TextView]
|
||||
val time = view.findViewById(R.id.time).asInstanceOf[TextView]
|
||||
|
||||
val msg = getItem(position)
|
||||
text.setText(msg.body.asInstanceOf[Text].text)
|
||||
time.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(msg.header.asInstanceOf[ContentHeader].time))
|
||||
text.setText(msg.body.asInstanceOf[Text].text)
|
||||
val formattedDate = DateFormat
|
||||
.getTimeInstance(DateFormat.SHORT)
|
||||
.format(msg.header.asInstanceOf[ContentHeader].time)
|
||||
time.setText(formattedDate)
|
||||
|
||||
val lp = new LinearLayout.LayoutParams(view.getLayoutParams)
|
||||
val margin = (MessageMargin * context.getResources.getDisplayMetrics.density).toInt
|
||||
val container = view.findViewById(R.id.container).asInstanceOf[LinearLayout]
|
||||
if (getItem(position).header.origin != remoteAddress) {
|
||||
container.setGravity(Gravity.RIGHT)
|
||||
view.setGravity(Gravity.RIGHT)
|
||||
lp.setMargins(margin, 0, 0, 0)
|
||||
} else {
|
||||
container.setGravity(Gravity.LEFT)
|
||||
view.setGravity(Gravity.LEFT)
|
||||
lp.setMargins(0, 0, margin, 0)
|
||||
val lp = new LinearLayout.LayoutParams(view.getLayoutParams)
|
||||
val margin = (MessageMargin * context.getResources.getDisplayMetrics.density).toInt
|
||||
if (msg.header.origin != remoteAddress) {
|
||||
container.setGravity(Gravity.RIGHT)
|
||||
root.setGravity(Gravity.RIGHT)
|
||||
lp.setMargins(margin, 0, 0, 0)
|
||||
} else {
|
||||
container.setGravity(Gravity.LEFT)
|
||||
root.setGravity(Gravity.LEFT)
|
||||
lp.setMargins(0, 0, margin, 0)
|
||||
}
|
||||
view.setLayoutParams(lp)
|
||||
|
||||
view
|
||||
}
|
||||
view.setLayoutParams(lp)
|
||||
})
|
||||
|
||||
view
|
||||
}
|
||||
override def getInstance (cursor: Cursor) = Database.messageFromCursor(cursor)
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue