diff --git a/ANDROID_DEBUGGING.md b/ANDROID_DEBUGGING.md new file mode 100644 index 00000000..9378bffc --- /dev/null +++ b/ANDROID_DEBUGGING.md @@ -0,0 +1,82 @@ +# Notes on Android Debugging + +If you are reading this you are probably interested in developing Cwtch for Android! Awesome. + +The Cwtch UI app is intended to be a single codebase that runs on multiple platforms. This +complicates the build process in favour of simplifying the code (so goes the theory). + +We make use of https://github.com/therecipe/qt/ for deploying Go/Qt code to Android. Before you venture into the weeds +of this README please take a look at the [Installation](https://github.com/therecipe/qt/wiki/Installation) +and [Setup instructions](https://github.com/therecipe/qt/wiki/Deploying-Linux-to-Android) in therecipe/qt. + +## Building + +Check out and follow the instructions at https://github.com/therecipe/qt/wiki/Deploying-Linux-to-Android as they are sufficient, +below you will find high-level notes regarding the process. + +You need to run `qtsetup --qt_version= full android` for the non-docker setup. You will need to do this +for every major version change of therecipe dependencies. + +You will also need the Android 28 SDK (Pie), the NDK, SDK build tools and platform tools, gradle and **JDK 8** + + JAVA_HOME=/path/to/jre8 + ANDROID_NDK_DIR=/path/to/ndk + +Once all that setup is done you should be able to run: + + qtdeploy build android + +2-4 minutes later an android apk will pop out in `./deploy/android/build-debug.apk`. + +### Build Setup Issues we have seen + +* `Could not determine java version from ` - this is thrown by gradle inside the `androiddeployqt` process when the +Java version is *not* JRE8. Ensure that JAVA_HOME is pointed to the correct java installation. +* ` readelf "is not an ordinary file"` - this isn't actually an error that will stop the build, but sometimes +because of the very long debug log output you will come across it when trying to find the *actual* error (which is +probably a Java version issue). It can be safely ignored. +* `could not find QAndroid...` / `CPP build errors` - you will need to run `qtsetup` full android` for the Qt version +you are using. + * Example: androidextras_android.cpp:9:10: fatal error: 'QAndroidActivityResultReceiver' file not found + +## Testing on a Real Device + +Consult the Android documentation on setting up your device for development. + +You will need an android sdk, setup your device for USB Debugging and then with `adb` you can do: + + adb install -r ./deploy/android/build-debug.apk + + To get the logs you can run + + adb logcat + +Android Studio provides a nice logcat interface for quickly filtering log files that can be very useful when trying to +debug complex behavior, but command line tools like `grep` and the built-in [logcat filtering](https://developer.android.com/studio/command-line/logcat) + should also suffice. + + *Important*: Cwtch UI technically runs *3* different applications: Cwtch Frontend (application client), + Cwtch Backend (application server) and Tor. When filtering logcat you should be aware that some of your messages might + be getting logged by a different process. + + (*Ctrl-F Helper: "Why are log messages missing"*) + +# Bundled Libraries + +There seems to be a bug in Qt (https://bugreports.qt.io/browse/QTBUG-84371) that prevents the use of +`AndroidExtras` in `ANDROID_MODULES_INCLUDE` so we bundle it in `android/libQt5AndroidExtras.so` along with +`libtor` for Tor support. + +## Non-SDK Interfaces + +e.g. java.lang.NoSuchFieldException: No field mPivotX in class Landroid/graphics/drawable/RotateDrawable$RotateState; + +* https://bugreports.qt.io/browse/QTBUG-71590 + +## Plugins + +Theoretically speaking it should be possible to use `ANDROID_EXTRA_PLUGINS` to include support for e.g. +SVG images on Android. However, we have been unable to make it work. If you would like to try, the following +issues might be helpful: + +* https://bugreports.qt.io/browse/QTBUG-60022 \ No newline at end of file diff --git a/Makefile b/Makefile index 6a66eee2..8d1e200b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ .PHONY: all clean linux windows android all: clean linux windows android -default: linux +default: linux + +SHELL := env QT_BUILD_VERSION=$(QT_BUILD_VERSION) $(SHELL) +QT_BUILD_VERSION ?= "5.13.4" clean: rm -r vendor || true @@ -18,7 +21,7 @@ android: linux_build: date - qtdeploy -qt_version "5.13.0" build linux 2>&1 | tee qtdeploy.log | pv + qtdeploy -qt_version $(QT_BUILD_VERSION) build linux 2>&1 | tee qtdeploy.log | pv date cp -R assets deploy/linux/ $(MAKE) linux_clean @@ -28,7 +31,7 @@ linux_clean: windows_build: date - qtdeploy -qt_version "5.13.0" build windows 2>&1 | tee qtdeploy.log | pv + qtdeploy -qt_version $(QT_BUILD_VERSION) build windows 2>&1 | tee qtdeploy.log | pv date cp -R assets deploy/windows/ $(MAKE) linux_clean @@ -37,11 +40,11 @@ windows_clean: #ntd android_build: - mv assets android/ + cp -R assets android/ date - qtdeploy -docker build android 2>&1 | tee qtdeploy.log | pv + ## TODO have this also include AndroidExtras (see ANDROID_DEBUGGING) for full notes. + env ANDROID_MODULES_INCLUDE="Core,Gui,Svg,QuickWidgets,Xml" qtdeploy -debug -qt_version $(QT_BUILD_VERSION) build android 2>&1 | tee qtdeploy.log | pv date - $(MAKE) android_clean android_clean: mv android/assets assets diff --git a/android/libs/armeabi-v7a/libQt5AndroidExtras.so b/android/libs/armeabi-v7a/libQt5AndroidExtras.so new file mode 100755 index 00000000..5e583212 Binary files /dev/null and b/android/libs/armeabi-v7a/libQt5AndroidExtras.so differ diff --git a/go.sum b/go.sum index cc462697..4fb6bf08 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,7 @@ github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/b github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -77,8 +78,19 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/struCoder/pidusage v0.1.3 h1:pZcSa6asBE38TJtW0Nui6GeCjLTpaT/jAnNP7dUTLSQ= github.com/struCoder/pidusage v0.1.3/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI= +github.com/therecipe/env_darwin_amd64_513 v0.0.0-20190626001412-d8e92e8db4d0 h1:Txh3Vvzx49BQg6OwSuYqOGNndpCWPYScIpEgK5BcGpc= +github.com/therecipe/env_darwin_amd64_513 v0.0.0-20190626001412-d8e92e8db4d0/go.mod h1:mdZdqBBs62KM68t1wD7rjG2NumvwuSNLqmMetEAqI14= +github.com/therecipe/env_linux_amd64_513 v0.0.0-20190626000307-e137a3934da6 h1:i0/LROzMqqMuHJ9gPeH2+So1Icle7zSVRqzXR4Z75hw= +github.com/therecipe/env_linux_amd64_513 v0.0.0-20190626000307-e137a3934da6/go.mod h1:Cq/lZrZTuGhRckzJgZFONK4WCE67AssWhHYj82U5FFI= +github.com/therecipe/env_windows_amd64_513 v0.0.0-20190626000028-79ec8bd06fb2 h1:dpqvgFCZRuxwiJhWVwQZSJ8zDaORf+GiUGxxOGzlQtc= +github.com/therecipe/env_windows_amd64_513 v0.0.0-20190626000028-79ec8bd06fb2/go.mod h1:evzb6PHK/MrRdJyhL1kbQXTfbMu4t4JOLl6iz55ywvk= +github.com/therecipe/env_windows_amd64_513/Tools v0.0.0-20190626000028-79ec8bd06fb2 h1:hM5KSUn4YbSvPuXAWJyywohkDocI+hSEsL+Msc9/FDA= +github.com/therecipe/env_windows_amd64_513/Tools v0.0.0-20190626000028-79ec8bd06fb2/go.mod h1:75GdIZ2clS7WUwhRklktkP02ffFz7+tBx8/Ue8eFexU= github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41 h1:yBVcrpbaQYJBdKT2pxTdlL4hBE/eM4UPcyj9YpyvSok= github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us= +github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d h1:T+d8FnaLSvM/1BdlDXhW4d5dr2F07bAbB+LpgzMxx+o= +github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us= +github.com/therecipe/qt/internal/binding/files/docs v0.0.0-20191019224306-1097424d656c h1:/VhcwU7WuFEVgDHZ9V8PIYAyYqQ6KNxFUjBMOf2aFZM= github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 h1:My9HYsfDI/fJPZGyilw6066buBiZ7pgKRRgAyvKK5lA= github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:7m8PDYDEtEVqfjoUQc2UrFqhG0CDmoVJjRlQxexndFc= github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 h1:jTzKrQ6EIPvKw1B9/wwoKJLrXF+ManMsXoUzufxAdsg= diff --git a/go/ui/gcd.go b/go/ui/gcd.go index 0e169d9c..c8bb2ccf 100644 --- a/go/ui/gcd.go +++ b/go/ui/gcd.go @@ -690,12 +690,6 @@ func (this *GrandCentralDispatcher) setLocaleHelper(locale string) { } func (this *GrandCentralDispatcher) themeScaleChanged(newThemeScale float32) { - // TODO: solve why themeScale > 2.0 halts app launch - related task - solve all the qml launch warnings around anchors/layouts - if this.Os() != "android" { - if newThemeScale > 1.99 { - this.SetThemeScale(1.99) - } - } this.GlobalSettings.Zoom = newThemeScale WriteGlobalSettings(this.GlobalSettings) } diff --git a/go/ui/settings.go b/go/ui/settings.go index a5d40edf..137c68e4 100644 --- a/go/ui/settings.go +++ b/go/ui/settings.go @@ -25,7 +25,7 @@ type GlobalSettings struct { } var DefaultGlobalSettings = GlobalSettings{ - Zoom: 1.0, + Zoom: 1.9, Locale: "en", Theme: "light", PreviousPid: -1, @@ -68,11 +68,13 @@ func ReadGlobalSettings() *GlobalSettings { return &settings } + err = json.Unmarshal(settingsBytes, &settings) if err != nil { log.Errorf("Could not parse global ui settings: %v\n", err) } - log.Debugf("MAP: %v", settings.Experiments) + + log.Debugf("Settings: %v", settings) return &settings } diff --git a/main.go b/main.go index d1654e9e..6032c1bf 100644 --- a/main.go +++ b/main.go @@ -44,6 +44,7 @@ func init() { } func main() { + if os.Getenv("CWTCH_FOLDER") != "" { the.CwtchDir = os.Getenv("CWTCH_FOLDER") } else if runtime.GOOS == "android" { @@ -259,6 +260,7 @@ func loadACN() { } } + // generate a random socks and control port (not real random...these are port numbers...) mrand.Seed(int64(time.Now().Nanosecond())) port := mrand.Intn(1000) + 9600 diff --git a/qml/main.qml b/qml/main.qml index 8a553b9d..55a3aa20 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -75,8 +75,6 @@ ApplicationWindow { return px * 72 / (Screen.pixelDensity * 25.4) } - - StackView { id: rootStack @@ -115,6 +113,7 @@ ApplicationWindow { } } + // The actual app property Item mainLayout: Rectangle { color: Theme.backgroundMainColor @@ -191,6 +190,7 @@ ApplicationWindow { } } + RowLayout { // Profile Pane (contact list + overlays) Layout.fillHeight: true Layout.fillWidth: true diff --git a/qml/opaque b/qml/opaque index b8d01338..3b9675e2 160000 --- a/qml/opaque +++ b/qml/opaque @@ -1 +1 @@ -Subproject commit b8d01338786625a41ba430ede6430715f5c82b33 +Subproject commit 3b9675e25917f667ba4b1cf1db09d44ed328f010 diff --git a/qml/overlays/ListOverlay.qml b/qml/overlays/ListOverlay.qml index 52b8150a..0fcd1e64 100644 --- a/qml/overlays/ListOverlay.qml +++ b/qml/overlays/ListOverlay.qml @@ -32,7 +32,7 @@ ColumnLayout { //: ex: "... paste an address here to add a contact ..." placeholderText: qsTr("search-list") horizontalAlignment: TextInput.AlignHCenter - icon: gcd.assetPath + "core/search-24px.svg" + icon: gcd.assetPath + "core/search-24px.webp" onTextChanged: { @@ -47,18 +47,19 @@ ColumnLayout { Opaque.Icon { visible:!listpanel.online - source: gcd.assetPath + "core/negative_heart_24px.svg" + source: gcd.assetPath + "core/negative_heart_24px.webp" iconColor: Theme.mainTextColor backgroundColor: Theme.backgroundPaneColor Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter height: 150 width: 150 } - Opaque.EllipsisLabel { + Label { visible:!listpanel.online color: Theme.mainTextColor Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - size: 18 * gcd.themeScale + elide: Text.ElideRight + font.pixelSize: 18 * gcd.themeScale text: qsTr("peer-not-online") } diff --git a/qml/panes/GroupSettingsPane.qml b/qml/panes/GroupSettingsPane.qml index e7d45789..0c52f7e5 100644 --- a/qml/panes/GroupSettingsPane.qml +++ b/qml/panes/GroupSettingsPane.qml @@ -97,7 +97,7 @@ Opaque.SettingsList { // groupSettingsPane width: 18 Layout.alignment: Qt.AlignRight iconColor: gsp.connected ? Theme.statusbarOnlineFontColor : Theme.statusbarDisconnectedTorFontColor - source: gcd.assetPath + (gsp.connected ? "core/signal_cellular_4_bar-24px.svg" : "core/signal_cellular_connected_no_internet_4_bar-24px.svg") + source: gcd.assetPath + (gsp.connected ? "core/signal_cellular_4_bar-24px.webp" : "core/signal_cellular_connected_no_internet_4_bar-24px.webp") } } RowLayout { @@ -115,7 +115,7 @@ Opaque.SettingsList { // groupSettingsPane width: 18 Layout.alignment: Qt.AlignRight iconColor : gsp.synced ? Theme.statusbarOnlineFontColor : Theme.statusbarConnectingFontColor - source: gcd.assetPath + (gsp.synced ? "core/syncing-01.svg" : "core/syncing-03.svg") + source: gcd.assetPath + (gsp.synced ? "core/syncing-01.webp" : "core/syncing-03.webp") } } diff --git a/qml/panes/ProfileAddEditPane.qml b/qml/panes/ProfileAddEditPane.qml index 4c80de0c..dd949e50 100644 --- a/qml/panes/ProfileAddEditPane.qml +++ b/qml/panes/ProfileAddEditPane.qml @@ -43,7 +43,7 @@ Opaque.Flickable { nameLabel.text = "" portrait.performTransform = true - portrait.source = "core/account_circle-24px_negative_space.svg" + portrait.source = "core/account_circle-24px_negative_space.webp" tag = "" confirmDeleteTxt.text = "" radioUsePassword.checked = true @@ -136,7 +136,7 @@ Opaque.Flickable { badgeContent: Image {// Profle Type id: profiletype - source: radioUsePassword.checked ? gcd.assetPath + "/fontawesome/solid/lock.svg" : gcd.assetPath + "/fontawesome/solid/lock-open.svg" + source: radioUsePassword.checked ? gcd.assetPath + "core/lock-24px.webp" : gcd.assetPath + "core/lock-open-24px.webp" height: 40 * gcd.themeScale width: height } diff --git a/qml/panes/ProfileManagerPane.qml b/qml/panes/ProfileManagerPane.qml index 7c039151..a073f15d 100644 --- a/qml/panes/ProfileManagerPane.qml +++ b/qml/panes/ProfileManagerPane.qml @@ -25,7 +25,7 @@ ColumnLayout { spacing: 20 * gcd.themeScale Opaque.ScalingLabel { - anchors.horizontalCenter: parent.horizontalCenter + Layout.alignment: Qt.AlignHCenter wrapMode: TextEdit.Wrap size: Theme.primaryTextSize @@ -56,16 +56,13 @@ ColumnLayout { Opaque.Button { id: "button" - //anchors.horizontalCenter: parent.horizontalCenter - width: 100 * gcd.themeScale + height: Theme.primaryTextSize * gcd.themeScale + icon: "lock_open-24px" //: Unlock text: qsTr("unlock") - height: Theme.primaryTextSize * gcd.themeScale - - onClicked: { gcd.unlockProfiles(txtPassword.text) txtPassword.text = "" @@ -76,7 +73,7 @@ ColumnLayout { Opaque.ScalingLabel { id: error - anchors.horizontalCenter: parent.horizontalCenter + Layout.alignment: Qt.AlignHCenter color: Theme.textfieldErrorColor //: 0 profiles loaded with that password text: qsTr("error-0-profiles-loaded-for-password") diff --git a/qml/panes/ServerAddEditPane.qml b/qml/panes/ServerAddEditPane.qml index 9764a9b8..563ab79a 100644 --- a/qml/panes/ServerAddEditPane.qml +++ b/qml/panes/ServerAddEditPane.qml @@ -34,33 +34,40 @@ Opaque.SettingsList { // Add Profile Pane serverAddEditPane.server_messages = server_messages; } - settings: Column { - anchors.horizontalCenter: parent.horizontalCenter - width: 700 + settings: Column { - Opaque.ScalingLabel { - text: server_name - size: 16 - } + anchors.horizontalCenter: parent.horizontalCenter + width: 700 - Opaque.Setting { - label: qsTr("server-availability") + Opaque.ScalingLabel { + text: server_name + size: 16 + } + + Opaque.Setting { + label: qsTr("server-availability") - field: Opaque.ToggleSwitch { - anchors.right: parent.right + field: Opaque.ToggleSwitch { + anchors.right: parent.right - isToggled: serverAddEditPane.server_available - onToggled: function() { - serverAddEditPane.server_available = !serverAddEditPane.server_available - if (serverAddEditPane.server_available) { - gcd.startServer(serverAddEditPane.server_name) - } else { - gcd.stopServer(serverAddEditPane.server_name) + isToggled: serverAddEditPane.server_available + onToggled: function() { + serverAddEditPane.server_available = !serverAddEditPane.server_available + if (serverAddEditPane.server_available) { + gcd.startServer(serverAddEditPane.server_name) + } else { + gcd.stopServer(serverAddEditPane.server_name) + } } } } - } + + + + + + Opaque.Setting { label: qsTr("server-autostart") @@ -87,6 +94,7 @@ Opaque.SettingsList { // Add Profile Pane } } + Opaque.Setting { inline: false label: qsTr("server-key-bundle") diff --git a/qml/panes/SettingsPane.qml b/qml/panes/SettingsPane.qml index a214ae7d..cc7fe4d1 100644 --- a/qml/panes/SettingsPane.qml +++ b/qml/panes/SettingsPane.qml @@ -20,7 +20,7 @@ Opaque.SettingsList { // settingsPane settings: Column { anchors.horizontalCenter: parent.horizontalCenter - width: 700 + width: parent.width - 20 Opaque.Setting { //: Language @@ -70,8 +70,7 @@ Opaque.SettingsList { // settingsPane Opaque.Slider { id: zoomSlider from: 0.5 - // TODO: find out why > 2.0 halts desktop app on load - task: fix all the qml anchor/layout warnings on load - to: gcd.os == "android" ? 4.0 : 1.9 + to: 4.0 value: gcd.themeScale live: false snapMode: Slider.SnapAlways @@ -158,8 +157,6 @@ Opaque.SettingsList { // settingsPane target: gcd onSupplySettings: function(locale, zoom, theme) { - if (zoom != "") zoomSlider.value = zoom - for (var i=0; i < cbLangItems.count; i++) { var item = cbLangItems.get(i) if (item["value"] == locale) { diff --git a/qml/widgets/ContactList.qml b/qml/widgets/ContactList.qml index e391df71..92ac2120 100644 --- a/qml/widgets/ContactList.qml +++ b/qml/widgets/ContactList.qml @@ -56,7 +56,7 @@ ColumnLayout { //: 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" + icon: gcd.assetPath + "core/search-24px.webp" onTextChanged: { diff --git a/qml/widgets/ContactRow.qml b/qml/widgets/ContactRow.qml index 25bf535b..ddb93340 100644 --- a/qml/widgets/ContactRow.qml +++ b/qml/widgets/ContactRow.qml @@ -76,7 +76,7 @@ Opaque.PortraitRow { spacing: 16 * gcd.themeScale Opaque.Icon { - source: gcd.assetPath + "core/favorite-24px.svg" + source: gcd.assetPath + "core/favorite-24px.webp" iconColor: Theme.toolbarIconColor backgroundColor: rowColor height: 18 * gcd.themeScale @@ -86,7 +86,7 @@ Opaque.PortraitRow { } Opaque.Icon { - source: gcd.assetPath + "core/delete-24px.svg" + source: gcd.assetPath + "core/delete-24px.webp" iconColor: Theme.toolbarIconColor backgroundColor: rowColor height: 18 * gcd.themeScale diff --git a/qml/widgets/Message.qml b/qml/widgets/Message.qml index e8d2788d..23cec57e 100644 --- a/qml/widgets/Message.qml +++ b/qml/widgets/Message.qml @@ -109,25 +109,23 @@ Rectangle { color: parent.color } - Opaque.EllipsisLabel { + Label { id: handle visible: !fromMe && !calendarEvent text: displayName color: Theme.messageFromOtherTextColor - size: Theme.chatSize * gcd.themeScale - weight: Font.Bold + + elide: Text.ElideRight + font.pixelSize: Theme.chatSize * gcd.themeScale + font.weight: Font.Bold font.family: Fonts.applicationFontBold.name font.styleName: "Bold" leftPadding: 10 * gcd.themeScale topPadding: 10 * gcd.themeScale - - container: lbl } - onWidthChanged: { handle.textResize() } - Column { id: colMessageBubble @@ -176,7 +174,7 @@ Rectangle { Image { // ACKNOWLEDGEMENT ICON id: ack - 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") + source: root.error != "" ? gcd.assetPath + "core/fontawesome/regular/window-close.webp" : (root.ackd ? gcd.assetPath + "core/fontawesome/regular/check-circle.svg" : gcd.assetPath + "core/fontawesome/regular/hourglass.svg") height: Theme.chatMetaTextSize * gcd.themeScale width: Theme.chatMetaTextSize * gcd.themeScale anchors.bottom: parent.bottom diff --git a/qml/widgets/MessageEditor.qml b/qml/widgets/MessageEditor.qml index 1311fbd5..f77d8d58 100644 --- a/qml/widgets/MessageEditor.qml +++ b/qml/widgets/MessageEditor.qml @@ -111,7 +111,7 @@ ColumnLayout { text: "" padding: 6 * gcd.themeScale wrapMode: TextEdit.Wrap - textFormat: Text.RichText + textFormat: Text.PlainText width: rectMessage.width color: Theme.mainTextColor @@ -208,7 +208,7 @@ ColumnLayout { Opaque.Icon { // SEND MESSAGE BUTTON id: btnSend - source: gcd.assetPath + "core/send-24px.svg" + source: gcd.assetPath + "core/send-24px.webp" width: colRight.width height: 50 * gcd.themeScale size: 36 * gcd.themeScale @@ -219,24 +219,10 @@ ColumnLayout { property int nextMessageID: 1 - TextEdit { - id: txtHidden - visible: false - textFormat: Text.RichText - } - onClicked: { - // Cannot use .text b/c in rich text mode it is always full of html - if (txtMessage.length != 0) { - txtHidden.text = restoreEmoji(txtMessage.text) - txtHidden.text = txtHidden.text.replace(/
/g,"[:newline:]"); - - var txt = txtHidden.text.trim() - if (txt.length > 0) { - var rawText = txtHidden.getText(0, txtHidden.text.length) - - root.sendClicked(rawText) - } + var txt = txtMessage.text.trim() + if (txt.length > 0) { + root.sendClicked(txt) } txtMessage.text = "" } @@ -248,7 +234,7 @@ ColumnLayout { Opaque.Icon { // EMOJI DRAWER BUTTON id: btnEmoji - source: gcd.assetPath + "core/mood-24px.svg" + source: gcd.assetPath + "core/mood-24px.webp" size: 25 height: 36 * gcd.themeScale @@ -263,7 +249,7 @@ ColumnLayout { Opaque.Icon { id: btnAttach - source: gcd.assetPath + "core/attach_file-24px.svg" + source: gcd.assetPath + "core/attach_file-24px.webp" size: 25 height: 36 * gcd.themeScale diff --git a/qml/widgets/MyProfile.qml b/qml/widgets/MyProfile.qml index a7048bf5..0d0086d1 100644 --- a/qml/widgets/MyProfile.qml +++ b/qml/widgets/MyProfile.qml @@ -31,6 +31,7 @@ Item { onDualPaneChanged: { realignProfile() } function realignProfile() { + if (dualPane) { profile.height = Theme.contactPortraitSize * logscale @@ -89,7 +90,7 @@ Item { badgeContent: Image {// Profle Type id: profiletype - source: tag == "v1-userPassword" ? gcd.assetPath + "/fontawesome/solid/lock.svg" : gcd.assetPath + "/fontawesome/solid/lock-open.svg" + source: tag == "v1-userPassword" ? gcd.assetPath + "core/lock-24px.webp" : gcd.assetPath + "core/lock_open-24px.webp" height: Theme.badgeTextSize * gcd.themeScale width: height } @@ -105,17 +106,16 @@ Item { id: nameCenter width: name.width + addBtn.width - Opaque.EllipsisLabel { + Label { id: name color: Theme.portraitOnlineTextColor - size: Theme.usernameSize * gcd.themeScale - weight: Font.Bold + elide: Text.ElideRight + font.pixelSize: Theme.usernameSize * gcd.themeScale + font.weight: Font.Bold font.family: Fonts.applicationFontExtraBold.name font.styleName: "ExtraBold" text: nick - extraPadding: addBtn.width + 30 - container: nameRow } Opaque.Button { // Add Button @@ -124,7 +124,7 @@ Item { anchors.left: name.right anchors.top: name.top - icon: "solid/plus" + icon: "fontawesome/solid/plus" height: name.height width: height diff --git a/qml/widgets/ProfileList.qml b/qml/widgets/ProfileList.qml index 6fa1aa9e..bcf4d0ef 100644 --- a/qml/widgets/ProfileList.qml +++ b/qml/widgets/ProfileList.qml @@ -93,6 +93,17 @@ ColumnLayout { image: _image tag: _tag Layout.fillWidth: true + rowClicked: function(handle) { + gcd.broadcast("ResetMessagePane"); + gcd.broadcast("ResetProfile"); + gcd.selectedProfile = handle; + gcd.loadProfile(handle); + parentStack.pane = parentStack.profilePane; + } + editClicked: function(handle, displayName, tag, image) { + profileAddEditPane.load(handle, displayName, tag, image); + parentStack.pane = parentStack.addEditProfilePane; + } } } @@ -101,7 +112,7 @@ ColumnLayout { handle: "" displayName: qsTr("add-new-profile-btn") nameColor: Theme.mainTextColor - image: "/core/account_circle-24px_negative_space.svg" //"/fontawesome/regular/user.svg" + image: "/core/account_circle-24px_negative_space.webp" tag: "" portraitBorderColor: Theme.defaultButtonColor portraitColor: Theme.defaultButtonColor @@ -109,7 +120,7 @@ ColumnLayout { portraitPerformTransform: true badgeVisible: true badgeContent: Image { - source: gcd.assetPath + "/fontawesome/solid/plus.svg" + source: gcd.assetPath + "core/fontawesome/solid/plus.webp" height: Theme.badgeTextSize * gcd.themeScale width: height } diff --git a/qml/widgets/ProfileRow.qml b/qml/widgets/ProfileRow.qml index 18422731..c058b01c 100644 --- a/qml/widgets/ProfileRow.qml +++ b/qml/widgets/ProfileRow.qml @@ -11,55 +11,53 @@ import "../opaque" as Opaque import "../opaque/styles" import "../opaque/theme" -Opaque.PortraitRow { +RowLayout { id: root - badgeColor: Theme.portraitProfileBadgeColor + property alias handle: prow.handle + property alias displayName: prow.displayName + property alias image: prow.image + property alias tag: prow.tag + property alias badgeColor: prow.badgeColor + property var rowClicked: {} + property var editClicked: {} - portraitBorderColor: Theme.portraitOnlineBorderColor - portraitColor: Theme.portraitOnlineBackgroundColor - nameColor: Theme.portraitOnlineTextColor - onionColor: Theme.portraitOnlineTextColor + Opaque.PortraitRow { + id: prow + badgeColor: Theme.portraitProfileBadgeColor + Layout.fillWidth: true + 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 + badgeContent: Image {// Profle Type + id: profiletype + source: tag == "v1-userPassword" ? gcd.assetPath + "core/lock-24px.webp" : gcd.assetPath + "core/lock_open-24px.webp" + height: Theme.badgeTextSize * gcd.themeScale + width: height + } + + onClicked: rowClicked(handle) } Opaque.Icon {// Edit BUTTON id: btnEdit - source: gcd.assetPath + "core/edit-24px.svg" - - backgroundColor: root.color + source: gcd.assetPath + "core/edit-24px.webp" + Layout.minimumWidth: 80 + Layout.fillHeight: true + backgroundColor: Theme.backgroundMainColor + hilightBackgroundColor: Theme.backgroundHilightElementColor iconColor: Theme.altTextColor - anchors.right: parent.right - - //rectUnread.left anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: 1 * gcd.themeScale - anchors.rightMargin: 20 * gcd.themeScale + // Layout.alignment: Qt.AlignVCenter - height: parent.height * 0.5 - width: parent.height * 0.5 - size: parent.height * 0.5 - onClicked: { - profileAddEditPane.load(handle, displayName, tag, image) - parentStack.pane = parentStack.addEditProfilePane - } + height: root.height / 2 + width: root.height / 2 + size: root.height / 2 - onHover: function (hover) { - root.isHover = hover - } - } - - onClicked: function openClick(handle) { - gcd.broadcast("ResetMessagePane"); - gcd.broadcast("ResetProfile"); - gcd.selectedProfile = handle - gcd.loadProfile(handle) - parentStack.pane = parentStack.profilePane + onClicked: editClicked(handle, displayName, tag, image) } } + diff --git a/qml/widgets/ServerList.qml b/qml/widgets/ServerList.qml index 777bda74..2fcb61a1 100644 --- a/qml/widgets/ServerList.qml +++ b/qml/widgets/ServerList.qml @@ -93,6 +93,14 @@ ColumnLayout { autostart: _autostart messages: _messages Layout.fillWidth: true + rowClicked: function(handle) { + + } + editClicked: function(handle, displayName, tag, image) { + gcd.checkServer(handle) + serverAddEditPane.load(handle, displayName, status, _autostart, _messages, _bundle) + parentStack.pane = parentStack.addEditServerPane + } } } @@ -101,13 +109,13 @@ ColumnLayout { handle: "" displayName: qsTr("add-new-profile-btn") nameColor: Theme.mainTextColor - image: "/fontawesome/regular/user.svg" + image: "core/fontawesome/regular/user.webp" tag: "" portraitBorderColor: Theme.portraitOnlineBorderColor portraitColor: Theme.portraitOnlineBackgroundColor badgeVisible: true badgeContent: Image { - source: gcd.assetPath + "/fontawesome/solid/plus.svg" + source: gcd.assetPath + "core/fontawesome/solid/plus.webp" height: Theme.badgeTextSize * gcd.themeScale width: height } diff --git a/qml/widgets/ServerRow.qml b/qml/widgets/ServerRow.qml index 0585a13b..a448c19d 100644 --- a/qml/widgets/ServerRow.qml +++ b/qml/widgets/ServerRow.qml @@ -11,55 +11,13 @@ import "../opaque" as Opaque import "../opaque/styles" import "../opaque/theme" -Opaque.PortraitRow { +ProfileRow { id: root - property int status; - property string bundle; - property bool autostart; - property int messages; - - portraitBorderColor: Theme.portraitOnlineBorderColor - portraitColor: Theme.portraitOnlineBackgroundColor - nameColor: Theme.portraitOnlineTextColor - onionColor: Theme.portraitOnlineTextColor + property int status + property string bundle + property bool autostart + property int messages badgeColor: status == 1 ? Theme.portraitOnlineBadgeColor : Theme.portraitOfflineBadgeColor - badgeVisible: true - - Opaque.Icon {// Edit BUTTON - id: btnEdit - source: gcd.assetPath + "core/edit-24px.svg" - - backgroundColor: root.color - iconColor: Theme.altTextColor - - anchors.right: parent.right - - //rectUnread.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: 1 * gcd.themeScale - anchors.rightMargin: 20 * gcd.themeScale - - height: parent.height * 0.5 - width: parent.height * 0.5 - size: parent.height * 0.5 - - onClicked: { - gcd.checkServer(handle) - serverAddEditPane.load(handle, displayName, status, autostart, messages, bundle) - parentStack.pane = parentStack.addEditServerPane - } - - onHover: function (hover) { - root.isHover = hover - gcd.checkServer(handle) - } - - } - - onClicked: function openClick(handle) { - - } - - + // TODO Badge Images } diff --git a/qml/widgets/Statusbar.qml b/qml/widgets/Statusbar.qml index 8e13bbf9..4a64bb8b 100644 --- a/qml/widgets/Statusbar.qml +++ b/qml/widgets/Statusbar.qml @@ -63,9 +63,9 @@ Rectangle { statusbar.color = Theme.statusbarDisconnectedInternetColor statusMessage.color = Theme.statusbarDisconnectedInternetFontColor networkStatus.iconColor = Theme.statusbarDisconnectedInternetFontColor - networkStatus.source = gcd.assetPath + "core/signal_cellular_off-24px.svg" + networkStatus.source = gcd.assetPath + "core/signal_cellular_off-24px.webp" connectionStatus.iconColor = Theme.statusbarDisconnectedInternetFontColor - connectionStatus.source = gcd.assetPath + "core/syncing-03.svg" + connectionStatus.source = gcd.assetPath + "core/syncing-03.webp" //: Disconnected from the internet, check your connection statusMessage.text = qsTr("network-status-disconnected") show() @@ -73,9 +73,9 @@ Rectangle { 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" + networkStatus.source = gcd.assetPath + "core/signal_cellular_connected_no_internet_4_bar-24px.webp" connectionStatus.iconColor = Theme.statusbarDisconnectedTorFontColor - connectionStatus.source = gcd.assetPath + "core/syncing-03.svg" + connectionStatus.source = gcd.assetPath + "core/syncing-03.webp" //: Attempting to connect to Tor network statusMessage.text = qsTr("network-status-attempting-tor") show() @@ -83,9 +83,9 @@ Rectangle { 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" + networkStatus.source = gcd.assetPath + "core/signal_cellular_connected_no_internet_4_bar-24px.webp" connectionStatus.iconColor = Theme.statusbarConnectingFontColor - connectionStatus.source = gcd.assetPath + "core/syncing-02.svg" + connectionStatus.source = gcd.assetPath + "core/syncing-02.webp" //: Connecting... statusMessage.text = qsTr("network-status-connecting") show() @@ -93,9 +93,9 @@ Rectangle { statusbar.color = Theme.statusbarOnlineColor statusMessage.color = Theme.statusbarOnlineFontColor networkStatus.iconColor = Theme.statusbarOnlineFontColor - networkStatus.source = gcd.assetPath + "core/signal_cellular_4_bar-24px.svg" + networkStatus.source = gcd.assetPath + "core/signal_cellular_4_bar-24px.webp" connectionStatus.iconColor = Theme.statusbarOnlineFontColor - connectionStatus.source = gcd.assetPath + "core/syncing-01.svg" + connectionStatus.source = gcd.assetPath + "core/syncing-01.webp" //: Online statusMessage.text = qsTr("network-status-online") hide()