diff --git a/README.md b/README.md
index 9f4e39f..c456227 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,8 @@ Sebastian J. Wolf [sebastian@ygriega.de](mailto:sebastian@ygriega.de) and severa
Fernschreiber wouldn't be the same without all the people helping in making it better. Thank you very much to all contributors!
### Code (Features, Bugfixes, Optimizations etc.)
-- Chat list model, notifications, TDLib receiver, animated stickers, project dependencies: [Slava Monich](https://github.com/monich)
-- Chat info page, performance improvements to chat page, location support, app initialization/registration with Telegram, project dependencies: [jgibbon](https://github.com/jgibbon)
+- Chat list model, chat model, notifications, TDLib receiver, animated stickers, project dependencies, qml/c++ optimizations, chatPhoto, TDLibFile, code reviews, logging categories: [Slava Monich](https://github.com/monich)
+- Chat info page, performance improvements to chat page, location support, app initialization/registration with Telegram, project dependencies, emoji handling, qml/js optimizations, multi-message actions, i18n fixes, chat permission handling, code reviews, logging categories: [jgibbon](https://github.com/jgibbon)
- Copy message to clipboard [Christian Stemmle](https://github.com/chstem)
### Logo/Icon
@@ -44,6 +44,13 @@ You get the Telegram API ID and hash as soon as you've registered your own appli
Moreover, you need to have a compiled version of [TDLib](https://github.com/tdlib/td) in the sub-directory `tdlib`. This sub-directory must contain another sub-directory that fits to the target device architecture (e.g. armv7hl, i486). Within this directory, there needs to be a folder called `lib` that contains at least `libtdjson.so`. For armv7hl the relative path would consequently be `tdlib/armv7hl/lib`.
+## Debug
+Fernschreiber does only output a few TDLib messages by default. To get its own debug log messages, you can either run a debug build to see all of them or use the environment variable `QT_LOGGING_RULES` to specify/filter which messages you'd like to see.
+
+Run `QT_LOGGING_RULES="fernschreiber.*=true" harbour-fernschreiber` to see all messages or replace the `*` with specific logging categories. You'll find the logging category inside the corresponding `.cpp` file for backend usage or you can use `JS` to only see frontend messages.
+
+## Contribute
+
If you want to contribute bug fixes, improvements, new features etc. please create a pull request (PR). PRs are always welcome and will be reviewed as soon as possible, but may take some time. :)
## Credits
diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro
index ceace8a..67d6326 100644
--- a/harbour-fernschreiber.pro
+++ b/harbour-fernschreiber.pro
@@ -28,6 +28,7 @@ SOURCES += src/harbour-fernschreiber.cpp \
src/dbusinterface.cpp \
src/emojisearchworker.cpp \
src/fernschreiberutils.cpp \
+ src/mceinterface.cpp \
src/notificationmanager.cpp \
src/processlauncher.cpp \
src/stickermanager.cpp \
@@ -64,6 +65,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \
qml/components/chatInformationPage/ChatInformationTextItem.qml \
qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml \
qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml \
+ qml/js/debug.js \
qml/js/functions.js \
qml/pages/ChatInformationPage.qml \
qml/pages/ChatPage.qml \
@@ -146,8 +148,11 @@ HEADERS += \
src/chatmodel.h \
src/dbusadaptor.h \
src/dbusinterface.h \
+ src/debuglog.h \
+ src/debuglogjs.h \
src/emojisearchworker.h \
src/fernschreiberutils.h \
+ src/mceinterface.h \
src/notificationmanager.h \
src/processlauncher.h \
src/stickermanager.h \
diff --git a/qml/components/AudioPreview.qml b/qml/components/AudioPreview.qml
index f64bea1..425d35b 100644
--- a/qml/components/AudioPreview.qml
+++ b/qml/components/AudioPreview.qml
@@ -20,6 +20,8 @@ import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import "../js/functions.js" as Functions
+import "../js/debug.js" as Debug
+
Item {
id: audioMessageComponent
@@ -249,39 +251,39 @@ Item {
onStatusChanged: {
if (status == MediaPlayer.NoMedia) {
- console.log("No Media");
+ Debug.log("No Media");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.Loading) {
- console.log("Loading");
+ Debug.log("Loading");
audioBusyIndicator.visible = true;
}
if (status == MediaPlayer.Loaded) {
- console.log("Loaded");
+ Debug.log("Loaded");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.Buffering) {
- console.log("Buffering");
+ Debug.log("Buffering");
audioBusyIndicator.visible = true;
}
if (status == MediaPlayer.Stalled) {
- console.log("Stalled");
+ Debug.log("Stalled");
audioBusyIndicator.visible = true;
}
if (status == MediaPlayer.Buffered) {
- console.log("Buffered");
+ Debug.log("Buffered");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.EndOfMedia) {
- console.log("End of Media");
+ Debug.log("End of Media");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.InvalidMedia) {
- console.log("Invalid Media");
+ Debug.log("Invalid Media");
audioBusyIndicator.visible = false;
}
if (status == MediaPlayer.UnknownStatus) {
- console.log("Unknown Status");
+ Debug.log("Unknown Status");
audioBusyIndicator.visible = false;
}
}
diff --git a/qml/components/ChatListViewItem.qml b/qml/components/ChatListViewItem.qml
index c6b8a6f..47bf5fc 100644
--- a/qml/components/ChatListViewItem.qml
+++ b/qml/components/ChatListViewItem.qml
@@ -10,14 +10,13 @@ PhotoTextsListItem {
photoData: photo_small || ({})
}
property int ownUserId
- property url emojiBase: "../js/emoji/"
// chat title
- primaryText.text: title ? Emoji.emojify(title + ( display.notification_settings.mute_for > 0 ? " 🔇" : "" ), Theme.fontSizeMedium, emojiBase) : qsTr("Unknown")
+ primaryText.text: title ? Emoji.emojify(title + ( display.notification_settings.mute_for > 0 ? " 🔇" : "" ), Theme.fontSizeMedium) : qsTr("Unknown")
// last user
prologSecondaryText.text: is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), primaryText.font.pixelSize) : qsTr("You") ) : qsTr("Unknown") )
// last message
- secondaryText.text: last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall, emojiBase) : qsTr("Unknown")
+ secondaryText.text: last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall) : qsTr("Unknown")
// message date
tertiaryText.text: ( last_message_date ? Functions.getDateTimeElapsed(last_message_date) : qsTr("Unknown") ) + Emoji.emojify(last_message_status, tertiaryText.font.pixelSize)
unreadCount: unread_count
diff --git a/qml/components/InReplyToRow.qml b/qml/components/InReplyToRow.qml
index 225e7fc..3756852 100644
--- a/qml/components/InReplyToRow.qml
+++ b/qml/components/InReplyToRow.qml
@@ -58,33 +58,24 @@ Row {
spacing: Theme.paddingSmall
width: parent.width - ( inReplyToRow.editable ? ( Theme.paddingSmall + removeInReplyToIconButton.width ) : 0 )
- Text {
+ Label {
id: inReplyToUserText
width: parent.width
font.pixelSize: Theme.fontSizeExtraSmall
font.weight: Font.ExtraBold
- color: Theme.primaryColor
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
horizontalAlignment: Text.AlignLeft
}
- Text {
+ Label {
id: inReplyToMessageText
font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.primaryColor
width: parent.width
- elide: Text.ElideRight
textFormat: Text.StyledText
- onTruncatedChanged: {
- // There is obviously a bug in QML in truncating text with images.
- // We simply remove Emojis then...
- if (truncated) {
- text = text.replace(/\]+\/\>/g, "");
- }
- }
+ truncationMode: TruncationMode.Fade
}
}
diff --git a/qml/components/MessageListViewItem.qml b/qml/components/MessageListViewItem.qml
index f30454b..07574e3 100644
--- a/qml/components/MessageListViewItem.qml
+++ b/qml/components/MessageListViewItem.qml
@@ -21,6 +21,7 @@ import Sailfish.Silica 1.0
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
import QtQml.Models 2.3
+import "../js/debug.js" as Debug
ListItem {
id: messageListItem
@@ -136,12 +137,12 @@ ListItem {
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex();
}
onLastReadSentMessageUpdated: {
- console.log("[ChatModel] Messages in this chat were read, new last read: " + lastReadSentIndex + ", updating description for index " + index + ", status: " + (index <= lastReadSentIndex));
+ Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (index <= lastReadSentIndex));
messageDateText.text = getMessageStatusText(myMessage, index, lastReadSentIndex, messageDateText.useElapsed);
}
onMessageUpdated: {
if (index === modelIndex) {
- console.log("[ChatModel] This message was updated, index " + index + ", updating content...");
+ Debug.log("[ChatModel] This message was updated, index ", index, ", updating content...");
messageDateText.text = getMessageStatusText(myMessage, index, chatView.lastReadSentIndex, messageDateText.useElapsed);
messageText.text = Emoji.emojify(Functions.getMessageText(myMessage, false, messageListItem.isOwnMessage), messageText.font.pixelSize);
}
@@ -254,7 +255,7 @@ ListItem {
anchors.centerIn: messageBackground
- Text {
+ Label {
id: userText
width: parent.width
@@ -263,7 +264,7 @@ ListItem {
font.weight: Font.ExtraBold
color: messageListItem.textColor
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
horizontalAlignment: messageListItem.textAlign
visible: precalculatedValues.showUserInfo
@@ -341,38 +342,23 @@ ListItem {
Column {
spacing: Theme.paddingSmall
width: parent.width - forwardedThumbnail.width - Theme.paddingSmall
- Text {
+ Label {
font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.primaryColor
width: parent.width
font.italic: true
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
text: qsTr("Forwarded Message")
- onTruncatedChanged: {
- // There is obviously a bug in QML in truncating text with images.
- // We simply remove Emojis then...
- if (truncated) {
- text = text.replace(/\]+\/\>/g, "");
- }
- }
}
- Text {
+ Label {
id: forwardedChannelText
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.primaryColor
width: parent.width
font.bold: true
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
text: Emoji.emojify(forwardedMessageInformationRow.otherChatInformation.title, font.pixelSize)
- onTruncatedChanged: {
- // There is obviously a bug in QML in truncating text with images.
- // We simply remove Emojis then...
- if (truncated) {
- text = text.replace(/\]+\/\>/g, "");
- }
- }
}
}
}
diff --git a/qml/components/MessageOverlayFlickable.qml b/qml/components/MessageOverlayFlickable.qml
index c70f8a1..cfcef90 100644
--- a/qml/components/MessageOverlayFlickable.qml
+++ b/qml/components/MessageOverlayFlickable.qml
@@ -109,7 +109,7 @@ Flickable {
width: Theme.itemSizeLarge
height: Theme.itemSizeLarge
}
- Text {
+ Label {
id: overlayMessageUserText
width: parent.width - overlayMessagePictureThumbnail.width
@@ -117,9 +117,8 @@ Flickable {
text: messageOverlayFlickable.isOwnMessage ? qsTr("You") : Emoji.emojify(Functions.getUserName(messageOverlayFlickable.userInformation), font.pixelSize)
font.pixelSize: Theme.fontSizeExtraLarge
font.weight: Font.ExtraBold
- color: Theme.primaryColor
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
}
}
@@ -163,7 +162,7 @@ Flickable {
id: webPagePreview
onImplicitHeightChanged: {
- webPagePreviewLoader.height = webPagePreview.implicitHeight;
+ overlayWebPagePreviewLoader.height = webPagePreview.implicitHeight;
}
webPageData: overlayMessage.content.web_page
diff --git a/qml/components/PhotoTextsListItem.qml b/qml/components/PhotoTextsListItem.qml
index 7fbaf08..0a40a37 100644
--- a/qml/components/PhotoTextsListItem.qml
+++ b/qml/components/PhotoTextsListItem.qml
@@ -78,61 +78,41 @@ ListItem {
width: parent.width * 5 / 6 - Theme.horizontalPageMargin
spacing: Theme.paddingSmall
- Text {
+ Label {
id: primaryText
textFormat: Text.StyledText
font.pixelSize: Theme.fontSizeMedium
- color: Theme.primaryColor
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
width: parent.width
- onTruncatedChanged: {
- // There is obviously a bug in QML in truncating text with images.
- // We simply remove Emojis then...
- if (truncated) {
- text = text.replace(/\]+\/\>/g, "");
- }
- }
}
Row {
id: additionalTextRow
width: parent.width
spacing: Theme.paddingSmall
- Text {
+ Label {
id: prologSecondaryText
font.pixelSize: Theme.fontSizeExtraSmall
+ width: Math.min(implicitWidth, parent.width)
color: Theme.highlightColor
textFormat: Text.StyledText
- onTruncatedChanged: {
- // There is obviously a bug in QML in truncating text with images.
- // We simply remove Emojis then...
- if (truncated) {
- text = text.replace(/\]+\/\>/g, "");
- }
- }
+ truncationMode: TruncationMode.Fade
}
- Text {
+ Label {
id: secondaryText
font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.primaryColor
width: parent.width - Theme.paddingMedium - prologSecondaryText.width
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
- onTruncatedChanged: {
- // There is obviously a bug in QML in truncating text with images.
- // We simply remove Emojis then...
- if (truncated) {
- text = text.replace(/\]+\/\>/g, "");
- }
- }
}
}
- Text {
+ Label {
id: tertiaryText
width: parent.width
font.pixelSize: Theme.fontSizeTiny
color: Theme.secondaryColor
+ truncationMode: TruncationMode.Fade
}
}
}
diff --git a/qml/components/PinnedMessageItem.qml b/qml/components/PinnedMessageItem.qml
index 9040a8a..c7ba1b1 100644
--- a/qml/components/PinnedMessageItem.qml
+++ b/qml/components/PinnedMessageItem.qml
@@ -21,6 +21,7 @@ import Sailfish.Silica 1.0
import "../components"
import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji
+import "../js/debug.js" as Debug
Item {
id: pinnedMessageItem
@@ -31,7 +32,7 @@ Item {
onPinnedMessageChanged: {
if (pinnedMessage) {
- console.log("[ChatPage] Activating pinned message");
+ Debug.log("[ChatPage] Activating pinned message");
var messageUserText = (pinnedMessage.sender_user_id !== chatPage.myUserId) ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(pinnedMessage.sender_user_id)), pinnedMessageUserText.font.pixelSize) : qsTr("You");
pinnedMessageUserText.text = (messageUserText === "" ? qsTr("Pinned Message") : messageUserText );
pinnedMessageText.text = Emoji.emojify(Functions.getMessageText(pinnedMessage, true, pinnedMessage.sender_user_id === chatPage.myUserId), pinnedMessageText.font.pixelSize);
@@ -77,7 +78,7 @@ Item {
spacing: Theme.paddingSmall
width: parent.width
- Text {
+ Label {
id: pinnedMessageUserText
width: parent.width
@@ -85,18 +86,18 @@ Item {
font.weight: Font.ExtraBold
color: Theme.primaryColor
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
textFormat: Text.StyledText
horizontalAlignment: Text.AlignLeft
}
- Text {
+ Label {
id: pinnedMessageText
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.primaryColor
width: parent.width
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
maximumLineCount: 1
textFormat: Text.StyledText
}
diff --git a/qml/components/PollPreview.qml b/qml/components/PollPreview.qml
index 79d5689..4157936 100644
--- a/qml/components/PollPreview.qml
+++ b/qml/components/PollPreview.qml
@@ -106,11 +106,9 @@ Item {
id: canAnswerDelegate
TextSwitch {
id: optionDelegate
- // TextSwitch changes the html base path:
- property url emojiBase: "../js/emoji/"
width: pollMessageComponent.width
automaticCheck: false
- text: Emoji.emojify(modelData.text, Theme.fontSizeMedium, emojiBase)
+ text: Emoji.emojify(modelData.text, Theme.fontSizeMedium)
checked: pollMessageComponent.chosenIndexes.indexOf(index) > -1
onClicked: {
pollMessageComponent.handleChoose(index);
diff --git a/qml/components/StickerPicker.qml b/qml/components/StickerPicker.qml
index 1cd6172..bc4eb93 100644
--- a/qml/components/StickerPicker.qml
+++ b/qml/components/StickerPicker.qml
@@ -63,13 +63,12 @@ Item {
id: stickerPickerColumn
spacing: Theme.paddingMedium
width: stickerPickerFlickable.width
- Text {
+ Label {
font.pixelSize: Theme.fontSizeMedium
font.bold: true
- color: Theme.primaryColor
width: parent.width
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
text: qsTr("Recently used")
}
@@ -122,13 +121,12 @@ Item {
Column {
spacing: Theme.paddingMedium
width: parent.width
- Text {
+ Label {
font.pixelSize: Theme.fontSizeMedium
font.bold: true
- color: Theme.primaryColor
width: parent.width
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
text: modelData.title
}
@@ -159,12 +157,11 @@ Item {
}
}
}
- Text {
+ Label {
font.pixelSize: Theme.fontSizeHuge
- color: Theme.primaryColor
anchors.fill: parent
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
text: Emoji.emojify(modelData.emoji, font.pixelSize)
visible: !modelData.thumbnail.photo.local.is_downloading_completed
}
diff --git a/qml/components/VideoPreview.qml b/qml/components/VideoPreview.qml
index a224742..daf7c65 100644
--- a/qml/components/VideoPreview.qml
+++ b/qml/components/VideoPreview.qml
@@ -20,6 +20,7 @@ import QtQuick 2.6
import Sailfish.Silica 1.0
import QtMultimedia 5.6
import "../js/functions.js" as Functions
+import "../js/debug.js" as Debug
Item {
id: videoMessageComponent
@@ -302,39 +303,39 @@ Item {
onStatusChanged: {
if (status == MediaPlayer.NoMedia) {
- console.log("No Media");
+ Debug.log("No Media");
videoBusyIndicator.visible = false;
}
if (status == MediaPlayer.Loading) {
- console.log("Loading");
+ Debug.log("Loading");
videoBusyIndicator.visible = true;
}
if (status == MediaPlayer.Loaded) {
- console.log("Loaded");
+ Debug.log("Loaded");
videoBusyIndicator.visible = false;
}
if (status == MediaPlayer.Buffering) {
- console.log("Buffering");
+ Debug.log("Buffering");
videoBusyIndicator.visible = true;
}
if (status == MediaPlayer.Stalled) {
- console.log("Stalled");
+ Debug.log("Stalled");
videoBusyIndicator.visible = true;
}
if (status == MediaPlayer.Buffered) {
- console.log("Buffered");
+ Debug.log("Buffered");
videoBusyIndicator.visible = false;
}
if (status == MediaPlayer.EndOfMedia) {
- console.log("End of Media");
+ Debug.log("End of Media");
videoBusyIndicator.visible = false;
}
if (status == MediaPlayer.InvalidMedia) {
- console.log("Invalid Media");
+ Debug.log("Invalid Media");
videoBusyIndicator.visible = false;
}
if (status == MediaPlayer.UnknownStatus) {
- console.log("Unknown Status");
+ Debug.log("Unknown Status");
videoBusyIndicator.visible = false;
}
}
diff --git a/qml/components/WebPagePreview.qml b/qml/components/WebPagePreview.qml
index 3437110..e90178d 100644
--- a/qml/components/WebPagePreview.qml
+++ b/qml/components/WebPagePreview.qml
@@ -70,7 +70,7 @@ Column {
}
}
- Text {
+ Label {
id: siteNameText
width: parent.width
@@ -78,35 +78,33 @@ Column {
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
font.bold: true
color: Theme.secondaryHighlightColor
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
maximumLineCount: 1
textFormat: Text.StyledText
visible: (text !== "")
}
- Text {
+ Label {
id: titleText
width: parent.width
text: webPageData.title ? Emoji.emojify(webPageData.title, font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
font.bold: true
- color: Theme.primaryColor
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 2
textFormat: Text.StyledText
visible: (text !== "")
}
- Text {
+ Label {
id: descriptionText
width: parent.width
text: webPageData.description ? Emoji.emojify(webPageData.description, font.pixelSize) : ""
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall
- color: Theme.primaryColor
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 3
textFormat: Text.StyledText
@@ -146,7 +144,7 @@ Column {
}
}
- Text {
+ Label {
id: noPreviewAvailableText
width: parent.width
@@ -154,7 +152,7 @@ Column {
font.pixelSize: webPagePreviewColumn.largerFontSize ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny
font.italic: true
color: Theme.secondaryColor
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
maximumLineCount: 1
textFormat: Text.StyledText
diff --git a/qml/components/chatInformationPage/ChatInformationPageContent.qml b/qml/components/chatInformationPage/ChatInformationPageContent.qml
index a7778ab..0d63419 100644
--- a/qml/components/chatInformationPage/ChatInformationPageContent.qml
+++ b/qml/components/chatInformationPage/ChatInformationPageContent.qml
@@ -21,6 +21,7 @@ import Sailfish.Silica 1.0
import "../"
import "../../js/twemoji.js" as Emoji
import "../../js/functions.js" as Functions
+import "../../js/debug.js" as Debug
SilicaFlickable {
@@ -59,7 +60,7 @@ SilicaFlickable {
chatInformationPage.isChannel = chatInformationPage.groupInformation.is_channel;
break;
}
- console.log("is set up", chatInformationPage.isPrivateChat, chatInformationPage.isBasicGroup, chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId)
+ Debug.log("is set up", chatInformationPage.isPrivateChat, chatInformationPage.isBasicGroup, chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId)
if(!chatInformationPage.isPrivateChat) {
updateGroupStatusText();
}
@@ -123,13 +124,13 @@ SilicaFlickable {
}
}
onSupergroupFullInfoReceived: {
- console.log("onSupergroupFullInfoReceived", chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId, groupId)
+ Debug.log("onSupergroupFullInfoReceived", chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId, groupId)
if(chatInformationPage.isSuperGroup && chatInformationPage.chatPartnerGroupId === groupId) {
chatInformationPage.groupFullInformation = groupFullInfo;
}
}
onSupergroupFullInfoUpdated: {
- console.log("onSupergroupFullInfoUpdated", chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId, groupId)
+ Debug.log("onSupergroupFullInfoUpdated", chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId, groupId)
if(chatInformationPage.isSuperGroup && chatInformationPage.chatPartnerGroupId === groupId) {
chatInformationPage.groupFullInformation = groupFullInfo;
}
@@ -281,14 +282,12 @@ SilicaFlickable {
asynchronous: true
anchors.fill: chatPictureThumbnail
source: chatInformationPage.isPrivateChat
- ? "../components/chatInformationPage/ChatInformationProfilePictureList.qml"
- : "../components/chatInformationPage/ChatInformationProfilePicture.qml"
+ ? "ChatInformationProfilePictureList.qml"
+ : "ChatInformationProfilePicture.qml"
}
}
- // PageHeader changes the html base path:
- property url emojiBase: "../js/emoji/"
leftMargin: imageContainer.getEased((imageContainer.minDimension + Theme.paddingMedium), 0, imageContainer.tweenFactor) + Theme.horizontalPageMargin
- title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge, emojiBase) : qsTr("Unknown")
+ title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown")
description: chatInformationPage.isPrivateChat ? ("@"+(chatInformationPage.privateChatUserInformation.username || chatInformationPage.chatPartnerGroupId)) : ""
}
diff --git a/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml b/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml
index ef0ddc1..9d9243f 100644
--- a/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml
+++ b/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml
@@ -77,19 +77,18 @@ ChatInformationTabItemBase {
width: parent.width
// chat title
- primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize, "../js/emoji/")
+ primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize)
// last user
prologSecondaryText.text: "@"+(user.username !== "" ? user.username : user_id) + (user_id === chatInformationPage.myUserId ? " " + qsTr("You") : "")
secondaryText {
horizontalAlignment: Text.AlignRight
property string statusText: Functions.getChatMemberStatusText(model.status["@type"])
- property string customText: model.status.custom_title ? Emoji.emojify(model.status.custom_title, secondaryText.font.pixelSize, "../js/emoji/") : ""
+ property string customText: model.status.custom_title ? Emoji.emojify(model.status.custom_title, secondaryText.font.pixelSize) : ""
text: (statusText !== "" && customText !== "") ? statusText + ", " + customText : statusText + customText
}
tertiaryText {
maximumLineCount: 1
- text: user.type["@type"] === "userTypeBot" ? (Emoji.emojify("🤖 "+bot_info.description, tertiaryText.font.pixelSize, "../js/emoji/")) : Functions.getChatPartnerStatusText(user.status["@type"], user.status.was_online);
- elide: Text.ElideRight
+ text: user.type["@type"] === "userTypeBot" ? (Emoji.emojify("🤖 "+bot_info.description, tertiaryText.font.pixelSize)) : Functions.getChatPartnerStatusText(user.status["@type"], user.status.was_online);
}
onClicked: {
@@ -160,7 +159,7 @@ ChatInformationTabItemBase {
onChatChanged: {
if (changedChatId === chat_id) {
// Force update of some list item elements (currently only last message text seems to create problems). dataChanged() doesn't seem to trigger them all :(
- secondaryText.text = last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall, "../../js/emoji/") : qsTr("Unknown")
+ secondaryText.text = last_message_text ? Emoji.emojify(Functions.enhanceHtmlEntities(last_message_text), Theme.fontSizeExtraSmall) : qsTr("Unknown")
}
}
}
diff --git a/qml/components/chatInformationPage/ChatInformationTabView.qml b/qml/components/chatInformationPage/ChatInformationTabView.qml
index f550821..4e09e69 100644
--- a/qml/components/chatInformationPage/ChatInformationTabView.qml
+++ b/qml/components/chatInformationPage/ChatInformationTabView.qml
@@ -61,7 +61,6 @@ Item {
width: loaded ? (headerGrid.width / tabView.count) : 0
opacity: loaded ? 1.0 : 0.0
- Behavior on width { PropertyAnimation {duration: 200}}
Behavior on opacity { FadeAnimation {}}
height: Theme.itemSizeLarge
property int itemIndex: index
diff --git a/qml/components/chatInformationPage/ChatInformationTextItem.qml b/qml/components/chatInformationPage/ChatInformationTextItem.qml
index d93d3b7..db9ca5f 100644
--- a/qml/components/chatInformationPage/ChatInformationTextItem.qml
+++ b/qml/components/chatInformationPage/ChatInformationTextItem.qml
@@ -50,7 +50,7 @@ Column {
font.pixelSize: Theme.fontSizeSmall
textFormat: Text.StyledText
color: Theme.primaryColor
- text: Emoji.emojify( Functions.replaceUrlsWithLinks(textItem.text).replace(/\n/g, "
"), Theme.fontSizeExtraSmall, "../../js/emoji/")
+ text: Emoji.emojify( Functions.replaceUrlsWithLinks(textItem.text).replace(/\n/g, "
"), Theme.fontSizeExtraSmall)
linkColor: Theme.highlightColor
visible: text !== ""
onLinkActivated: {
diff --git a/qml/js/debug.js b/qml/js/debug.js
new file mode 100644
index 0000000..011ccff
--- /dev/null
+++ b/qml/js/debug.js
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2020 Sebastian J. Wolf and other contributors
+
+ This file is part of Fernschreiber.
+
+ Fernschreiber 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.
+
+ Fernschreiber 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 Fernschreiber. If not, see .
+*/
+
+.pragma library
+.import WerkWolf.Fernschreiber 1.0 as Fernschreiber
+var enabled = Fernschreiber.DebugLog.enabled;
+var log = enabled ? console.log : function(){};
+var assert = enabled ? console.assert : function(){};
+var time = enabled ? console.time : function(){};
+var timeEnd = enabled ? console.timeEnd : function(){};
+var trace = enabled ? console.trace : function(){};
+var count = enabled ? console.count : function(){};
+var profile = enabled ? console.profile : function(){};
+var exception = enabled ? console.exception : function(){};
+
+Fernschreiber.DebugLog.enabledChanged.connect(function() {
+ enabled = Fernschreiber.DebugLog.enabled;
+ if(enabled) {
+ log = console.log;
+ assert = console.assert;
+ time = console.time;
+ timeEnd = console.timeEnd;
+ trace = console.trace;
+ count = console.count;
+ profile = console.profile;
+ exception = console.exception;
+ } else {
+ log = assert = time = timeEnd = trace = count = profile = exception = function(){};
+ }
+
+});
diff --git a/qml/js/emoji/1f3a2.svg b/qml/js/emoji/1f3a2.svg
index b1e64ec..256d8af 100644
--- a/qml/js/emoji/1f3a2.svg
+++ b/qml/js/emoji/1f3a2.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f441.svg b/qml/js/emoji/1f441.svg
index 75e9c48..bd1a45e 100644
--- a/qml/js/emoji/1f441.svg
+++ b/qml/js/emoji/1f441.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f4c5.svg b/qml/js/emoji/1f4c5.svg
index ca68a82..476a950 100644
--- a/qml/js/emoji/1f4c5.svg
+++ b/qml/js/emoji/1f4c5.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f4c6.svg b/qml/js/emoji/1f4c6.svg
index ff073d7..b2de8c5 100644
--- a/qml/js/emoji/1f4c6.svg
+++ b/qml/js/emoji/1f4c6.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f536.svg b/qml/js/emoji/1f536.svg
index 116e722..9695be3 100644
--- a/qml/js/emoji/1f536.svg
+++ b/qml/js/emoji/1f536.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f538.svg b/qml/js/emoji/1f538.svg
index 435ad6a..842ffcc 100644
--- a/qml/js/emoji/1f538.svg
+++ b/qml/js/emoji/1f538.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f7e0.svg b/qml/js/emoji/1f7e0.svg
index 2db43d5..f5e1200 100644
--- a/qml/js/emoji/1f7e0.svg
+++ b/qml/js/emoji/1f7e0.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f7e7.svg b/qml/js/emoji/1f7e7.svg
index 3cbdde4..1377a4e 100644
--- a/qml/js/emoji/1f7e7.svg
+++ b/qml/js/emoji/1f7e7.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fb-200d-2640-fe0f.svg b/qml/js/emoji/1f9ce-1f3fb-200d-2640-fe0f.svg
index 77c8b9b..3750749 100644
--- a/qml/js/emoji/1f9ce-1f3fb-200d-2640-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fb-200d-2640-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fb-200d-2642-fe0f.svg b/qml/js/emoji/1f9ce-1f3fb-200d-2642-fe0f.svg
index 09e6f4d..97de596 100644
--- a/qml/js/emoji/1f9ce-1f3fb-200d-2642-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fb-200d-2642-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fb.svg b/qml/js/emoji/1f9ce-1f3fb.svg
index 9e269bd..6f97b1b 100644
--- a/qml/js/emoji/1f9ce-1f3fb.svg
+++ b/qml/js/emoji/1f9ce-1f3fb.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fc-200d-2640-fe0f.svg b/qml/js/emoji/1f9ce-1f3fc-200d-2640-fe0f.svg
index cf2ca0c..ee5bf15 100644
--- a/qml/js/emoji/1f9ce-1f3fc-200d-2640-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fc-200d-2640-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fc-200d-2642-fe0f.svg b/qml/js/emoji/1f9ce-1f3fc-200d-2642-fe0f.svg
index 9bd2fc0..e518657 100644
--- a/qml/js/emoji/1f9ce-1f3fc-200d-2642-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fc-200d-2642-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fc.svg b/qml/js/emoji/1f9ce-1f3fc.svg
index bdd410e..0977ee6 100644
--- a/qml/js/emoji/1f9ce-1f3fc.svg
+++ b/qml/js/emoji/1f9ce-1f3fc.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fd-200d-2640-fe0f.svg b/qml/js/emoji/1f9ce-1f3fd-200d-2640-fe0f.svg
index ed058b9..e210695 100644
--- a/qml/js/emoji/1f9ce-1f3fd-200d-2640-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fd-200d-2640-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fd-200d-2642-fe0f.svg b/qml/js/emoji/1f9ce-1f3fd-200d-2642-fe0f.svg
index 10df60c..269c7ce 100644
--- a/qml/js/emoji/1f9ce-1f3fd-200d-2642-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fd-200d-2642-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fd.svg b/qml/js/emoji/1f9ce-1f3fd.svg
index 465db1d..7fe4f06 100644
--- a/qml/js/emoji/1f9ce-1f3fd.svg
+++ b/qml/js/emoji/1f9ce-1f3fd.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fe-200d-2640-fe0f.svg b/qml/js/emoji/1f9ce-1f3fe-200d-2640-fe0f.svg
index 83206f8..e2b0930 100644
--- a/qml/js/emoji/1f9ce-1f3fe-200d-2640-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fe-200d-2640-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fe-200d-2642-fe0f.svg b/qml/js/emoji/1f9ce-1f3fe-200d-2642-fe0f.svg
index fb24b6d..54e4ba9 100644
--- a/qml/js/emoji/1f9ce-1f3fe-200d-2642-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3fe-200d-2642-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3fe.svg b/qml/js/emoji/1f9ce-1f3fe.svg
index e84e123..2f70944 100644
--- a/qml/js/emoji/1f9ce-1f3fe.svg
+++ b/qml/js/emoji/1f9ce-1f3fe.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3ff-200d-2640-fe0f.svg b/qml/js/emoji/1f9ce-1f3ff-200d-2640-fe0f.svg
index 442cb9c..0f2dc0c 100644
--- a/qml/js/emoji/1f9ce-1f3ff-200d-2640-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3ff-200d-2640-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3ff-200d-2642-fe0f.svg b/qml/js/emoji/1f9ce-1f3ff-200d-2642-fe0f.svg
index aba0cb4..b51d7ff 100644
--- a/qml/js/emoji/1f9ce-1f3ff-200d-2642-fe0f.svg
+++ b/qml/js/emoji/1f9ce-1f3ff-200d-2642-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-1f3ff.svg b/qml/js/emoji/1f9ce-1f3ff.svg
index c07e81f..542a604 100644
--- a/qml/js/emoji/1f9ce-1f3ff.svg
+++ b/qml/js/emoji/1f9ce-1f3ff.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-200d-2640-fe0f.svg b/qml/js/emoji/1f9ce-200d-2640-fe0f.svg
index 89c9ff4..40b5754 100644
--- a/qml/js/emoji/1f9ce-200d-2640-fe0f.svg
+++ b/qml/js/emoji/1f9ce-200d-2640-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce-200d-2642-fe0f.svg b/qml/js/emoji/1f9ce-200d-2642-fe0f.svg
index 403d73e..1c8ddcd 100644
--- a/qml/js/emoji/1f9ce-200d-2642-fe0f.svg
+++ b/qml/js/emoji/1f9ce-200d-2642-fe0f.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9ce.svg b/qml/js/emoji/1f9ce.svg
index 60fe537..86a60cb 100644
--- a/qml/js/emoji/1f9ce.svg
+++ b/qml/js/emoji/1f9ce.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1f9e1.svg b/qml/js/emoji/1f9e1.svg
index 26ae9e7..0e61b14 100644
--- a/qml/js/emoji/1f9e1.svg
+++ b/qml/js/emoji/1f9e1.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/emoji/1faa4.svg b/qml/js/emoji/1faa4.svg
index 0f68455..a680fb7 100644
--- a/qml/js/emoji/1faa4.svg
+++ b/qml/js/emoji/1faa4.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/qml/js/functions.js b/qml/js/functions.js
index 9fd5e98..aa12234 100644
--- a/qml/js/functions.js
+++ b/qml/js/functions.js
@@ -17,6 +17,10 @@
along with Fernschreiber. If not, see .
*/
+.pragma library
+.import "debug.js" as Debug
+.import Sailfish.Silica 1.0 as Silica
+
function getUserName(userInformation) {
var firstName = typeof userInformation.first_name !== "undefined" ? userInformation.first_name : "";
var lastName = typeof userInformation.last_name !== "undefined" ? userInformation.last_name : "";
@@ -194,7 +198,7 @@ function getShortenedCount(count) {
}
function getDateTimeElapsed(timestamp) {
- return Format.formatDate(new Date(timestamp * 1000), Formatter.DurationElapsed);
+ return Silica.Format.formatDate(new Date(timestamp * 1000), Silica.Formatter.DurationElapsed);
}
function getDateTimeTranslated(timestamp) {
@@ -344,7 +348,7 @@ function handleLink(link) {
} else if (link.indexOf("userId://") === 0) {
tdLibWrapper.createPrivateChat(link.substring(9));
} else if (link.indexOf("tg://") === 0) {
- console.log("Special TG link: " + link);
+ Debug.log("Special TG link: ", link);
if (link.indexOf("tg://join?invite=") === 0) {
tdLibWrapper.joinChatByInviteLink(tMePrefix + "joinchat/" + link.substring(17));
} else if (link.indexOf("tg://resolve?domain=") === 0) {
@@ -353,12 +357,12 @@ function handleLink(link) {
} else {
if (link.indexOf(tMePrefix) === 0) {
if (link.indexOf("joinchat") !== -1) {
- console.log("Joining Chat: " + link);
+ Debug.log("Joining Chat: ", link);
tdLibWrapper.joinChatByInviteLink(link);
// Do the necessary stuff to open the chat if successful
// Fail with nice error message if it doesn't work
} else {
- console.log("Search public chat: " + link.substring(tMePrefix.length));
+ Debug.log("Search public chat: ", link.substring(tMePrefix.length));
tdLibWrapper.searchPublicChat(link.substring(tMePrefix.length));
// Check responses for updateBasicGroup or updateSupergroup
// Fire createBasicGroupChat or createSupergroupChat
diff --git a/qml/js/twemoji.js b/qml/js/twemoji.js
index 446931a..67f677c 100644
--- a/qml/js/twemoji.js
+++ b/qml/js/twemoji.js
@@ -1,588 +1,66 @@
-/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */
-var twemoji = (function (
- /*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*
- https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
- */
+/*! Copyright Twitter Inc. and other contributors. Licensed under MIT */
+/*
+ https://github.com/twitter/twemoji/blob/gh-pages/LICENSE
- // WARNING: this file is generated automatically via
- // `node scripts/build.js`
- // please update its `createTwemoji` function
- // at the bottom of the same file instead.
+ Stripped down for usage in Fernschreiber.
+*/
+.pragma library
-) {
- 'use strict';
+// RegExp based on emoji's official Unicode standards
+// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
+var re = /(?:\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d])|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udeeb\udeec\udef4-\udefc\udfe0-\udfeb]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd1d\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78\udd7a-\uddb4\uddb7\uddba\uddbc-\uddcb\uddd0\uddde-\uddff\ude70-\ude74\ude78-\ude7a\ude80-\ude86\ude90-\udea8\udeb0-\udeb6\udec0-\udec2\uded0-\uded6]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g,
- /*jshint maxparams:4 */
+ // avoid runtime RegExp creation for not so smart,
+ // not JIT based, and old browsers / engines
+ UFE0Fg = /\uFE0F/g,
+ // avoid using a string literal like '\u200D' here because minifiers expand it inline
+ U200D = String.fromCharCode(0x200D),
+ basePath = Qt.resolvedUrl("./emoji/"),
+ ampersandRe = /\&(?!amp;)/g;
+
+function toCodePoint(unicodeSurrogates) {
var
- // the exported module object
- twemoji = {
-
-
- /////////////////////////
- // properties //
- /////////////////////////
-
- // default assets url
- base: '../js/emoji/',
-
- // default assets file extensions, by default '.png'
- ext: '.png',
-
- // default assets/folder size, by default "72x72"
- // available via Twitter CDN: 72
- size: '72x72',
-
- // default class name, by default 'emoji'
- className: 'emoji',
-
- // basic utilities / helpers to convert code points
- // to JavaScript surrogates and vice versa
- convert: {
-
- /**
- * Given an HEX codepoint, returns UTF16 surrogate pairs.
- *
- * @param string generic codepoint, i.e. '1F4A9'
- * @return string codepoint transformed into utf16 surrogates pair,
- * i.e. \uD83D\uDCA9
- *
- * @example
- * twemoji.convert.fromCodePoint('1f1e8');
- * // "\ud83c\udde8"
- *
- * '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('')
- * // "\ud83c\udde8\ud83c\uddf3"
- */
- fromCodePoint: fromCodePoint,
-
- /**
- * Given UTF16 surrogate pairs, returns the equivalent HEX codepoint.
- *
- * @param string generic utf16 surrogates pair, i.e. \uD83D\uDCA9
- * @param string optional separator for double code points, default='-'
- * @return string utf16 transformed into codepoint, i.e. '1F4A9'
- *
- * @example
- * twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3');
- * // "1f1e8-1f1f3"
- *
- * twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3', '~');
- * // "1f1e8~1f1f3"
- */
- toCodePoint: toCodePoint
- },
-
-
- /////////////////////////
- // methods //
- /////////////////////////
-
- /**
- * User first: used to remove missing images
- * preserving the original text intent when
- * a fallback for network problems is desired.
- * Automatically added to Image nodes via DOM
- * It could be recycled for string operations via:
- * $('img.emoji').on('error', twemoji.onerror)
- */
- onerror: function onerror() {
- if (this.parentNode) {
- this.parentNode.replaceChild(createText(this.alt, false), this);
- }
- },
-
- /**
- * Main method/logic to generate either tags or HTMLImage nodes.
- * "emojify" a generic text or DOM Element.
- *
- * @overloads
- *
- * String replacement for `innerHTML` or server side operations
- * twemoji.parse(string);
- * twemoji.parse(string, Function);
- * twemoji.parse(string, Object);
- *
- * HTMLElement tree parsing for safer operations over existing DOM
- * twemoji.parse(HTMLElement);
- * twemoji.parse(HTMLElement, Function);
- * twemoji.parse(HTMLElement, Object);
- *
- * @param string|HTMLElement the source to parse and enrich with emoji.
- *
- * string replace emoji matches with tags.
- * Mainly used to inject emoji via `innerHTML`
- * It does **not** parse the string or validate it,
- * it simply replaces found emoji with a tag.
- * NOTE: be sure this won't affect security.
- *
- * HTMLElement walk through the DOM tree and find emoji
- * that are inside **text node only** (nodeType === 3)
- * Mainly used to put emoji in already generated DOM
- * without compromising surrounding nodes and
- * **avoiding** the usage of `innerHTML`.
- * NOTE: Using DOM elements instead of strings should
- * improve security without compromising too much
- * performance compared with a less safe `innerHTML`.
- *
- * @param Function|Object [optional]
- * either the callback that will be invoked or an object
- * with all properties to use per each found emoji.
- *
- * Function if specified, this will be invoked per each emoji
- * that has been found through the RegExp except
- * those follwed by the invariant \uFE0E ("as text").
- * Once invoked, parameters will be:
- *
- * iconId:string the lower case HEX code point
- * i.e. "1f4a9"
- *
- * options:Object all info for this parsing operation
- *
- * variant:char the optional \uFE0F ("as image")
- * variant, in case this info
- * is anyhow meaningful.
- * By default this is ignored.
- *
- * If such callback will return a falsy value instead
- * of a valid `src` to use for the image, nothing will
- * actually change for that specific emoji.
- *
- *
- * Object if specified, an object containing the following properties
- *
- * callback Function the callback to invoke per each found emoji.
- * base string the base url, by default twemoji.base
- * ext string the image extension, by default twemoji.ext
- * size string the assets size, by default twemoji.size
- *
- * @example
- *
- * twemoji.parse("I \u2764\uFE0F emoji!");
- * // I emoji!
- *
- *
- * twemoji.parse("I \u2764\uFE0F emoji!", function(iconId, options) {
- * return '/assets/' + iconId + '.gif';
- * });
- * // I emoji!
- *
- *
- * twemoji.parse("I \u2764\uFE0F emoji!", {
- * size: 72,
- * callback: function(iconId, options) {
- * return '/assets/' + options.size + '/' + iconId + options.ext;
- * }
- * });
- * // I emoji!
- *
- */
- parse: parse,
-
- /**
- * Given a string, invokes the callback argument
- * per each emoji found in such string.
- * This is the most raw version used by
- * the .parse(string) method itself.
- *
- * @param string generic string to parse
- * @param Function a generic callback that will be
- * invoked to replace the content.
- * This calback wil receive standard
- * String.prototype.replace(str, callback)
- * arguments such:
- * callback(
- * rawText, // the emoji match
- * );
- *
- * and others commonly received via replace.
- */
- replace: replace,
-
- /**
- * Simplify string tests against emoji.
- *
- * @param string some text that might contain emoji
- * @return boolean true if any emoji was found, false otherwise.
- *
- * @example
- *
- * if (twemoji.test(someContent)) {
- * console.log("emoji All The Things!");
- * }
- */
- test: test
- },
-
- // used to escape HTML special chars in attributes
- escaper = {
- '&': '&',
- '<': '<',
- '>': '>',
- "'": ''',
- '"': '"'
- },
-
- // RegExp based on emoji's official Unicode standards
- // http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
- re = /(?:\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d])|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udeeb\udeec\udef4-\udefc\udfe0-\udfeb]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd1d\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78\udd7a-\uddb4\uddb7\uddba\uddbc-\uddcb\uddd0\uddde-\uddff\ude70-\ude74\ude78-\ude7a\ude80-\ude86\ude90-\udea8\udeb0-\udeb6\udec0-\udec2\uded0-\uded6]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g,
-
- // avoid runtime RegExp creation for not so smart,
- // not JIT based, and old browsers / engines
- UFE0Fg = /\uFE0F/g,
-
- // avoid using a string literal like '\u200D' here because minifiers expand it inline
- U200D = String.fromCharCode(0x200D),
-
- // used to find HTML special chars in attributes
- rescaper = /[&<>'"]/g,
-
- // nodes with type 1 which should **not** be parsed
- shouldntBeParsed = /^(?:iframe|noframes|noscript|script|select|style|textarea)$/,
-
- // just a private shortcut
- fromCharCode = String.fromCharCode;
-
- return twemoji;
-
-
- /////////////////////////
- // private functions //
- // declaration //
- /////////////////////////
-
- /**
- * Shortcut to create text nodes
- * @param string text used to create DOM text node
- * @return Node a DOM node with that text
- */
- function createText(text, clean) {
- return document.createTextNode(clean ? text.replace(UFE0Fg, '') : text);
- }
-
- /**
- * Utility function to escape html attribute text
- * @param string text use in HTML attribute
- * @return string text encoded to use in HTML attribute
- */
- function escapeHTML(s) {
- return s.replace(rescaper, replacer);
- }
-
- /**
- * Default callback used to generate emoji src
- * based on Twitter CDN
- * @param string the emoji codepoint string
- * @param string the default size to use, i.e. "36x36"
- * @return string the image source to use
- */
- function defaultImageSrcGenerator(icon, options) {
- return ''.concat(options.base, options.size, '/', icon, options.ext);
- }
-
- /**
- * Given a generic DOM nodeType 1, walk through all children
- * and store every nodeType 3 (#text) found in the tree.
- * @param Element a DOM Element with probably some text in it
- * @param Array the list of previously discovered text nodes
- * @return Array same list with new discovered nodes, if any
- */
- function grabAllTextNodes(node, allText) {
- var
- childNodes = node.childNodes,
- length = childNodes.length,
- subnode,
- nodeType;
- while (length--) {
- subnode = childNodes[length];
- nodeType = subnode.nodeType;
- // parse emoji only in text nodes
- if (nodeType === 3) {
- // collect them to process emoji later
- allText.push(subnode);
- }
- // ignore all nodes that are not type 1, that are svg, or that
- // should not be parsed as script, style, and others
- else if (nodeType === 1 && !('ownerSVGElement' in subnode) &&
- !shouldntBeParsed.test(subnode.nodeName.toLowerCase())) {
- grabAllTextNodes(subnode, allText);
- }
+ r = [],
+ c = 0,
+ p = 0,
+ i = 0;
+ while (i < unicodeSurrogates.length) {
+ c = unicodeSurrogates.charCodeAt(i++);
+ if (p) {
+ r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
+ p = 0;
+ } else if (0xD800 <= c && c <= 0xDBFF) {
+ p = c;
+ } else {
+ r.push(c.toString(16));
}
- return allText;
}
-
- /**
- * Used to both remove the possible variant
- * and to convert utf16 into code points.
- * If there is a zero-width-joiner (U+200D), leave the variants in.
- * @param string the raw text of the emoji match
- * @return string the code point
- */
- function grabTheRightIcon(rawText) {
- // if variant is present as \uFE0F
- return toCodePoint(rawText.indexOf(U200D) < 0 ?
- rawText.replace(UFE0Fg, '') :
- rawText
- );
- }
-
- /**
- * DOM version of the same logic / parser:
- * emojify all found sub-text nodes placing images node instead.
- * @param Element generic DOM node with some text in some child node
- * @param Object options containing info about how to parse
- *
- * .callback Function the callback to invoke per each found emoji.
- * .base string the base url, by default twemoji.base
- * .ext string the image extension, by default twemoji.ext
- * .size string the assets size, by default twemoji.size
- *
- * @return Element same generic node with emoji in place, if any.
- */
- function parseNode(node, options) {
- var
- allText = grabAllTextNodes(node, []),
- length = allText.length,
- attrib,
- attrname,
- modified,
- fragment,
- subnode,
- text,
- match,
- i,
- index,
- img,
- rawText,
- iconId,
- src;
- while (length--) {
- modified = false;
- fragment = document.createDocumentFragment();
- subnode = allText[length];
- text = subnode.nodeValue;
- i = 0;
- while ((match = re.exec(text))) {
- index = match.index;
- if (index !== i) {
- fragment.appendChild(
- createText(text.slice(i, index), true)
- );
- }
- rawText = match[0];
- iconId = grabTheRightIcon(rawText);
- i = index + rawText.length;
- src = options.callback(iconId, options);
- if (iconId && src) {
- img = new Image();
- img.onerror = options.onerror;
- img.setAttribute('draggable', 'false');
- attrib = options.attributes(rawText, iconId);
- for (attrname in attrib) {
- if (
- attrib.hasOwnProperty(attrname) &&
- // don't allow any handlers to be set + don't allow overrides
- attrname.indexOf('on') !== 0 &&
- !img.hasAttribute(attrname)
- ) {
- img.setAttribute(attrname, attrib[attrname]);
- }
- }
- img.className = options.className;
- img.alt = rawText;
- img.src = src;
- modified = true;
- fragment.appendChild(img);
- }
- if (!img) fragment.appendChild(createText(rawText, false));
- img = null;
- }
- // is there actually anything to replace in here ?
- if (modified) {
- // any text left to be added ?
- if (i < text.length) {
- fragment.appendChild(
- createText(text.slice(i), true)
- );
- }
- // replace the text node only, leave intact
- // anything else surrounding such text
- subnode.parentNode.replaceChild(fragment, subnode);
- }
- }
- return node;
- }
-
- /**
- * String/HTML version of the same logic / parser:
- * emojify a generic text placing images tags instead of surrogates pair.
- * @param string generic string with possibly some emoji in it
- * @param Object options containing info about how to parse
- *
- * .callback Function the callback to invoke per each found emoji.
- * .base string the base url, by default twemoji.base
- * .ext string the image extension, by default twemoji.ext
- * .size string the assets size, by default twemoji.size
- *
- * @return the string with replacing all found and parsed emoji
- */
- function parseString(str, options) {
- return replace(str, function (rawText) {
- var
- ret = rawText,
- iconId = grabTheRightIcon(rawText),
- src = options.callback(iconId, options),
- attrib,
- attrname;
- if (iconId && src) {
- // recycle the match string replacing the emoji
- // with its image counter part
- ret = '');
- }
- return ret;
- });
- }
-
- /**
- * Function used to actually replace HTML special chars
- * @param string HTML special char
- * @return string encoded HTML special char
- */
- function replacer(m) {
- return escaper[m];
- }
-
- /**
- * Default options.attribute callback
- * @return null
- */
- function returnNull() {
- return null;
- }
-
- /**
- * Given a generic value, creates its squared counterpart if it's a number.
- * As example, number 36 will return '36x36'.
- * @param any a generic value.
- * @return any a string representing asset size, i.e. "36x36"
- * only in case the value was a number.
- * Returns initial value otherwise.
- */
- function toSizeSquaredAsset(value) {
- return typeof value === 'number' ?
- value + 'x' + value :
- value;
- }
-
-
- /////////////////////////
- // exported functions //
- // declaration //
- /////////////////////////
-
- function fromCodePoint(codepoint) {
- var code = typeof codepoint === 'string' ?
- parseInt(codepoint, 16) : codepoint;
- if (code < 0x10000) {
- return fromCharCode(code);
- }
- code -= 0x10000;
- return fromCharCode(
- 0xD800 + (code >> 10),
- 0xDC00 + (code & 0x3FF)
- );
- }
-
- function parse(what, how) {
- if (!how || typeof how === 'function') {
- how = {callback: how};
- }
- // if first argument is string, inject html tags
- // otherwise use the DOM tree and parse text nodes only
- return (typeof what === 'string' ? parseString : parseNode)(what, {
- callback: how.callback || defaultImageSrcGenerator,
- attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,
- base: typeof how.base === 'string' ? how.base : twemoji.base,
- ext: how.ext || twemoji.ext,
- size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),
- width: how.size,
- height: how.size,
- className: how.className || twemoji.className,
- onerror: how.onerror || twemoji.onerror
- });
- }
-
- function replace(text, callback) {
- return String(text).replace(re, callback);
- }
-
- function test(text) {
- // IE6 needs a reset before too
- re.lastIndex = 0;
- var result = re.test(text);
- re.lastIndex = 0;
- return result;
- }
-
- function toCodePoint(unicodeSurrogates, sep) {
- var
- r = [],
- c = 0,
- p = 0,
- i = 0;
- while (i < unicodeSurrogates.length) {
- c = unicodeSurrogates.charCodeAt(i++);
- if (p) {
- r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
- p = 0;
- } else if (0xD800 <= c && c <= 0xDBFF) {
- p = c;
- } else {
- r.push(c.toString(16));
- }
- }
- return r.join(sep || '-');
- }
-
-}());
-
-
-function emojify(rawText, emojiSize, basePath) {
- var curatedText = twemoji.parse(rawText, { callback: function(icon, options, variant) { return (basePath || '../js/emoji/') + icon + '.svg'; }, size: emojiSize });
- // QML has a weird bug. If an ampersand is followed by an HTML tag or a character, the tag is ignored and returned as string or the following string is omitted
- // Therefore replacing the ampersand with & in these cases...
- return curatedText.replace(/((\&[\w\d]+\;)|((\&)(\<|\w+)))/g, function(match, p1, p2, p3, p4, p5, offset, string) {
- var returnString = "";
- if ( typeof p2 !== "undefined" ) {
- returnString += p2;
- }
- if (p4 === "&") {
- returnString += "&";
- }
- if ( typeof p5 !== "undefined" ) {
- returnString += p5;
- }
- return returnString;
- });
+ return r.join('-');
}
+
+function emojify(str, emojiSize) {
+ return String(str).replace(re, function (rawText) {
+ var ret = rawText,
+ iconId = toCodePoint(rawText.indexOf(U200D) < 0 ?
+ rawText.replace(UFE0Fg, '') :
+ rawText
+ );
+ if (iconId) {
+ // recycle the match string replacing the emoji
+ // with its image counter part
+ ret = ''
+ );
+ }
+ return ret.replace(ampersandRe, "&");
+ });
+}
\ No newline at end of file
diff --git a/qml/pages/ChatInformationPage.qml b/qml/pages/ChatInformationPage.qml
index 0a1ff0c..d143bd6 100644
--- a/qml/pages/ChatInformationPage.qml
+++ b/qml/pages/ChatInformationPage.qml
@@ -22,6 +22,7 @@ import "../components"
import "../components/chatInformationPage"
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
+import "../js/debug.js" as Debug
Page {
id: chatInformationPage
@@ -59,7 +60,7 @@ Page {
onStatusChanged: {
switch(status) {
case PageStatus.Activating:
- console.log("activating Loader")
+ Debug.log("activating Loader")
mainContentLoader.active = true
break;
case PageStatus.Active:
diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml
index 649c1be..70bb91d 100644
--- a/qml/pages/ChatPage.qml
+++ b/qml/pages/ChatPage.qml
@@ -23,6 +23,7 @@ import Sailfish.Pickers 1.0
import Nemo.Thumbnailer 1.0
import WerkWolf.Fernschreiber 1.0
import "../components"
+import "../js/debug.js" as Debug
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
@@ -133,7 +134,7 @@ Page {
}
function initializePage() {
- console.log("[ChatPage] Initializing chat page...");
+ Debug.log("[ChatPage] Initializing chat page...");
chatView.currentIndex = -1;
chatView.lastReadSentIndex = 0;
var chatType = chatInformation.type['@type'];
@@ -154,13 +155,13 @@ Page {
updateGroupStatusText();
}
if (stickerManager.needsReload()) {
- console.log("[ChatPage] Stickers will be reloaded!");
+ Debug.log("[ChatPage] Stickers will be reloaded!");
tdLibWrapper.getRecentStickers();
tdLibWrapper.getInstalledStickerSets();
stickerManager.setNeedsReload(false);
}
if (chatInformation.pinned_message_id.toString() !== "0") {
- console.log("[ChatPage] Loading pinned message " + chatInformation.pinned_message_id);
+ Debug.log("[ChatPage] Loading pinned message ", chatInformation.pinned_message_id);
tdLibWrapper.getMessage(chatInformation.id, chatInformation.pinned_message_id);
}
}
@@ -292,28 +293,28 @@ Page {
|| (groupStatusType === "chatMemberStatusRestricted" && groupStatus.permissions[privilege])
}
function canPinMessages() {
- console.log("Can we pin messages?");
+ Debug.log("Can we pin messages?");
if (chatPage.isPrivateChat) {
- console.log("Private Chat: No!");
+ Debug.log("Private Chat: No!");
return false;
}
if (chatPage.chatGroupInformation.status["@type"] === "chatMemberStatusCreator") {
- console.log("Creator of this chat: Yes!");
+ Debug.log("Creator of this chat: Yes!");
return true;
}
if (chatPage.chatInformation.permissions.can_pin_messages) {
- console.log("All people can pin: Yes!");
+ Debug.log("All people can pin: Yes!");
return true;
}
if (chatPage.chatGroupInformation.status["@type"] === "chatMemberStatusAdministrator") {
- console.log("Admin with privileges? " + chatPage.chatGroupInformation.status.can_pin_messages);
+ Debug.log("Admin with privileges? ", chatPage.chatGroupInformation.status.can_pin_messages);
return chatPage.chatGroupInformation.status.can_pin_messages;
}
if (chatPage.chatGroupInformation.status["@type"] === "chatMemberStatusRestricted") {
- console.log("Restricted, but can pin messages? " + chatPage.chatGroupInformation.status.permissions.can_pin_messages);
+ Debug.log("Restricted, but can pin messages? ", chatPage.chatGroupInformation.status.permissions.can_pin_messages);
return chatPage.chatGroupInformation.status.permissions.can_pin_messages;
}
- console.log("Something else: No!");
+ Debug.log("Something else: No!");
return false;
}
@@ -384,7 +385,7 @@ Page {
}
}
onChatOnlineMemberCountUpdated: {
- console.log(isSuperGroup + "/" + isBasicGroup + "/" + chatInformation.id.toString() + "/" + chatId);
+ Debug.log(isSuperGroup, "/", isBasicGroup, "/", chatInformation.id.toString(), "/", chatId);
if ((isSuperGroup || isBasicGroup) && chatInformation.id.toString() === chatId) {
chatOnlineMemberCount = onlineMemberCount;
updateGroupStatusText();
@@ -405,7 +406,7 @@ Page {
}
onReceivedMessage: {
if (messageId === chatInformation.pinned_message_id.toString()) {
- console.log("[ChatPage] Received pinned message");
+ Debug.log("[ChatPage] Received pinned message");
pinnedMessageItem.pinnedMessage = message;
}
}
@@ -414,11 +415,11 @@ Page {
Connections {
target: chatModel
onMessagesReceived: {
- console.log("[ChatPage] Messages received, view has " + chatView.count + " messages, setting view to index " + modelIndex + ", own messages were read before index " + lastReadSentIndex);
+ Debug.log("[ChatPage] Messages received, view has ", chatView.count, " messages, setting view to index ", modelIndex, ", own messages were read before index ", lastReadSentIndex);
if (totalCount === 0) {
if (chatPage.iterativeInitialization) {
chatPage.iterativeInitialization = false;
- console.log("[ChatPage] actually, skipping that: No Messages in Chat.");
+ Debug.log("[ChatPage] actually, skipping that: No Messages in Chat.");
chatView.positionViewAtEnd();
chatPage.loading = false;
return;
@@ -436,28 +437,28 @@ Page {
}
if (chatView.height > chatView.contentHeight) {
- console.log("[ChatPage] Chat content quite small...");
+ Debug.log("[ChatPage] Chat content quite small...");
viewMessageTimer.queueViewMessage(chatView.count - 1);
}
}
onNewMessageReceived: {
if (chatView.manuallyScrolledToBottom || message.sender_user_id === chatPage.myUserId) {
- console.log("[ChatPage] Own message received or was scrolled to bottom, scrolling down to see it...");
+ Debug.log("[ChatPage] Own message received or was scrolled to bottom, scrolling down to see it...");
chatView.scrollToIndex(chatView.count - 1);
}
}
onUnreadCountUpdated: {
- console.log("[ChatPage] Unread count updated, new count: " + unreadCount);
+ Debug.log("[ChatPage] Unread count updated, new count: ", unreadCount);
chatInformation.unread_count = unreadCount;
chatUnreadMessagesCountBackground.visible = ( !chatPage.loading && unreadCount > 0 );
chatUnreadMessagesCount.text = unreadCount > 99 ? "99+" : unreadCount;
}
onLastReadSentMessageUpdated: {
- console.log("[ChatPage] Updating last read sent index, new index: " + lastReadSentIndex);
+ Debug.log("[ChatPage] Updating last read sent index, new index: ", lastReadSentIndex);
chatView.lastReadSentIndex = lastReadSentIndex;
}
onMessagesIncrementalUpdate: {
- console.log("Incremental update received. View now has " + chatView.count + " messages, view is on index " + modelIndex + ", own messages were read before index " + lastReadSentIndex);
+ Debug.log("Incremental update received. View now has ", chatView.count, " messages, view is on index ", modelIndex, ", own messages were read before index ", lastReadSentIndex);
chatView.lastReadSentIndex = lastReadSentIndex;
chatViewCooldownTimer.start();
}
@@ -468,7 +469,7 @@ Page {
onPinnedMessageChanged: {
chatInformation = chatModel.getChatInformation();
if (chatInformation.pinned_message_id.toString() !== "0") {
- console.log("[ChatPage] Loading pinned message " + chatInformation.pinned_message_id);
+ Debug.log("[ChatPage] Loading pinned message ", chatInformation.pinned_message_id);
tdLibWrapper.getMessage(chatInformation.id, chatInformation.pinned_message_id);
} else {
pinnedMessageItem.pinnedMessage = undefined;
@@ -603,15 +604,15 @@ Page {
Row {
id: headerRow
width: parent.width - (3 * Theme.horizontalPageMargin)
- height: chatOverviewColumn.height + ( chatPage.isPortrait ? (2 * Theme.paddingMedium) : (2 * Theme.paddingSmall) )
+ height: chatOverviewItem.height + ( chatPage.isPortrait ? (2 * Theme.paddingMedium) : (2 * Theme.paddingSmall) )
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.paddingMedium
ProfileThumbnail {
id: chatPictureThumbnail
replacementStringHint: chatNameText.text
- width: chatOverviewColumn.height
- height: chatOverviewColumn.height
+ width: chatOverviewItem.height
+ height: chatOverviewItem.height
anchors.bottom: parent.bottom
anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingMedium : Theme.paddingSmall
@@ -626,34 +627,38 @@ Page {
}
}
- Column {
- id: chatOverviewColumn
+ Item {
+ id: chatOverviewItem
width: parent.width - chatPictureThumbnail.width - Theme.paddingMedium
+ height: chatNameText.height + chatStatusText.height
anchors.bottom: parent.bottom
anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingMedium : Theme.paddingSmall
- Text {
+ Label {
id: chatNameText
+ width: Math.min(implicitWidth, parent.width)
+ anchors.right: parent.right
text: chatInformation.title !== "" ? Emoji.emojify(chatInformation.title, font.pixelSize) : qsTr("Unknown")
textFormat: Text.StyledText
font.pixelSize: chatPage.isPortrait ? Theme.fontSizeLarge : Theme.fontSizeMedium
font.family: Theme.fontFamilyHeading
color: Theme.highlightColor
- elide: Text.ElideRight
- width: parent.width
+ truncationMode: TruncationMode.Fade
maximumLineCount: 1
- horizontalAlignment: Text.AlignRight
}
- Text {
+ Label {
id: chatStatusText
+ width: Math.min(implicitWidth, parent.width)
+ anchors {
+ right: parent.right
+ bottom: parent.bottom
+ }
text: ""
textFormat: Text.StyledText
font.pixelSize: chatPage.isPortrait ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny
font.family: Theme.fontFamilyHeading
color: headerMouseArea.pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor
- elide: Text.ElideRight
- width: parent.width
+ truncationMode: TruncationMode.Fade
maximumLineCount: 1
- horizontalAlignment: Text.AlignRight
}
}
}
@@ -693,7 +698,7 @@ Page {
repeat: false
running: false
onTriggered: {
- console.log("[ChatPage] Cooldown completed...");
+ Debug.log("[ChatPage] Cooldown completed...");
chatView.inCooldown = false;
}
}
@@ -743,7 +748,7 @@ Page {
}
function handleScrollPositionChanged() {
- console.log("Current position: " + chatView.contentY);
+ Debug.log("Current position: ", chatView.contentY);
if (chatInformation.unread_count > 0) {
var bottomIndex = chatView.indexAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin ));
if (bottomIndex > -1) {
@@ -766,11 +771,11 @@ Page {
onContentYChanged: {
if (!chatPage.loading && !chatView.inCooldown) {
if (chatView.indexAt(chatView.contentX, chatView.contentY) < 10) {
- console.log("[ChatPage] Trying to get older history items...");
+ Debug.log("[ChatPage] Trying to get older history items...");
chatView.inCooldown = true;
chatModel.triggerLoadMoreHistory();
} else if (chatView.indexAt(chatView.contentX, chatView.contentY) > ( count - 10)) {
- console.log("[ChatPage] Trying to get newer history items...");
+ Debug.log("[ChatPage] Trying to get newer history items...");
chatView.inCooldown = true;
chatModel.triggerLoadMoreFuture();
}
@@ -995,7 +1000,7 @@ Page {
var picker = pageStack.push("Sailfish.Pickers.ImagePickerPage");
picker.selectedContentPropertiesChanged.connect(function(){
attachmentOptionsRow.visible = false;
- console.log("Selected document: " + picker.selectedContentProperties.filePath );
+ Debug.log("Selected document: ", picker.selectedContentProperties.filePath );
attachmentPreviewRow.fileProperties = picker.selectedContentProperties;
attachmentPreviewRow.isPicture = true;
attachmentPreviewRow.visible = true;
@@ -1010,7 +1015,7 @@ Page {
var picker = pageStack.push("Sailfish.Pickers.VideoPickerPage");
picker.selectedContentPropertiesChanged.connect(function(){
attachmentOptionsRow.visible = false;
- console.log("Selected video: " + picker.selectedContentProperties.filePath );
+ Debug.log("Selected video: ", picker.selectedContentProperties.filePath );
attachmentPreviewRow.fileProperties = picker.selectedContentProperties;
attachmentPreviewRow.isVideo = true;
attachmentPreviewRow.visible = true;
@@ -1025,7 +1030,7 @@ Page {
var picker = pageStack.push("Sailfish.Pickers.DocumentPickerPage");
picker.selectedContentPropertiesChanged.connect(function(){
attachmentOptionsRow.visible = false;
- console.log("Selected document: " + picker.selectedContentProperties.filePath );
+ Debug.log("Selected document: ", picker.selectedContentProperties.filePath );
attachmentPreviewRow.fileProperties = picker.selectedContentProperties;
attachmentPreviewRow.isDocument = true;
attachmentPreviewRow.visible = true;
@@ -1093,14 +1098,14 @@ Page {
visible: attachmentPreviewRow.isPicture || attachmentPreviewRow.isVideo
}
- Text {
+ Label {
id: attachmentPreviewText
font.pixelSize: Theme.fontSizeSmall
text: typeof attachmentPreviewRow.fileProperties !== "undefined" ? attachmentPreviewRow.fileProperties.fileName || "" : "";
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
color: Theme.secondaryColor
visible: attachmentPreviewRow.isDocument
}
diff --git a/qml/pages/CoverPage.qml b/qml/pages/CoverPage.qml
index 5df9580..9e5df33 100644
--- a/qml/pages/CoverPage.qml
+++ b/qml/pages/CoverPage.qml
@@ -120,15 +120,14 @@ CoverBackground {
color: Theme.primaryColor
text: Functions.getShortenedCount(coverPage.unreadMessages)
}
- Text {
+ Label {
id: unreadMessagesText
font.pixelSize: Theme.fontSizeSmall
- color: Theme.primaryColor
width: parent.width - unreadMessagesCountText.width - Theme.paddingMedium
wrapMode: Text.Wrap
anchors.verticalCenter: unreadMessagesCountText.verticalCenter
maximumLineCount: 2
- elide: Text.ElideRight
+ truncationMode: TruncationMode.Fade
}
}
diff --git a/qml/pages/ImagePage.qml b/qml/pages/ImagePage.qml
index 0ee5413..b0d67cf 100644
--- a/qml/pages/ImagePage.qml
+++ b/qml/pages/ImagePage.qml
@@ -20,6 +20,7 @@ import QtQuick 2.6
import Sailfish.Silica 1.0
import "../components"
import "../js/functions.js" as Functions
+import "../js/debug.js" as Debug
Page {
id: imagePage
@@ -73,7 +74,7 @@ Page {
target: tdLibWrapper
onFileUpdated: {
if (fileId === imagePage.pictureFileInformation.id) {
- console.log("File updated, completed? " + fileInformation.local.is_downloading_completed);
+ Debug.log("File updated, completed? ", fileInformation.local.is_downloading_completed);
if (fileInformation.local.is_downloading_completed) {
imagePage.pictureFileInformation = fileInformation;
imagePage.imageUrl = fileInformation.local.path;
diff --git a/qml/pages/OverviewPage.qml b/qml/pages/OverviewPage.qml
index cad8fc0..3421189 100644
--- a/qml/pages/OverviewPage.qml
+++ b/qml/pages/OverviewPage.qml
@@ -23,6 +23,7 @@ import WerkWolf.Fernschreiber 1.0
import "../components"
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
+import "../js/debug.js" as Debug
Page {
id: overviewPage
@@ -44,14 +45,14 @@ Page {
Connections {
target: dBusAdaptor
onPleaseOpenMessage: {
- console.log("[OverviewPage] Opening chat from external call...")
+ Debug.log("[OverviewPage] Opening chat from external call...")
if (chatListCreated) {
pageStack.pop(overviewPage, PageStackAction.Immediate)
pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : chatListModel.getById(chatId) }, PageStackAction.Immediate)
}
}
onPleaseOpenUrl: {
- console.log("[OverviewPage] Opening URL requested: " + url);
+ Debug.log("[OverviewPage] Opening URL requested: ", url);
Functions.handleLink(url);
}
}
diff --git a/qml/pages/PollResultsPage.qml b/qml/pages/PollResultsPage.qml
index c77231b..a3cd6b3 100644
--- a/qml/pages/PollResultsPage.qml
+++ b/qml/pages/PollResultsPage.qml
@@ -21,6 +21,7 @@ import Sailfish.Silica 1.0
import "../components"
import "../js/functions.js" as Functions
import "../js/twemoji.js" as Emoji
+import "../js/debug.js" as Debug
Page {
id: pollResultsPage
@@ -146,7 +147,6 @@ Page {
if(extra === optionDelegate.usersResponseIdentifierString) {
for(var i = 0; i < userIds.length; i += 1) {
optionDelegate.users.append({id: userIds[i], user:tdLibWrapper.getUserInformation(userIds[i])});
- console.log("APPEND USER", JSON.stringify({id: userIds[i], user:tdLibWrapper.getUserInformation(userIds[i])}));
}
loadUsersTimer.start();
}
diff --git a/src/appsettings.cpp b/src/appsettings.cpp
index 6dd3bcc..5f402ff 100644
--- a/src/appsettings.cpp
+++ b/src/appsettings.cpp
@@ -16,9 +16,9 @@
*/
#include "appsettings.h"
-#include
-#define LOG(x) qDebug() << "[AppSettings]" << x
+#define DEBUG_MODULE AppSettings
+#include "debuglog.h"
namespace {
const QString KEY_SEND_BY_ENTER("sendByEnter");
diff --git a/src/chatlistmodel.cpp b/src/chatlistmodel.cpp
index 2610179..4a48045 100644
--- a/src/chatlistmodel.cpp
+++ b/src/chatlistmodel.cpp
@@ -19,9 +19,9 @@
#include "chatlistmodel.h"
#include "fernschreiberutils.h"
-#include
-#define LOG(x) qDebug() << "[ChatListModel]" << x
+#define DEBUG_MODULE ChatListModel
+#include "debuglog.h"
namespace {
const QString ID("id");
diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp
index 084a737..0b02943 100644
--- a/src/chatmodel.cpp
+++ b/src/chatmodel.cpp
@@ -22,9 +22,9 @@
#include
#include
#include
-#include
-#define LOG(x) qDebug() << "[ChatModel]" << x
+#define DEBUG_MODULE ChatModel
+#include "debuglog.h"
namespace {
const QString ID("id");
diff --git a/src/dbusadaptor.cpp b/src/dbusadaptor.cpp
index f2b91a1..16e17ed 100644
--- a/src/dbusadaptor.cpp
+++ b/src/dbusadaptor.cpp
@@ -19,22 +19,22 @@
#include "dbusadaptor.h"
-#include
+#define DEBUG_MODULE DBusAdaptor
+#include "debuglog.h"
DBusAdaptor::DBusAdaptor(QObject *parent): QDBusAbstractAdaptor(parent)
{
-
}
void DBusAdaptor::openMessage(const QString &chatId, const QString &messageId)
{
- qDebug() << "[DBusAdaptor] Open Message " << chatId << messageId;
+ LOG("Open Message" << chatId << messageId);
emit pleaseOpenMessage(chatId, messageId);
}
void DBusAdaptor::openUrl(const QStringList &arguments)
{
- qDebug() << "[DBusAdaptor] Open Url" << arguments;
+ LOG("Open Url" << arguments);
if (arguments.length() >= 1) {
emit pleaseOpenUrl(arguments.first());
}
diff --git a/src/dbusinterface.cpp b/src/dbusinterface.cpp
index ab38826..38753d0 100644
--- a/src/dbusinterface.cpp
+++ b/src/dbusinterface.cpp
@@ -19,27 +19,29 @@
#include "dbusinterface.h"
+#define DEBUG_MODULE DBusInterface
+#include "debuglog.h"
+
DBusInterface::DBusInterface(QObject *parent) : QObject(parent)
{
- qDebug() << "[DBusInterface] Initializing D-BUS connectivity";
+ LOG("Initializing D-BUS connectivity");
this->dbusAdaptor = new DBusAdaptor(this);
QDBusConnection sessionBusConnection = QDBusConnection::sessionBus();
if (!sessionBusConnection.isConnected()) {
- qDebug() << "[DBusInterface] Error connecting to D-BUS";
+ WARN("Error connecting to D-BUS");
return;
}
if (!sessionBusConnection.registerObject(PATH_NAME, this)) {
- qDebug() << "[DBusInterface] Error registering root object to D-BUS" << sessionBusConnection.lastError().message();
+ WARN("Error registering root object to D-BUS" << sessionBusConnection.lastError().message());
return;
}
if (!sessionBusConnection.registerService(INTERFACE_NAME)) {
- qDebug() << "[DBusInterface] Error registering interface to D-BUS" << sessionBusConnection.lastError().message();
+ WARN("Error registering interface to D-BUS" << sessionBusConnection.lastError().message());
return;
}
-
}
DBusAdaptor *DBusInterface::getDBusAdaptor()
diff --git a/src/debuglog.h b/src/debuglog.h
new file mode 100644
index 0000000..d198781
--- /dev/null
+++ b/src/debuglog.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2020 Slava Monich et al.
+
+ This file is part of Fernschreiber.
+
+ Fernschreiber 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.
+
+ Fernschreiber 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 Fernschreiber. If not, see .
+*/
+
+#ifndef FERNSCHREIBER_DEBUG_LOG_H
+#define FERNSCHREIBER_DEBUG_LOG_H
+
+#include
+
+#ifndef DEBUG_MODULE
+# define DEBUG_MODULE Debug
+#endif
+
+#define LOG_CATEGORY__(x) x##Log
+#define LOG_CATEGORY_(x) LOG_CATEGORY__(x)
+#define LOG_CATEGORY LOG_CATEGORY_(DEBUG_MODULE)
+static const QLoggingCategory LOG_CATEGORY("fernschreiber." QT_STRINGIFY(DEBUG_MODULE));
+#define LOG(x) qCDebug(LOG_CATEGORY) << "[" QT_STRINGIFY(DEBUG_MODULE) "]" << x
+#define WARN(x) qCWarning(LOG_CATEGORY) << "[" QT_STRINGIFY(DEBUG_MODULE) "]" << x
+
+// No VERBOSE in release build
+#ifndef VERBOSE
+# if defined (QT_DEBUG) || defined (DEBUG)
+# define VERBOSE(x) LOG(x)
+# else
+# define VERBOSE(x)
+# endif
+#endif
+
+#endif // FERNSCHREIBER_DEBUG_LOG_H
diff --git a/src/debuglogjs.h b/src/debuglogjs.h
new file mode 100644
index 0000000..356fe27
--- /dev/null
+++ b/src/debuglogjs.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2020 Sebastian J. Wolf and other contributors
+
+ This file is part of Fernschreiber.
+
+ Fernschreiber 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.
+
+ Fernschreiber 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 Fernschreiber. If not, see .
+*/
+
+#ifndef DEBUGLOGJS_H
+#define DEBUGLOGJS_H
+
+#include
+#include
+#include
+
+class DebugLogJS : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+public:
+
+ DebugLogJS(QObject* parent = Q_NULLPTR) : QObject(parent), category("fernschreiber.JS") {
+ enabled = category.isDebugEnabled();
+ }
+ static QObject* createSingleton(QQmlEngine*, QJSEngine*) { return new DebugLogJS(); }
+ bool isEnabled() const { return enabled; }
+ void setEnabled(bool value) {
+ if (enabled != value) {
+ enabled = value;
+ Q_EMIT enabledChanged();
+ }
+ }
+Q_SIGNALS:
+ void enabledChanged();
+private:
+ bool enabled;
+ const QLoggingCategory category;
+};
+
+#endif // DEBUGLOGJS_H
diff --git a/src/emojisearchworker.cpp b/src/emojisearchworker.cpp
index c239157..c01bfd5 100644
--- a/src/emojisearchworker.cpp
+++ b/src/emojisearchworker.cpp
@@ -18,7 +18,8 @@
*/
#include "emojisearchworker.h"
-#define LOG(x) qDebug() << "[EmojiSearchWorker]" << x
+#define DEBUG_MODULE EmojiSearchWorker
+#include "debuglog.h"
EmojiSearchWorker::~EmojiSearchWorker()
{
diff --git a/src/emojisearchworker.h b/src/emojisearchworker.h
index 25a785d..7401225 100644
--- a/src/emojisearchworker.h
+++ b/src/emojisearchworker.h
@@ -24,7 +24,6 @@
#include
#include
#include
-#include
class EmojiSearchWorker : public QThread
{
diff --git a/src/harbour-fernschreiber.cpp b/src/harbour-fernschreiber.cpp
index 5d413a1..1c54a3e 100644
--- a/src/harbour-fernschreiber.cpp
+++ b/src/harbour-fernschreiber.cpp
@@ -28,23 +28,35 @@
#include
#include
#include
-
+#include
#include "appsettings.h"
+#include "debuglogjs.h"
#include "tdlibfile.h"
#include "tdlibwrapper.h"
#include "chatlistmodel.h"
#include "chatmodel.h"
#include "notificationmanager.h"
+#include "mceinterface.h"
#include "dbusadaptor.h"
#include "processlauncher.h"
#include "stickermanager.h"
#include "tgsplugin.h"
#include "fernschreiberutils.h"
+// The default filter can be overridden by QT_LOGGING_RULES envinronment variable, e.g.
+// QT_LOGGING_RULES="fernschreiber.*=true" harbour-fernschreiber
+#if defined (QT_DEBUG) || defined(DEBUG)
+# define DEFAULT_LOG_FILTER "fernschreiber.*=true"
+#else
+# define DEFAULT_LOG_FILTER "fernschreiber.*=false"
+#endif
+
Q_IMPORT_PLUGIN(TgsIOPlugin)
int main(int argc, char *argv[])
{
+ QLoggingCategory::setFilterRules(DEFAULT_LOG_FILTER);
+
QScopedPointer app(SailfishApp::application(argc, argv));
QScopedPointer view(SailfishApp::createView());
@@ -52,12 +64,14 @@ int main(int argc, char *argv[])
const char *uri = "WerkWolf.Fernschreiber";
qmlRegisterType(uri, 1, 0, "TDLibFile");
+ qmlRegisterSingletonType(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton);
AppSettings *appSettings = new AppSettings(view.data());
context->setContextProperty("appSettings", appSettings);
qmlRegisterUncreatableType(uri, 1, 0, "AppSettings", QString());
- TDLibWrapper *tdLibWrapper = new TDLibWrapper(appSettings, view.data());
+ MceInterface *mceInterface = new MceInterface(view.data());
+ TDLibWrapper *tdLibWrapper = new TDLibWrapper(appSettings, mceInterface, view.data());
context->setContextProperty("tdLibWrapper", tdLibWrapper);
qmlRegisterUncreatableType(uri, 1, 0, "TelegramAPI", QString());
@@ -73,7 +87,7 @@ int main(int argc, char *argv[])
ChatModel chatModel(tdLibWrapper);
context->setContextProperty("chatModel", &chatModel);
- NotificationManager notificationManager(tdLibWrapper, appSettings, &chatModel);
+ NotificationManager notificationManager(tdLibWrapper, appSettings, mceInterface, &chatModel);
context->setContextProperty("notificationManager", ¬ificationManager);
ProcessLauncher processLauncher;
diff --git a/src/mceinterface.cpp b/src/mceinterface.cpp
new file mode 100644
index 0000000..87393b5
--- /dev/null
+++ b/src/mceinterface.cpp
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2020 Slava Monich et al.
+
+ This file is part of Fernschreiber.
+
+ Fernschreiber 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.
+
+ Fernschreiber 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 Fernschreiber. If not, see .
+*/
+
+#include "mceinterface.h"
+#include
+
+#define DEBUG_MODULE MceInterface
+#include "debuglog.h"
+
+MceInterface::MceInterface(QObject *parent) :
+ QDBusInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request",
+ QDBusConnection::systemBus(), parent)
+{
+}
+
+void MceInterface::ledPatternActivate(const QString &pattern)
+{
+ LOG("Activating pattern" << pattern);
+ call(QStringLiteral("req_led_pattern_activate"), pattern);
+}
+
+void MceInterface::ledPatternDeactivate(const QString &pattern)
+{
+ LOG("Deactivating pattern" << pattern);
+ call(QStringLiteral("req_led_pattern_deactivate"), pattern);
+}
+
+void MceInterface::displayCancelBlankingPause()
+{
+ LOG("Enabling display blanking");
+ call(QStringLiteral("req_display_cancel_blanking_pause"));
+}
+
+void MceInterface::displayBlankingPause()
+{
+ LOG("Disabling display blanking");
+ call(QStringLiteral("req_display_blanking_pause"));
+}
diff --git a/src/mceinterface.h b/src/mceinterface.h
new file mode 100644
index 0000000..8d0ee64
--- /dev/null
+++ b/src/mceinterface.h
@@ -0,0 +1,37 @@
+/*
+ Copyright (C) 2020 Slava Monich et al.
+
+ This file is part of Fernschreiber.
+
+ Fernschreiber 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.
+
+ Fernschreiber 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 Fernschreiber. If not, see .
+*/
+
+#ifndef MCE_INTERFACE_H
+#define MCE_INTERFACE_H
+
+#include
+
+class MceInterface : public QDBusInterface
+{
+public:
+ MceInterface(QObject *parent = Q_NULLPTR);
+
+ void ledPatternActivate(const QString &pattern);
+ void ledPatternDeactivate(const QString &pattern);
+ void displayCancelBlankingPause();
+ void displayBlankingPause();
+};
+
+#endif // MCE_INTERFACE_H
+
diff --git a/src/notificationmanager.cpp b/src/notificationmanager.cpp
index f1c6914..69ec7c1 100644
--- a/src/notificationmanager.cpp
+++ b/src/notificationmanager.cpp
@@ -21,14 +21,14 @@
#include "fernschreiberutils.h"
#include "chatmodel.h"
#include
-#include
#include
#include
#include
#include
#include
-#define LOG(x) qDebug() << "[NotificationManager]" << x
+#define DEBUG_MODULE NotificationManager
+#include "debuglog.h"
namespace {
const QString _TYPE("@type");
@@ -120,14 +120,13 @@ NotificationManager::NotificationGroup::~NotificationGroup()
delete nemoNotification;
}
-NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, ChatModel *chatModel) :
- mceInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", QDBusConnection::systemBus()),
+NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, MceInterface *mceInterface, ChatModel *chatModel) :
appIconFile(SailfishApp::pathTo("images/fernschreiber-notification.png").toLocalFile())
{
LOG("Initializing...");
this->tdLibWrapper = tdLibWrapper;
this->appSettings = appSettings;
- this->appSettings = appSettings;
+ this->mceInterface = mceInterface;
this->chatModel = chatModel;
connect(this->tdLibWrapper, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SLOT(handleUpdateActiveNotifications(QVariantList)));
@@ -383,9 +382,9 @@ QString NotificationManager::getNotificationText(const QVariantMap ¬ification
void NotificationManager::controlLedNotification(bool enabled)
{
static const QString PATTERN("PatternCommunicationIM");
- static const QString ACTIVATE("req_led_pattern_activate");
- static const QString DEACTIVATE("req_led_pattern_deactivate");
-
- LOG("Controlling notification LED" << enabled);
- mceInterface.call(enabled ? ACTIVATE : DEACTIVATE, PATTERN);
+ if (enabled) {
+ mceInterface->ledPatternActivate(PATTERN);
+ } else {
+ mceInterface->ledPatternDeactivate(PATTERN);
+ }
}
diff --git a/src/notificationmanager.h b/src/notificationmanager.h
index 79e242f..57c66eb 100644
--- a/src/notificationmanager.h
+++ b/src/notificationmanager.h
@@ -21,10 +21,10 @@
#define NOTIFICATIONMANAGER_H
#include
-#include
#include
#include "tdlibwrapper.h"
#include "appsettings.h"
+#include "mceinterface.h"
class ChatModel;
@@ -36,7 +36,7 @@ class NotificationManager : public QObject
public:
- NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, ChatModel *chatModel);
+ NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, MceInterface *mceInterface, ChatModel *chatModel);
~NotificationManager() override;
public slots:
@@ -61,10 +61,10 @@ private:
TDLibWrapper *tdLibWrapper;
AppSettings *appSettings;
+ MceInterface *mceInterface;
ChatModel *chatModel;
QMap chatMap;
QMap notificationGroups;
- QDBusInterface mceInterface;
QString appIconFile;
};
diff --git a/src/processlauncher.cpp b/src/processlauncher.cpp
index b2f9b5f..323822b 100644
--- a/src/processlauncher.cpp
+++ b/src/processlauncher.cpp
@@ -1,18 +1,23 @@
#include "processlauncher.h"
+#include
+#include
-#define LOG(x) qDebug() << "[ProcessLauncher]" << x
+#define DEBUG_MODULE ProcessLauncher
+#include "debuglog.h"
ProcessLauncher::ProcessLauncher(QObject *parent) : QObject(parent)
{
-
}
+
bool ProcessLauncher::launchProgram(const QString &program, const QStringList &arguments)
{
- QString executablePath = QStandardPaths::findExecutable(program);
- if(executablePath == "") {
- LOG("[ProcessLauncher] Program " + program + "not found");
+ const QString executablePath(QStandardPaths::findExecutable(program));
+ if (executablePath.isEmpty()) {
+ LOG("Program" << program << "not found");
return false;
}
- QProcess *externalProcess = new QProcess(this);
- return externalProcess->startDetached(program, arguments);
+
+ QProcess *process = new QProcess(this);
+ connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
+ return process->startDetached(program, arguments);
}
diff --git a/src/processlauncher.h b/src/processlauncher.h
index 5583637..84ae84a 100644
--- a/src/processlauncher.h
+++ b/src/processlauncher.h
@@ -2,9 +2,6 @@
#define PROCESSLAUNCHER_H
#include
-#include
-#include
-#include
class ProcessLauncher : public QObject
{
diff --git a/src/stickermanager.cpp b/src/stickermanager.cpp
index fc6b593..f09ca3b 100644
--- a/src/stickermanager.cpp
+++ b/src/stickermanager.cpp
@@ -18,10 +18,10 @@
*/
#include "stickermanager.h"
-#include
#include
-#define LOG(x) qDebug() << "[StickerManager]" << x
+#define DEBUG_MODULE StickerManager
+#include "debuglog.h"
StickerManager::StickerManager(TDLibWrapper *tdLibWrapper, QObject *parent) : QObject(parent)
{
diff --git a/src/tdlibfile.cpp b/src/tdlibfile.cpp
index 7e98979..232fa9a 100644
--- a/src/tdlibfile.cpp
+++ b/src/tdlibfile.cpp
@@ -18,9 +18,9 @@
*/
#include "tdlibfile.h"
-#include
-#define LOG(x) qDebug() << "[TDLibFile]" << x
+#define DEBUG_MODULE TDLibFile
+#include "debuglog.h"
namespace {
const QString ID("id");
diff --git a/src/tdlibreceiver.cpp b/src/tdlibreceiver.cpp
index a37f1a9..b15230c 100644
--- a/src/tdlibreceiver.cpp
+++ b/src/tdlibreceiver.cpp
@@ -18,13 +18,8 @@
*/
#include "tdlibreceiver.h"
-#define LOG(x) qDebug() << "[TDLibReceiver]" << x
-
-#if defined (QT_DEBUG) || defined (DEBUG)
-# define VERBOSE(x) LOG(x)
-#else
-# define VERBOSE(x)
-#endif
+#define DEBUG_MODULE TDLibReceiver
+#include "debuglog.h"
namespace {
const QString ID("id");
diff --git a/src/tdlibreceiver.h b/src/tdlibreceiver.h
index 3d041c7..48b04af 100644
--- a/src/tdlibreceiver.h
+++ b/src/tdlibreceiver.h
@@ -19,7 +19,8 @@
#ifndef TDLIBRECEIVER_H
#define TDLIBRECEIVER_H
-#include
+#include
+#include
#include
#include
#include
diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp
index 35627f6..91d5fa0 100644
--- a/src/tdlibwrapper.cpp
+++ b/src/tdlibwrapper.cpp
@@ -25,19 +25,13 @@
#include
#include
#include
-#include
#include
#include
#include
#include
-#define LOG(x) qDebug() << "[TDLibWrapper]" << x
-
-#if defined (QT_DEBUG) || defined (DEBUG)
-# define VERBOSE(x) LOG(x)
-#else
-# define VERBOSE(x)
-#endif
+#define DEBUG_MODULE TDLibWrapper
+#include "debuglog.h"
namespace {
const QString STATUS("status");
@@ -50,10 +44,11 @@ namespace {
const QString _EXTRA("@extra");
}
-TDLibWrapper::TDLibWrapper(AppSettings *appSettings, QObject *parent) : QObject(parent), joinChatRequested(false), contactsRequested(false)
+TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface, QObject *parent) : QObject(parent), joinChatRequested(false), contactsRequested(false)
{
LOG("Initializing TD Lib...");
this->appSettings = appSettings;
+ this->mceInterface = mceInterface;
this->tdLibClient = td_json_client_create();
this->tdLibReceiver = new TDLibReceiver(this->tdLibClient, this);
@@ -202,7 +197,7 @@ void TDLibWrapper::setAuthenticationPassword(const QString &authenticationPasswo
void TDLibWrapper::registerUser(const QString &firstName, const QString &lastName)
{
- qDebug() << "[TDLibWrapper] Register User " << firstName << lastName;
+ LOG("Register User " << firstName << lastName);
QVariantMap requestObject;
requestObject.insert("@type", "registerUser");
requestObject.insert("first_name", firstName);
@@ -907,24 +902,18 @@ void TDLibWrapper::openFileOnDevice(const QString &filePath)
argumentsList.append(filePath);
bool successfullyStarted = QProcess::startDetached("xdg-open", argumentsList);
if (successfullyStarted) {
- qDebug() << "Successfully opened file " << filePath;
+ LOG("Successfully opened file " << filePath);
} else {
- qDebug() << "Error opening file " << filePath;
+ LOG("Error opening file " << filePath);
}
}
void TDLibWrapper::controlScreenSaver(bool enabled)
{
- LOG("Controlling device screen saver" << enabled);
- QDBusConnection dbusConnection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system");
- QDBusInterface dbusInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", dbusConnection);
-
if (enabled) {
- qDebug() << "Enabling screensaver";
- dbusInterface.call("req_display_cancel_blanking_pause");
+ mceInterface->displayCancelBlankingPause();
} else {
- qDebug() << "Disabling screensaver";
- dbusInterface.call("req_display_blanking_pause");
+ mceInterface->displayBlankingPause();
}
}
@@ -1259,21 +1248,21 @@ void TDLibWrapper::setLogVerbosityLevel()
void TDLibWrapper::initializeOpenWith()
{
LOG("Initialize open-with");
-
- qDebug() << "Checking standard open URL file...";
- QString openUrlFilePath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/open-url.desktop";
+ LOG("Checking standard open URL file...");
+ const QString applicationsLocation(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
+ const QString openUrlFilePath(applicationsLocation + "/open-url.desktop");
if (QFile::exists(openUrlFilePath)) {
- qDebug() << "Standard open URL file exists, good!";
+ LOG("Standard open URL file exists, good!");
} else {
- qDebug() << "Copying standard open URL file to " << openUrlFilePath;
+ LOG("Copying standard open URL file to " << openUrlFilePath);
QFile::copy("/usr/share/applications/open-url.desktop", openUrlFilePath);
- QProcess::startDetached("update-desktop-database " + QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
+ QProcess::startDetached("update-desktop-database " + applicationsLocation);
}
- QString desktopFilePath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/harbour-fernschreiber-open-url.desktop";
+ const QString desktopFilePath(applicationsLocation + "/harbour-fernschreiber-open-url.desktop");
QFile desktopFile(desktopFilePath);
if (!desktopFile.exists()) {
- qDebug() << "Creating Open-With file at " << desktopFile.fileName();
+ LOG("Creating Open-With file at " << desktopFile.fileName());
if (desktopFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream fileOut(&desktopFile);
fileOut.setCodec("UTF-8");
@@ -1289,7 +1278,7 @@ void TDLibWrapper::initializeOpenWith()
fileOut << QString("Hidden=true;").toUtf8() << "\n";
fileOut.flush();
desktopFile.close();
- QProcess::startDetached("update-desktop-database " + QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
+ QProcess::startDetached("update-desktop-database " + applicationsLocation);
}
}
diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h
index c716bc5..9a0142a 100644
--- a/src/tdlibwrapper.h
+++ b/src/tdlibwrapper.h
@@ -26,12 +26,13 @@
#include "dbusinterface.h"
#include "emojisearchworker.h"
#include "appsettings.h"
+#include "mceinterface.h"
class TDLibWrapper : public QObject
{
Q_OBJECT
public:
- explicit TDLibWrapper(AppSettings *appSettings, QObject *parent = nullptr);
+ explicit TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface, QObject *parent = nullptr);
~TDLibWrapper();
enum AuthorizationState {
@@ -255,6 +256,7 @@ private:
private:
void *tdLibClient;
AppSettings *appSettings;
+ MceInterface *mceInterface;
TDLibReceiver *tdLibReceiver;
DBusInterface *dbusInterface;
QString version;
diff --git a/src/tgsplugin.cpp b/src/tgsplugin.cpp
index 23a7193..e95b46e 100644
--- a/src/tgsplugin.cpp
+++ b/src/tgsplugin.cpp
@@ -18,7 +18,6 @@
#include "tgsplugin.h"
#include "rlottie.h"
-#include
#include
#include
#include
@@ -27,8 +26,9 @@
#include
-#define LOG(x) qDebug() << "[TgsIOHandler]" << qPrintable(fileName) << x
-#define WARN(x) qWarning() << "[TgsIOHandler]" << qPrintable(fileName) << x
+#define DEBUG_MODULE TgsIOHandler
+#include "debuglog.h"
+#define LOG_(x) LOG(qPrintable(fileName) << x)
class TgsIOHandler : public QImageIOHandler
{
@@ -93,7 +93,7 @@ TgsIOHandler::~TgsIOHandler()
if (currentRender.valid()) {
currentRender.get();
}
- LOG("Done");
+ LOG_("Done");
}
TgsIOHandler::ByteArray TgsIOHandler::uncompress()
@@ -112,7 +112,7 @@ TgsIOHandler::ByteArray TgsIOHandler::uncompress()
unzip.next_out = (Bytef*)unzipped.data();
unzip.avail_in = zipped.size();
unzip.avail_out = chunk;
- LOG("Compressed size" << zipped.size());
+ LOG_("Compressed size" << zipped.size());
while (unzip.avail_out > 0 && zerr == Z_OK) {
zerr = inflate(&unzip, Z_NO_FLUSH);
if (zerr == Z_OK && unzip.avail_out < chunk) {
@@ -124,7 +124,7 @@ TgsIOHandler::ByteArray TgsIOHandler::uncompress()
}
if (zerr == Z_STREAM_END) {
unzipped.resize(unzip.next_out - (Bytef*)unzipped.data());
- LOG("Uncompressed size" << unzipped.size());
+ LOG_("Uncompressed size" << unzipped.size());
} else {
unzipped.clear();
}
@@ -146,7 +146,7 @@ bool TgsIOHandler::load()
frameRate = animation->frameRate();
frameCount = (int) animation->totalFrame();
size = QSize(width, height);
- LOG(size << frameCount << "frames," << frameRate << "fps");
+ LOG_(size << frameCount << "frames," << frameRate << "fps");
render(0); // Pre-render first frame
}
}
@@ -160,7 +160,7 @@ void TgsIOHandler::finishRendering()
currentRender.get();
prevImage = currentImage;
if (!currentFrame && !firstImage.isNull()) {
- LOG("Rendered first frame");
+ LOG_("Rendered first frame");
firstImage = currentImage;
}
} else {
@@ -192,7 +192,7 @@ bool TgsIOHandler::read(QImage* out)
if (currentFrame && currentRender.valid()) {
std::future_status status = currentRender.wait_for(std::chrono::milliseconds(0));
if (status != std::future_status::ready) {
- LOG("Skipping frame" << currentFrame);
+ LOG_("Skipping frame" << currentFrame);
currentFrame = (currentFrame + 1) % frameCount;
*out = prevImage;
return true;
diff --git a/translations/harbour-fernschreiber-fi.ts b/translations/harbour-fernschreiber-fi.ts
index c85edfa..e294f4b 100644
--- a/translations/harbour-fernschreiber-fi.ts
+++ b/translations/harbour-fernschreiber-fi.ts
@@ -99,84 +99,84 @@
ChatInformationPageContent
-
+
+ %1 tilaaja
%1 tilaajaa
-
-
+
+ %1 jäsen
%1 jäsentä
-
- Poistu keskustelusta
+ Poistu keskustelusta
- Liity keskusteluun
+ Liity keskusteluun
- Poistutaan keskustelusta
+ Poistutaan keskustelusta
- Poista keskustelun vaimennus
+ Poista keskustelun vaimennus
- Vaimenna keskustelu
+ Vaimenna keskustelu
- Tuntematon
+ Tuntematon
group title header
- Keskustelun otsikko
+ Keskustelun otsikko
- Syötä 1-128 merkkiä
+ Syötä 1-128 merkkiä
- Tietoa ei ole vielä saatavilla.
+ Tietoa ei ole vielä saatavilla.
group or user infotext header
- Tietoa
+ Tietoa
user phone number header
- Puhelinnumero
+ Puhelinnumero
header
- Kutsulinkki
+ Kutsulinkki
- Kutsulinkki on kopioitu leikepöydälle.
+ Kutsulinkki on kopioitu leikepöydälle.
combination of '[x members], [y online]', which are separate translations
-
+ %1, %2
-
-
-
+
+ %1 paikalla
+ %1 paikalla
@@ -217,17 +217,17 @@
Button: groups in common (short)
- Ryhmät
+ Ryhmät
Button: Group Members
- Jäsenet
+ Jäsenet
Button: Chat Settings
- Asetukset
+ Asetukset
@@ -273,16 +273,16 @@
-
+
+ %1 jäsen
%1 jäsentä
-
-
+
+ %1 tilaaja
%1 tilaajaa
-
@@ -331,48 +331,48 @@
-
+ Valitse viestejä
-
-
-
+
+ %Ln Viesti poistettu
+ %Ln Viestiä poistettu
-
-
-
+
+ %Ln viesti kopioitu
+ %Ln viestiä kopioitu
dialog header
-
-
-
+
+ Välitä %Ln viesti
+ Välitä %Ln viestiä
number of messages selected
-
-
-
+
+ %Ln viesti valittu
+ %Ln viestiä valittu
combination of '[x members], [y online]', which are separate translations
-
+ %1, %2
-
-
-
+
+ %1 paikalla
+ %1 paikalla
@@ -380,11 +380,11 @@
ChatSelectionPage
-
+ Valitse keskustelu
- Sinulla ei ole vielä keskusteluja.
+ Sinulla ei ole vielä keskusteluja.
@@ -866,11 +866,11 @@
-
+ Valitse viesti
-
+ Kiinnitä viesti
@@ -884,11 +884,11 @@
MessageOverlayFlickable
- Sinä
+ Sinä
-
+ Välitetty viesti. Alkuperäinen lähettäjä: %1
@@ -926,9 +926,9 @@
NotificationManager
-
-
-
+
+ %Ln lukematon viesti
+ %Ln lukematonta viestiä
@@ -983,15 +983,15 @@
PinnedMessageItem
- Sinä
+ Sinä
-
+ Kiinnitetty viesti
-
+ Viestin kiinnitys poistettu
@@ -1084,9 +1084,9 @@
% of votes for option
-
+
+ %Ln%
%Ln%
-
@@ -1153,9 +1153,9 @@
% of votes for option
-
+
+ %Ln%
%Ln%
-
@@ -1236,7 +1236,7 @@
-
+ Ilmoitus kytkee näytön päälle
@@ -1269,7 +1269,7 @@
WebPagePreview
-
+ Esikatselua ei tueta tälle linkille...
@@ -1630,11 +1630,11 @@
myself
-
+ lähetit videoviestin
-
+ lähetti videoviestin
diff --git a/translations/harbour-fernschreiber-it.ts b/translations/harbour-fernschreiber-it.ts
index 1d6a9bd..3cb5d6e 100644
--- a/translations/harbour-fernschreiber-it.ts
+++ b/translations/harbour-fernschreiber-it.ts
@@ -99,84 +99,84 @@
ChatInformationPageContent
-
+
+ %1 abbonato
%1 abbonati
-
-
+
+ %1 membro
%1 membri
-
- Lascia chat
+ Lascia chat
- Entra nella chat
+ Entra nella chat
- Lascia chat
+ Lascia chat
- Riattiva suoni chat
+ Riattiva suoni chat
- Silenzia chat
+ Silenzia chat
- Sconosciuto
+ Sconosciuto
group title header
- Titolo chat
+ Titolo chat
- Inserisci da 1 a 128 caratteri
+ Inserisci da 1 a 128 caratteri
- Attualmente non è disponibile nessuna informazione.
+ Nessuna informazione disponibile.
group or user infotext header
- Info
+ Info
user phone number header
- Telefono
+ Telefono
header
- Link d'invito
+ Link d'invito
- Il link d'invito è stato copiato nella clipboard.
+ Il link d'invito è stato copiato.
combination of '[x members], [y online]', which are separate translations
-
+ %1, %2
-
-
-
+
+ %1 online
+ %1 online
@@ -217,17 +217,17 @@
Button: groups in common (short)
- Gruppi
+ Gruppi
Button: Group Members
- Membri
+ Membri
Button: Chat Settings
- Impostazioni
+ Impostazioni
@@ -269,20 +269,20 @@
- Tuo messaggio
+ Scrivi un messaggio...
-
+
+ %1 membro
%1 membri
-
-
+
+ %1 abbonato
%1 abbonati
-
@@ -331,48 +331,48 @@
-
+ Seleziona messaggi
-
-
-
+
+ %Ln messaggio cancellato
+ %Ln messaggi cancellati
-
-
-
+
+ %Ln messaggio copiato
+ %Ln messaggi copiati
dialog header
-
-
-
+
+ Inoltra %Ln messaggio
+ Inoltra %Ln messaggi
number of messages selected
-
-
-
+
+ %Ln messaggio selezionato
+ %Ln messaggi selezionati
combination of '[x members], [y online]', which are separate translations
-
+ %1, %2
-
-
-
+
+ %1 online
+ %1 online
@@ -380,11 +380,11 @@
ChatSelectionPage
-
+ Seleziona chat
- Non hai nessuna chat.
+ Nessuna chat presente.
@@ -865,11 +865,11 @@
-
+ Seleziona messaggio
-
+ Metti messaggio in evidenza
@@ -883,11 +883,11 @@
MessageOverlayFlickable
- Tu
+ Tu
-
+ Questo è un messaggio inoltrato. Autore originale: %1
@@ -925,9 +925,9 @@
NotificationManager
-
-
-
+
+ %Ln messaggio non letto
+ %Ln messaggi non letti
@@ -982,15 +982,15 @@
PinnedMessageItem
- Tu
+ Tu
-
+ Messaggio in evidenza
-
+ Messaggio non più in evidenza
@@ -1083,9 +1083,9 @@
% of votes for option
-
+
+ %Ln%
%Ln%
-
@@ -1152,9 +1152,9 @@
% of votes for option
-
+
+ %Ln%
%Ln%
-
@@ -1235,7 +1235,7 @@
-
+ Notifiche attivano il display
@@ -1268,7 +1268,7 @@
WebPagePreview
-
+ Anteprima non supportata per questo link...
@@ -1629,11 +1629,11 @@
myself
-
+ hai inviato un videomessaggio
-
+ ha inviato un videomessaggio
diff --git a/translations/harbour-fernschreiber-sv.ts b/translations/harbour-fernschreiber-sv.ts
index 419b395..6d177c4 100644
--- a/translations/harbour-fernschreiber-sv.ts
+++ b/translations/harbour-fernschreiber-sv.ts
@@ -1235,7 +1235,7 @@
-
+ Avisering tänder skärmen
diff --git a/translations/harbour-fernschreiber-zh_CN.ts b/translations/harbour-fernschreiber-zh_CN.ts
index 9334db7..a1d1f1e 100644
--- a/translations/harbour-fernschreiber-zh_CN.ts
+++ b/translations/harbour-fernschreiber-zh_CN.ts
@@ -1216,7 +1216,7 @@
-
+ 收到通知时点亮屏幕