From d4a1192af79fbe057ffb3fee90caad5438b47f70 Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Tue, 27 Mar 2018 17:44:42 +0200 Subject: [PATCH] Implements day change messages --- .../ui/chat/messages/MessageAdapter.kt | 10 ++- .../ui/chat/messages/MessageListFragment.kt | 12 ++- .../chat/messages/QuasselMessageRenderer.kt | 38 ++++++--- .../layout/widget_chatmessage_daychange.xml | 36 +++++++++ .../persistence/QuasselDatabase.kt | 81 ++++++++++++++++++- 5 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 app/src/main/res/layout/widget_chatmessage_daychange.xml diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt index e1b60e6b4..5814c3932 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt @@ -104,13 +104,15 @@ class MessageAdapter( expansionListener: ((QuasselDatabase.DatabaseMessage) -> Unit)? = null ) : RecyclerView.ViewHolder(itemView) { @BindView(R.id.time) - lateinit var time: TextView + @JvmField + var time: TextView? = null @BindView(R.id.content) lateinit var content: TextView @BindView(R.id.markerline) - lateinit var markerline: View + @JvmField + var markerline: View? = null private var message: FormattedMessage? = null @@ -142,9 +144,9 @@ class MessageAdapter( fun bind(message: FormattedMessage) { this.message = message - time.text = message.time + time?.text = message.time content.text = message.content - markerline.visibleIf(message.isMarkerLine) + markerline?.visibleIf(message.isMarkerLine) this.itemView.isSelected = message.isSelected } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt index e6a55ceef..91ae8ed45 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt @@ -20,6 +20,7 @@ import de.kuschku.libquassel.quassel.syncables.BufferSyncer import de.kuschku.libquassel.util.helpers.value import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.persistence.QuasselDatabase +import de.kuschku.quasseldroid.persistence.findByBufferIdPagedWithDayChange import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.BacklogSettings import de.kuschku.quasseldroid.util.helper.* @@ -126,8 +127,7 @@ class MessageListFragment : ServiceBoundFragment() { private val boundaryCallback = object : PagedList.BoundaryCallback<DisplayMessage>() { override fun onItemAtFrontLoaded(itemAtFront: DisplayMessage) = Unit - override fun onItemAtEndLoaded(itemAtEnd: DisplayMessage) = - loadMore(lastMessageId = itemAtEnd.content.messageId) + override fun onItemAtEndLoaded(itemAtEnd: DisplayMessage) = loadMore() } override fun onCreateView( @@ -162,6 +162,9 @@ class MessageListFragment : ServiceBoundFragment() { messageList.layoutManager = linearLayoutManager messageList.itemAnimator = null messageList.setItemViewCacheSize(20) + messageList.addItemDecoration(object : RecyclerView.ItemDecoration() { + + }) var isScrolling = false messageList.addOnScrollListener( @@ -189,8 +192,9 @@ class MessageListFragment : ServiceBoundFragment() { viewModel.markerLine) .toLiveData().switchMapNotNull { (buffer, selected, expanded, markerLine) -> database.filtered().listen(accountId, buffer).switchMapNotNull { filtered -> + LivePagedListBuilder( - database.message().findByBufferIdPaged(buffer, filtered).map { + database.message().findByBufferIdPagedWithDayChange(buffer, filtered).map { DisplayMessage( content = it, isSelected = selected.contains(it.messageId), @@ -307,4 +311,4 @@ class MessageListFragment : ServiceBoundFragment() { } } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt index 5aff45b92..597b8246c 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt @@ -26,6 +26,7 @@ import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage import org.intellij.lang.annotations.Language import org.threeten.bp.ZoneId import org.threeten.bp.format.DateTimeFormatter +import org.threeten.bp.format.FormatStyle import javax.inject.Inject class QuasselMessageRenderer @Inject constructor( @@ -36,6 +37,8 @@ class QuasselMessageRenderer @Inject constructor( timePattern(appearanceSettings.showSeconds, appearanceSettings.use24hClock) ) + private val dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) + val monospaceItalic = Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC) private fun timePattern(showSeconds: Boolean, @@ -52,14 +55,15 @@ class QuasselMessageRenderer @Inject constructor( private val zoneId = ZoneId.systemDefault() override fun layout(type: Message_Type?, hasHighlight: Boolean) = when (type) { - Notice -> R.layout.widget_chatmessage_notice - Server -> R.layout.widget_chatmessage_server - Error -> R.layout.widget_chatmessage_error - Action -> R.layout.widget_chatmessage_action - Plain -> R.layout.widget_chatmessage_plain - Nick, Mode, Join, Part, Quit, Kick, Kill, Info, DayChange, Topic, NetsplitJoin, NetsplitQuit, - Invite -> R.layout.widget_chatmessage_info - else -> R.layout.widget_chatmessage_placeholder + Notice -> R.layout.widget_chatmessage_notice + Server -> R.layout.widget_chatmessage_server + Error -> R.layout.widget_chatmessage_error + Action -> R.layout.widget_chatmessage_action + Plain -> R.layout.widget_chatmessage_plain + Nick, Mode, Join, Part, Quit, Kick, Kill, Info, Topic, NetsplitJoin, NetsplitQuit, + Invite -> R.layout.widget_chatmessage_info + DayChange -> R.layout.widget_chatmessage_daychange + else -> R.layout.widget_chatmessage_placeholder } override fun init(viewHolder: MessageAdapter.QuasselMessageViewHolder, @@ -69,7 +73,7 @@ class QuasselMessageRenderer @Inject constructor( viewHolder.itemView.context.theme.styledAttributes( R.attr.colorForegroundHighlight, R.attr.colorBackgroundHighlight ) { - viewHolder.time.setTextColor(getColor(0, 0)) + viewHolder.time?.setTextColor(getColor(0, 0)) viewHolder.content.setTextColor(getColor(0, 0)) viewHolder.itemView.setBackgroundColor(getColor(1, 0)) } @@ -83,7 +87,7 @@ class QuasselMessageRenderer @Inject constructor( } } val textSize = appearanceSettings.textSize.toFloat() - viewHolder.time.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) + viewHolder.time?.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) viewHolder.content.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) } @@ -322,7 +326,7 @@ class QuasselMessageRenderer @Inject constructor( } Message_Type.Server, Message_Type.Info, - Message_Type.Error -> FormattedMessage( + Message_Type.Error -> FormattedMessage( message.content.messageId, timeFormatter.format(message.content.time.atZone(zoneId)), formatContent(context, message.content.content, highlight), @@ -330,7 +334,7 @@ class QuasselMessageRenderer @Inject constructor( isExpanded = message.isExpanded, isSelected = message.isSelected ) - Message_Type.Topic -> FormattedMessage( + Message_Type.Topic -> FormattedMessage( message.content.messageId, timeFormatter.format(message.content.time.atZone(zoneId)), formatContent(context, message.content.content, highlight), @@ -338,7 +342,15 @@ class QuasselMessageRenderer @Inject constructor( isExpanded = message.isExpanded, isSelected = message.isSelected ) - else -> FormattedMessage( + DayChange -> FormattedMessage( + message.content.messageId, + "", + dateFormatter.format(message.content.time.atZone(zoneId)), + isMarkerLine = false, + isExpanded = false, + isSelected = false + ) + else -> FormattedMessage( message.content.messageId, timeFormatter.format(message.content.time.atZone(zoneId)), SpanFormatter.format( diff --git a/app/src/main/res/layout/widget_chatmessage_daychange.xml b/app/src/main/res/layout/widget_chatmessage_daychange.xml new file mode 100644 index 000000000..9b5338654 --- /dev/null +++ b/app/src/main/res/layout/widget_chatmessage_daychange.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/backgroundMenuItem" + android:orientation="vertical" + android:textAppearance="?android:attr/textAppearanceListItemSmall"> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="?colorDivider" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingBottom="@dimen/message_vertical" + android:paddingEnd="@dimen/message_horizontal" + android:paddingLeft="@dimen/message_horizontal" + android:paddingRight="@dimen/message_horizontal" + android:paddingStart="@dimen/message_horizontal" + android:paddingTop="@dimen/message_vertical"> + + <TextView + android:id="@+id/content" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:gravity="center" + android:textColor="?attr/colorForeground" + android:textStyle="bold" + tools:text="27.03.2018" /> + </LinearLayout> +</LinearLayout> \ No newline at end of file diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt index 9f3645142..274e2465f 100644 --- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt +++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt @@ -2,7 +2,9 @@ package de.kuschku.quasseldroid.persistence import android.arch.lifecycle.LiveData import android.arch.paging.DataSource +import android.arch.persistence.db.SimpleSQLiteQuery import android.arch.persistence.db.SupportSQLiteDatabase +import android.arch.persistence.db.SupportSQLiteQuery import android.arch.persistence.room.* import android.arch.persistence.room.migration.Migration import android.content.Context @@ -60,6 +62,15 @@ abstract class QuasselDatabase : RoomDatabase() { ) fun findByBufferIdPaged(bufferId: Int, type: Int): DataSource.Factory<Int, DatabaseMessage> + @RawQuery(observedEntities = [DatabaseMessage::class]) + fun findMessagesRawPaged(query: SupportSQLiteQuery): DataSource.Factory<Int, DatabaseMessage> + + @RawQuery + fun findDaysRaw(query: SupportSQLiteQuery): List<Instant> + + @RawQuery + fun findMessagesRaw(query: SupportSQLiteQuery): List<DatabaseMessage> + @Query("SELECT * FROM message WHERE bufferId = :bufferId ORDER BY messageId DESC LIMIT 1") fun findLastByBufferId(bufferId: Int): DatabaseMessage? @@ -163,4 +174,72 @@ fun QuasselDatabase.MessageDao.clearMessages( idRange: kotlin.ranges.IntRange ) { this.clearMessages(bufferId, idRange.first, idRange.last) -} \ No newline at end of file +} + +fun QuasselDatabase.MessageDao.findByBufferIdPagedWithDayChange(bufferId: Int, type: Int) = + this.findMessagesRawPaged(SimpleSQLiteQuery(""" +SELECT t.* +FROM + ( + SELECT + messageId, + time, + type, + flag, + bufferId, + sender, + senderPrefixes, + content + FROM message + WHERE bufferId = ? + AND type & ~? > 0 + UNION ALL + SELECT DISTINCT + strftime('%s', date(datetime(time / 1000, 'unixepoch')), 'utc') * -1000 AS messageId, + strftime('%s', date(datetime(time / 1000, 'unixepoch')), 'utc') * 1000 AS time, + 8192 AS type, + 0 AS flag, + ? AS bufferId, + '' AS sender, + '' AS senderPrefixes, + '' AS content + FROM message + WHERE bufferId = ? + AND type & ~? > 0 + ) t +ORDER BY time DESC + """, arrayOf(bufferId, type, bufferId, bufferId, type))) + +fun QuasselDatabase.MessageDao.findByBufferIdWithDayChange(bufferId: Int, type: Int) = + this.findMessagesRaw(SimpleSQLiteQuery(""" +SELECT t.* +FROM + ( + SELECT + messageId, + time, + type, + flag, + bufferId, + sender, + senderPrefixes, + content + FROM message + WHERE bufferId = ? + AND type & ~? > 0 + UNION ALL + SELECT DISTINCT + strftime('%s', date(datetime(time / 1000, 'unixepoch'))) * -1000 AS messageId, + strftime('%s', date(datetime(time / 1000, 'unixepoch'))) * 1000 AS time, + 8192 AS type, + 0 AS flag, + ? AS bufferId, + '' AS sender, + '' AS senderPrefixes, + '' AS content + FROM message + WHERE bufferId = ? + AND type & ~? > 0 + ) t +ORDER BY time DESC + """, arrayOf(bufferId, type, bufferId, bufferId, type))) \ No newline at end of file -- GitLab