Use CursorAdapter for messages so all messages can be viewed.

This commit is contained in:
Felix Ableitner 2015-08-24 23:38:55 +02:00
parent 6ec9b949c5
commit 0aeb82553a
6 changed files with 76 additions and 55 deletions

View file

@ -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"/>

View file

@ -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"

View file

@ -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 _ =>
}
}

View file

@ -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

View file

@ -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()
}

View file

@ -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)
}