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 "opaque" import "opaque/fonts" import "opaque/fonts/Twemoji.js" as T import "opaque/fonts/MutantStandard.js" as Mutant import "opaque/theme" import "overlays" import "panes" import "widgets" import "utils.js" as Utils ApplicationWindow { id: windowItem width: 1200 height: 800 visible: true title: "cwtch" + "" font.family: Fonts.applicationFontRegular.name font.styleName: "Light" readonly property real ratio: height / width FontAwesome { // PRETTY BUTTON ICONS id: awesome resource: "qrc:/qml/opaque/fonts/fontawesome.ttf" } FontLoader { source: "qrc:/qml/opaque/fonts/AdobeBlank.ttf" } function parse(text, size, isntEditable) { // REPLACE EMOJI WITH TAGS T.twemoji.base = gcd.assetPath + "twemoji/" T.twemoji.ext = ".png" T.twemoji.size = "72x72" T.twemoji.className = "\" height=\""+size+"\" width=\""+size var retText = T.twemoji.parse(Utils.htmlEscaped(text)) retText = retText.replace(/\n/g,"
") // mutant standard stickers if (isntEditable) retText = Mutant.standard.parse(retText) return retText } function restoreEmoji(text) { // REPLACE TAGS WITH EMOJI var re = RegExp('', 'g') var arr var newtext = text while (arr = re.exec(text)) { var pieces = arr[1].split("-") var replacement = "" for (var i = 0; i < pieces.length; i++) { replacement += T.twemoji.convert.fromCodePoint(pieces[i]) } newtext = newtext.replace(arr[0], replacement) } return newtext } function ptToPx(pt) { return Screen.pixelDensity * 25.4 * pt / 72 } function pxToPt(px) { return px * 72 / (Screen.pixelDensity * 25.4) } Toolbar { id: toolbar onLeftMenu: { gcd.requestSettings() parentStack.pane = parentStack.settingsPane } onBack: { backFn() } onRightMenu: { if (gcd.selectedConversation.length == 32) { theStack.pane = theStack.groupProfilePane gcd.requestGroupSettings(gcd.selectedConversation) } else { theStack.pane = theStack.userProfilePane gcd.requestPeerSettings() } } } StackLayout { id: parentStack currentIndex: 1 anchors.right: parent.right anchors.left: parent.left anchors.bottom: statusbar.top anchors.top: toolbar.bottom readonly property int splashPane: 0 readonly property int managementPane: 1 readonly property int settingsPane: 2 readonly property int addEditProfilePane: 3 readonly property int profilePane: 4 property alias pane: parentStack.currentIndex Rectangle { // Splash pane color: Theme.backgroundMainColor Layout.fillHeight: true Layout.fillWidth: true //anchors.fill: parent visible: true SplashPane { id: splashPane anchors.fill: parent running: true } } Rectangle { // Profile login/management pane Layout.fillHeight: true Layout.fillWidth: true visible: false color: Theme.backgroundMainColor ProfileManagerPane { id: profilesPane anchors.fill: parent } } Rectangle { // Settings pane Layout.fillHeight: true Layout.fillWidth: true color: Theme.backgroundPaneColor SettingsPane { id: settingsPane anchors.fill: parent } } Rectangle { // Profile Add / Edit pane Layout.fillHeight: true Layout.fillWidth: true color: Theme.backgroundMainColor ProfileAddEditPane{ id: profileAddEditPane anchors.fill: parent } } RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR Layout.fillHeight: true Layout.fillWidth: true spacing: 0 Rectangle { // THE LEFT PANE WITH TOOLS AND CONTACTS color: Theme.backgroundMainColor Layout.fillHeight: true Layout.minimumWidth: Layout.maximumWidth Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : Theme.sidePaneMinSize visible: (windowItem.width >= Theme.doublePaneMinSize && !Qt.inputMethod.visible) || theStack.pane == theStack.emptyPane ContactList { anchors.fill: parent dualPane: theStack.pane != theStack.emptyPane || theStack.pane == undefined } } Rectangle { // THE RIGHT PANE WHERE THE MESSAGES AND STUFF GO color: Theme.backgroundPaneColor Layout.fillWidth: true Layout.fillHeight: true StackLayout { id: theStack anchors.fill: parent currentIndex: 0 property alias pane: theStack.currentIndex readonly property int emptyPane: 0 readonly property int messagePane: 1 readonly property int userProfilePane: 2 readonly property int groupProfilePane: 3 readonly property int addGroupPane: 4 Item { anchors.fill: parent } // empty Rectangle { color: Theme.backgroundMainColor Layout.fillWidth: true Layout.fillHeight: true OverlayPane { // messagePane anchors.fill: parent } } PeerSettingsPane { anchors.fill: parent } GroupSettingsPane{ anchors.fill: parent } AddGroupPane { anchors.fill: parent } onCurrentIndexChanged: { parentStack.updateToolbar() if (currentIndex == emptyPane) { toolbar.hideTitle() toolbar.rightMenuVisible = false } } onWidthChanged: {toolbar.titleWidth = width} } } } focus: true Keys.onPressed: { if (event.key == Qt.Key_Back) { event.accepted = true backFn() } } onCurrentIndexChanged : { updateToolbar(); statusbar.resetHeight() } function updateToolbar() { if (currentIndex == splashPane) { toolbar.hideTitle() toolbar.rightMenuVisible = false toolbar.visible = false } else { toolbar.visible = true if (currentIndex == managementPane) { toolbar.hideTitle() toolbar.rightMenuVisible = false toolbar.color = Theme.backgroundMainColor toolbar.leftMenuVisible = true toolbar.backVisible = false } else { toolbar.leftMenuVisible = false toolbar.backVisible = true if (currentIndex == profilePane && theStack.currentIndex == theStack.emptyPane) { toolbar.hideTitle() toolbar.rightMenuVisible = false toolbar.color = Theme.backgroundMainColor } else { toolbar.color = Theme.backgroundPaneColor } } } } Component.onCompleted: updateToolbar() Connections { target: Theme onThemeChanged: { parentStack.updateToolbar() } } } Statusbar { id: statusbar } function backFn() { if (parentStack.currentIndex == parentStack.managementPane) { androidCwtchActivity.rootHomeButtonHandle() } else if (parentStack.currentIndex != parentStack.profilePane) { parentStack.currentIndex = parentStack.managementPane } else { if (theStack.currentIndex == theStack.emptyPane) { gcd.selectedProfile = "none" gcd.reloadProfileList() parentStack.pane = parentStack.managementPane } else if (theStack.currentIndex == theStack.userProfilePane || theStack.currentIndex == theStack.groupProfilePane) { theStack.currentIndex = theStack.messagePane } else { theStack.currentIndex = theStack.emptyPane } } } PropertyAnimation { id: anmPopup; easing.type: Easing.InQuart; duration: 7000; target: popup; property: "opacity"; to: 0; } Rectangle { // THE ERROR MESSAGE POPUP id: popup anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 20 width: lblPopup.width + 30 height: lblPopup.height + 8 * gcd.themeScale color: "#000000" opacity: 0.5 radius: 15 visible: false Label { id: lblPopup anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter font.pixelSize: 18 * gcd.themeScale color: "#FFFFFF" } } Connections { // POPUPS ARE INVOKED BY GO FUNCS target: gcd onInvokePopup: function(str) { lblPopup.text = str popup.opacity = 0.5 popup.visible = true anmPopup.restart() } onLoaded: function() { parentStack.pane = parentStack.managementPane splashPane.running = false } } Component.onCompleted: Mutant.standard.imagePath = gcd.assetPath; Connections { target: Qt.application onStateChanged: function() { // https://doc.qt.io/qt-5/qt.html#ApplicationState-enum if (Qt.application.state == 4) { // Active gcd.onActivate() } } } }