...
 
Commits (2)
......@@ -15,6 +15,7 @@ Copyright: 2016-2019, Linus Jahn <lnj@kaidan.im>
2018, Marco Martin <notmart@gmail.com>
2017, probonopd <probonopd@users.noreply.github.com>
2016, Marzanna <MRZA-MRZA@users.noreply.github.com>
2017-2018, Eike Hein <hein@kde.org>
License: GPL-3+ with OpenSSL exception
Files: i18n/*
......@@ -27,6 +28,7 @@ Copyright: 2017-2018, Linus Jahn <lnj@kaidan.im>
2017, Ilya Bizyaev <bizyaev@zoho.com>
2017, ZatroxDE <zatroxde@outlook.com>
2018, aitzol berasategi <aitzol@disroot.org>
2019, ssantos <ssantos@web.de>
2018, oiseauroch <tobias.ollive@mailoo.org>
2018, Andreas Kleinert <Andy.Kleinert@gmail.com>
2017, Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
......@@ -35,12 +37,16 @@ License: GPL-3+ with OpenSSL exception
Files: src/StatusBar.cpp
src/StatusBar.h
src/singleapp/*
src/hsluv-c/*
data/images/xmpp.svg
utils/generate-license.py
Copyright: 2016, J-P Nurmi <jpnurmi@gmail.com>
2007, Raja Sandhu, XMPP Standards Foundation
2018, LNJ <git@lnj.li>
2018-2019, Linus Jahn <lnj@kaidan.im>
2015-2018, Itay Grudev <itay+github.com@grudev.com>
2015, Alexei Boronine <alexei@boronine.com>
2015, Roger Tallada <info@rogertallada.com>
2017, Martin Mitas <mity@morous.org>
License: MIT
Files: src/EmojiModel.cpp
......@@ -61,10 +67,8 @@ Comment:
Files: misc/kaidan.svg
misc/kaidan-small-margin.svg
misc/kaidan-128x128.png
data/images/fallback-avatar.svg
data/images/banner.png
Copyright: 2016-2017, Ilya Bizyaev <bizyaev@zoho.com>
2017, LNJ <git@lnj.li>
2016, MBB <mbb-mail@gmx.de>
License: CC-BY-SA-4.0
......
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<defs>
<clipPath id="a">
<path fill="#338000" d="M0 0h256v256H0z"/>
</clipPath>
</defs>
<path fill="#338000" d="M0 0h256v256H0z"/>
<path d="M99.3 130.8l57-84.8 113.5 113.5-9.2 132.6z" clip-path="url(#a)" fill="#000007" opacity=".3"/>
<path d="M173 88.4a45 54.4 0 0 1-45 54.5 45 54.4 0 0 1-45-55 45 54.4 0 0 1 45-54 45 54.4 0 0 1 45 54.3zm61 107.2a106 45 0 0 1-106 45 106 45 0 0 1-106-45 106 45 0 0 1 106-45 106 45 0 0 1 106 45z" fill="#55d400"/>
<path d="M22 195.3h212V256H22z" fill="#55d400"/>
</svg>
......@@ -23,6 +23,7 @@
<file alias="qml/elements/MediaPreviewImage.qml">src/qml/elements/MediaPreviewImage.qml</file>
<file alias="qml/elements/MediaPreviewOther.qml">src/qml/elements/MediaPreviewOther.qml</file>
<file alias="qml/elements/EmojiPicker.qml">src/qml/elements/EmojiPicker.qml</file>
<file alias="qml/elements/TextAvatar.qml">src/qml/elements/TextAvatar.qml</file>
<file alias="qtquickcontrols2.conf">misc/qtquickcontrols2.conf</file>
</qresource>
......
......@@ -29,6 +29,10 @@ set(KAIDAN_SOURCES
${CURDIR}/qxmpp-exts/QXmppHttpUploadIq.cpp
${CURDIR}/qxmpp-exts/QXmppUploadRequestManager.cpp
${CURDIR}/qxmpp-exts/QXmppUploadManager.cpp
${CURDIR}/qxmpp-exts/QXmppColorGenerator.cpp
# hsluv-c required for color generation
${CURDIR}/hsluv-c/hsluv.c
)
if (NOT ANDROID AND NOT IOS)
......
......@@ -43,6 +43,7 @@
#include <QUrl>
// QXmpp
#include <QXmppClient.h>
#include "qxmpp-exts/QXmppColorGenerator.h"
// Kaidan
#include "AvatarFileStorage.h"
#include "Database.h"
......@@ -293,6 +294,12 @@ QString Kaidan::formatMessage(QString message)
return processMsgFormatting(message.split(" "));
}
QColor Kaidan::getUserColor(QString nickName) const
{
QXmppColorGenerator::RGBColor color = QXmppColorGenerator::generateColor(nickName);
return QColor(color.red, color.green, color.blue);
}
QString Kaidan::processMsgFormatting(QStringList list, bool isFirst)
{
if (list.isEmpty())
......
......@@ -34,6 +34,7 @@
// Qt
#include <QObject>
#include <QString>
#include <QColor>
// Kaidan
#include "ClientWorker.h"
#include "Globals.h"
......@@ -263,6 +264,11 @@ public:
*/
Q_INVOKABLE QString formatMessage(QString message);
/**
* Returns a consistent user color generated from the nickname.
*/
Q_INVOKABLE QColor getUserColor(QString nickName) const;
signals:
void avatarStorageChanged();
......
This diff is collapsed.
/*
* HSLuv-C: Human-friendly HSL
* <http://github.com/hsluv/hsluv-c>
* <http://www.hsluv.org/>
*
* Copyright (c) 2015 Alexei Boronine (original idea, JavaScript implementation)
* Copyright (c) 2015 Roger Tallada (Obj-C implementation)
* Copyright (c) 2017 Martin Mitas (C implementation, based on Obj-C implementation)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef HSLUV_H
#define HSLUV_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* Convert HSLuv to RGB.
*
* @param h Hue. Between 0.0 and 360.0.
* @param s Saturation. Between 0.0 and 100.0.
* @param l Lightness. Between 0.0 and 100.0.
* @param[out] pr Red component. Between 0.0 and 1.0.
* @param[out] pr Green component. Between 0.0 and 1.0.
* @param[out] pr Blue component. Between 0.0 and 1.0.
*/
void hsluv2rgb(double h, double s, double l, double* pr, double* pg, double* pb);
/**
* Convert RGB to HSLuv.
*
* @param r Red component. Between 0.0 and 1.0.
* @param g Green component. Between 0.0 and 1.0.
* @param b Blue component. Between 0.0 and 1.0.
* @param[out] ph Hue. Between 0.0 and 360.0.
* @param[out] ps Saturation. Between 0.0 and 100.0.
* @param[out] pl Lightness. Between 0.0 and 100.0.
*/
void rgb2hsluv(double r, double g, double b, double* ph, double* ps, double* pl);
/**
* Convert HPLuv to RGB.
*
* @param h Hue. Between 0.0 and 360.0.
* @param s Saturation. Between 0.0 and 100.0.
* @param l Lightness. Between 0.0 and 100.0.
* @param[out] pr Red component. Between 0.0 and 1.0.
* @param[out] pg Green component. Between 0.0 and 1.0.
* @param[out] pb Blue component. Between 0.0 and 1.0.
*/
void hpluv2rgb(double h, double s, double l, double* pr, double* pg, double* pb);
/**
* Convert RGB to HPLuv.
*
* @param r Red component. Between 0.0 and 1.0.
* @param g Green component. Between 0.0 and 1.0.
* @param b Blue component. Between 0.0 and 1.0.
* @param[out] ph Hue. Between 0.0 and 360.0.
* @param[out] ps Saturation. Between 0.0 and 100.0.
* @param[out] pl Lightness. Between 0.0 and 100.0.
*/
void rgb2hpluv(double r, double g, double b, double* ph, double* ps, double* pl);
#ifdef __cplusplus
}
#endif
#endif /* HSLUV_H */
......@@ -133,9 +133,9 @@ Kirigami.ScrollablePage {
isRead: model.isDelivered
recipientAvatarUrl: {
kaidan.avatarStorage.getHashOfJid(author) !== "" ?
kaidan.avatarStorage.getAvatarUrl(author) :
kaidan.getResourcePath("images/fallback-avatar.svg")
kaidan.avatarStorage.getAvatarUrl(author) : ""
}
name: chatName
mediaType: model.type
mediaGetUrl: model.mediaUrl
mediaLocation: model.mediaLocation
......
......@@ -73,8 +73,7 @@ Kirigami.ScrollablePage {
statusMsg: kaidan.presenceCache.getStatusText(model.jid)
unreadMessages: model.unreadMessages
avatarImagePath: kaidan.avatarStorage.getHashOfJid(model.jid) !== "" ?
kaidan.avatarStorage.getAvatarUrl(model.jid) :
kaidan.getResourcePath("images/fallback-avatar.svg")
kaidan.avatarStorage.getAvatarUrl(model.jid) : ""
backgroundColor: {
if (!Kirigami.Settings.isMobile && kaidan.chatPartner == model.jid) {
Kirigami.Theme.highlightColor
......
......@@ -51,6 +51,7 @@ RowLayout {
property bool isLastMessage
property bool edited
property bool isLoading: kaidan.transferCache.hasUpload(msgId)
property string name
property var upload: {
if (mediaType !== Enums.MessageText &&
kaidan.transferCache.hasUpload(msgId)) {
......@@ -70,7 +71,7 @@ RowLayout {
RoundImage {
id: avatar
visible: !sentByMe
visible: !sentByMe && recipientAvatarUrl !== ""
source: recipientAvatarUrl
fillMode: Image.PreserveAspectFit
mipmap: true
......@@ -82,6 +83,15 @@ RowLayout {
sourceSize.width: Kirigami.Units.gridUnit * 2.2
}
TextAvatar {
id: textAvatar
visible: !sentByMe && recipientAvatarUrl == ""
name: root.name
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.2
Layout.preferredWidth: Kirigami.Units.gridUnit * 2.2
}
// message bubble/box
Item {
Layout.preferredWidth: content.width + 13
......
......@@ -58,20 +58,29 @@ Kirigami.SwipeListItem {
Layout.preferredHeight: parent.height
Layout.preferredWidth: parent.height
Controls.ToolTip {
visible: hovered && !Kirigami.Settings.isMobile
delay: Qt.styleHints.mousePressAndHoldInterval
text: generateToolTipText(listItem.name, listItem.jid,
listItem.presenceType, listItem.statusMsg)
}
RoundImage {
id: avatar
visible: avatarImagePath !== ""
anchors.fill: parent
source: avatarImagePath
width: height
fillMode: Image.PreserveAspectFit
mipmap: true
}
Controls.ToolTip {
visible: hovered && !Kirigami.Settings.isMobile
delay: Qt.styleHints.mousePressAndHoldInterval
text: generateToolTipText(listItem.name, listItem.jid,
listItem.presenceType, listItem.statusMsg)
}
TextAvatar {
visible: avatarImagePath == ""
anchors.fill: parent
width: height
id: textAvatar
name: listItem.name
}
Rectangle {
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
import org.kde.kirigami 2.2 as Kirigami
import QtQuick 2.7
import QtQuick.Layouts 1.2
Rectangle {
id: avatar
property string name
color: Qt.lighter(kaidan.getUserColor(name))
radius: width * 0.5
Text {
id: text
anchors.fill: parent
anchors.margins: Kirigami.Units.devicePixelRatio * 5
property var model
renderType: Text.QtRendering
color: Kirigami.Theme.textColor
font.weight: Font.Bold
font.pointSize: 100
minimumPointSize: Kirigami.Theme.defaultFont.pointSize
fontSizeMode: Text.Fit
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: {
// WIPQTQUICK HACK TODO Probably doesn't work with non-latin1.
var match = name.match(/([a-zA-Z0-9])([a-zA-Z0-9])/);
var abbrev = match[1].toUpperCase();
if (match.length > 2) {
abbrev += match[2].toLowerCase();
}
return abbrev;
}
}
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "QXmppColorGenerator.h"
#include "../hsluv-c/hsluv.h"
#include <ctgmath>
#include <QCryptographicHash>
/// \brief Generates a color from the input value. This is intended for
/// generating colors for contacts. The generated colors are "consistent", so
/// they are shared between all clients with support for XEP-0392: Consistent
/// Color Generation.
///
/// \param name This should be the (user-specified) nickname of the
/// participant. If there is no nickname set, the bare JID shall be used.
/// \param deficiency Color correction to be done, defaults to
/// ColorVisionDeficiency::NoDeficiency.
QXmppColorGenerator::RGBColor QXmppColorGenerator::generateColor(
const QString &name, ColorVisionDeficiency deficiency)
{
QByteArray input = name.toUtf8();
// hash input through SHA-1
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(input);
// the first two bytes are used to calculate the angle/hue
int angle = hash.result().at(0) + hash.result().at(1) * 256;
double hue = double(angle) / 65536.0 * 360.0;
double saturation = 100.0;
double lightness = 50.0;
// Corrections for Color Vision Deficiencies
// this uses floating point modulo (fmod)
if (deficiency == RedGreenBlindness) {
hue += 90.0;
hue = fmod(hue, 180);
hue -= 90.0;
hue = fmod(hue, 360);
} else if (deficiency == BlueBlindness) {
hue = fmod(hue, 180);
}
// convert to rgb values (values are between 0.0 and 1.0)
double red, green, blue = 0.0;
hsluv2rgb(hue, saturation, lightness, &red, &green, &blue);
RGBColor color;
color.red = quint8(red * 255.0);
color.green = quint8(green * 255.0);
color.blue = quint8(blue * 255.0);
return color;
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QXMPPCOLORGENERATOR_H
#define QXMPPCOLORGENERATOR_H
#include <QByteArray>
#include <QString>
class QXmppColorGenerator
{
public:
struct RGBColor {
quint8 red = 0;
quint8 green = 0;
quint8 blue = 0;
};
enum ColorVisionDeficiency {
NoDeficiency,
RedGreenBlindness,
BlueBlindness
};
static RGBColor generateColor(const QString&,
ColorVisionDeficiency = NoDeficiency);
};
#endif // QXMPPCOLORGENERATOR_H
#!/usr/bin/env python3
#
# Copyright (C) 2018 Linus Jahn <lnj@kaidan.im>
# Copyright (C) 2018-2019 Linus Jahn <lnj@kaidan.im>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
......@@ -168,8 +168,8 @@ def createLongField(name, heading, content):
class CopyrightTarget:
def __init__(self, directories = None, files = None, licenseName = "",
licenseContent = "", replaceUids = None, excludeUids = None,
authorList = None, comment = ""):
licenseContent = "", replaceUids = None, excludeUids = None,
authorList = None, additionalAuthors = None, comment = ""):
self.repo = git.Repo(".");
self.files = files or list([]);
self.directories = directories or list([]);
......@@ -183,6 +183,8 @@ class CopyrightTarget:
self.excludeUids.extend(EXCLUDE_USER_IDS);
self.authorList = authorList or self.getAuthorList();
if additionalAuthors:
self.authorList.update(additionalAuthors)
def replaceUid(self, uid):
for pair in self.replaceUids:
......@@ -200,7 +202,7 @@ class CopyrightTarget:
for commit in commitList:
# create user id and check replacements and excludes
uid = "{} <{}>".format(commit.author.name,
commit.author.email);
commit.author.email);
uid = self.replaceUid(uid);
if uid in self.excludeUids:
......@@ -257,7 +259,10 @@ def main():
copyrightTargets = [
CopyrightTarget(
directories = ["src", "utils", "misc"],
licenseName = "GPL-3+ with OpenSSL exception"
licenseName = "GPL-3+ with OpenSSL exception",
additionalAuthors = {
"Eike Hein <hein@kde.org>": CopyrightAuthor(years = "2017-2018")
}
),
CopyrightTarget(
directories = ["i18n"],
......@@ -265,13 +270,17 @@ def main():
),
CopyrightTarget(
files = ["src/StatusBar.cpp", "src/StatusBar.h", "src/singleapp/*",
"data/images/xmpp.svg", "utils/generate-license.py"],
"src/hsluv-c/*", "data/images/xmpp.svg",
"utils/generate-license.py"],
licenseName = "MIT",
authorList = {
"J-P Nurmi <jpnurmi@gmail.com>": CopyrightAuthor(years = "2016"),
"Raja Sandhu, XMPP Standards Foundation": CopyrightAuthor(years = "2007"),
"LNJ <git@lnj.li>": CopyrightAuthor(years = "2018"),
"Itay Grudev <itay+github.com@grudev.com>": CopyrightAuthor(years = "2015-2018")
"Linus Jahn <lnj@kaidan.im>": CopyrightAuthor(years = "2018-2019"),
"Itay Grudev <itay+github.com@grudev.com>": CopyrightAuthor(years = "2015-2018"),
"Alexei Boronine <alexei@boronine.com>": CopyrightAuthor(years = "2015"),
"Roger Tallada <info@rogertallada.com>": CopyrightAuthor(years = "2015"),
"Martin Mitas <mity@morous.org>": CopyrightAuthor(years = "2017"),
}
),
CopyrightTarget(
......@@ -289,17 +298,16 @@ def main():
"Gregor Santner <gsantner@mailbox.org>": CopyrightAuthor(years = "2016"),
},
comment = "message_checkmark.svg: Originally from conversations, optimized using SVGO by LNJ <git@lnj.li>\n"
"diaspora.svg: Originally from dandelion, <https://github.com/diaspora-for-android/dandelion>"
"diaspora.svg: Originally from dandelion, <https://github.com/diaspora-for-android/dandelion>"
),
CopyrightTarget(
files = [
"misc/kaidan.svg", "misc/kaidan-small-margin.svg", "misc/kaidan-128x128.png",
"data/images/fallback-avatar.svg", "data/images/banner.png"
"data/images/banner.png"
],
licenseName = "CC-BY-SA-4.0",
authorList = {
"Ilya Bizyaev <bizyaev@zoho.com>": CopyrightAuthor(years = "2016-2017"),
"LNJ <git@lnj.li>": CopyrightAuthor(years = "2017"),
"MBB <mbb-mail@gmx.de>": CopyrightAuthor(years = "2016"),
}
),
......