From 79eff3c0f6d2cfb2915c4d582bc4c67646797c2f Mon Sep 17 00:00:00 2001 From: erinn Date: Tue, 19 May 2020 12:49:52 -0700 Subject: [PATCH] initial commit --- .gitignore | 1 + Badge.qml | 24 ++ Button.qml | 79 +++++ ButtonTextField.qml | 49 +++ ContactList.qml | 171 ++++++++++ ContactRow.qml | 102 ++++++ EllipsisLabel.qml | 59 ++++ EmojiDrawer.qml | 400 ++++++++++++++++++++++ FontAwesome.qml | 50 +++ HLine.qml | 28 ++ Icon.qml | 63 ++++ IconTextField.qml | 49 +++ InplaceEditText.qml | 92 +++++ Message.qml | 192 +++++++++++ MyProfile.qml | 155 +++++++++ Portrait.qml | 71 ++++ PortraitRow.qml | 141 ++++++++ ProfileList.qml | 124 +++++++ ProfileRow.qml | 56 +++ RadioButton.qml | 27 ++ ScalingLabel.qml | 15 + Statusbar.qml | 186 ++++++++++ TextField.qml | 16 + ToggleSwitch.qml | 32 ++ Toolbar.qml | 123 +++++++ UnderlineTextField.qml | 34 ++ controls/FlagButton.qml | 43 +++ controls/ImageButton.qml | 33 ++ controls/Loader.qml | 38 +++ controls/Variables.qml | 580 ++++++++++++++++++++++++++++++++ styles/CwtchComboBoxStyle.qml | 7 + styles/CwtchExpandingButton.qml | 21 ++ styles/CwtchProgress.qml | 39 +++ styles/CwtchTextAreaStyle.qml | 8 + styles/CwtchTextFieldStyle.qml | 15 + theme/CwtchDark.qml | 51 +++ theme/CwtchLight.qml | 51 +++ theme/Theme.qml | 61 ++++ theme/ThemeType.qml | 46 +++ theme/qmldir | 1 + 40 files changed, 3333 insertions(+) create mode 100644 .gitignore create mode 100644 Badge.qml create mode 100644 Button.qml create mode 100644 ButtonTextField.qml create mode 100644 ContactList.qml create mode 100644 ContactRow.qml create mode 100644 EllipsisLabel.qml create mode 100644 EmojiDrawer.qml create mode 100644 FontAwesome.qml create mode 100644 HLine.qml create mode 100644 Icon.qml create mode 100644 IconTextField.qml create mode 100644 InplaceEditText.qml create mode 100644 Message.qml create mode 100644 MyProfile.qml create mode 100644 Portrait.qml create mode 100644 PortraitRow.qml create mode 100644 ProfileList.qml create mode 100644 ProfileRow.qml create mode 100644 RadioButton.qml create mode 100644 ScalingLabel.qml create mode 100644 Statusbar.qml create mode 100644 TextField.qml create mode 100644 ToggleSwitch.qml create mode 100644 Toolbar.qml create mode 100644 UnderlineTextField.qml create mode 100644 controls/FlagButton.qml create mode 100644 controls/ImageButton.qml create mode 100644 controls/Loader.qml create mode 100644 controls/Variables.qml create mode 100644 styles/CwtchComboBoxStyle.qml create mode 100644 styles/CwtchExpandingButton.qml create mode 100644 styles/CwtchProgress.qml create mode 100644 styles/CwtchTextAreaStyle.qml create mode 100644 styles/CwtchTextFieldStyle.qml create mode 100644 theme/CwtchDark.qml create mode 100644 theme/CwtchLight.qml create mode 100644 theme/Theme.qml create mode 100644 theme/ThemeType.qml create mode 100644 theme/qmldir diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86950b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.qmlc diff --git a/Badge.qml b/Badge.qml new file mode 100644 index 0000000..6369eab --- /dev/null +++ b/Badge.qml @@ -0,0 +1,24 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import CustomQmlTypes 1.0 +import "../theme" + +Rectangle { + width: parent.width * 0.25 + height: width + radius: width/2 + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: parent.width * 0.09 + property alias content: container.children + + Column { + id: container + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + +} diff --git a/Button.qml b/Button.qml new file mode 100644 index 0000000..c341334 --- /dev/null +++ b/Button.qml @@ -0,0 +1,79 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 + +import "../fonts/Twemoji.js" as T +import "../theme" +import "../fonts" + +Rectangle { + id: button + width: (text == undefined || text == "" ? 0 : buttonText.width) + (icon == undefined || icon == "" ? 0 : ico.width) + 24 * gcd.themeScale + Layout.minimumWidth: width + Layout.maximumWidth: width + height: 20 * gcd.themeScale + Layout.minimumHeight: height + Layout.maximumHeight: height + color: mousedown ? Theme.defaultButtonActiveColor : Theme.defaultButtonColor + border.color: mousedown ? Theme.defaultButtonActiveColor : Theme.defaultButtonColor + border.width: 1 + radius: override_radius + antialiasing: true + + property bool checked: false + property double override_radius: (height / 2.0) + property alias text: buttonText.text + property alias font: buttonText.font.family + property string icon + property bool mousedown + property string tooltip + signal clicked + + + RowLayout { + anchors.centerIn: parent + + Image { + anchors.left: parent.left + id: ico + source: icon!="" ? gcd.assetPath + "fontawesome/"+icon+".svg" : ""; + height: button.height / 2 + sourceSize.height: button.height / 2 + } + + Label { + id: buttonText + font.family: Fonts.applicationFontRegular.name + font.styleName: "ExtraBold" + font.pixelSize: button.height / 2 + color: Theme.defaultButtonTextColor + anchors.left: ico.right + anchors.leftMargin: 6 + visible: button.text != "" && button.text != undefined + } + + ToolTip.visible: tooltip != "" && mouseArea.containsMouse + ToolTip.text: tooltip + } + + + MouseArea { + id: mouseArea + anchors.fill: parent + + onClicked: { + parent.focus = true + parent.clicked() + } + + onPressed: mousedown = true + + onReleased: mousedown = false + + hoverEnabled: true + } + + Keys.onSpacePressed: clicked() +} diff --git a/ButtonTextField.qml b/ButtonTextField.qml new file mode 100644 index 0000000..9962ce2 --- /dev/null +++ b/ButtonTextField.qml @@ -0,0 +1,49 @@ +import QtQuick 2.7 + +import QtQuick.Controls 2.13 +import QtQuick.Controls.Styles 1.4 +import QtGraphicalEffects 1.12 +import "." as Widgets +import "../theme" + + +// ButtonTextField integrates a text field and a button +TextField { + id: tf + color: Theme.mainTextColor + font.pixelSize: Theme.secondaryTextSize * gcd.themeScale + width: parent.width - 20 + property string icon + property string button_text + signal clicked + smooth: true + property color dropShadowColor: Theme.dropShadowColor + + background: Rectangle { + radius: 10 + color: Theme.backgroundMainColor + border.color: Theme.backgroundMainColor + layer.enabled: true + layer.effect: DropShadow { + transparentBorder: true + horizontalOffset: 4 + verticalOffset: 4 + samples:10 + color: tf.dropShadowColor + } + } + + Widgets.Button { + icon: "" + text: button_text + anchors { top: parent.top; right: parent.right } + override_radius: 10 + height: parent.height; width: parent.height * 4 + + onClicked: { + parent.focus = true; + parent.clicked(); + } + } + +} diff --git a/ContactList.qml b/ContactList.qml new file mode 100644 index 0000000..2011784 --- /dev/null +++ b/ContactList.qml @@ -0,0 +1,171 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import "../theme" + +ColumnLayout { + id: root + + property alias dualPane: myprof.dualPane + + spacing: 10 + + MouseArea { + anchors.fill: parent + + onClicked: { + forceActiveFocus() + } + } + + MyProfile { // CURRENT PROFILE INFO AND CONTROL BAR + id: myprof + } + + + IconTextField { + id: searchAddText + anchors.horizontalCenter: parent.horizontalCenter + + Layout.minimumWidth: parent.width - 60 + Layout.maximumWidth: parent.width - 60 + + + + + //: ex: "... paste an address here to add a contact ..." + placeholderText: qsTr("paste-address-to-add-contact") + horizontalAlignment: TextInput.AlignHCenter + icon: gcd.assetPath + "core/search-24px.svg" + + + onTextChanged: { + if (text != "") { + gcd.importString(text) + text = "" + } + } + } + + + Flickable { // THE ACTUAL CONTACT LIST + id: sv + //Layout.alignment: Qt.AlignLeft | Qt.AlignTop + clip: true + Layout.minimumHeight: 100 + //Layout.maximumHeight: parent.height - 30 + Layout.fillHeight: true + Layout.minimumWidth: parent.width + Layout.maximumWidth: parent.width + contentWidth: colContacts.width + contentHeight: colContacts.height + boundsBehavior: Flickable.StopAtBounds + maximumFlickVelocity: 400 + + ScrollBar.vertical: ScrollBar { + policy: ScrollBar.AsNeeded + background: Rectangle { + implicitWidth: 6 + + color: Theme.backgroundMainColor + } + contentItem: Rectangle { + implicitWidth: 6 + implicitHeight:1 + color: Theme.backgroundPaneColor + } + } + + ColumnLayout { + id: colContacts + width: root.width + spacing: 0 + + Connections { // ADD/REMOVE CONTACT ENTRIES + target: gcd + + onAddContact: function(handle, displayName, image, badge, status, blocked, loading, lastMsgTs) { + + for (var i = 0; i < contactsModel.count; i++) { + if (contactsModel.get(i)["_handle"] == handle) { + return + } + } + + var index = contactsModel.count + for (var i = 0; i < contactsModel.count; i++) { + if (contactsModel.get(i)["_lastMsgTs"] < lastMsgTs) { + index = i + break + } + } + + var newContact = { + "_handle": handle, + "_displayName": displayName + (blocked ? " (blocked)" : "" ), + "_image": image, + "_badge": badge, + "_status": status, + "_blocked": blocked, + "_loading": loading, + "_loading": loading, + "_lastMsgTs": lastMsgTs + } + + contactsModel.insert(index, newContact) + } + + onRemoveContact: function(handle) { + for(var i = 0; i < contactsModel.count; i++){ + if(contactsModel.get(i)["_handle"] == handle) { + console.log("deleting contact " + contactsModel.get(i)["_handle"]) + contactsModel.remove(i) + return + } + } + } + + onIncContactUnreadCount: function(handle) { + var ts = Math.round((new Date()).getTime() / 1000); + for(var i = 0; i < contactsModel.count; i++){ + if(contactsModel.get(i)["_handle"] == handle) { + var contact = contactsModel.get(i) + contact["_lastMsgTs"] = ts + contactsModel.move(i, 0, 1) + } + } + } + + onResetProfile: function() { + contactsModel.clear() + } + } + + ListModel { // CONTACT OBJECTS ARE STORED HERE ... + id: contactsModel + } + + Repeater { + model: contactsModel // ... AND DISPLAYED HERE + delegate: ContactRow { + handle: _handle + displayName: _displayName + image: _image + badge: _badge + status: _status + blocked: _blocked + loading: _loading + } + } + + + } + } + + +} + + + diff --git a/ContactRow.qml b/ContactRow.qml new file mode 100644 index 0000000..bed4b98 --- /dev/null +++ b/ContactRow.qml @@ -0,0 +1,102 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import CustomQmlTypes 1.0 +import "../styles" +import "../widgets" as Widgets +import "../theme" +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +PortraitRow { + + property int status: 0 + property int badge + property bool loading + + badgeColor: Theme.portraitContactBadgeColor + badgeVisible: badge > 0 + + badgeContent: Label { + id: lblUnread + color: Theme.portraitContactBadgeTextColor + font.pixelSize: Theme.badgeTextSize * gcd.themeScale + font.weight: Font.Bold + text: badge > 99 ? "99+" : badge + } + + ProgressBar { // LOADING ? + id: loadingProgress + property bool running + running: loading + visible: loading + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 1 * gcd.themeScale + anchors.rightMargin: 25 * gcd.themeScale + + height: parent.height * .1 + width: 100 * gcd.themeScale + + indeterminate: true + + style: ProgressBarStyle { + progress: CwtchProgress { running: loadingProgress.running} + } + } + + onClicked: function(handle) { + gcd.broadcast("ResetMessagePane") + isActive = true + theStack.pane = theStack.messagePane + gcd.loadMessagesPane(handle) + badge = 0 + if (handle.length == 32) { + gcd.requestGroupSettings(handle) + } + } + + Component.onCompleted: { setColors(status) } + + onStatusChanged: { setColors(status) } + + function setColors(status) { + //-2:WtfCodeError,-1:Error,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Synced,5:Failed,6:Killed + if (status == 4 || status == 3) { + portraitBorderColor = Theme.portraitOnlineBorderColor + portraitColor = Theme.portraitOnlineBackgroundColor + nameColor = Theme.portraitOnlineTextColor + onionColor = Theme.portraitOnlineTextColor + } else if (status == 2 || status == 1) { + portraitBorderColor = Theme.portraitConnectingBorderColor + portraitColor = Theme.portraitConnectingBackgroundColor + nameColor = Theme.portraitConnectingTextColor + onionColor = Theme.portraitConnectingTextColor + } else { + portraitBorderColor = Theme.portraitOfflineBorderColor + portraitColor = Theme.portraitOfflineBackgroundColor + nameColor = Theme.portraitOfflineTextColor + onionColor = Theme.portraitOfflineTextColor + } + } + + Connections { // UPDATE UNREAD MESSAGES COUNTER + target: gcd + + onUpdateContactStatus: function(_handle, _status, _loading) { + if (handle == _handle) { + status = _status + loadingProgress.visible = loadingProgress.running = loading = _loading + } + } + + onIncContactUnreadCount: function(handle) { + if (handle == _handle && gcd.selectedConversation != handle) { + badge++ + } + } + } +} diff --git a/EllipsisLabel.qml b/EllipsisLabel.qml new file mode 100644 index 0000000..a0d042c --- /dev/null +++ b/EllipsisLabel.qml @@ -0,0 +1,59 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import CustomQmlTypes 1.0 +import "../widgets" as Widgets +import "../theme" + + +// Needs the parent to have an onWidthChanged that calls .textResize() +Item { + anchors.right: parent.right + anchors.left: parent.left + + property string text + + property alias color: label.color + property alias pixelSize: label.font.pixelSize + property alias weight: label.font.weight + property alias strikeout: label.font.strikeout + property alias font: label.font + property int extraPadding: 0 + + property Item container: parent + + height: textMetric.height + width: textMetric.width + 10 + anchors.leftMargin: 10 + + Label { + id: label + textFormat: Text.PlainText + + elide: Text.ElideRight + text: textMetric.text + } + + TextMetrics { + id: textMetric + text: text + font: label.font + } + + onTextChanged: { + textResize() + } + + function textResize() { + textMetric.text = text + var i = 2 + var containerWidth = container != null ? container.width : 50 + // - 30 for padding + while (textMetric.width > containerWidth - ((30 + extraPadding) * gcd.themeScale) && containerWidth > 50) { + textMetric.text = text.slice(0, text.length - (i * 3)) + "..." + i++ + } + } + +} diff --git a/EmojiDrawer.qml b/EmojiDrawer.qml new file mode 100644 index 0000000..7bb9bba --- /dev/null +++ b/EmojiDrawer.qml @@ -0,0 +1,400 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.13 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import Qt.labs.folderlistmodel 2.13 +import QtQml.Models 2.13 + +import "../fonts/MutantStandard.js" as Mutant +import "controls" + +Item { + id: root + height: 0 + property int size: 24 + property int requestedHeight: size * 8 + property string morph: "clw" + property string color: "v1" + property bool narrowMode: width < (txtSearch.width + root.size * 14 + btnX.width) + signal picked(string shortcode) + signal slideopen() + signal slideclosed() + visible: height != 0 + + Rectangle { + color: windowItem.cwtch_dark_color + anchors.fill: parent + } + + PropertyAnimation { + id: animClose; + target: root; + properties: "height"; + to: 0; + duration: 400; + } + + PropertyAnimation { + id: animOpen; + target: root; + properties: "height"; + to: requestedHeight; + duration: 400; + } + + Button { + id: btnX + anchors.top: parent.top + anchors.right: parent.right + text: "x" + + onClicked: animClose.start() + } + + ColumnLayout { + anchors.fill: parent + + + RowLayout { + TextField { + id: txtSearch + //: Search... + placeholderText: qsTr("search") + onTextChanged: { + if (text == "") emojiModel.model = folder_expressions + else emojiModel.model = folder_search + emojiModel.updatefilters() + } + } + + ImageButton { + id: btnEmojiExpressionsGroup + visible: !root.narrowMode + //: Expressions + tooltip: qsTr("emojicat-expressions") + source: gcd.assetPath + "mutstd/smile.webp" + size: root.size + onClicked: emojiModel.model = folder_expressions + } + ImageButton { + visible: !root.narrowMode + //: Activities + tooltip: qsTr("emojicat-activities") + source: gcd.assetPath + "mutstd/artist_r1.webp" + size: root.size + onClicked: emojiModel.model = folder_activities_clothing + } + ImageButton { + visible: !root.narrowMode + //: Food, drink & herbs + tooltip: qsTr("emojicat-food") + source: gcd.assetPath + "mutstd/red_apple.webp" + size: root.size + onClicked: emojiModel.model = folder_food_drink_herbs + } + ImageButton { + visible: !root.narrowMode + //: Gender, relationships & sexuality + tooltip: qsTr("emojicat-gender") + size: root.size + source: gcd.assetPath + "mutstd/pride_100.webp" + onClicked: emojiModel.model = folder_gsr + } + ImageButton { + visible: !root.narrowMode + //: Nature and effects + tooltip: qsTr("emojicat-nature") + source: gcd.assetPath + "mutstd/sun_behind_small_cloud.webp" + size: root.size + onClicked: emojiModel.model = folder_nature + } + ImageButton { + visible: !root.narrowMode + //: Objects + tooltip: qsTr("emojicat-objects") + source: gcd.assetPath + "mutstd/crystal_ball.webp" + size: root.size + onClicked: emojiModel.model = folder_objects + } + ImageButton { + visible: !root.narrowMode + //: People and animals + tooltip: qsTr("emojicat-people") + source: gcd.assetPath + "mutstd/crow.webp" + size: root.size + onClicked: emojiModel.model = folder_people + } + ImageButton { + visible: !root.narrowMode + //: Symbols + tooltip: qsTr("emojicat-symbols") + source: gcd.assetPath + "mutstd/purple_heart.webp" + size: root.size + onClicked: emojiModel.model = folder_symbols + } + ImageButton { + visible: !root.narrowMode + //: Travel & places + tooltip: qsTr("emojicat-travel") + source: gcd.assetPath + "mutstd/airplane.webp" + size: root.size + onClicked: emojiModel.model = folder_travel_places + } + ImageButton { + visible: !root.narrowMode + //: Miscellaneous + tooltip: qsTr("emojicat-misc") + source: gcd.assetPath + "mutstd/hash_char.webp" + size: root.size + onClicked: emojiModel.model = folder_utils + } + ImageButton { + visible: !root.narrowMode + id: btnUndefinedGroup + // (no tooltip; this is a catchall group meant to detect unclassified emoji during development) + //TODO: remove this category upon finalizing the Emoji Drawer + source: gcd.assetPath + "mutstd/undefined_character.webp" + size: root.size + onClicked: emojiModel.model = folder_other + } + + Item { + visible: root.narrowMode + height: root.size + width: root.size + + Image { + id: imgCatRot + anchors.centerIn: parent + source: cats[index].source + property int index: 0 + property var cats: [ + {source: gcd.assetPath + "mutstd/smile.webp", model: folder_expressions}, + {source: gcd.assetPath + "mutstd/artist_r1.webp", model: folder_activities_clothing}, + {source: gcd.assetPath + "mutstd/red_apple.webp", model: folder_food_drink_herbs}, + {source: gcd.assetPath + "mutstd/pride_100.webp", model: folder_gsr}, + {source: gcd.assetPath + "mutstd/sun_behind_small_cloud.webp", model: folder_nature}, + {source: gcd.assetPath + "mutstd/crystal_ball.webp", model: folder_objects}, + {source: gcd.assetPath + "mutstd/crow.webp", model: folder_people}, + {source: gcd.assetPath + "mutstd/purple_heart.webp", model: folder_symbols}, + {source: gcd.assetPath + "mutstd/airplane.webp", model: folder_travel_places}, + {source: gcd.assetPath + "mutstd/hash_char.webp", model: folder_utils}, + {source: gcd.assetPath + "mutstd/undefined_character.webp", model: folder_other} + ] + height: root.size * (maCatRot.pressed ? 0.8 : 1.0) + width: root.size * (maCatRot.pressed ? 0.8 : 1.0) + + ToolTip.visible: maCatRot.containsMouse + ToolTip.text: gcd.os == "android" ? qsTr("cycle-cats-android") : qsTr("cycle-cats-desktop") + + MouseArea { + id: maCatRot + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + anchors.fill: parent; + + onClicked: { + if (mouse.button == Qt.RightButton) {//todo: long press on android + imgCatRot.index = 0 + } else { + imgCatRot.index = (imgCatRot.index + 1) % imgCatRot.cats.length + } + emojiModel.model = imgCatRot.cats[imgCatRot.index].model + //root.morph = Mutant.standard.morphs[imgMorph.index] + //emojiModel.updatefilters() + } + } + } + } + + Item { + height: root.size + width: root.size + + Image { + id: imgMorph + anchors.centerIn: parent + source: gcd.assetPath + "mutstd/hand_"+Mutant.standard.morphs[index]+"_"+root.color+".webp" + property int index: 0 + height: root.size + width: root.size + + ToolTip.visible: maMorph.containsMouse + ToolTip.text: gcd.os == "android" ? qsTr("cycle-morphs-android") : qsTr("cycle-morphs-desktop") + + MouseArea { + id: maMorph + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + anchors.fill: parent; + onClicked: { + if (mouse.button == Qt.RightButton) {//todo: long press on android + imgMorph.index = 0//TODO: saved morph + } else { + imgMorph.index = (imgMorph.index + 1) % Mutant.standard.morphs.length + } + root.morph = Mutant.standard.morphs[imgMorph.index] + emojiModel.updatefilters() + } + } + } + } + + Item { + height: root.size + width: root.size + + Image { + id: imgColor + anchors.centerIn: parent + source: gcd.assetPath + "mutstd/color_modifier_"+Mutant.standard.colorByIndex(index, root.morph)+".webp" + property int index: 0 + height: root.size + width: root.size + + ToolTip.visible: ma.containsMouse + ToolTip.text: gcd.os == "android" ? qsTr("cycle-colours-android") : qsTr("cycle-colours-desktop") + + MouseArea { + id: ma + anchors.fill: parent; + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: function(mouse){ + if (mouse.button == Qt.RightButton) {//todo: long press on android + imgColor.index = 0//todo: saved color + } else { + imgColor.index = (imgColor.index + 1) % Mutant.standard.numColors(root.morph) + } + root.color = Mutant.standard.colorByIndex(imgColor.index, root.morph) + emojiModel.updatefilters() + } + } + } + } + } + + GridView { + Layout.fillWidth: true + Layout.fillHeight: true + height: root.size * 3 + cellWidth: root.size + cellHeight: root.size + clip: true + ScrollBar.vertical: ScrollBar {} + maximumFlickVelocity: 1250 + boundsBehavior: GridView.StopAtBounds + + + model: emojiModel + } + } + + ListModel { id: folder_activities_clothing } + ListModel { id: folder_expressions } + ListModel { id: folder_food_drink_herbs } + ListModel { id: folder_gsr } + ListModel { id: folder_nature } + ListModel { id: folder_objects } + ListModel { id: folder_people } + ListModel { id: folder_symbols } + ListModel { id: folder_travel_places } + ListModel { id: folder_utils } + ListModel { id: folder_other } + ListModel { id: folder_search } + + DelegateModel { + id: emojiModel + model: folder_expressions + + delegate: Item { + width: root.size + height: root.size + + Image { + id: img + //source: "file://" + gcd.binaryPath + "/assets/mutstd/" + code + ".webp" + source: gcd.assetPath + "mutstd/" + code + ".webp" + width: root.size * (mouseArea.pressed ? 0.7 : 0.8) + height: width + anchors.centerIn: parent + property string shortcode: code + + ToolTip.visible: mouseArea.containsMouse + ToolTip.text: desc + "\n:" + shortcode + ":" + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + onClicked: root.picked(img.shortcode) + } + } + } + + Component.onCompleted: updatefilters() + + function clearall() { + folder_activities_clothing.clear() + folder_expressions.clear() + folder_food_drink_herbs.clear() + folder_gsr.clear() + folder_nature.clear() + folder_objects.clear() + folder_people.clear() + folder_symbols.clear() + folder_travel_places.clear() + folder_utils.clear() + folder_other.clear() + folder_search.clear() + } + + function updatefilters() { + clearall() + + for (var i in Mutant.standard.manifest) { + if (typeof Mutant.standard.manifest[i].morph !== "undefined" && Mutant.standard.manifest[i].morph != root.morph) + continue; + + if (typeof Mutant.standard.manifest[i].color !== "undefined" && Mutant.standard.manifest[i].color != root.color) + continue; + + if (txtSearch.text != "" && !(Mutant.standard.manifest[i].code.includes(txtSearch.text) || Mutant.standard.manifest[i].desc.includes(txtSearch.text))) { + continue; + } + + var model = folder_other + if (txtSearch.text == "") { + switch(Mutant.standard.manifest[i].cat) { + case "activities_clothing": model = folder_activities_clothing; break; + case "expressions": model = folder_expressions; break; + case "symbols": model = folder_symbols; break; + case "food_drink_herbs": model = folder_food_drink_herbs; break; + case "gsr": model = folder_gsr; break; + case "nature": model = folder_nature; break; + case "objects": model = folder_objects; break; + case "people": model = folder_people; break; + case "travel_places": model = folder_travel_places; break; + case "utils": model = folder_utils; break; + } + } else { + model = folder_search + } + + model.append({ + cat: Mutant.standard.manifest[i].cat, + code: Mutant.standard.manifest[i].code, + color: Mutant.standard.manifest[i].color, + morph: Mutant.standard.manifest[i].morph, + desc: Mutant.standard.manifest[i].desc + }) + } + } + } + + onSlideopen: animOpen.start() + onSlideclosed: animClose.start() +} diff --git a/FontAwesome.qml b/FontAwesome.qml new file mode 100644 index 0000000..dcdaed1 --- /dev/null +++ b/FontAwesome.qml @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** The MIT License (MIT) +** +** Copyright (c) 2014 Ricardo do Valle Flores de Oliveira +** +** $BEGIN_LICENSE:MIT$ +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +** +** $END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +import "controls" as Awesome + +Item { + id: awesome + + property alias icons: variables + property alias loaded: loader.loaded + property alias resource: loader.resource + + readonly property string family: "FontAwesome" + + Awesome.Loader { + id: loader + } + + Awesome.Variables { + id: variables + } +} diff --git a/HLine.qml b/HLine.qml new file mode 100644 index 0000000..33c342a --- /dev/null +++ b/HLine.qml @@ -0,0 +1,28 @@ +import QtQuick 2.12 +import "../theme" + +Column { + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + + Rectangle { + height: 10 + color:"transparent" + width: parent.width + } + + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + height: 1 + width: parent.width * 0.95 + color: Theme.dropShadowColor + } + + + Rectangle { + height: 10 + color:"transparent" + width: parent.width + } +} diff --git a/Icon.qml b/Icon.qml new file mode 100644 index 0000000..471a3a4 --- /dev/null +++ b/Icon.qml @@ -0,0 +1,63 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 + +import "../fonts/Twemoji.js" as T +import "." as Widgets +import "../theme" + +Rectangle { + id: root + + property color backgroundColor: parent.color + property color hilightBackgroundColor: backgroundColor + + property bool isHover: false + + color: isHover ? backgroundColor : hilightBackgroundColor + + property alias iconColor: iconColorOverlay.color + + property alias source: srcImg.source + + signal clicked() + + Image { + id: srcImg + anchors.fill: parent + antialiasing: true + smooth: true + visible: false + // Apparently qml can now only DOWN-SCALE/SHRINK the SVG, so with this hack it which won't cause blurriness/pixelation + sourceSize.width: root.width*2 + sourceSize.height: root.height*2 + } + + ColorOverlay{ + id: iconColorOverlay + anchors.fill: srcImg + source: srcImg + + antialiasing: true + smooth: true + } + + MouseArea { // Full row mouse area triggering onClick + id: ma + anchors.fill: parent + hoverEnabled: true + + onClicked: { root.clicked() } + + onEntered: { + isHover = true + } + + onExited: { + isHover = false + } + } + +} diff --git a/IconTextField.qml b/IconTextField.qml new file mode 100644 index 0000000..a1a8018 --- /dev/null +++ b/IconTextField.qml @@ -0,0 +1,49 @@ +import QtQuick 2.7 + +import QtQuick.Controls 2.13 +import QtQuick.Controls.Styles 1.4 +import QtGraphicalEffects 1.12 +import "." as Widgets +import "../theme" + +// IconTextField integrates a text field and an icon +TextField { + color: Theme.mainTextColor + font.pixelSize: Theme.secondaryTextSize * gcd.themeScale * gcd.themeScale + width: parent.width - 20 + property alias icon: icon_.source + signal clicked + smooth: true + placeholderTextColor: Theme.altTextColor + + + background: Rectangle { + radius: 10 + color: Theme.backgroundMainColor + border.color: Theme.backgroundMainColor + layer.enabled: true + layer.effect: DropShadow { + transparentBorder: true + horizontalOffset: 0 + verticalOffset: 0 + samples: 10 + radius: 8 + color: Theme.dropShadowColor + } + } + + Widgets.Icon { + id: icon_ + + anchors.right: parent.right + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + + height: parent.height-4; + width: parent.height-4; + + iconColor: Theme.altTextColor + backgroundColor: Theme.backgroundMainColor + } + +} diff --git a/InplaceEditText.qml b/InplaceEditText.qml new file mode 100644 index 0000000..6cf68c6 --- /dev/null +++ b/InplaceEditText.qml @@ -0,0 +1,92 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import "../widgets" as Widgets + + + +Item { + id: root + height: lbl.visible ? lbl.height : txt.height + (gcd.os == "android" ? btn.height + 3 : 0) //lbl.height + implicitHeight: height //lbl.height + + property alias text: lbl.text + signal updated + + Text { // DISPLAY THE TEXT IN READONLY MODE + id: lbl + fontSizeMode: Text.HorizontalFit + font.pixelSize: 36 + minimumPixelSize: 8 + horizontalAlignment: Text.AlignHCenter + textFormat: Text.PlainText + anchors.horizontalCenter: parent.horizontalCenter + } + + Image { + id: img + anchors.left: lbl.right + anchors.leftMargin: 3 + source: gcd.assetPath + "fontawesome/solid/edit.svg" + height: 16 + sourceSize.height: 16 + } + + + MouseArea { + anchors.fill: lbl + + + onClicked: { + lbl.visible = img.visible = false + txt.visible = true + if (gcd.os == "android") btn.visible = true + txt.text = lbl.text + txt.selectAll() + txt.focus = true + } + } + + TextEdit { // MAKE IT AN EDITOR WHEN EDITING + id: txt + text: root.text + visible: false + selectByMouse: true + font.pixelSize: lbl.font.pixelSize + anchors.horizontalCenter: parent.horizontalCenter + + + onActiveFocusChanged: { + if (!activeFocus) { + save() + } + } + + Keys.onReturnPressed: { + if (event.modifiers == Qt.NoModifier) { + save() + } + } + + function save() { + root.text = txt.text + txt.visible = btn.visible = false + lbl.visible = img.visible = true + root.updated(txt.text) + } + } + + Widgets.Button { + id: btn + anchors.top: txt.bottom + anchors.topMargin: 3 + anchors.horizontalCenter: parent.horizontalCenter + visible: false + text: qsTr("Update") + + + onClicked: txt.save() + } +} diff --git a/Message.qml b/Message.qml new file mode 100644 index 0000000..d9f6e3c --- /dev/null +++ b/Message.qml @@ -0,0 +1,192 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 + +import "controls" as Awesome + +Item { + id: root + + anchors.left: fromMe ? undefined : parent.left + anchors.right: fromMe ? parent.right : undefined + height: Math.max(imgProfile.height, rectMessageBubble.height) + + property string message + property string rawMessage + property string from + property string handle + property string displayName + property string messageID + property bool fromMe + property bool ackd + property alias timestamp: ts.text + property alias image: imgProfile.source + property string error + + Connections { + target: gcd + + onAcknowledged: function(mid) { + if (mid == messageID) { + root.ackd = true + } + } + + onGroupSendError: function(mid, error) { + if (mid == messageID) { + root.error = error + } + } + } + + + Portrait { + id: imgProfile + anchors.left: parent.left + // TODO: currently unused? + //handle: root.from + visible: !fromMe + //showStatus: false + //highlight: ima.containsMouse + + ToolTip.visible: ima.containsMouse + //: Click to DM + ToolTip.text: qsTr("dm-tooltip") + + MouseArea { + id: ima + anchors.fill: parent + hoverEnabled: overlay.inGroup + + + onClicked: { + gcd.createContact(from) + gcd.broadcast("ResetMessagePane") + theStack.pane = theStack.messagePane + gcd.loadMessagesPane(from) + overlayStack.overlay = overlayStack.chatOverlay + } + } + + } + + Rectangle { // THIS IS JUST A PRETTY MESSAGE-HOLDING RECTANGLE + id: rectMessageBubble + height: colMessageBubble.height + 8 + width: colMessageBubble.width + 6 + color: fromMe ? "#B09CBC" : "#4B3557" + radius: 5 + + // the console will complain constantly about me setting these anchors, but qt only allows margins if they've been set to something + // a kludge to fix this would be to have spacers before/after and set the widths according to the side they're on ^ea + anchors.left: fromMe ? undefined : imgProfile.right //parent.left + anchors.right: fromMe ? parent.right : undefined + anchors.leftMargin: 5 + anchors.rightMargin: 9 + anchors.topMargin: 5 + + + ColumnLayout { + id: colMessageBubble + + + Column { // combine these into one element or else childrenRect won't play nicely + TextEdit { // this is used as a helper to calculate the message box width + id: dummy + visible: false + padding: 6 + leftPadding: 10 + font.pixelSize: gcd.themeScale * 12 + wrapMode: TextEdit.NoWrap + text: lbl.text + textFormat: Text.RichText + } + + TextEdit { // this is the actual text display + id: lbl + text: parse(message, 12, true) + color: "#FFFFFF" + padding: 6 + leftPadding: 10 + font.pixelSize: gcd.themeScale * 12 + selectByMouse: gcd.os != "android" + readOnly: true + width: Math.min(dummy.width, root.parent.width - (imgProfile.visible ? imgProfile.width : 0) - 40) + wrapMode: TextEdit.Wrap + textFormat: Text.RichText + } + } + + RowLayout { + id: rowBottom + anchors.left: parent.left + anchors.right: parent.right + + + Label { // TIMESTAMP + id: ts + color: "#FFFFFF" + font.pixelSize: 10 * gcd.themeScale + anchors.left: parent.left + leftPadding: 10 + } + + Label { // DISPLAY NAME FOR GROUPS + color: "#FFFFFF" + font.pixelSize: 10 * gcd.themeScale + anchors.right: parent.right + text: displayName.length > 12 ? displayName.substr(0,12) + "..." : displayName + visible: !fromMe + ToolTip.text: from + ToolTip.visible: ma2.containsMouse + ToolTip.delay: 200 + + MouseArea { + id: ma2 + anchors.fill: parent + hoverEnabled: true + } + } + + Image { // ACKNOWLEDGEMENT ICON + id: ack + anchors.right: parent.right + source: root.error != "" ? gcd.assetPath + "fontawesome/regular/window-close.svg" : (root.ackd ? gcd.assetPath + "fontawesome/regular/check-circle.svg" : gcd.assetPath + "fontawesome/regular/hourglass.svg") + height: 10 * gcd.themeScale + sourceSize.height: 10 * gcd.themeScale + visible: fromMe + ToolTip.visible: ma.containsMouse + ToolTip.delay: 200 + //: Could not send this message + ToolTip.text: root.error != "" ? qsTr("could-not-send-msg-error") + ":" + root.error : (root.ackd ? qsTr("acknowledged-label") : qsTr("pending-label")) + + + MouseArea { + id: ma + anchors.fill: parent + hoverEnabled: true + } + } + } + } + + TextEdit { + id: copyhelper + visible: false + text: root.rawMessage + } + + MouseArea { + anchors.fill: gcd.os == "android" ? parent : null + + + onPressAndHold: { + copyhelper.selectAll() + copyhelper.copy() + gcd.popup("message copied") + } + } + } +} diff --git a/MyProfile.qml b/MyProfile.qml new file mode 100644 index 0000000..a8937bf --- /dev/null +++ b/MyProfile.qml @@ -0,0 +1,155 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Window 2.11 +import QtQuick.Controls 1.4 + +import "." as Widgets +import "../styles" +import "../theme" + +Item { + id: root + anchors.fill: parent + width: parent.width + + height: profile.height + implicitHeight: profile.height + + property string image + property string nick + property string onion + property string tag + property bool dualPane: false + + property real logscale: 4 * Math.log10(gcd.themeScale + 1) + + onDualPaneChanged: { realignProfile() } + + function realignProfile() { + if (dualPane) { + profile.height = 78 * logscale + + portrait.baseWidth = 78 * logscale + portrait.height = 78 * logscale + + portrait.anchors.horizontalCenter = undefined + portrait.anchors.left = profile.left + portrait.anchors.leftMargin = 25 * logscale + + nameRow.anchors.right = undefined + nameRow.anchors.left = portrait.right + + nameRow.anchors.top = undefined + nameRow.anchors.verticalCenter = portrait.verticalCenter + + nameCenter.anchors.horizontalCenter = undefined + nameCenter.anchors.left = nameRow.left + } else { + profile.height = (150 * logscale) + + portrait.baseWidth = 100 * logscale + portrait.height = 100 * logscale + + portrait.anchors.left = undefined + portrait.anchors.leftMargin = undefined + portrait.anchors.horizontalCenter = profile.horizontalCenter + + nameRow.anchors.left = profile.left + nameRow.anchors.right = profile.right + + nameRow.anchors.verticalCenter = undefined + nameRow.anchors.top = portrait.bottom + + nameCenter.anchors.left = undefined + nameCenter.anchors.horizontalCenter = nameRow.horizontalCenter + + } + } + + Rectangle { + + anchors.left: parent.left + anchors.right: parent.right + width: parent.width + id: profile + color: Theme.backgroundMainColor + + Portrait { + id: portrait + + source: root.image + + badgeColor: Theme.portraitProfileBadgeColor + portraitBorderColor: Theme.portraitOnlineBorderColor + portraitColor: Theme.portraitOnlineBackgroundColor + + badgeContent: Image {// Profle Type + id: profiletype + source: tag == "v1-userPassword" ? gcd.assetPath + "/fontawesome/solid/lock.svg" : gcd.assetPath + "/fontawesome/solid/lock-open.svg" + height: Theme.badgeTextSize * gcd.themeScale + width: height + } + } + + Rectangle { + id: nameRow + height: name.height + onWidthChanged: { name.textResize() } + color: Theme.backgroundMainColor + + Rectangle { + id: nameCenter + width: name.width + addBtn.width + + EllipsisLabel { + id: name + + anchors.right: undefined + anchors.left: undefined + + color: Theme.portraitOnlineTextColor + pixelSize: Theme.usernameSize * gcd.themeScale + weight: Font.Bold + text: nick + extraPadding: addBtn.width + 30 + container: nameRow + } + + Widgets.Button { // Add Button + id: addBtn + + anchors.left: name.right + anchors.top: name.top + + icon: "solid/plus" + + height: name.height + width: height + radius: width * 0.3 + onClicked: { + + } + } + } + } + + } + + Connections { + target: gcd + + onUpdateMyProfile: function(_nick, _onion, _image, _tag) { + nick = _nick + onion = _onion + image = _image + tag = _tag + //realignProfile() + } + + onResetProfile: { realignProfile() } + } +} diff --git a/Portrait.qml b/Portrait.qml new file mode 100644 index 0000000..41728cd --- /dev/null +++ b/Portrait.qml @@ -0,0 +1,71 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import CustomQmlTypes 1.0 +import "../theme" + +Item { + id: imgProfile + implicitWidth: baseWidth + implicitHeight: baseWidth + + property string source + property alias badgeColor: badge.color + + property real logscale: 4 * Math.log10(gcd.themeScale + 1) + property int baseWidth: 78 * logscale + height: 78 * logscale + + property alias portraitBorderColor: mainImage.color + property alias portraitColor: imageInner.color + property alias badgeVisible: badge.visible + property alias badgeContent: badge.content + + + Rectangle { + id: mainImage + //anchors.leftMargin: baseWidth * 0.1 + anchors.horizontalCenter: parent.horizontalCenter + width: baseWidth * 0.8 + height: width + anchors.verticalCenter: parent.verticalCenter + color: Theme.portraitOfflineBorderColor + radius: width / 2 + + Rectangle { + id: imageInner + width: parent.width - 4 + height: width + color: Theme.portraitOfflineBorderColor + radius: width / 2 + anchors.centerIn:parent + + Image { // PROFILE IMAGE + id: img + source: gcd.assetPath + imgProfile.source + anchors.fill: parent + fillMode: Image.PreserveAspectFit + visible: false + } + + Image { // CIRCLE MASK + id: mask + fillMode: Image.PreserveAspectFit + visible: false + source: "qrc:/qml/images/extra/clipcircle.png" + } + + OpacityMask { + anchors.fill: img + source: img + maskSource: mask + } + } + } + + Badge { + id: badge + } +} diff --git a/PortraitRow.qml b/PortraitRow.qml new file mode 100644 index 0000000..ba65e88 --- /dev/null +++ b/PortraitRow.qml @@ -0,0 +1,141 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import CustomQmlTypes 1.0 +import "../styles" +import "../widgets" as Widgets +import "../theme" +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY + id: crItem + anchors.left: parent.left + anchors.right: parent.right + height: 78 * logscale + 3 + implicitHeight: 78 * logscale + 3 //height + + property real logscale: 4 * Math.log10(gcd.themeScale + 1) + property string displayName + property alias image: portrait.source + property string handle + property bool isActive + property bool isHover + property string tag // profile version/type + + property alias badgeColor: portrait.badgeColor + property alias portraitBorderColor: portrait.portraitBorderColor + property alias portraitColor: portrait.portraitColor + property alias nameColor: cn.color + property alias onionColor: onion.color + property alias onionVisible: onion.visible + property alias badgeVisible: portrait.badgeVisible + property alias badgeContent: portrait.badgeContent + property alias hoverEnabled: buttonMA.hoverEnabled + + property alias content: extraMeta.children + + // TODO: should be in ContactRow + property bool blocked + + signal clicked(string handle) + + Rectangle { // CONTACT ENTRY BACKGROUND COLOR + id: crRect + anchors.left: parent.left + anchors.right: parent.right + height: crItem.height + width: parent.width + color: isHover ? Theme.backgroundPaneColor : (isActive ? Theme.backgroundPaneColor : Theme.backgroundMainColor) + + Portrait { + id: portrait + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 25 * logscale + } + + ColumnLayout { + id: portraitMeta + + anchors.left: portrait.right + anchors.right: parent.right + anchors.leftMargin: 4 * logscale + anchors.verticalCenter: parent.verticalCenter + + spacing: 2 * gcd.themeScale + + + EllipsisLabel { // CONTACT NAME + id: cn + pixelSize: Theme.usernameSize * gcd.themeScale + weight: Font.Bold + strikeout: blocked + text: displayName + } + + EllipsisLabel { // Onion + id: onion + text: handle + pixelSize: Theme.secondaryTextSize * gcd.themeScale + strikeout: blocked + } + + onWidthChanged: { + cn.textResize() + onion.textResize() + } + + } + + Column { + id: extraMeta + anchors.left: portraitMeta.right + anchors.verticalCenter: parent.verticalCenter + } + } + + MouseArea { // Full row mouse area triggering onClick + id: buttonMA + anchors.fill: parent + hoverEnabled: true + + onClicked: { crItem.clicked(crItem.handle) } + + onEntered: { + isHover = true + } + + onExited: { + isHover = false + } + } + + Connections { // UPDATE UNREAD MESSAGES COUNTER + target: gcd + + onResetMessagePane: function() { + isActive = false + } + + onUpdateContactBlocked: function(_handle, _blocked) { + if (handle == _handle) { + blocked = _blocked + } + } + + onUpdateContactDisplayName: function(_handle, _displayName) { + if (handle == _handle) { + displayName = _displayName + (blocked == true ? " (blocked)" : "") + } + } + + onUpdateContactPicture: function(_handle, _image) { + if (handle == _handle) { + image = _image + } + } + } +} diff --git a/ProfileList.qml b/ProfileList.qml new file mode 100644 index 0000000..0e8618a --- /dev/null +++ b/ProfileList.qml @@ -0,0 +1,124 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import "../theme" + +ColumnLayout { + id: root + + MouseArea { + anchors.fill: parent + + onClicked: { + forceActiveFocus() + } + } + + Flickable { // Profile List + id: sv + clip: true + Layout.minimumHeight: 100 + Layout.fillHeight: true + Layout.minimumWidth: parent.width + Layout.maximumWidth: parent.width + contentWidth: colContacts.width + contentHeight: colContacts.height + boundsBehavior: Flickable.StopAtBounds + maximumFlickVelocity: 400 + + + ScrollBar.vertical: ScrollBar { + policy: ScrollBar.AlwaysOn + } + + ColumnLayout { + id: colContacts + width: root.width + spacing: 0 + + Connections { // ADD/REMOVE CONTACT ENTRIES + target: gcd + + onAddProfile: function(handle, displayName, image, tag) { + + // don't add duplicates + for (var i = 0; i < profilesModel.count; i++) { + if (profilesModel.get(i)["_handle"] == handle) { + return + } + } + + // find index for insert (sort by onion) + var index = profilesModel.count + for (var i = 0; i < profilesModel.count; i++) { + if (profilesModel.get(i)["_handle"] > handle) { + index = i + break + } + } + + profilesModel.insert(index, + { + _handle: handle, + _displayName: displayName, + _image: image, + _tag: tag, + _status: 4, + }) + } + + /* + onRemoveProfile: function(handle) { + for(var i = 0; i < profilesModel.count; i++){ + if(profilesModel.get(i)["_handle"] == handle) { + console.log("deleting contact " + profilesModel.get(i)["_handle"]) + profilesModel.remove(i) + return + } + } + }*/ + + onResetProfileList: function() { + profilesModel.clear() + } + } + + ListModel { // Profile OBJECTS ARE STORED HERE ... + id: profilesModel + } + + Repeater { + id: profileList + model: profilesModel // ... AND DISPLAYED HERE + delegate: ProfileRow { + handle: _handle + displayName: _displayName + image: _image + blocked: false + tag: _tag + } + } + + PortraitRow { + handle: "" + displayName: qsTr("add-new-profile-btn") + nameColor: Theme.mainTextColor + image: "/fontawesome/regular/user.svg" + tag: "" + portraitBorderColor: Theme.portraitOnlineBorderColor + portraitColor: Theme.portraitOnlineBackgroundColor + badgeVisible: true + badgeContent: Image { + source: gcd.assetPath + "/fontawesome/solid/plus.svg" + height: Theme.badgeTextSize * gcd.themeScale + width: height + } + badgeColor: Theme.defaultButtonColor + + onClicked: function(handle) { profileAddEditPane.reset(); parentStack.pane = parentStack.addEditProfilePane } + } + } + } +} diff --git a/ProfileRow.qml b/ProfileRow.qml new file mode 100644 index 0000000..c70ee2d --- /dev/null +++ b/ProfileRow.qml @@ -0,0 +1,56 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import CustomQmlTypes 1.0 +import "../styles" +import "../widgets" as Widgets +import "../theme" +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +PortraitRow { + + badgeColor: Theme.portraitProfileBadgeColor + + portraitBorderColor: Theme.portraitOnlineBorderColor + portraitColor: Theme.portraitOnlineBackgroundColor + nameColor: Theme.portraitOnlineTextColor + onionColor: Theme.portraitOnlineTextColor + + badgeContent: Image {// Profle Type + id: profiletype + source: tag == "v1-userPassword" ? gcd.assetPath + "/fontawesome/solid/lock.svg" : gcd.assetPath + "/fontawesome/solid/lock-open.svg" + height: Theme.badgeTextSize * gcd.themeScale + width: height + } + + Widgets.Button {// Edit BUTTON + id: btnEdit + icon: "solid/user-edit" + + anchors.right: parent.right + + //rectUnread.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 1 * gcd.themeScale + anchors.rightMargin: 20 * gcd.themeScale + height: parent.height * 0.75 + + + + onClicked: { + profileAddEditPane.load(handle, displayName, tag) + parentStack.pane = parentStack.addEditProfilePane + } + } + + onClicked: function openClick(handle) { + gcd.broadcast("ResetMessagePane"); + gcd.broadcast("ResetProfile"); + gcd.selectedProfile = handle + gcd.loadProfile(handle) + parentStack.pane = parentStack.profilePane + } +} diff --git a/RadioButton.qml b/RadioButton.qml new file mode 100644 index 0000000..5ce7b21 --- /dev/null +++ b/RadioButton.qml @@ -0,0 +1,27 @@ +import QtQuick 2.7 + +import QtQuick.Controls 2.13 + + +RadioButton { + id: control + + property real size: 12 + spacing: 0 + + indicator: Rectangle { + width: 16 * gcd.themeScale + height: 16 * gcd.themeScale + anchors.verticalCenter: parent.verticalCenter + radius: 9 + border.width: 1 + + Rectangle { + anchors.fill: parent + visible: control.checked + color: "black" + radius: 9 + anchors.margins: 4 + } + } +} diff --git a/ScalingLabel.qml b/ScalingLabel.qml new file mode 100644 index 0000000..e0471fd --- /dev/null +++ b/ScalingLabel.qml @@ -0,0 +1,15 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Window 2.11 + + +Label { + font.pixelSize: gcd.themeScale * size + wrapMode: Text.WordWrap + color: "#000000" + textFormat: Text.PlainText + property real size: 12 +} diff --git a/Statusbar.qml b/Statusbar.qml new file mode 100644 index 0000000..38e4aaf --- /dev/null +++ b/Statusbar.qml @@ -0,0 +1,186 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.4 + +import "." as Widgets +import "../theme" + +// Statusbar is a app wide 10-25 tall bar that should be place at the bottom of the app that gives network health information +// it changes color and text/icon message based on network health. when netowrk is not healthy it is always in fullsized mode +// when network is health it reduces to a minimal color strip unless mouse overed / clicked to reveal the text/icons +Rectangle { + id: statusbar + + property int status: statusDisconnectedInternet + + readonly property int statusDisconnectedInternet: 0 + readonly property int statusDisconnectedTor: 1 + readonly property int statusConnecting: 2 + readonly property int statusOnline: 3 + + readonly property int openHeight: 25 + readonly property int hideHeight: 10 + + property bool isHover: false + + height: openHeight + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + Text { + id: statusMessage + opacity: 0 + anchors.right: networkStatus.left + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 5 * gcd.themeScale + + font.pixelSize: Theme.statusTextSize * gcd.themeScale + } + + Icon { + id: networkStatus + opacity: 0 + anchors.right: connectionStatus.left + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 5 * gcd.themeScale + height: 18 + width: 18 + + } + + Icon { + id: connectionStatus + opacity: 0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 10 * gcd.themeScale + height: 18 * gcd.themeScale + width: 18 * gcd.themeScale + } + + function changeStatus() { + if (status == statusDisconnectedInternet) { + statusbar.color = Theme.statusbarDisconnectedInternetColor + statusMessage.color = Theme.statusbarDisconnectedInternetFontColor + networkStatus.iconColor = Theme.statusbarDisconnectedInternetFontColor + networkStatus.source = gcd.assetPath + "core/signal_cellular_off-24px.svg" + connectionStatus.iconColor = Theme.statusbarDisconnectedInternetFontColor + connectionStatus.source = gcd.assetPath + "core/syncing-03.svg" + //: Disconnected from the internet, check your connection + statusMessage.text = qsTr("network-status-disconnected") + show() + } else if (status == statusDisconnectedTor) { + statusbar.color = Theme.statusbarDisconnectedTorColor + statusMessage.color = Theme.statusbarDisconnectedTorFontColor + networkStatus.iconColor = Theme.statusbarDisconnectedTorFontColor + networkStatus.source = gcd.assetPath + "core/signal_cellular_connected_no_internet_4_bar-24px.svg" + connectionStatus.iconColor = Theme.statusbarDisconnectedTorFontColor + connectionStatus.source = gcd.assetPath + "core/syncing-03.svg" + //: Attempting to connect to Tor network + statusMessage.text = qsTr("network-status-attempting-tor") + show() + } else if (status == statusConnecting) { + statusbar.color = Theme.statusbarConnectingColor + statusMessage.color = Theme.statusbarConnectingFontColor + networkStatus.iconColor = Theme.statusbarConnectingFontColor + networkStatus.source = gcd.assetPath + "core/signal_cellular_connected_no_internet_4_bar-24px.svg" + connectionStatus.iconColor = Theme.statusbarConnectingFontColor + connectionStatus.source = gcd.assetPath + "core/syncing-02.svg" + //: Connecting... + statusMessage.text = qsTr("network-status-connecting") + show() + } else { + statusbar.color = Theme.statusbarOnlineColor + statusMessage.color = Theme.statusbarOnlineFontColor + networkStatus.iconColor = Theme.statusbarOnlineFontColor + networkStatus.source = gcd.assetPath + "core/signal_cellular_4_bar-24px.svg" + connectionStatus.iconColor = Theme.statusbarOnlineFontColor + connectionStatus.source = gcd.assetPath + "core/syncing-01.svg" + //: Online + statusMessage.text = qsTr("network-status-online") + hide() + } + } + + MouseArea { + id: ma + anchors.fill: parent + hoverEnabled: true + + SequentialAnimation { + id: showAnim + PropertyAnimation { id: openStatus; target: statusbar; property: "height"; to: openHeight} + ParallelAnimation { + PropertyAnimation { id: showStatus; target: statusMessage; property: "opacity"; to: 1} + PropertyAnimation { id: showNetIcon; target: networkStatus; property: "opacity"; to: 1} + PropertyAnimation { id: showConnIcon; target: connectionStatus; property: "opacity"; to: 1} + } + } + + SequentialAnimation { + id: hideAnim + ParallelAnimation { + PropertyAnimation { id: hideStatus; target: statusMessage; property: "opacity"; to: 0} + PropertyAnimation { id: hideNetIcon; target: networkStatus; property: "opacity"; to: 0} + PropertyAnimation { id: hideConnIcon; target: connectionStatus; property: "opacity"; to: 0} + } + PropertyAnimation { id: closeStatus; target: statusbar; property: "height"; to: hideHeight; duration: 200 } + } + + onEntered: { + isHover = true + show() + } + + + onExited: { + isHover = false + hide() + } + + onPressed: { + isHover = true + show() + } + + onReleased: { + isHover = false + hide() + } + } + + function resetHeight() { + if (isHover || status != statusOnline) { + height = openHeight + } else { + height = hideHeight + } + } + + function show() { + if (isHover || status != statusOnline) { + hideAnim.stop() + showAnim.start() + } + } + + function hide() { + if (!isHover && status == statusOnline) { + showAnim.stop() + hideAnim.start() + } + } + + onStatusChanged: { changeStatus() } + + Component.onCompleted: { resetHeight() } + + Connections { + target: gcd + + onTorStatus: function(code) { + status = code + } + } + +} diff --git a/TextField.qml b/TextField.qml new file mode 100644 index 0000000..333f3bb --- /dev/null +++ b/TextField.qml @@ -0,0 +1,16 @@ +import QtQuick 2.7 + +import QtQuick.Controls 2.13 + + +TextField { + color: "black" + font.pointSize: 10 * gcd.themeScale + width: 100 + + background: Rectangle { + radius: 2 + color: windowItem.cwtch_background_color + border.color: windowItem.cwtch_color + } +} diff --git a/ToggleSwitch.qml b/ToggleSwitch.qml new file mode 100644 index 0000000..4c151aa --- /dev/null +++ b/ToggleSwitch.qml @@ -0,0 +1,32 @@ +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick 2.12 +import "../theme" + +// ToggleSwtch implements a stylized toggle switch. It requires the user create a function called onToggled to +// perform any additional operations needed to define the behavior of the toggle switch +Switch { + property bool isToggled + property var onToggled: function () { console.log("In Superclass") }; + + style: SwitchStyle { + handle: Rectangle { + implicitWidth: 25 + implicitHeight: 25 + radius: width*0.5 + color: Theme.toggleColor + border.color: isToggled ? Theme.toggleOnColor :Theme.toggleOffColor + border.width:5 + } + groove: Rectangle { + implicitWidth: 50 + implicitHeight: 25 + radius: 25*0.5 + color: isToggled ? Theme.toggleOnColor :Theme.toggleOffColor + } + } + + onClicked: function() {isToggled = !isToggled; onToggled()} +} + + diff --git a/Toolbar.qml b/Toolbar.qml new file mode 100644 index 0000000..70d373d --- /dev/null +++ b/Toolbar.qml @@ -0,0 +1,123 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 + +import "../fonts/Twemoji.js" as T +import "." as Widgets +import "../theme" + +Rectangle { // Global Toolbar + id: toolbar + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + height: 35 * gcd.themeScale + + + Layout.minimumHeight: height + Layout.maximumHeight: height + color: Theme.backgroundMainColor + + property alias leftMenuVisible: btnLeftMenu.visible + property alias backVisible: btnLeftBack.visible + property alias rightMenuVisible: btnRightMenu.visible + + property alias titleWidth: paneArea.width + + + signal leftMenu() + signal back() + signal rightMenu() + + Icon { + id: btnLeftMenu + iconColor: Theme.toolbarIconColor + source: gcd.assetPath + "core/menu-24px.svg" + + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + width: 30 + height: 30 + + onClicked: { leftMenu() } + } + + Icon { + id: btnLeftBack + iconColor: Theme.toolbarIconColor + source: gcd.assetPath + "core/chevron_left-24px.svg" + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + width: 30 + height: 30 + + onClicked: { back() } + } + + + + Rectangle { + id: paneArea + anchors.right: parent.right + + EllipsisLabel { + id: paneTitle + + visible: true + anchors.left: undefined + anchors.right: undefined + anchors.horizontalCenter: parent.horizontalCenter + + color: Theme.mainTextColor + pixelSize: Theme.tabSize * gcd.themeScale + weight: Font.Bold + text: "global toolbar" + + //extraPadding: btnRightMenu.width + 10 + + } + + onWidthChanged: { paneTitle.textResize() } + } + + Icon { + id: btnRightMenu + iconColor: Theme.toolbarIconColor + source: gcd.assetPath + "core/more_vert-24px.svg" + + visible: false + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + width: 30 + height: 30 + + onClicked: { rightMenu() } + } + + function setTitle(text, width) { + paneTitle.text = text + paneArea.width = width + paneTitle.textResize() + paneTitle.visible = true + } + + function hideTitle() { + paneTitle.visible = false + } + + + Connections { + target: gcd + + onSetToolbarTitle: function(handle) { + setTitle(handle, theStack.width) + btnRightMenu.visible = true + } + } + +} diff --git a/UnderlineTextField.qml b/UnderlineTextField.qml new file mode 100644 index 0000000..c5d2661 --- /dev/null +++ b/UnderlineTextField.qml @@ -0,0 +1,34 @@ +import QtQuick 2.7 + +import QtQuick.Controls 2.13 +import QtQuick.Controls.Styles 1.4 +import QtGraphicalEffects 1.12 +import "." as Widgets +import "../theme" + +// UnderlineTextField is a textfield styled as just an underline +TextField { + property alias backgroundColor: bg.color + + color: Theme.mainTextColor + font.pixelSize: Theme.secondaryTextSize * gcd.themeScale * gcd.themeScale + signal clicked + smooth: true + placeholderTextColor: Theme.altTextColor + + background: Rectangle { + id: bg + anchors.fill: parent + color: Theme.backgroundMainColor + border.color: color + } + + Rectangle { + id: bottomBar + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: 2 + color: Theme.mainTextColor + } +} diff --git a/controls/FlagButton.qml b/controls/FlagButton.qml new file mode 100644 index 0000000..760ed21 --- /dev/null +++ b/controls/FlagButton.qml @@ -0,0 +1,43 @@ +import QtGraphicalEffects 1.0 +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Window 2.11 +import QtQuick.Controls 1.4 + +Rectangle { + width: img.width + 10 + height: img.height + 5 + property string emoji + color: selected ? windowItem.cwtch_color : windowItem.cwtch_background_color + property bool selected + property string locale + + + Image { + id: img + anchors.centerIn:parent + opacity: 1.0 + + + source: gcd.assetPath + "twemoji/72x72/" + emoji + ".png" + + + MouseArea { + anchors.fill: parent + + onClicked: { + gcd.setLocale(locale) + } + } + } + + Connections { + target: gcd + + onSupplySettings: function(zoom, newLocale) { + selected = newLocale == locale + } + } +} diff --git a/controls/ImageButton.qml b/controls/ImageButton.qml new file mode 100644 index 0000000..b7665c0 --- /dev/null +++ b/controls/ImageButton.qml @@ -0,0 +1,33 @@ +import QtQuick 2.4 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +Item { + id: root + property alias source: img.source + property int size: 24 + property string tooltip: "" + width: size + height: size + signal clicked() + + ToolTip.visible: tooltip != "" && ma.containsMouse + ToolTip.text: tooltip + + Image { + id: img + width: root.size * (ma.pressed ? 0.5 : 0.8) + height: root.size * (ma.pressed ? 0.5 : 0.8) + anchors.topMargin: ma.pressed ? 2 : 0 + anchors.leftMargin: anchors.topMargin + anchors.centerIn: parent + } + + MouseArea { + id: ma + anchors.fill: root + + onClicked: root.clicked() + hoverEnabled: tooltip != "" + } +} diff --git a/controls/Loader.qml b/controls/Loader.qml new file mode 100644 index 0000000..0aa7132 --- /dev/null +++ b/controls/Loader.qml @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** The MIT License (MIT) +** +** Copyright (c) 2014 Ricardo do Valle Flores de Oliveira +** +** $BEGIN_LICENSE:MIT$ +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +** +** $END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +FontLoader { + property string resource + property bool loaded: false + + source: resource + onStatusChanged: (status === FontLoader.Ready) ? loaded = true : loaded = false +} diff --git a/controls/Variables.qml b/controls/Variables.qml new file mode 100644 index 0000000..c0f51db --- /dev/null +++ b/controls/Variables.qml @@ -0,0 +1,580 @@ +/**************************************************************************** +** +** The MIT License (MIT) +** +** Copyright (c) 2014 Ricardo do Valle Flores de Oliveira +** +** $BEGIN_LICENSE:MIT$ +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +** +** $END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + readonly property string fa_adjust : "\uf042" + readonly property string fa_adn : "\uf170" + readonly property string fa_align_center : "\uf037" + readonly property string fa_align_justify : "\uf039" + readonly property string fa_align_left : "\uf036" + readonly property string fa_align_right : "\uf038" + readonly property string fa_ambulance : "\uf0f9" + readonly property string fa_anchor : "\uf13d" + readonly property string fa_android : "\uf17b" + readonly property string fa_angellist : "\uf209" + readonly property string fa_angle_double_down : "\uf103" + readonly property string fa_angle_double_left : "\uf100" + readonly property string fa_angle_double_right : "\uf101" + readonly property string fa_angle_double_up : "\uf102" + readonly property string fa_angle_down : "\uf107" + readonly property string fa_angle_left : "\uf104" + readonly property string fa_angle_right : "\uf105" + readonly property string fa_angle_up : "\uf106" + readonly property string fa_apple : "\uf179" + readonly property string fa_archive : "\uf187" + readonly property string fa_area_chart : "\uf1fe" + readonly property string fa_arrow_circle_down : "\uf0ab" + readonly property string fa_arrow_circle_left : "\uf0a8" + readonly property string fa_arrow_circle_o_down : "\uf01a" + readonly property string fa_arrow_circle_o_left : "\uf190" + readonly property string fa_arrow_circle_o_right : "\uf18e" + readonly property string fa_arrow_circle_o_up : "\uf01b" + readonly property string fa_arrow_circle_right : "\uf0a9" + readonly property string fa_arrow_circle_up : "\uf0aa" + readonly property string fa_arrow_down : "\uf063" + readonly property string fa_arrow_left : "\uf060" + readonly property string fa_arrow_right : "\uf061" + readonly property string fa_arrow_up : "\uf062" + readonly property string fa_arrows : "\uf047" + readonly property string fa_arrows_alt : "\uf0b2" + readonly property string fa_arrows_h : "\uf07e" + readonly property string fa_arrows_v : "\uf07d" + readonly property string fa_asterisk : "\uf069" + readonly property string fa_at : "\uf1fa" + readonly property string fa_automobile : "\uf1b9" + readonly property string fa_backward : "\uf04a" + readonly property string fa_ban : "\uf05e" + readonly property string fa_bank : "\uf19c" + readonly property string fa_bar_chart_o : "\uf080" + readonly property string fa_barcode : "\uf02a" + readonly property string fa_bars : "\uf0c9" + readonly property string fa_beer : "\uf0fc" + readonly property string fa_behance : "\uf1b4" + readonly property string fa_behance_square : "\uf1b5" + readonly property string fa_bell : "\uf0f3" + readonly property string fa_bell_o : "\uf0a2" + readonly property string fa_bell_slash : "\uf1f6" + readonly property string fa_bell_slash_o : "\uf1f7" + readonly property string fa_bicycle : "\uf206" + readonly property string fa_binoculars : "\uf1e5" + readonly property string fa_birthday_cake : "\uf1fd" + readonly property string fa_bitbucket : "\uf171" + readonly property string fa_bitbucket_square : "\uf172" + readonly property string fa_bitcoin : "\uf15a" + readonly property string fa_bold : "\uf032" + readonly property string fa_bolt : "\uf0e7" + readonly property string fa_bomb : "\uf1e2" + readonly property string fa_book : "\uf02d" + readonly property string fa_bookmark : "\uf02e" + readonly property string fa_bookmark_o : "\uf097" + readonly property string fa_briefcase : "\uf0b1" + readonly property string fa_btc : "\uf15a" + readonly property string fa_bug : "\uf188" + readonly property string fa_building : "\uf1ad" + readonly property string fa_building_o : "\uf0f7" + readonly property string fa_bullhorn : "\uf0a1" + readonly property string fa_bullseye : "\uf140" + readonly property string $fa_bus : "\uf207" + readonly property string fa_cab : "\uf1ba" + readonly property string $fa_calculator : "\uf1ec" + readonly property string fa_calendar : "\uf073" + readonly property string fa_calendar_o : "\uf133" + readonly property string fa_camera : "\uf030" + readonly property string fa_camera_retro : "\uf083" + readonly property string fa_car : "\uf1b9" + readonly property string fa_caret_down : "\uf0d7" + readonly property string fa_caret_left : "\uf0d9" + readonly property string fa_caret_right : "\uf0da" + readonly property string fa_caret_square_o_down : "\uf150" + readonly property string fa_caret_square_o_left : "\uf191" + readonly property string fa_caret_square_o_right : "\uf152" + readonly property string fa_caret_square_o_up : "\uf151" + readonly property string fa_caret_up : "\uf0d8" + readonly property string fa_cc : "\uf20a" + readonly property string fa_cc_amex : "\uf1f3" + readonly property string fa_cc_discover : "\uf1f2" + readonly property string fa_cc_mastercard : "\uf1f1" + readonly property string fa_cc_paypal : "\uf1f4" + readonly property string fa_cc_stripe : "\uf1f5" + readonly property string fa_cc_visa : "\uf1f0" + readonly property string fa_certificate : "\uf0a3" + readonly property string fa_chain : "\uf0c1" + readonly property string fa_chain_broken : "\uf127" + readonly property string fa_check : "\uf00c" + readonly property string fa_check_circle : "\uf058" + readonly property string fa_check_circle_o : "\uf05d" + readonly property string fa_check_square : "\uf14a" + readonly property string fa_check_square_o : "\uf046" + readonly property string fa_chevron_circle_down : "\uf13a" + readonly property string fa_chevron_circle_left : "\uf137" + readonly property string fa_chevron_circle_right : "\uf138" + readonly property string fa_chevron_circle_up : "\uf139" + readonly property string fa_chevron_down : "\uf078" + readonly property string fa_chevron_left : "\uf053" + readonly property string fa_chevron_right : "\uf054" + readonly property string fa_chevron_up : "\uf077" + readonly property string fa_child : "\uf1ae" + readonly property string fa_circle : "\uf111" + readonly property string fa_circle_o : "\uf10c" + readonly property string fa_circle_o_notch : "\uf1ce" + readonly property string fa_circle_thin : "\uf1db" + readonly property string fa_clipboard : "\uf0ea" + readonly property string fa_clock_o : "\uf017" + readonly property string fa_cloud : "\uf0c2" + readonly property string fa_cloud_download : "\uf0ed" + readonly property string fa_cloud_upload : "\uf0ee" + readonly property string fa_cny : "\uf157" + readonly property string fa_code : "\uf121" + readonly property string fa_code_fork : "\uf126" + readonly property string fa_codepen : "\uf1cb" + readonly property string fa_coffee : "\uf0f4" + readonly property string fa_cog : "\uf013" + readonly property string fa_cogs : "\uf085" + readonly property string fa_columns : "\uf0db" + readonly property string fa_comment : "\uf075" + readonly property string fa_comment_o : "\uf0e5" + readonly property string fa_comments : "\uf086" + readonly property string fa_comments_o : "\uf0e6" + readonly property string fa_compass : "\uf14e" + readonly property string fa_compress : "\uf066" + readonly property string fa_copy : "\uf0c5" + readonly property string fa_copyright : "\uf1f9" + readonly property string fa_credit_card : "\uf09d" + readonly property string fa_crop : "\uf125" + readonly property string fa_crosshairs : "\uf05b" + readonly property string fa_css3 : "\uf13c" + readonly property string fa_cube : "\uf1b2" + readonly property string fa_cubes : "\uf1b3" + readonly property string fa_cut : "\uf0c4" + readonly property string fa_cutlery : "\uf0f5" + readonly property string fa_dashboard : "\uf0e4" + readonly property string fa_database : "\uf1c0" + readonly property string fa_dedent : "\uf03b" + readonly property string fa_delicious : "\uf1a5" + readonly property string fa_desktop : "\uf108" + readonly property string fa_deviantart : "\uf1bd" + readonly property string fa_digg : "\uf1a6" + readonly property string fa_dollar : "\uf155" + readonly property string fa_dot_circle_o : "\uf192" + readonly property string fa_download : "\uf019" + readonly property string fa_dribbble : "\uf17d" + readonly property string fa_dropbox : "\uf16b" + readonly property string fa_drupal : "\uf1a9" + readonly property string fa_edit : "\uf044" + readonly property string fa_eject : "\uf052" + readonly property string fa_ellipsis_h : "\uf141" + readonly property string fa_ellipsis_v : "\uf142" + readonly property string fa_empire : "\uf1d1" + readonly property string fa_envelope : "\uf0e0" + readonly property string fa_envelope_o : "\uf003" + readonly property string fa_envelope_square : "\uf199" + readonly property string fa_eraser : "\uf12d" + readonly property string fa_eur : "\uf153" + readonly property string fa_euro : "\uf153" + readonly property string fa_exchange : "\uf0ec" + readonly property string fa_exclamation : "\uf12a" + readonly property string fa_exclamation_circle : "\uf06a" + readonly property string fa_exclamation_triangle : "\uf071" + readonly property string fa_expand : "\uf065" + readonly property string fa_external_link : "\uf08e" + readonly property string fa_external_link_square : "\uf14c" + readonly property string fa_eye : "\uf06e" + readonly property string fa_eye_slash : "\uf070" + readonly property string fa_eyedropper : "\uf1fb" + readonly property string fa_facebook : "\uf09a" + readonly property string fa_facebook_square : "\uf082" + readonly property string fa_fast_backward : "\uf049" + readonly property string fa_fast_forward : "\uf050" + readonly property string fa_fax : "\uf1ac" + readonly property string fa_female : "\uf182" + readonly property string fa_fighter_jet : "\uf0fb" + readonly property string fa_file : "\uf15b" + readonly property string fa_file_archive_o : "\uf1c6" + readonly property string fa_file_audio_o : "\uf1c7" + readonly property string fa_file_code_o : "\uf1c9" + readonly property string fa_file_excel_o : "\uf1c3" + readonly property string fa_file_image_o : "\uf1c5" + readonly property string fa_file_movie_o : "\uf1c8" + readonly property string fa_file_o : "\uf016" + readonly property string fa_file_pdf_o : "\uf1c1" + readonly property string fa_file_photo_o : "\uf1c5" + readonly property string fa_file_picture_o : "\uf1c5" + readonly property string fa_file_powerpoint_o : "\uf1c4" + readonly property string fa_file_sound_o : "\uf1c7" + readonly property string fa_file_text : "\uf15c" + readonly property string fa_file_text_o : "\uf0f6" + readonly property string fa_file_video_o : "\uf1c8" + readonly property string fa_file_word_o : "\uf1c2" + readonly property string fa_file_zip_o : "\uf1c6" + readonly property string fa_files_o : "\uf0c5" + readonly property string fa_film : "\uf008" + readonly property string fa_filter : "\uf0b0" + readonly property string fa_fire : "\uf06d" + readonly property string fa_fire_extinguisher : "\uf134" + readonly property string fa_flag : "\uf024" + readonly property string fa_flag_checkered : "\uf11e" + readonly property string fa_flag_o : "\uf11d" + readonly property string fa_flash : "\uf0e7" + readonly property string fa_flask : "\uf0c3" + readonly property string fa_flickr : "\uf16e" + readonly property string fa_floppy_o : "\uf0c7" + readonly property string fa_folder : "\uf07b" + readonly property string fa_folder_o : "\uf114" + readonly property string fa_folder_open : "\uf07c" + readonly property string fa_folder_open_o : "\uf115" + readonly property string fa_font : "\uf031" + readonly property string fa_forward : "\uf04e" + readonly property string fa_foursquare : "\uf180" + readonly property string fa_frown_o : "\uf119" + readonly property string fa_futbol_o : "\uf1e3" + readonly property string fa_gamepad : "\uf11b" + readonly property string fa_gavel : "\uf0e3" + readonly property string fa_gbp : "\uf154" + readonly property string fa_ge : "\uf1d1" + readonly property string fa_gear : "\uf013" + readonly property string fa_gears : "\uf085" + readonly property string fa_gift : "\uf06b" + readonly property string fa_git : "\uf1d3" + readonly property string fa_git_square : "\uf1d2" + readonly property string fa_github : "\uf09b" + readonly property string fa_github_alt : "\uf113" + readonly property string fa_github_square : "\uf092" + readonly property string fa_gittip : "\uf184" + readonly property string fa_glass : "\uf000" + readonly property string fa_globe : "\uf0ac" + readonly property string fa_google : "\uf1a0" + readonly property string fa_google_plus : "\uf0d5" + readonly property string fa_google_plus_square : "\uf0d4" + readonly property string fa_google_wallet : "\uf1ee" + readonly property string fa_graduation_cap : "\uf19d" + readonly property string fa_group : "\uf0c0" + readonly property string fa_h_square : "\uf0fd" + readonly property string fa_hacker_news : "\uf1d4" + readonly property string fa_hand_o_down : "\uf0a7" + readonly property string fa_hand_o_left : "\uf0a5" + readonly property string fa_hand_o_right : "\uf0a4" + readonly property string fa_hand_o_up : "\uf0a6" + readonly property string fa_hdd_o : "\uf0a0" + readonly property string fa_header : "\uf1dc" + readonly property string fa_headphones : "\uf025" + readonly property string fa_heart : "\uf004" + readonly property string fa_heart_o : "\uf08a" + readonly property string fa_history : "\uf1da" + readonly property string fa_home : "\uf015" + readonly property string fa_hospital_o : "\uf0f8" + readonly property string fa_html5 : "\uf13b" + readonly property string fa_ils : "\uf20b" + readonly property string fa_image : "\uf03e" + readonly property string fa_inbox : "\uf01c" + readonly property string fa_indent : "\uf03c" + readonly property string fa_info : "\uf129" + readonly property string fa_info_circle : "\uf05a" + readonly property string fa_inr : "\uf156" + readonly property string fa_instagram : "\uf16d" + readonly property string fa_institution : "\uf19c" + readonly property string fa_ioxhost : "\uf208" + readonly property string fa_italic : "\uf033" + readonly property string fa_joomla : "\uf1aa" + readonly property string fa_jpy : "\uf157" + readonly property string fa_jsfiddle : "\uf1cc" + readonly property string fa_key : "\uf084" + readonly property string fa_keyboard_o : "\uf11c" + readonly property string fa_krw : "\uf159" + readonly property string fa_language : "\uf1ab" + readonly property string fa_laptop : "\uf109" + readonly property string fa_lastfm : "\uf202" + readonly property string fa_lastfm_square : "\uf203" + readonly property string fa_leaf : "\uf06c" + readonly property string fa_legal : "\uf0e3" + readonly property string fa_lemon_o : "\uf094" + readonly property string fa_level_down : "\uf149" + readonly property string fa_level_up : "\uf148" + readonly property string fa_life_bouy : "\uf1cd" + readonly property string fa_life_buoy : "\uf1cd" + readonly property string fa_life_ring : "\uf1cd" + readonly property string fa_life_saver : "\uf1cd" + readonly property string fa_lightbulb_o : "\uf0eb" + readonly property string fa_line_chart : "\uf201" + readonly property string fa_link : "\uf0c1" + readonly property string fa_linkedin : "\uf0e1" + readonly property string fa_linkedin_square : "\uf08c" + readonly property string fa_linux : "\uf17c" + readonly property string fa_list : "\uf03a" + readonly property string fa_list_alt : "\uf022" + readonly property string fa_list_ol : "\uf0cb" + readonly property string fa_list_ul : "\uf0ca" + readonly property string fa_location_arrow : "\uf124" + readonly property string fa_lock : "\uf023" + readonly property string fa_long_arrow_down : "\uf175" + readonly property string fa_long_arrow_left : "\uf177" + readonly property string fa_long_arrow_right : "\uf178" + readonly property string fa_long_arrow_up : "\uf176" + readonly property string fa_magic : "\uf0d0" + readonly property string fa_magnet : "\uf076" + readonly property string fa_mail_forward : "\uf064" + readonly property string fa_mail_reply : "\uf112" + readonly property string fa_mail_reply_all : "\uf122" + readonly property string fa_male : "\uf183" + readonly property string fa_map_marker : "\uf041" + readonly property string fa_maxcdn : "\uf136" + readonly property string fa_meanpath : "\uf20c" + readonly property string fa_medkit : "\uf0fa" + readonly property string fa_meh_o : "\uf11a" + readonly property string fa_microphone : "\uf130" + readonly property string fa_microphone_slash : "\uf131" + readonly property string fa_minus : "\uf068" + readonly property string fa_minus_circle : "\uf056" + readonly property string fa_minus_square : "\uf146" + readonly property string fa_minus_square_o : "\uf147" + readonly property string fa_mobile : "\uf10b" + readonly property string fa_mobile_phone : "\uf10b" + readonly property string fa_money : "\uf0d6" + readonly property string fa_moon_o : "\uf186" + readonly property string fa_mortar_board : "\uf19d" + readonly property string fa_music : "\uf001" + readonly property string fa_navicon : "\uf0c9" + readonly property string fa_newspaper_o : "\uf1ea" + readonly property string fa_openid : "\uf19b" + readonly property string fa_outdent : "\uf03b" + readonly property string fa_pagelines : "\uf18c" + readonly property string fa_paint_brush : "\uf1fc" + readonly property string fa_paper_plane : "\uf1d8" + readonly property string fa_paper_plane_o : "\uf1d9" + readonly property string fa_paperclip : "\uf0c6" + readonly property string fa_paragraph : "\uf1dd" + readonly property string fa_paste : "\uf0ea" + readonly property string fa_pause : "\uf04c" + readonly property string fa_paw : "\uf1b0" + readonly property string fa_paypal : "\uf1ed" + readonly property string fa_pencil : "\uf040" + readonly property string fa_pencil_square : "\uf14b" + readonly property string fa_pencil_square_o : "\uf044" + readonly property string fa_phone : "\uf095" + readonly property string fa_phone_square : "\uf098" + readonly property string fa_photo : "\uf03e" + readonly property string fa_picture_o : "\uf03e" + readonly property string fa_pie_chart : "\uf200" + readonly property string fa_pied_piper : "\uf1a7" + readonly property string fa_pied_piper_alt : "\uf1a8" + readonly property string fa_pinterest : "\uf0d2" + readonly property string fa_pinterest_square : "\uf0d3" + readonly property string fa_plane : "\uf072" + readonly property string fa_play : "\uf04b" + readonly property string fa_play_circle : "\uf144" + readonly property string fa_play_circle_o : "\uf01d" + readonly property string fa_plug : "\uf1e6" + readonly property string fa_plus : "\uf067" + readonly property string fa_plus_circle : "\uf055" + readonly property string fa_plus_square : "\uf0fe" + readonly property string fa_plus_square_o : "\uf196" + readonly property string fa_power_off : "\uf011" + readonly property string fa_print : "\uf02f" + readonly property string fa_puzzle_piece : "\uf12e" + readonly property string fa_qq : "\uf1d6" + readonly property string fa_qrcode : "\uf029" + readonly property string fa_question : "\uf128" + readonly property string fa_question_circle : "\uf059" + readonly property string fa_quote_left : "\uf10d" + readonly property string fa_quote_right : "\uf10e" + readonly property string fa_ra : "\uf1d0" + readonly property string fa_random : "\uf074" + readonly property string fa_rebel : "\uf1d0" + readonly property string fa_recycle : "\uf1b8" + readonly property string fa_reddit : "\uf1a1" + readonly property string fa_reddit_square : "\uf1a2" + readonly property string fa_refresh : "\uf021" + readonly property string fa_remove : "\uf00d" + readonly property string fa_renren : "\uf18b" + readonly property string fa_reorder : "\uf0c9" + readonly property string fa_repeat : "\uf01e" + readonly property string fa_reply : "\uf112" + readonly property string fa_reply_all : "\uf122" + readonly property string fa_retweet : "\uf079" + readonly property string fa_rmb : "\uf157" + readonly property string fa_road : "\uf018" + readonly property string fa_rocket : "\uf135" + readonly property string fa_rotate_left : "\uf0e2" + readonly property string fa_rotate_right : "\uf01e" + readonly property string fa_rouble : "\uf158" + readonly property string fa_rss : "\uf09e" + readonly property string fa_rss_square : "\uf143" + readonly property string fa_rub : "\uf158" + readonly property string fa_ruble : "\uf158" + readonly property string fa_rupee : "\uf156" + readonly property string fa_save : "\uf0c7" + readonly property string fa_scissors : "\uf0c4" + readonly property string fa_search : "\uf002" + readonly property string fa_search_minus : "\uf010" + readonly property string fa_search_plus : "\uf00e" + readonly property string fa_send : "\uf1d8" + readonly property string fa_send_o : "\uf1d9" + readonly property string fa_share : "\uf064" + readonly property string fa_share_alt : "\uf1e0" + readonly property string fa_share_alt_square : "\uf1e1" + readonly property string fa_share_square : "\uf14d" + readonly property string fa_share_square_o : "\uf045" + readonly property string fa_shekel : "\uf20b" + readonly property string fa_sheqel : "\uf20b" + readonly property string fa_shield : "\uf132" + readonly property string fa_shopping_cart : "\uf07a" + readonly property string fa_sign_in : "\uf090" + readonly property string fa_sign_out : "\uf08b" + readonly property string fa_signal : "\uf012" + readonly property string fa_sitemap : "\uf0e8" + readonly property string fa_skype : "\uf17e" + readonly property string fa_slack : "\uf198" + readonly property string fa_sliders : "\uf1de" + readonly property string fa_slideshare : "\uf1e7" + readonly property string fa_smile_o : "\uf118" + readonly property string fa_soccer_ball_o : "\uf1e3" + readonly property string fa_sort : "\uf0dc" + readonly property string fa_sort_alpha_asc : "\uf15d" + readonly property string fa_sort_alpha_desc : "\uf15e" + readonly property string fa_sort_amount_asc : "\uf160" + readonly property string fa_sort_amount_desc : "\uf161" + readonly property string fa_sort_asc : "\uf0de" + readonly property string fa_sort_desc : "\uf0dd" + readonly property string fa_sort_down : "\uf0dd" + readonly property string fa_sort_numeric_asc : "\uf162" + readonly property string fa_sort_numeric_desc : "\uf163" + readonly property string fa_sort_up : "\uf0de" + readonly property string fa_soundcloud : "\uf1be" + readonly property string fa_space_shuttle : "\uf197" + readonly property string fa_spinner : "\uf110" + readonly property string fa_spoon : "\uf1b1" + readonly property string fa_spotify : "\uf1bc" + readonly property string fa_square : "\uf0c8" + readonly property string fa_square_o : "\uf096" + readonly property string fa_stack_exchange : "\uf18d" + readonly property string fa_stack_overflow : "\uf16c" + readonly property string fa_star : "\uf005" + readonly property string fa_star_half : "\uf089" + readonly property string fa_star_half_empty : "\uf123" + readonly property string fa_star_half_full : "\uf123" + readonly property string fa_star_half_o : "\uf123" + readonly property string fa_star_o : "\uf006" + readonly property string fa_steam : "\uf1b6" + readonly property string fa_steam_square : "\uf1b7" + readonly property string fa_step_backward : "\uf048" + readonly property string fa_step_forward : "\uf051" + readonly property string fa_stethoscope : "\uf0f1" + readonly property string fa_stop : "\uf04d" + readonly property string fa_strikethrough : "\uf0cc" + readonly property string fa_stumbleupon : "\uf1a4" + readonly property string fa_stumbleupon_circle : "\uf1a3" + readonly property string fa_subscript : "\uf12c" + readonly property string fa_suitcase : "\uf0f2" + readonly property string fa_sun_o : "\uf185" + readonly property string fa_superscript : "\uf12b" + readonly property string fa_support : "\uf1cd" + readonly property string fa_table : "\uf0ce" + readonly property string fa_tablet : "\uf10a" + readonly property string fa_tachometer : "\uf0e4" + readonly property string fa_tag : "\uf02b" + readonly property string fa_tags : "\uf02c" + readonly property string fa_tasks : "\uf0ae" + readonly property string fa_taxi : "\uf1ba" + readonly property string fa_tencent_weibo : "\uf1d5" + readonly property string fa_terminal : "\uf120" + readonly property string fa_text_height : "\uf034" + readonly property string fa_text_width : "\uf035" + readonly property string fa_th : "\uf00a" + readonly property string fa_th_large : "\uf009" + readonly property string fa_th_list : "\uf00b" + readonly property string fa_thumb_tack : "\uf08d" + readonly property string fa_thumbs_down : "\uf165" + readonly property string fa_thumbs_o_down : "\uf088" + readonly property string fa_thumbs_o_up : "\uf087" + readonly property string fa_thumbs_up : "\uf164" + readonly property string fa_ticket : "\uf145" + readonly property string fa_times : "\uf00d" + readonly property string fa_times_circle : "\uf057" + readonly property string fa_times_circle_o : "\uf05c" + readonly property string fa_tint : "\uf043" + readonly property string fa_toggle_down : "\uf150" + readonly property string fa_toggle_left : "\uf191" + readonly property string fa_toggle_off : "\uf204" + readonly property string fa_toggle_on : "\uf205" + readonly property string fa_toggle_right : "\uf152" + readonly property string fa_toggle_up : "\uf151" + readonly property string fa_trash : "\uf1f8" + readonly property string fa_trash_o : "\uf014" + readonly property string fa_tree : "\uf1bb" + readonly property string fa_trello : "\uf181" + readonly property string fa_trophy : "\uf091" + readonly property string fa_truck : "\uf0d1" + readonly property string fa_try : "\uf195" + readonly property string fa_tty : "\uf1e4" + readonly property string fa_tumblr : "\uf173" + readonly property string fa_tumblr_square : "\uf174" + readonly property string fa_turkish_lira : "\uf195" + readonly property string fa_twitch : "\uf1e8" + readonly property string fa_twitter : "\uf099" + readonly property string fa_twitter_square : "\uf081" + readonly property string fa_umbrella : "\uf0e9" + readonly property string fa_underline : "\uf0cd" + readonly property string fa_undo : "\uf0e2" + readonly property string fa_university : "\uf19c" + readonly property string fa_unlink : "\uf127" + readonly property string fa_unlock : "\uf09c" + readonly property string fa_unlock_alt : "\uf13e" + readonly property string fa_unsorted : "\uf0dc" + readonly property string fa_upload : "\uf093" + readonly property string fa_usd : "\uf155" + readonly property string fa_user : "\uf007" + readonly property string fa_user_md : "\uf0f0" + readonly property string fa_users : "\uf0c0" + readonly property string fa_video_camera : "\uf03d" + readonly property string fa_vimeo_square : "\uf194" + readonly property string fa_vine : "\uf1ca" + readonly property string fa_vk : "\uf189" + readonly property string fa_volume_down : "\uf027" + readonly property string fa_volume_off : "\uf026" + readonly property string fa_volume_up : "\uf028" + readonly property string fa_warning : "\uf071" + readonly property string fa_wechat : "\uf1d7" + readonly property string fa_weibo : "\uf18a" + readonly property string fa_weixin : "\uf1d7" + readonly property string fa_wheelchair : "\uf193" + readonly property string fa_wifi : "\uf1eb" + readonly property string fa_windows : "\uf17a" + readonly property string fa_won : "\uf159" + readonly property string fa_wordpress : "\uf19a" + readonly property string fa_wrench : "\uf0ad" + readonly property string fa_xing : "\uf168" + readonly property string fa_xing_square : "\uf169" + readonly property string fa_yahoo : "\uf19e" + readonly property string fa_yelp : "\uf1e9" + readonly property string fa_yen : "\uf157" + readonly property string fa_youtube : "\uf167" + readonly property string fa_youtube_play : "\uf16a" + readonly property string fa_youtube_square : "\uf166" +} diff --git a/styles/CwtchComboBoxStyle.qml b/styles/CwtchComboBoxStyle.qml new file mode 100644 index 0000000..b4536eb --- /dev/null +++ b/styles/CwtchComboBoxStyle.qml @@ -0,0 +1,7 @@ +import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 + + +ComboBoxStyle { + textColor: "#000" +} diff --git a/styles/CwtchExpandingButton.qml b/styles/CwtchExpandingButton.qml new file mode 100644 index 0000000..76e71d2 --- /dev/null +++ b/styles/CwtchExpandingButton.qml @@ -0,0 +1,21 @@ +import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 + +ButtonStyle { + background: Rectangle { + width:25 + height:25 + color: windowItem.cwtch_dark_color + border.color: windowItem.cwtch_color + } + + label: Text { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.family: "Monospace" + font.pointSize: 8 + color: windowItem.cwtch_background_color + text: control.text + } +} diff --git a/styles/CwtchProgress.qml b/styles/CwtchProgress.qml new file mode 100644 index 0000000..711227c --- /dev/null +++ b/styles/CwtchProgress.qml @@ -0,0 +1,39 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Window 2.11 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + + +Rectangle { + id: pb + border.color: "#FFFFFF" + border.width: 1 + + color: "#D2C0DD" + property bool running + + // Indeterminate animation by animating alternating stripes: + Item { + anchors.fill: parent + anchors.margins: 1 + visible: control.indeterminate + clip: true + Row { + Repeater { + Rectangle { + color: index % 2 ? "#D2C0DD" : "#b29dbe" + width: 20 ; height: control.height + } + model: control.width / 20 + 2 + } + XAnimator on x { + from: 0 ; to: -40 + loops: Animation.Infinite + running: pb.running + } + } + } +} diff --git a/styles/CwtchTextAreaStyle.qml b/styles/CwtchTextAreaStyle.qml new file mode 100644 index 0000000..4e0e584 --- /dev/null +++ b/styles/CwtchTextAreaStyle.qml @@ -0,0 +1,8 @@ +import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 + + +TextAreaStyle { + textColor: "black" + backgroundColor: windowItem.cwtch_background_color +} diff --git a/styles/CwtchTextFieldStyle.qml b/styles/CwtchTextFieldStyle.qml new file mode 100644 index 0000000..9175e21 --- /dev/null +++ b/styles/CwtchTextFieldStyle.qml @@ -0,0 +1,15 @@ +import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 + +TextFieldStyle { + id: root + textColor: "black" + font.pointSize: 10 * gcd.themeScale + property int width: parent.width + + background: Rectangle { + radius: 2 + color: windowItem.cwtch_background_color + border.color: windowItem.cwtch_color + } +} diff --git a/theme/CwtchDark.qml b/theme/CwtchDark.qml new file mode 100644 index 0000000..35f0442 --- /dev/null +++ b/theme/CwtchDark.qml @@ -0,0 +1,51 @@ + +ThemeType { + readonly property color darkGrayPurple: "#281831" + readonly property color deepPurple: "#422850" + readonly property color mauvePurple: "#8E64A5" + readonly property color purple: "#DFB9DE" + readonly property color whitePurple: "#FFFDFF" + readonly property color softPurple: "#FDF3FC" + readonly property color pink: "#E85DA1" + readonly property color hotPink: "#D01972" + + backgroundMainColor: darkGrayPurple + backgroundPaneColor: deepPurple + + mainTextColor: purple + altTextColor: mauvePurple + defaultButtonColor: mauvePurple + defaultButtonActiveColor: pink + defaultButtonTextColor: whitePurple + + portraitOnlineBorderColor: whitePurple + portraitOnlineBackgroundColor: darkGrayPurple + portraitOnlineTextColor: whitePurple + portraitConnectingBorderColor: mauvePurple + portraitConnectingBackgroundColor: darkGrayPurple + portraitConnectingTextColor: whitePurple + portraitOfflineBorderColor: deepPurple + portraitOfflineBackgroundColor: darkGrayPurple + portraitOfflineTextColor: softPurple + + portraitContactBadgeColor: hotPink + portraitContactBadgeTextColor: whitePurple + portraitProfileBadgeColor: mauvePurple + dropShadowColor: mauvePurple + dropShadowPaneColor: darkGrayPurple + + toggleColor: darkGrayPurple + toggleOnColor: whitePurple + toggleOffColor: mauvePurple + + toolbarIconColor: whitePurple + + statusbarDisconnectedInternetColor: whitePurple + statusbarDisconnectedInternetFontColor: deepPurple + statusbarDisconnectedTorColor: darkGrayPurple + statusbarDisconnectedTorFontColor: whitePurple + statusbarConnectingColor: deepPurple + statusbarConnectingFontColor: whitePurple + statusbarOnlineColor: mauvePurple + statusbarOnlineFontColor: whitePurple +} diff --git a/theme/CwtchLight.qml b/theme/CwtchLight.qml new file mode 100644 index 0000000..aac033e --- /dev/null +++ b/theme/CwtchLight.qml @@ -0,0 +1,51 @@ + +ThemeType { + readonly property color whitePurple: "#FFFDFF" + readonly property color softPurple: "#FDF3FC" + readonly property color purple: "#DFB9DE" + readonly property color brightPurple: "#760388" + readonly property color darkPurple: "#350052" + readonly property color greyPurple: "#775F84" + readonly property color pink: "#E85DA1" + readonly property color hotPink: "#D01972" + + backgroundMainColor: whitePurple + backgroundPaneColor: softPurple + + mainTextColor: darkPurple + altTextColor: purple + defaultButtonColor: hotPink + defaultButtonActiveColor: pink + defaultButtonTextColor: whitePurple + + portraitOnlineBorderColor: darkPurple + portraitOnlineBackgroundColor: darkPurple + portraitOnlineTextColor: darkPurple + portraitConnectingBorderColor: greyPurple + portraitConnectingBackgroundColor: greyPurple + portraitConnectingTextColor: greyPurple + portraitOfflineBorderColor: purple + portraitOfflineBackgroundColor: purple + portraitOfflineTextColor: purple + + portraitContactBadgeColor: hotPink + portraitContactBadgeTextColor: whitePurple + portraitProfileBadgeColor: brightPurple + dropShadowColor: purple + dropShadowPaneColor: purple + + toggleColor: whitePurple + toggleOnColor: hotPink + toggleOffColor: purple + + toolbarIconColor: darkPurple + + statusbarDisconnectedInternetColor: softPurple + statusbarDisconnectedInternetFontColor: darkPurple + statusbarDisconnectedTorColor: purple + statusbarDisconnectedTorFontColor: darkPurple + statusbarConnectingColor: greyPurple + statusbarConnectingFontColor: whitePurple + statusbarOnlineColor: darkPurple + statusbarOnlineFontColor: whitePurple +} diff --git a/theme/Theme.qml b/theme/Theme.qml new file mode 100644 index 0000000..7570b24 --- /dev/null +++ b/theme/Theme.qml @@ -0,0 +1,61 @@ +pragma Singleton + +import QtQuick 2.0 + +Item { + readonly property color backgroundMainColor: theme.backgroundMainColor + readonly property color backgroundPaneColor: theme.backgroundPaneColor + + readonly property color mainTextColor: theme.mainTextColor + readonly property color altTextColor: theme.altTextColor + readonly property color defaultButtonColor: theme.defaultButtonColor + readonly property color defaultButtonActiveColor: theme.defaultButtonActiveColor + readonly property color defaultButtonTextColor: theme.defaultButtonTextColor + + readonly property color dropShadowColor: theme.dropShadowColor + readonly property color dropShadowPaneColor: theme.dropShadowPaneColor + + readonly property color portraitOnlineBorderColor: theme.portraitOnlineBorderColor + readonly property color portraitOnlineBackgroundColor: theme.portraitOnlineBackgroundColor + readonly property color portraitOnlineTextColor: theme.portraitOnlineTextColor + readonly property color portraitConnectingBorderColor: theme.portraitConnectingBorderColor + readonly property color portraitConnectingBackgroundColor: theme.portraitConnectingBackgroundColor + readonly property color portraitConnectingTextColor: theme.portraitConnectingTextColor + readonly property color portraitOfflineBorderColor: theme.portraitOfflineBorderColor + readonly property color portraitOfflineBackgroundColor: theme.portraitOfflineBackgroundColor + readonly property color portraitOfflineTextColor: theme.portraitOfflineTextColor + + readonly property color portraitContactBadgeColor: theme.portraitContactBadgeColor + readonly property color portraitContactBadgeTextColor: theme.portraitContactBadgeTextColor + readonly property color portraitProfileBadgeColor: theme.portraitProfileBadgeColor + + readonly property color toggleColor: theme.toggleColor + readonly property color toggleOffColor: theme.toggleOffColor + readonly property color toggleOnColor: theme.toggleOnColor + + readonly property color toolbarIconColor: theme.toolbarIconColor + + readonly property color statusbarDisconnectedInternetColor: theme.statusbarDisconnectedInternetColor + readonly property color statusbarDisconnectedInternetFontColor: theme.statusbarDisconnectedInternetFontColor + readonly property color statusbarDisconnectedTorFontColor: theme.statusbarDisconnectedTorFontColor + readonly property color statusbarDisconnectedTorColor: theme.statusbarDisconnectedTorColor + readonly property color statusbarConnectingColor: theme.statusbarConnectingColor + readonly property color statusbarConnectingFontColor: theme.statusbarConnectingFontColor + readonly property color statusbarOnlineColor: theme.statusbarOnlineColor + readonly property color statusbarOnlineFontColor: theme.statusbarOnlineFontColor + + readonly property int headerSize: 50 + readonly property int usernameSize: 30 + readonly property int tabSize: 25 + readonly property int chatSize: 20 + readonly property int secondaryTextSize: 20 // address + readonly property int chatMetaTextSize: 15 + readonly property int badgeTextSize: 12 + readonly property int statusTextSize: 12 + + readonly property int sidePaneMinSize: 700 + readonly property int doublePaneMinSize: 1000 + + property ThemeType theme: CwtchLight { } + +} diff --git a/theme/ThemeType.qml b/theme/ThemeType.qml new file mode 100644 index 0000000..55dc9c2 --- /dev/null +++ b/theme/ThemeType.qml @@ -0,0 +1,46 @@ +import QtQuick 2.0 + +QtObject { + property color backgroundMainColor: "red" + property color backgroundPaneColor: "red" + + property color mainTextColor: "red" + property color altTextColor: "red" + property color defaultButtonColor: "red" + property color defaultButtonActiveColor: "red" + property color defaultButtonTextColor: "red" + + property color portraitOnlineBorderColor: "red" + property color portraitOnlineBackgroundColor: "red" + property color portraitOnlineTextColor: "red" + property color portraitConnectingBorderColor: "red" + property color portraitConnectingBackgroundColor: "red" + property color portraitConnectingTextColor: "red" + property color portraitOfflineBorderColor: "red" + property color portraitOfflineBackgroundColor: "red" + property color portraitOfflineTextColor: "red" + + property color portraitContactBadgeColor: "red" + property color portraitContactBadgeTextColor: "red" + property color portraitProfileBadgeColor: "red" + property color dropShadowColor: "black" + property color dropShadowPaneColor: "black" + property color toggleColor: "black" + property color toggleOnColor: "black" + property color toggleOffColor: "black" + + property color toolbarIconColor: "red" + + property color statusbarDisconnectedInternetColor: "red" + property color statusbarDisconnectedInternetFontColor: "red" + property color statusbarDisconnectedTorFontColor: "red" + property color statusbarDisconnectedTorColor: "red" + property color statusbarConnectingColor: "red" + property color statusbarConnectingFontColor: "red" + property color statusbarOnlineColor: "red" + property color statusbarOnlineFontColor: "red" + + // ... more to come + + +} diff --git a/theme/qmldir b/theme/qmldir new file mode 100644 index 0000000..4954041 --- /dev/null +++ b/theme/qmldir @@ -0,0 +1 @@ +singleton Theme 1.0 Theme.qml \ No newline at end of file