174 lines
5.4 KiB
Kotlin
174 lines
5.4 KiB
Kotlin
package su.reya.coop
|
|
|
|
import kotlinx.datetime.DateTimeUnit
|
|
import kotlinx.datetime.TimeZone
|
|
import kotlinx.datetime.minus
|
|
import kotlinx.datetime.number
|
|
import kotlinx.datetime.toLocalDateTime
|
|
import rust.nostr.sdk.PublicKey
|
|
import rust.nostr.sdk.Timestamp
|
|
import rust.nostr.sdk.UnsignedEvent
|
|
import kotlin.time.Clock
|
|
import kotlin.time.Instant
|
|
|
|
enum class RoomKind {
|
|
Ongoing,
|
|
Request;
|
|
|
|
companion object {
|
|
fun default(): RoomKind = Request
|
|
}
|
|
}
|
|
|
|
data class Room(
|
|
val id: Long,
|
|
val createdAt: Timestamp,
|
|
val subject: String?,
|
|
val members: Set<PublicKey>,
|
|
val kind: RoomKind = RoomKind.default(),
|
|
val lastMessage: String? = null
|
|
) : Comparable<Room> {
|
|
override fun compareTo(other: Room): Int {
|
|
return this.createdAt.asSecs().compareTo(other.createdAt.asSecs())
|
|
}
|
|
|
|
companion object {
|
|
fun new(rumor: UnsignedEvent, userPubkey: PublicKey): Room {
|
|
val id = rumor.roomId()
|
|
val createdAt = rumor.createdAt()
|
|
val subject = rumor.tags().toVec().find { it.kind() == "subject" }?.content()
|
|
|
|
// Collect the author's public key and all public keys from tags
|
|
val pubkeys: MutableSet<PublicKey> = mutableSetOf()
|
|
pubkeys.add(rumor.author())
|
|
pubkeys.addAll(rumor.tags().publicKeys())
|
|
|
|
// Also remove the user's public key from the list, current user is always a member
|
|
if (pubkeys.size > 1 && pubkeys.contains(userPubkey)) {
|
|
pubkeys.remove(userPubkey)
|
|
}
|
|
|
|
// Create a new Room instance
|
|
return Room(
|
|
id = id,
|
|
createdAt = createdAt,
|
|
subject = subject,
|
|
members = pubkeys as Set<PublicKey>,
|
|
lastMessage = rumor.content()
|
|
)
|
|
}
|
|
}
|
|
|
|
fun setKind(kind: RoomKind): Room {
|
|
return this.copy(kind = kind)
|
|
}
|
|
|
|
fun setCreatedAt(createdAt: Timestamp): Room {
|
|
return this.copy(createdAt = createdAt)
|
|
}
|
|
|
|
fun setSubject(subject: String?): Room {
|
|
return this.copy(subject = subject)
|
|
}
|
|
|
|
fun setLastMessage(message: String?): Room {
|
|
return this.copy(lastMessage = message)
|
|
}
|
|
|
|
fun isGroup(): Boolean {
|
|
return members.size > 1
|
|
}
|
|
}
|
|
|
|
fun UnsignedEvent.roomId(): Long {
|
|
// Collect the author's public key and all public keys from tags
|
|
val pubkeys: MutableList<PublicKey> = mutableListOf()
|
|
pubkeys.add(this.author())
|
|
pubkeys.addAll(this.tags().publicKeys())
|
|
|
|
// Sort and hash the list of public keys
|
|
val sortedUniqueKeys = pubkeys
|
|
.distinctBy { it.toBech32() }
|
|
.sortedBy { it.toBech32() }
|
|
|
|
return sortedUniqueKeys.hashCode().toLong()
|
|
}
|
|
|
|
fun Timestamp.ago(): String {
|
|
val SECONDS_IN_MINUTE = 60L
|
|
val MINUTES_IN_HOUR = 60L
|
|
val HOURS_IN_DAY = 24L
|
|
val DAYS_IN_MONTH = 30L
|
|
|
|
val inputInstant = Instant.fromEpochSeconds(this.asSecs().toLong())
|
|
val now = Clock.System.now()
|
|
val duration = now - inputInstant
|
|
|
|
return when {
|
|
duration.inWholeSeconds < SECONDS_IN_MINUTE -> "Now"
|
|
duration.inWholeMinutes < MINUTES_IN_HOUR -> "${duration.inWholeMinutes}m"
|
|
duration.inWholeHours < HOURS_IN_DAY -> "${duration.inWholeHours}h"
|
|
duration.inWholeDays < DAYS_IN_MONTH -> "${duration.inWholeDays}d"
|
|
else -> {
|
|
val localDateTime = inputInstant.toLocalDateTime(TimeZone.currentSystemDefault())
|
|
val month =
|
|
localDateTime.month.name.take(3).lowercase().replaceFirstChar { it.uppercase() }
|
|
val day = localDateTime.dayOfMonth.toString().padStart(2, '0')
|
|
"$month $day"
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Timestamp.formatAsGroupHeader(): String {
|
|
val timeZone = TimeZone.currentSystemDefault()
|
|
val inputInstant = Instant.fromEpochSeconds(this.asSecs().toLong())
|
|
val inputDate = inputInstant.toLocalDateTime(timeZone).date
|
|
|
|
val now = Clock.System.now()
|
|
val today = now.toLocalDateTime(timeZone).date
|
|
val yesterday = today.minus(1, DateTimeUnit.DAY)
|
|
|
|
return when (inputDate) {
|
|
today -> "Today"
|
|
yesterday -> "Yesterday"
|
|
else -> {
|
|
val day = inputDate.day.toString().padStart(2, '0')
|
|
val month = inputDate.month.number.toString().padStart(2, '0')
|
|
val year = inputDate.year.toString().takeLast(2)
|
|
"$day/$month/$year"
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Timestamp.humanReadable(): String {
|
|
val timeZone = TimeZone.currentSystemDefault()
|
|
val inputInstant = Instant.fromEpochSeconds(this.asSecs().toLong())
|
|
val inputDateTime = inputInstant.toLocalDateTime(timeZone)
|
|
val inputDate = inputDateTime.date
|
|
|
|
val now = Clock.System.now()
|
|
val today = now.toLocalDateTime(timeZone).date
|
|
val yesterday = today.minus(1, DateTimeUnit.DAY)
|
|
|
|
val hour = inputDateTime.hour
|
|
val minute = inputDateTime.minute.toString().padStart(2, '0')
|
|
val amPm = if (hour < 12) "AM" else "PM"
|
|
val hour12 = when {
|
|
hour == 0 -> 12
|
|
hour > 12 -> hour - 12
|
|
else -> hour
|
|
}
|
|
val timeFormat = "$hour12:$minute $amPm"
|
|
|
|
return when (inputDate) {
|
|
today -> "Today at $timeFormat"
|
|
yesterday -> "Yesterday at $timeFormat"
|
|
else -> {
|
|
val day = inputDateTime.day.toString().padStart(2, '0')
|
|
val month = inputDateTime.month.number.toString().padStart(2, '0')
|
|
val year = inputDateTime.year.toString().takeLast(2)
|
|
"$day/$month/$year, $timeFormat"
|
|
}
|
|
}
|
|
}
|