2019-07-08 13:52:41 +10:00
|
|
|
// Copyright 2019 miruka
|
|
|
|
// This file is part of harmonyqml, licensed under LGPLv3.
|
|
|
|
|
2019-07-24 16:14:34 +10:00
|
|
|
|
|
|
|
function hsluv(hue, saturation, lightness, alpha=1.0) {
|
|
|
|
let rgb = py.call_sync("APP.backend.hsluv", [hue, saturation, lightness])
|
|
|
|
return Qt.rgba(rgb[0], rgb[1], rgb[2], alpha)
|
|
|
|
}
|
2019-07-18 18:38:22 +10:00
|
|
|
|
2019-07-18 15:27:14 +10:00
|
|
|
|
|
|
|
function hsl(hue, saturation, lightness) {
|
2019-07-18 17:35:30 +10:00
|
|
|
return hsla(hue, saturation, lightness)
|
2019-07-18 15:27:14 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-18 17:35:30 +10:00
|
|
|
function hsla(hue, saturation, lightness, alpha=1.0) {
|
2019-07-18 15:27:14 +10:00
|
|
|
// Convert standard hsla(0-360, 1-100, 1-100, 0-1) to Qt format
|
|
|
|
return Qt.hsla(hue / 360, saturation / 100, lightness / 100, alpha)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-18 18:46:37 +10:00
|
|
|
function arrayToModelItem(keysName, array) {
|
2019-07-06 09:54:16 +10:00
|
|
|
// Convert an array to an object suitable to be in a model, example:
|
2019-07-18 18:46:37 +10:00
|
|
|
// [1, 2, 3] → [{keysName: 1}, {keysName: 2}, {keysName: 3}]
|
2019-07-18 19:18:13 +10:00
|
|
|
let items = []
|
2019-07-06 09:54:16 +10:00
|
|
|
|
2019-07-18 19:18:13 +10:00
|
|
|
for (let item of array) {
|
|
|
|
let obj = {}
|
|
|
|
obj[keysName] = item
|
2019-07-06 09:54:16 +10:00
|
|
|
items.push(obj)
|
|
|
|
}
|
|
|
|
return items
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-04 12:31:29 +10:00
|
|
|
function hueFrom(string) {
|
2019-07-24 16:14:34 +10:00
|
|
|
// Calculate and return a unique hue between 0 and 360 for the string
|
2019-07-18 19:18:13 +10:00
|
|
|
let hue = 0
|
|
|
|
for (let i = 0; i < string.length; i++) {
|
2019-07-04 12:31:29 +10:00
|
|
|
hue += string.charCodeAt(i) * 99
|
|
|
|
}
|
2019-07-24 16:14:34 +10:00
|
|
|
return hue % 360
|
2019-07-04 12:31:29 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-05 06:56:34 +10:00
|
|
|
function nameColor(name) {
|
2019-07-24 16:14:34 +10:00
|
|
|
return hsl(
|
2019-07-04 12:31:29 +10:00
|
|
|
hueFrom(name),
|
2019-07-24 16:14:34 +10:00
|
|
|
theme.controls.displayName.saturation,
|
|
|
|
theme.controls.displayName.lightness,
|
2019-07-04 12:31:29 +10:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-18 18:46:37 +10:00
|
|
|
function coloredNameHtml(name, userId, displayText=null) {
|
2019-07-07 14:24:23 +10:00
|
|
|
// substring: remove leading @
|
2019-07-18 18:46:37 +10:00
|
|
|
return "<font color='" + nameColor(name || userId.substring(1)) + "'>" +
|
|
|
|
escapeHtml(displayText || name || userId) +
|
2019-07-05 06:56:34 +10:00
|
|
|
"</font>"
|
2019-07-04 14:24:21 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-04 12:31:29 +10:00
|
|
|
function escapeHtml(string) {
|
|
|
|
// Replace special HTML characters by encoded alternatives
|
|
|
|
return string.replace("&", "&")
|
|
|
|
.replace("<", "<")
|
|
|
|
.replace(">", ">")
|
|
|
|
.replace('"', """)
|
|
|
|
.replace("'", "'")
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-20 13:07:26 +10:00
|
|
|
function processedEventText(ev) {
|
|
|
|
if (ev.eventType == "RoomMessageEmote") {
|
|
|
|
let name = users.find(ev.senderId).displayName
|
|
|
|
return "<i>" + coloredNameHtml(name) + " " + ev.content + "</i>"
|
|
|
|
}
|
2019-07-04 14:24:21 +10:00
|
|
|
|
2019-07-20 13:07:26 +10:00
|
|
|
if (ev.eventType.startsWith("RoomMessage")) { return ev.content }
|
2019-07-04 12:31:29 +10:00
|
|
|
|
2019-07-18 19:18:13 +10:00
|
|
|
let name = users.find(ev.senderId).displayName
|
2019-07-20 13:07:26 +10:00
|
|
|
let text = qsTr(ev.content).arg(coloredNameHtml(name, ev.senderId))
|
2019-07-04 12:31:29 +10:00
|
|
|
|
2019-07-20 13:07:26 +10:00
|
|
|
if (text.includes("%2") && ev.targetUserId) {
|
2019-07-18 19:18:13 +10:00
|
|
|
let tname = users.find(ev.targetUserId).displayName
|
2019-07-20 13:07:26 +10:00
|
|
|
text = text.arg(coloredNameHtml(tname, ev.targetUserId))
|
2019-07-04 12:31:29 +10:00
|
|
|
}
|
|
|
|
|
2019-07-20 13:07:26 +10:00
|
|
|
return text
|
2019-07-04 12:31:29 +10:00
|
|
|
}
|
2019-07-07 19:49:02 +10:00
|
|
|
|
|
|
|
|
|
|
|
function filterMatches(filter, text) {
|
|
|
|
filter = filter.toLowerCase()
|
|
|
|
text = text.toLowerCase()
|
|
|
|
|
2019-07-18 19:18:13 +10:00
|
|
|
let words = filter.split(" ")
|
2019-07-07 19:49:02 +10:00
|
|
|
|
2019-07-18 19:18:13 +10:00
|
|
|
for (let word of words) {
|
|
|
|
if (word && ! text.includes(word)) {
|
2019-07-07 19:49:02 +10:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2019-07-14 10:15:20 +10:00
|
|
|
|
|
|
|
|
|
|
|
function thumbnailParametersFor(width, height) {
|
|
|
|
// https://matrix.org/docs/spec/client_server/latest#thumbnails
|
|
|
|
|
|
|
|
if (width > 640 || height > 480)
|
|
|
|
return {width: 800, height: 600, fillMode: Image.PreserveAspectFit}
|
|
|
|
|
|
|
|
if (width > 320 || height > 240)
|
|
|
|
return {width: 640, height: 480, fillMode: Image.PreserveAspectFit}
|
|
|
|
|
|
|
|
if (width > 96 || height > 96)
|
|
|
|
return {width: 320, height: 240, fillMode: Image.PreserveAspectFit}
|
|
|
|
|
|
|
|
if (width > 32 || height > 32)
|
|
|
|
return {width: 96, height: 96, fillMode: Image.PreserveAspectCrop}
|
|
|
|
|
|
|
|
return {width: 32, height: 32, fillMode: Image.PreserveAspectCrop}
|
|
|
|
}
|
2019-07-20 13:07:26 +10:00
|
|
|
|
|
|
|
|
|
|
|
function minutesBetween(date1, date2) {
|
|
|
|
return Math.round((((date2 - date1) % 86400000) % 3600000) / 60000)
|
|
|
|
}
|