diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Buffer.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Buffer.kt index c054f743..40d67945 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Buffer.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Buffer.kt @@ -25,6 +25,7 @@ class Buffer @WorkerThread constructor( @JvmField var shortName: String = "" @JvmField var hidden: Boolean = false @JvmField var type = BufferSpec.Type.Other + @JvmField var displayDayChange: Boolean = false private var notify: Notify = Notify.default @@ -34,6 +35,7 @@ class Buffer @WorkerThread constructor( internal var updateHidden = false internal var updateType = false internal var updateNotifyLevel = false + internal var updateDayChange = false var number: Int by updatable(::updateName, this@Buffer::number) var fullName: String by updatable(::updateName, this@Buffer::fullName) @@ -42,6 +44,7 @@ class Buffer @WorkerThread constructor( var hidden: Boolean by updatable(::updateHidden) var type: BufferSpec.Type by updatable(::updateType) var notify: Notify? by updatable(::updateNotifyLevel) + var displayDayChange: Boolean by updatable(::updateDayChange) } fun update(block: Updater.() -> Unit) { @@ -65,6 +68,7 @@ class Buffer @WorkerThread constructor( if (updater.updateNotifyLevel) notify = updater.notify ?: Notify.default if (updater.updateHidden) hidden = updater.hidden if (updater.updateType) type = updater.type + if (updater.updateDayChange) displayDayChange = updater.displayDayChange } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -215,7 +219,7 @@ class Buffer @WorkerThread constructor( } synchronized(this) { - lines.replaceLines(newLines) + lines.replaceLines(newLines, displayDayChange) } } @@ -227,7 +231,7 @@ class Buffer @WorkerThread constructor( val notifyPmOrMessage = line.notifyLevel == LineSpec.NotifyLevel.Message || notifyPm synchronized(this) { - lines.addLast(line) + lines.addLast(line, displayDayChange) // notify levels: 0 none 1 highlight 2 message 3 all // treat hidden lines and lines that are not supposed to generate a “notification” as read diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Lines.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Lines.kt index fc128e20..82478788 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Lines.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Lines.kt @@ -8,6 +8,11 @@ import com.ubergeek42.WeechatAndroid.utils.Linkify import com.ubergeek42.WeechatAndroid.utils.Utils import com.ubergeek42.WeechatAndroid.utils.invalidatableLazy import com.ubergeek42.weechat.Color +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle import java.util.* import kotlin.properties.Delegates.observable @@ -46,6 +51,13 @@ class Lines { var maxUnfilteredSize = P.lineIncrement private set + private var dateOfLastUnfilteredLine: LocalDate? = null + private var dateOfLastFilteredLine: LocalDate? = null + + private var lastOldDate: LocalDate? = null + private lateinit var lastNewDate: LocalDate + private lateinit var lastDateLine: Line + // after reconnecting, in *full sync mode*, we are receiving and adding new lines to buffers. // there can be inconsistencies; if some lines were added while we were offline, // we can't display them, but can display what's on top and what's on bottom. @@ -87,20 +99,70 @@ class Lines { // in very rare cases status might not be FETCHING here, particularly when closing buffers // while the app is connecting and has already requested lines - fun replaceLines(lines: Collection) { + fun replaceLines(lines: Collection, displayDayChange: Boolean) { if (status != Status.Fetching) return unfiltered.clear() filtered.clear() - unfiltered.addAll(lines) + dateOfLastUnfilteredLine = null + dateOfLastFilteredLine = null + for (line in lines) { - if (line.isVisible) filtered.add(line) + addLast(line, displayDayChange) } } - fun addLast(line: Line) { + private fun makeDateChangeLine(oldDate: LocalDate?, newDate: LocalDate) : Line { + val tstamp = newDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond() * 1000 + var msg = newDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)) + if (oldDate != null && oldDate.plusDays(1) != newDate) { + msg += " (" + + oldDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)) + + ")" + } + msg += " --" + + var datePointer = MAX_C_POINTER_VALUE shl 2 + newDate.getYear() shl 32 + + newDate.getDayOfYear() shl 20 + if (oldDate != null) { + datePointer += oldDate.getYear() shl 16 + oldDate.getDayOfYear() + } + return Line(datePointer, LineSpec.Type.Other, tstamp, "--", msg, + nick = null, isVisible = true, isHighlighted = false, + LineSpec.DisplayAs.Unspecified, LineSpec.NotifyLevel.Low) + } + + private fun obtainDateChangeLine(oldDate: LocalDate?, newDate: LocalDate) : Line { + if (oldDate == null || lastOldDate != oldDate || lastNewDate != newDate) { + lastDateLine = makeDateChangeLine(oldDate, newDate) + lastOldDate = oldDate + lastNewDate = newDate + } + return lastDateLine + } + + fun addLast(line: Line, displayDayChange: Boolean) { + if(displayDayChange) { + val newDate = Instant.ofEpochSecond(line.timestamp / 1000) + .atZone(ZoneId.systemDefault()) + .toLocalDate() + + if (dateOfLastUnfilteredLine != newDate) { + unfiltered.addLast(obtainDateChangeLine(dateOfLastUnfilteredLine, newDate)) + dateOfLastUnfilteredLine = newDate + skipUnfiltered++ + } + + if (line.isVisible && dateOfLastFilteredLine != newDate) { + filtered.addLast(obtainDateChangeLine(dateOfLastFilteredLine, newDate)) + dateOfLastFilteredLine = newDate + skipFiltered++ + } + } + if (shouldAddSquiggleOnNewLine) { shouldAddSquiggleOnNewLine = false - if (status == Status.Init && unfiltered.size > 0) addLast(SquiggleLine()) // invisible + if (status == Status.Init && unfiltered.size > 0) + addLast(SquiggleLine(), false) // invisible } if (shouldAddSquiggleOnNewVisibleLine && line.isVisible) { diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Spec.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Spec.kt index 7559ac4f..191c3d45 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Spec.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Spec.kt @@ -39,6 +39,7 @@ enum class Notify(val value: Int) { inline val notify: Notify? get() = Notify::value.find(entry.getIntOrNull("notify")) inline val type get() = Type.fromLocalVariables(entry.getHashtable("local_variables")) inline val hidden get() = entry.getIntOrNull("hidden") == 1 + inline val displayDayChange get() = entry.getIntOrNull("day_change") == 1 // todo get rid of openWhileRunning fun toBuffer(openWhileRunning: Boolean) = Buffer(pointer).apply { @@ -50,6 +51,7 @@ enum class Notify(val value: Int) { notify = this@BufferSpec.notify hidden = this@BufferSpec.hidden type = this@BufferSpec.type + displayDayChange = this@BufferSpec.displayDayChange } if (P.isBufferOpen(pointer)) setOpen(open = true, syncHotlistOnOpen = false) @@ -67,7 +69,7 @@ enum class Notify(val value: Int) { companion object { const val listBuffersRequest = "(listbuffers) hdata buffer:gui_buffers(*) " + - "number,full_name,short_name,type,title,nicklist,local_variables,notify,hidden" + "number,full_name,short_name,type,title,nicklist,local_variables,notify,hidden,day_change" const val renumberRequest = "(renumber) hdata buffer:gui_buffers(*) number" }