Compare commits

...
Author SHA1 Message Date
Igor Sirotin 45d7d80755 fix(StatusPopupMenu): Removed custom properties 2022-08-10 15:02:14 +03:00
PavelS 7fc207f75f fix(StatusImageCropPanel) add margins to crop area (#848)
Needed for status-im/status-desktop#6835

Required by status-im/status-desktop#6872
2022-08-10 13:58:52 +03:00
MishkaRogachev caaa2fc53b fix(StatusCommunityTags): fix width calculation 2022-08-10 12:07:32 +03:00
PavelS 98aa6a4b27 fix(StatusTabButton) adjust tab button height (#842)
Needed by https://github.com/status-im/status-desktop/issues/6786
2022-08-09 18:27:15 +03:00
Lukáš Tinkl b3ceb0aad9 feat/(Status[Base]Button): add a new Primary variant
we were missing this variant, needed for status-im/status-desktop#6081
2022-08-09 10:53:27 +02:00
Lukáš Tinkl fa16c32316 chore(Palette): do not define font properties twice
sue a shared impl, they are common to both light/dark palettes
2022-08-09 10:53:27 +02:00
PavelS 4282cc10c4 fix(StatusImageCropPanel) adjust Image Crop component (#839)
- update StatusSlider handle and background positioning

Needed for https://github.com/status-im/status-desktop/issues/6835
2022-08-09 09:54:19 +03:00
Stefan e5ddf28f02 fix(tests): fix building tests 2022-08-09 01:07:17 +02:00
Stefan 4937681645 fix(StatusImageCrop): fix artefacts due to offscreen caching
Fix by disabling layering, leftover from the previous approach of not
using Canvas.

Also investigate TODO regarding artefacts workaround and implement
a proper approach

Fixes: #6640
2022-08-09 01:07:17 +02:00
Lukáš Tinkl 39b1bcfe6b hotfix(StatusDatePicker): fix some UI issues
- make selectedDate read/write for preselecting the date
- minor toolbar spacing/sizing fixes
2022-08-08 23:20:41 +02:00
Michał 56f36ed627 fix(StatusSeedPhraseInput): fix notifying inserting word done (#841) 2022-08-08 17:38:43 +02:00
Lukáš Tinkl 789b773649 feat(StatusDatePicker): introduce StatusDatePicker component
nothing fancy, just a combo box with a calendar popup; needed for the
discord import tool UI

Related to status-im/status-desktop#6081
2022-08-08 15:05:12 +02:00
MishkaRogachev ad962a6009 fix(StatusInput): Add labelPadding customization and improve height calculation 2022-08-08 15:58:31 +03:00
MishkaRogachev f09565a4fa fix(StatusBaseInput): placeholder text is also can be multiline 2022-08-08 14:20:20 +03:00
MishkaRogachev d08339a7b0 fix(StatusStackView): Use availableWidth for content 2022-08-08 14:20:20 +03:00
Michal Iskierko 5c24767310 feat(StatusColorRadioButton): expose radio button diameter property
Issue #5982
2022-08-08 10:29:12 +02:00
Jonathan Rainville 737b9cfb3f fix(StatusChatList): fix wrong id used 2022-08-05 15:57:24 -04:00
Stefan 10d312ec8f feature(StatusAddressPanel): Implement generic address display control
Provides frame, prefix icon and copy operation int addition to StatusAddress

Updates: #6798
2022-08-05 17:01:25 +02:00
PavelS 2a377533f8 fix(StatusImageCropPanel) vertically align slider in ImageCropPanel (#829)
- change StatusSlider to be vertically centered

Needed for https://github.com/status-im/status-desktop/issues/6725
2022-08-05 16:53:55 +03:00
Boris Melnik 25e3c5526a fix(handler): Remove handler include from sandbox (#834) 2022-08-05 12:21:34 +03:00
Michał 94e59e1bf0 chore(StatusChatList): Keep sync with underlying model after reordering (#825) 2022-08-04 21:52:56 +02:00
Alexandra Betouni 3ac0187923 fix(StatusBaseInput): added left margin between text and left component (#830)
Needed for https://github.com/status-im/status-desktop/issues/6730
2022-08-04 18:03:33 +03:00
Michał a563687bf5 chore(StatusChatList)!: Use SortFilterProxyModel instead of filtering functions (#823)
BREAKING CHANGE: StatusChatList has no longer filterFn, model is
intended to be already filtered externally
2022-08-04 14:52:12 +02:00
Boris Melnik 40992f6718 feat(hot reloading): Add first version of hot reloading (#674)
Version for: https://github.com/status-im/status-desktop/issues/5690
2022-08-04 13:54:13 +03:00
Anthony Laibe 9738890d9d feat(@StatusAppNavBar): Add qr scan button 2022-08-04 09:45:59 +02:00
Jonathan Rainville 9dc2b10448 test(StatusSmartIdenticon): add objectName for tests 2022-08-04 09:45:25 +02:00
Alexandra Betouni 9df658a574 feat(StatusQ/Controls): introducing StatusBackButton
Closes: https://github.com/status-im/status-desktop/issues/6727
2022-08-03 20:41:24 +02:00
Boris Melnik 4b4b0950a6 fix(StatusSearchPopup): Fix forceActiveFocus method (#818) 2022-08-03 18:15:50 +03:00
Alexandra Betouni 7b047a4b26 fix(StatusInput): setting default 44px in min/max height (#817) 2022-08-03 16:04:52 +03:00
Igor Sirotin cff836280f Reimplemented components using StatusComboBox (#815)
* fix(StatusAccountSelector): Refactored and reimplemented using `StatusComboBox`
* fix(StatusAssetSelector): Refactored and reimplemented using `StatusComboBox`
* fix(StatusColorSelector): Reimplemented using `StatusComboBox`
* fix(StatusCardPage): Replaced `StatusSelect` with `StatusComboBox`
2022-08-03 15:13:31 +03:00
Mikhail Rogachev e432efac28 fix(StatusCommunityTag): Polish text and icon sizings (#824) 2022-08-03 12:44:35 +03:00
Alexandra Betouni 4dec615cea fix(Utils): moved emojilists.js instance inside Emoji singleton (#816)
Needed for: https://github.com/status-im/status-desktop/issues/6729
2022-08-03 11:51:38 +03:00
Khushboo-dev-cpp f4bf830ae7 feat(StatusDialog): Add DIalog Background componentto make the dialog background customizable (#809) 2022-08-03 09:27:28 +02:00
Khushboo-dev-cpp dbc0c1960a chore: Remove StatusAssetSelector from StatusQ (#806)
* fix(StatusSelect): Expose a property to make arrow in the select item visible/invisible

* chore: Remove StatusAssetSelector from StatusQ as its base component StatusSelect is enough to build this further on desktop side.

This component also has dependecy on BE and hence should be moved out.

BREAKING CHANGE:
2022-08-03 09:22:36 +02:00
Anthony Laibe 03fe75c875 feat(@StatusFloatingButtonsSelector): expose repeater (#795) 2022-08-03 09:08:47 +02:00
Patryk Osmaczko 26eaeb3ad5 chore(StatusListPicker): enable picker to work with incompatible models 2022-08-02 17:03:51 +02:00
Jonathan Rainville 462b905c5c test(StatusListItem): add objectName 2022-08-02 10:03:07 -04:00
Lukáš Tinkl 4e048f724c fix(StatusSeedPhraseInput): Back up seed phrase inputs are missing spacing
Closes: #6720
2022-08-02 13:51:58 +02:00
Lukáš Tinkl e6be4d9bad feat(StatusTextArea): Implement StatusTextArea
Implements a standard QQC2 TextArea control with Status styling

Closes #236
2022-08-02 11:35:11 +02:00
Jonathan Rainville e184348190 feat(StatusInput): add force argument to validate to force validation 2022-08-01 10:06:56 -04:00
Igor Sirotin 2270526071 feat(StatusComboBox): Introduced new component to replace StatusSelect (#790) 2022-07-30 17:45:22 +03:00
Noelia d412fe208e test(StatusTagSelector): Added objectName property needed for automation 2022-07-28 13:51:32 +02:00
Noelia 0040a2d86b test(StatusChatList): Added objectName property needed for automation 2022-07-28 13:51:32 +02:00
Noelia 431aab7bb8 test(StatusChatInfoButton): Added objectName property needed for automation 2022-07-28 13:51:32 +02:00
Alexandra Betouni 938ae6afd8 fix(StatusInput): Replaced layout spacing with margins (#808)
As part of https://github.com/status-im/status-desktop/issues/6022
2022-07-28 11:35:46 +03:00
Khushboo-dev-cpp 63c008571e fix(StatusModal): Adapt the status modal to have a user defined background color (#807)
Add a new color for StatusFloatingButtonSelector
2022-07-27 18:29:44 +02:00
Jonathan Rainville 08c53e2f52 chore(StatusScrollView): remove unused background property
BREAKING CHANGE: removes the background property of the StatusScrollView
2022-07-27 10:26:00 -04:00
Alexandra Betouni 64ec74117d fix(StatusInputPage): updated input height leftovers (#804)
As part of https://github.com/status-im/status-desktop/issues/6637
2022-07-27 16:33:55 +03:00
Patryk Osmaczko e5ab0cd2a7 chore(utils): add iconSource API to Emoji 2022-07-27 13:54:23 +02:00
Patryk Osmaczko 5f1df089eb chore(StatusListPicker): remove imperative updateInputListModel
closes: status-im/status-desktop#6500
2022-07-27 13:54:23 +02:00
Patryk Osmaczko b30f7b3ac5 chore(StatusListPicker): remove imperative filtering
iterates: status-im/status-desktop#6511, status-im/status-desktop#6500
2022-07-27 13:54:23 +02:00
Sale Djenic ac37549f62 fix(StatusSearchPopup): reset search location
New `resetSearchLocationClicked` signal introduced.

Click on `X` button is emitting `resetSearchLocationClicked` signal and
lets a component which is using this one to decide what to do instead just
reseting search selection locally to this component.

Needed for https://github.com/status-im/status-desktop/issues/6551
2022-07-26 14:37:42 +02:00
Khushboo-dev-cpp a60c44e387 Revert "chore: Remove StatusAssetSelector from StatusQ (#792)" (#805)
This reverts commit 3954d49266.
2022-07-26 14:36:26 +02:00
Mikhail Rogachev 694010da38 feat(StatusListView): Add availableWidth/availableHeight to api (#801) 2022-07-26 12:30:31 +03:00
Lukáš Tinkl c0c240ed6a hotfix(@qrc): remove the StatusAssetSelector from qrc files too
fixes the build of StatusQ/sandbox
2022-07-26 10:05:45 +02:00
Lukáš Tinkl 39c1ba4e66 fix(StatusAppNavBar): fix profile icon bottom margin
it should be 24px from the bottom according to the design
2022-07-26 10:05:45 +02:00
Khushboo-dev-cpp 3954d49266 chore: Remove StatusAssetSelector from StatusQ (#792)
* chore: Remove StatusAssetSelector from StatusQ as its base component StatusSelect is enough to build this further on desktop side.

This component also has dependecy on BE and hence should be moved out.

BREAKING CHANGE:

* fix(StatusSelect): Expose a property to make arrow in the select item visible/invisible
2022-07-25 21:16:15 +02:00
87 changed files with 2230 additions and 1189 deletions
+1 -3
View File
@@ -174,9 +174,7 @@ Rectangle {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
+18
View File
@@ -17,6 +17,24 @@ Column {
horizontalItemAlignment: Grid.AlignHCenter
// Primary
StatusButton {
text: "Button"
type: StatusBaseButton.Type.Primary
}
StatusButton {
text: "Button"
enabled: false
type: StatusBaseButton.Type.Primary
}
StatusButton {
text: "Button"
loading: true
type: StatusBaseButton.Type.Primary
}
// Large
StatusButton {
text: "Button"
+4 -12
View File
@@ -223,9 +223,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
@@ -308,9 +306,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
@@ -398,9 +394,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
@@ -493,9 +487,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
+4 -1
View File
@@ -57,5 +57,8 @@ ColumnLayout {
}
}
}
}
StatusDatePicker {
label: "Select date"
}
}
+3 -12
View File
@@ -119,10 +119,7 @@ Column {
header.subTitle: "Subtitle"
header.image.source: "qrc:/demoapp/data/profile-image-1.jpeg"
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
StatusBackButton { }
]
rightButtons: [
StatusButton {
@@ -152,10 +149,7 @@ Column {
}
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
StatusBackButton { }
]
rightButtons: [
StatusButton {
@@ -183,10 +177,7 @@ Column {
]
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
StatusBackButton { }
]
contentItem: StatusBaseText {
+1 -2
View File
@@ -103,8 +103,7 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
statusListItemTitle.font.pixelSize: 17
title: "Leave community"
icon.name: "arrow-right"
icon.rotation: 180
icon.name: "arrow-left"
type: StatusListItem.Type.Secondary
}
}
+1 -3
View File
@@ -199,9 +199,7 @@ StatusAppThreePanelLayout {
StatusMenuItem {
text: "Leave Chat"
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
-6
View File
@@ -1,6 +0,0 @@
#include "handler.h"
Handler::Handler(QObject *parent) : QObject(parent)
{
}
-16
View File
@@ -1,16 +0,0 @@
#ifndef HANDLER_H
#define HANDLER_H
#include <QObject>
class Handler : public QObject
{
Q_OBJECT
public:
explicit Handler(QObject *parent = nullptr);
signals:
void restartQml();
};
#endif // HANDLER_H
+7 -2
View File
@@ -197,18 +197,23 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusTextArea"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusSelect"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusAccountSelector"
title: "StatusComboBox"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusAssetSelector"
title: "StatusAccountSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
+51 -47
View File
@@ -8,57 +8,61 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
Column {
spacing: 8
StatusAccountSelector {
id: accountSelector
accounts: ListModel {
ListElement {
name: "Pascal"
address: "0x1234567891011"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "1199.02"
assets: []
}
ListElement {
name: "Boris"
address: "0x123"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
ListElement {
name: "Alexandra"
address: "0x123"
path: ""
color: "yellow"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
ListElement {
name: "Khushboo"
address: "0x123"
path: ""
color: "blue"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
id: selector1
width: 300
accounts: accountsModel
}
ListModel {
id: accountsModel
ListElement {
name: "Pascal"
address: "0x1234567891011"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "1199.02"
assets: []
}
ListElement {
name: "Boris"
address: "0x123"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "42.42"
assets: []
}
ListElement {
name: "Alexandra"
address: "0x123"
path: ""
color: "yellow"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
ListElement {
name: "Khushboo"
address: "0x123"
path: ""
color: "blue"
publicKey: ""
walletType: "watch" // Will be automatically filtered by StatusAccountSelector
isChat: ""
currencyBalance: "0"
assets: []
}
}
}
+82 -9
View File
@@ -2,24 +2,97 @@ import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import Sandbox 0.1
Column {
spacing: 8
Item {
id: root
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
}
implicitWidth: mainLayout.implicitWidth
implicitHeight: mainLayout.implicitHeight
Item {
width: 200
height: childrenRect.height
GridLayout {
id: mainLayout
columns: 2
anchors.fill: parent
columnSpacing: 15
rowSpacing: 8
StatusBaseText { text: "StatusAddress\nsimple" }
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
}
StatusBaseText { text: "StatusAddress\nclick-expandable" }
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
Layout.preferredWidth: 200
expandable: true
width: parent.width
}
StatusBaseText { text: `StatusAddressPanel\nfont.pixelSize: 13, copyable, no frame`}
StatusAddressPanel {
address: "0xDC2c4826f6C56F61C1b9cC6Bb531d0Fe45402fC9"
font.pixelSize: 13
font.weight: Font.Normal
showFrame: false
onDoCopy: copyAction.text = address
}
StatusBaseText { text: `StatusAddressPanel\ncompact; width ${simpleAddressPanel.width}px ${simpleAddressPanel.height}px`}
StatusAddressPanel {
id: simpleAddressPanel
address: "0xd8593DEACe2f44dF35dd23fD2BAFC2daeC2ae033"
showCopy: false
expanded: false
onDoCopy: copyAction.text = address
expandable: true
}
StatusBaseText { text: "StatusAddressPanel\ncopy-icon, non-expandable" }
StatusAddressPanel {
address: "0xDd5A0755e99D66a583253372B569231968A6CF7b"
onDoCopy: copyAction.text = address
}
StatusBaseText { text: "StatusAddressPanel\ncopy hiden" }
StatusAddressPanel {
address: "0xd2D44C2A1E78975506e474Ecdc7E4F272D7e9A6c"
autHideCopyIcon: true
onDoCopy: copyAction.text = address
expandable: true
}
StatusBaseText { text: "StatusAddressPanel\ncopy hiden, non-expandable" }
StatusAddressPanel {
address: "0xd2a44BA31E78975506e474Ecdc7E4F272D7F3BC5"
autHideCopyIcon: true
expanded: false
onDoCopy: copyAction.text = address
}
Rectangle {
color: "lightblue"
Layout.fillWidth: true
Layout.columnSpan: mainLayout.columns
Layout.preferredHeight: 2
}
StatusBaseText {
text: qsTr("Copy Action: ")
}
StatusBaseText {
id: copyAction
}
}
}
-50
View File
@@ -1,50 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import Sandbox 0.1
Column {
spacing: 8
StatusAssetSelector {
getCurrencyBalanceString: function (currencyBalance) {
return currencyBalance.toFixed(2) + " USD"
}
tokenAssetSourceFn: function (symbol) {
return "../../assets/img/icons/snt.svg"
}
assets: ListModel {
ListElement {
address: "0x1234"
name: "Status Network Token"
balance: "20"
symbol: "SNT"
totalCurrencyBalance: 9992.01
totalBalance: 9992.01
}
ListElement {
address: "0x1234"
name: "DAI Token"
balance: "15"
symbol: "DAI"
totalCurrencyBalance: 20.00001
totalBalance: 20.00001
}
ListElement {
address: "0x1234"
name: "ABYSS Token"
balance: "25"
symbol: "ABYSS"
totalCurrencyBalance: 24.1
totalBalance: 24.1
}
}
}
}
+20 -34
View File
@@ -19,9 +19,24 @@ Item {
spacing: 20
RowLayout {
StatusSelect {
id: select
label: "Select Card State"
Layout.fillWidth: true
StatusCard {
id: card
Layout.alignment: Qt.AlignVCenter
primaryText: "Mainnet"
secondaryText: state === "unavailable" ? "No Gas" : "75"
tertiaryText: state === "unpreferred" ? "UNPREFERRED" : "BALANCE: " + 250
cardIconName: "status"
advancedInputText: "75"
disabledText: "Disabled"
}
StatusComboBox {
Layout.alignment: Qt.AlignVCenter
Layout.maximumWidth: 200
label: "Card State"
onCurrentValueChanged: card.state = currentValue
model: ListModel {
ListElement {
name: "default"
@@ -36,47 +51,18 @@ Item {
name: "unpreferred"
}
}
selectMenu.delegate: StatusMenuItemDelegate {
statusPopupMenu: select
action: StatusMenuItem {
text: name
onTriggered: {
selectedItem.text = name
card.state = name
}
}
}
selectedItemComponent: Item {
id: selectedItem
anchors.fill: parent
property string text: "default"
StatusBaseText {
text: selectedItem.text
anchors.centerIn: parent
color: Theme.palette.directColor1
}
}
}
StatusCheckBox {
Layout.alignment: Qt.AlignVCenter
text: "advancedMode"
font.family: Theme.palette.monoFont.name
onClicked: {
card.advancedMode = checked
}
}
}
StatusCard {
id: card
primaryText: "Mainnet"
secondaryText: state === "unavailable" ? "No Gas" : "75"
tertiaryText: state === "unpreferred" ? "UNPREFERRED" : "BALANCE: " + 250
cardIconName: "status"
advancedInputText: "75"
disabledText: "Disabled"
}
Rectangle {
height: 1
width: 700
+1 -1
View File
@@ -8,7 +8,7 @@ import StatusQ.Controls 0.1
import Sandbox 0.1
Column {
Row {
spacing: 8
StatusColorSelector {
+72
View File
@@ -0,0 +1,72 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import Sandbox 0.1
Column {
spacing: 20
ListModel {
id: commmonModel
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
StatusComboBox {
id: combobox
label: "ComboBox"
model: commmonModel
}
StatusComboBox {
id: comboBox1
label: "ComboBox with custom delegate"
model: commmonModel
delegate: StatusItemDelegate {
width: comboBox1.control.width
highlighted: comboBox1.control.highlightedIndex === index
text: modelData
font: comboBox1.control.font
icon {
name: "filled-account"
color: Theme.palette.primaryColor1
}
enabled: index != 2
}
}
StatusComboBox {
model: commmonModel
label: "Disabled ComboBox"
enabled: false
}
StatusComboBox {
model: commmonModel
label: "ComboBox with validation error"
validationError: "Validation failed example"
}
StatusComboBox {
model: commmonModel
label: "Mirrored ComboBox"
LayoutMirroring.enabled: true
}
}
+188 -23
View File
@@ -1,11 +1,20 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQuick.Dialogs 1.3
import QtQml 2.14
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import QtGraphicalEffects 1.14
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
Item {
id: root
@@ -15,6 +24,12 @@ Item {
property var testControls: [ctrl1, ctrl2, ctrl3]
property bool globalStylePreferRound: true
property var testImageList: ["qrc:/demoapp/data/logo-test-image.png",
"qrc:/demoapp/data/profile-image-2.jpeg",
"qrc:/demoapp/data/profile-image-1.jpeg"]
property int testImageIndex: 0
property int testSpacing: 0
property int testFrameMargins: 10
ColumnLayout {
id: mainLayout
@@ -22,7 +37,12 @@ Item {
anchors.fill: parent
RowLayout {
spacing: root.testSpacing
ColumnLayout {
spacing: root.testSpacing
Layout.margins: root.testSpacing
Text {
text: `AR: ${ctrl1.aspectRatio.toFixed(2)}`
}
@@ -32,8 +52,9 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
source: "qrc:/demoapp/data/logo-test-image.png"
source: root.testImageList[root.testImageIndex]
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
margins: root.testFrameMargins
}
Text {
text: `AR: ${ctrl2.aspectRatio.toFixed(2)}`
@@ -43,13 +64,15 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
source: "qrc:/demoapp/data/logo-test-image.png"
source: root.testImageList[root.testImageIndex]
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rectangular : StatusImageCrop.WindowStyle.Rounded
aspectRatio: 16/9
enableCheckers: true
margins: root.testFrameMargins + 2
}
}
ColumnLayout {
Layout.margins: root.testSpacing
Text {
text: `AR: ${ctrl3.aspectRatio.toFixed(2)}`
}
@@ -59,36 +82,178 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
source: "qrc:/demoapp/data/logo-test-image.png"
source: root.testImageList[root.testImageIndex]
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
aspectRatio: 0.8
margins: root.testFrameMargins + 5.3
}
}
}
Shortcut {
sequence: StandardKey.ZoomIn
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, -0.05))
RowLayout {
StatusButton {
text: qsTr("Cycle image")
onClicked: {
let newIndex = root.testImageIndex
newIndex++
if(newIndex >= root.testImageList.length)
newIndex = 0
root.testImageIndex = newIndex
}
}
}
Shortcut {
sequence: StandardKey.ZoomOut
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, 0.05))
StatusButton {
text: qsTr("Cycle spacing")
onClicked: {
root.testSpacing += (root.testSpacing/2) + 1
if(root.testSpacing > 35)
root.testSpacing = 0
}
}
}
Shortcut {
sequences: ["Ctrl+W"]
onActivated: globalStylePreferRound = !globalStylePreferRound
StatusButton {
text: qsTr("Cycle frame margins")
onClicked: {
root.testFrameMargins += (root.testFrameMargins/2) + 1
if(root.testFrameMargins > 50)
root.testFrameMargins = 0
}
}
StatusButton {
text: qsTr("Load external image")
onClicked: workflowLoader.active = true
}
}
}
Loader {
id: workflowLoader
sourceComponent: workflowComponent
active: false
onStatusChanged: {
if(status === Loader.Ready) {
item.imageFileDialogTitle = qsTr("Test Title")
item.title = "Test popup"
item.acceptButtonText = "Load Custom Image"
item.chooseImageToCrop()
}
}
Connections {
target: workflowLoader.item
function onImageCropped(image, cropRect) {
ctrl1.source = image
ctrl2.source = image
ctrl3.source = image
}
function onCanceled() {
workflowLoader.active = false
}
}
}
Component {
id: workflowComponent
Item {
id: workflowItem
property alias aspectRatio: imageCropper.aspectRatio
property alias windowStyle: imageCropper.windowStyle
/*required*/ property string imageFileDialogTitle: ""
/*required*/ property string title: ""
/*required*/ property string acceptButtonText: ""
property bool roundedImage: true
signal imageCropped(var image, var cropRect)
signal canceled()
function chooseImageToCrop() {
fileDialog.open()
}
FileDialog {
id: fileDialog
title: workflowItem.imageFileDialogTitle
folder: workflowItem.userSelectedImage ? imageCropper.source.substr(0, imageCropper.source.lastIndexOf("/")) : shortcuts.pictures
nameFilters: [qsTr("Supported image formats (%1)").arg("*.jpg *.jpeg *.jfif *.webp *.png *.heif")]
onAccepted: {
if (fileDialog.fileUrls.length > 0) {
imageCropper.source = fileDialog.fileUrls[0]
imageCropperModal.open()
}
}
onRejected: workflowItem.canceled()
} // FileDialog
StatusModal {
id: imageCropperModal
header.title: workflowItem.title
anchors.centerIn: Overlay.overlay
width: workflowItem.roundedImage ? 480 : 580
onClosed: workflowItem.canceled()
StatusImageCropPanel {
id: imageCropper
implicitHeight: workflowItem.roundedImage ? 350 : 370
anchors {
fill: parent
leftMargin: 10 * 2
rightMargin: 10 * 2
topMargin: 15
bottomMargin: 15
}
margins: workflowItem.roundedImage ? 10 : 20
windowStyle: workflowItem.roundedImage ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
enableCheckers: true
}
rightButtons: [
StatusButton {
text: workflowItem.acceptButtonText
enabled: imageCropper.sourceSize.width > 0 && imageCropper.sourceSize.height > 0
onClicked: {
workflowItem.imageCropped(imageCropper.source, imageCropper.cropRect)
imageCropperModal.close()
}
}
]
} // StatusModal
} // Item
}
Shortcut {
sequence: StandardKey.ZoomIn
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, -0.05))
}
}
}
Shortcut {
sequence: StandardKey.ZoomOut
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, 0.05))
}
}
}
Shortcut {
sequences: ["Ctrl+W"]
onActivated: globalStylePreferRound = !globalStylePreferRound
}
}
+20 -3
View File
@@ -69,19 +69,34 @@ Column {
textEdit.input.anchors.leftMargin: 16
textEdit.input.anchors.rightMargin: 16
textEdit.input.anchors.topMargin: 11
textEdit.label: "Input with drop down selection list"
textEdit.label: "Input with drop down selection list" + (insertedWord ? ` (${insertedWord})` : "")
leftComponentText: "1"
inputList: ListModel {
ListElement {
seedWord: "add"
}
ListElement {
seedWord: "address"
}
ListElement {
seedWord: "panda"
}
ListElement {
seedWord: "posible"
}
ListElement {
seedWord: "win"
}
ListElement {
seedWord: "wine"
}
ListElement {
seedWord: "wing"
}
}
property string insertedWord: ""
onDoneInsertingWord: insertedWord = word
}
}
@@ -107,7 +122,8 @@ Column {
label: "Label"
secondaryLabel: "secondary label"
placeholderText: "Placeholder"
input.implicitHeight: 56
minimumHeight: 56
maximumHeight: 56
}
StatusInput {
@@ -162,7 +178,8 @@ Column {
StatusInput {
input.multiline: true
placeholderText: "Multiline with static height"
input.implicitHeight: 100
minimumHeight: 100
maximumHeight: 100
}
StatusInput {
+2 -1
View File
@@ -34,6 +34,7 @@ GridLayout {
inputList: Models.languageNoImagePickerModel
placeholderSearchText: qsTr("Search Languages")
menuAlignment: StatusListPicker.MenuAlignment.Center
multiSelection: true
}
StatusListPicker {
@@ -60,7 +61,7 @@ GridLayout {
width: 500
text: "4 different configurations for the `StatusListPicker` component:\n
* Single selection. \n
* Single selection but dynamically changed to multiple selection (model provides multiple selected items).\n
* Multiple selection without images.\n
* Multiple selection.\n
* Multiple selection and displayed name is the symbol + shortName\n"
color: Theme.palette.baseColor1
+27 -13
View File
@@ -22,8 +22,8 @@ GridLayout {
onClicked: complexMenu.popup()
}
StatusButton {
id: customPopupButton
text: "Menu with custom images and icons"
onClicked: customMenu.popup()
}
@@ -51,7 +51,7 @@ GridLayout {
StatusPopupMenu {
id: complexMenu
subMenuItemIcons: [{ icon: 'info' }]
// subMenuItemIcons: [{ icon: 'info' }]
StatusMenuItem {
text: "One"
@@ -68,10 +68,13 @@ GridLayout {
StatusMenuItem {
text: "Three"
iconSettings.name: "info"
enabled: false
}
StatusPopupMenu {
title: "Four"
iconSettings.name: "info"
StatusMenuItem {
text: "One"
iconSettings.name: "info"
@@ -85,17 +88,24 @@ GridLayout {
StatusPopupMenu {
id: customMenu
width: customPopupButton.width
subMenuItemIcons: [
{ icon: "chat" },
{
source: "qrc:/demoapp/data/profile-image-1.jpeg"
},
{
isLetterIdenticon: true,
color: "red"
}
]
// subMenuItemIcons: [
// {
// icon: "chat"
// },
// {
// source: "qrc:/demoapp/data/profile-image-1.jpeg"
// },
// {
// isLetterIdenticon: true,
// color: "red"
// }
// ]
MenuItem {
text: "Default MenuItem, action: " + action
}
StatusMenuItem {
text: "Anywhere"
@@ -104,7 +114,8 @@ GridLayout {
StatusMenuSeparator {}
StatusPopupMenu {
title: "Chat"
title: "Chat"
iconSettings.name: "chat"
StatusMenuItem {
text: "vitalik.eth"
@@ -121,6 +132,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusPopupMenu {
title: "Cryptokitties"
imageSettings.source: "qrc:/demoapp/data/profile-image-1.jpeg"
StatusMenuItem {
text: "welcome"
@@ -144,6 +156,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusPopupMenu {
title: "Another community"
iconSettings.isLetterIdenticon: true
iconSettings.color: "red"
StatusMenuItem {
text: "welcome"
+28 -16
View File
@@ -8,28 +8,39 @@ import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import Sandbox 0.1
Column {
spacing: 8
spacing: 20
ListModel {
id: commmonModel
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
StatusBaseText {
font.pixelSize: 16
color: Theme.palette.dangerColor1
text: "This component should no longer be used.<br />Please, use `StatusComboBox` instead."
textFormat: Text.MarkdownText
}
StatusSelect {
id: select
label: "Some label"
model: ListModel {
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
model: commmonModel
selectMenu.delegate: StatusMenuItemDelegate {
statusPopupMenu: select
action: StatusMenuItem {
iconSettings.name: "filled-account"
text: name
@@ -38,6 +49,7 @@ Column {
}
}
}
selectedItemComponent: Item {
id: selectedItem
anchors.fill: parent
+61
View File
@@ -0,0 +1,61 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Column {
id: root
spacing: 8
Component.onCompleted: {
focusedTextArea.forceActiveFocus()
}
StatusTextArea {
id: focusedTextArea
width: parent.width
placeholderText: "Initially focused text area"
KeyNavigation.tab: unfocusedTextArea
}
StatusTextArea {
id: unfocusedTextArea
width: parent.width
placeholderText: "Unfocused text area (hover me to see the color change)"
KeyNavigation.tab: invalidTextArea
}
StatusTextArea {
id: invalidTextArea
width: parent.width
valid: false
placeholderText: "Invalid text area, should display red border"
KeyNavigation.tab: longTextArea
}
StatusScrollView {
padding: 0 // use our own (StatusTextArea) padding
width: parent.width
height: 120
TextArea.flickable: longTextArea
StatusTextArea {
id: longTextArea
text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer imperdiet lectus quis justo. Sed vel lectus. \
Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Morbi scelerisque luctus velit. Nunc auctor. Nullam at \
arcu a est sollicitudin euismod. Cras elementum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, \
per inceptos hymenaeos. Fusce aliquam vestibulum ipsum. Etiam sapien elit, consequat eget, tristique non, venenatis quis, ante. \
Nullam sit amet magna in magna gravida vehicula. Cras pede libero, dapibus nec, pretium sit amet, tempor quis. Nullam faucibus \
mi quis velit. Nam sed tellus id magna elementum tincidunt. Duis bibendum, lectus ut viverra rhoncus, dolor nunc faucibus libero, \
eget facilisis enim ipsum id lacus. Maecenas aliquet accumsan leo. Aliquam erat volutpat."
KeyNavigation.tab: focusedTextArea
}
}
StatusTextArea {
enabled: false
placeholderText: "Disabled text area"
}
}
+2 -1
View File
@@ -44,7 +44,6 @@
<file>images/SuperRareCommunityBanner.png</file>
<file>pages/StatusAccountSelectorPage.qml</file>
<file>pages/StatusAddressPage.qml</file>
<file>pages/StatusAssetSelectorPage.qml</file>
<file>pages/StatusCardPage.qml</file>
<file>pages/StatusChatCommandButtonPage.qml</file>
<file>pages/StatusChatInfoToolBarPage.qml</file>
@@ -80,5 +79,7 @@
<file>images/SRToken.png</file>
<file>demoapp/data/profile-image-1.jpeg</file>
<file>demoapp/data/profile-image-2.jpeg</file>
<file>pages/StatusItemSelectorPage.qml</file>
<file>pages/StatusComboBoxPage.qml</file>
</qresource>
</RCC>
+17 -7
View File
@@ -3,15 +3,20 @@
#include <QQmlContext>
#include <QWindow>
#include <QDebug>
#include <QDirIterator>
#include "statuswindow.h"
#include "spellchecker.h"
SandboxApp::SandboxApp(int &argc, char **argv)
: QGuiApplication(argc, argv),
m_handler(new Handler(this))
: QGuiApplication(argc, argv)
{
connect(m_handler, &Handler::restartQml, this, &SandboxApp::restartEngine, Qt::QueuedConnection);
#ifdef QT_DEBUG
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, [this](const QString&) {
restartEngine();
});
#endif
}
void SandboxApp::startEngine()
@@ -21,13 +26,18 @@ void SandboxApp::startEngine()
#ifdef QT_DEBUG
const QUrl url = QUrl::fromLocalFile(SRC_DIR + QStringLiteral("/main.qml"));
m_watcher.addPath(applicationDirPath() + "/../");
QDirIterator it(applicationDirPath() + "/../", QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
while (it.hasNext()) {
if (!it.filePath().isEmpty()) {
m_watcher.addPath(it.filePath());
}
it.next();
}
#else
const QUrl url(QStringLiteral("qrc:/main.qml"));
#endif
m_engine.rootContext()->setContextProperty("app", m_handler);
#ifdef QT_DEBUG
m_engine.addImportPath(SRC_DIR + QStringLiteral("/../src"));
#else
@@ -44,7 +54,7 @@ void SandboxApp::startEngine()
void SandboxApp::restartEngine()
{
const QUrl url(applicationDirPath() + "/../main.qml");
const QUrl url = QUrl::fromLocalFile(SRC_DIR + QStringLiteral("/main.qml"));
QWindow *rootWindow = qobject_cast<QWindow*>(m_engine.rootObjects().at(0));
if (rootWindow) {
rootWindow->close();
+7 -2
View File
@@ -4,7 +4,9 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "handler.h"
#ifdef QT_DEBUG
#include <QFileSystemWatcher>
#endif
class SandboxApp : public QGuiApplication
{
@@ -18,7 +20,10 @@ public slots:
private:
QQmlApplicationEngine m_engine;
Handler *m_handler;
#ifdef QT_DEBUG
QFileSystemWatcher m_watcher;
#endif
};
#endif // SANDBOXAPP_H
+3 -3
View File
@@ -4,6 +4,7 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
/// Forces size, hard to reuse it
StatusBaseText {
id: root
@@ -18,7 +19,6 @@ StatusBaseText {
color: Theme.palette.baseColor1
Component.onCompleted: {
maxWidth = width
expanded = actualWidth <= maxWidth
}
@@ -29,9 +29,9 @@ StatusBaseText {
onClicked: {
if (root.expanded) {
width = root.width = root.maxWidth
root.width = root.maxWidth
} else {
width = root.width = root.actualWidth
root.width = root.actualWidth
}
root.expanded = !root.expanded
}
@@ -0,0 +1,189 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
/*!
\qmltype StatusAddressPanel
\inherits Item
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief Show an address as defined efined in design https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?node-id=4222%3A178403 and https://www.figma.com/file/h2Ab3k4wy1Y7SFHEvbcZZx/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop-(Copy)?node-id=1009%3A106451
Panel's components:
- Address: displays the rquired \c address property
- Frame: a rounded frame and the \c 0x icon prefix
- Copy action: clickable copy icon. Activable using \c showCopy
\qmlproperty string address address to show
\qmlproperty bool showCopy if \c true shows the copy action which triggers \c doCopy signal
\qmlproperty bool autHideCopyIcon if \c true shows the copy action when hovered. \see showCopy
\qmlproperty alias showFrame if \c true displays frame and \c 0x prefix
\qmlproperty bool expandable if \c true user can toggle between expanded and compact version; \see expanded
\qmlproperty bool expanded if \c true show address in full; if \c false show the address in compact mode eliding in the middle
\qmlproperty font: statusAddress.font
signal doCopy(string address)
\see StatusImageCrop for more details
Usage example:
\qml
StatusAddressPanel {
address: currentAccount.mixedcaseAddress
autHideCopyIcon: true
expanded: false
onDoCopy: (address) => root.store.copyToClipboard(address)
}
\endqml
For a list of components available see StatusQ.
*/
Item {
id: root
/*required*/ property string address: ""
property bool showCopy: true
property bool autHideCopyIcon: false
property alias showFrame: frameRect.visible
property bool expandable: false
property bool expanded: true
property alias font: statusAddress.font
signal doCopy(string address)
implicitWidth: frameLayout.implicitWidth
implicitHeight: frameLayout.implicitHeight
RowLayout {
id: frameLayout
anchors.fill: parent
RowLayout {
Layout.leftMargin: frameRect.visible ? 8 : undefined // Theme.geometry.halfPadding
Layout.rightMargin: Layout.leftMargin
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.minimumWidth: 120
Layout.preferredHeight: 32
spacing: 6
StatusIcon {
icon: "address"
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 19
Layout.preferredHeight: 19
visible: frameRect.visible
color: Theme.palette.baseColor1
opacity: 0.5
}
// Ensure the eliding is done in the middle of the value not taking into account `0x`
RowLayout {
spacing: 0
Layout.alignment: Qt.AlignVCenter
StatusBaseText {
text: "0x"
Layout.alignment: Qt.AlignVCenter
font: statusAddress.font
color: statusAddress.color
}
StatusBaseText {
id: statusAddress
text: root.address.replace("0x", "").replace("0X", "")
Layout.preferredWidth: expanded ? implicitWidth : (implicitWidth * 0.25).toFixed()
Layout.alignment: Qt.AlignVCenter
font.family: Theme.palette.monoFont.name
font.pixelSize: 15
font.weight: Font.Medium
elide: Text.ElideMiddle
color: Theme.palette.baseColor1
}
}
StatusIcon {
icon: "copy"
visible: root.autHideCopyIcon ? (mainMouseArea.containsMouse || copyMouseArea.containsMouse )
: root.showCopy
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: (statusAddress.font.pixelSize * 1.2).toFixed()
Layout.preferredHeight: Layout.preferredWidth
color: Theme.palette.baseColor1
MouseArea {
id: copyMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.ArrowCursor
preventStealing: true
onClicked: root.doCopy(root.address)
z: frameRect.z + 1
}
StatusIcon {
icon: parent.icon
x: 1
y: 1
width: parent.width
height: parent.height
visible: copyMouseArea.containsMouse && !copyMouseArea.pressed
color: "black"
opacity: 0.4
z: parent.z + 1
}
}
}
}
Rectangle {
id: frameRect
anchors.fill: frameLayout
color: "transparent"
border.width: 1
border.color: Theme.palette.baseColor2
radius: 36
}
MouseArea {
id: mainMouseArea
anchors.fill: parent
hoverEnabled: root.expandable || root.autHideCopyIcon
enabled: (root.autHideCopyIcon && root.showCopy) || root.expandable
acceptedButtons: root.expandable ? Qt.LeftButton : Qt.NoButton
cursorShape: root.expandable ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: root.expanded = !root.expanded
z: frameLayout.z - 1
}
}
+52 -23
View File
@@ -9,7 +9,7 @@ import StatusQ.Components 0.1
import StatusQ.Controls 0.1
Column {
id: statusChatList
id: root
spacing: 4
width: 288
@@ -23,8 +23,6 @@ Column {
property Component popupMenu
property var filterFn
signal chatItemSelected(string categoryId, string id)
signal chatItemUnmuted(string id)
signal chatItemReordered(string id, int from, int to)
@@ -35,22 +33,36 @@ Column {
}
}
onDraggableItemsChanged: delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
QtObject {
id: d
property int destinationPosition: -1
}
DelegateModel {
id: delegateModel
model: statusChatList.model
model: root.model
items.includeByDefault: !root.draggableItems
groups: DelegateModelGroup {
id: unsortedItems
name: "unsorted"
includeByDefault: root.draggableItems
onChanged: Utils.delegateModelSort(unsortedItems, delegateModel.items,
(a, b) => a.position < b.position)
}
delegate: Item {
id: draggable
width: statusChatList.width
objectName: model.name
width: root.width
height: statusChatListItem.height
property alias chatListItem: statusChatListItem
visible: {
if (!!statusChatList.filterFn) {
return statusChatList.filterFn(model)
}
return true
}
MouseArea {
id: dragSensor
@@ -58,7 +70,7 @@ Column {
cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
hoverEnabled: true
pressAndHoldInterval: 150
enabled: statusChatList.draggableItems
enabled: root.draggableItems
property bool active: false
property real startY: 0
@@ -74,8 +86,8 @@ Column {
}
onPressAndHold: active = true
onReleased: {
if (active) {
statusChatList.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, statusChatListItem.originalOrder)
if (active && d.destinationPosition !== -1 && statusChatListItem.originalOrder !== d.destinationPosition) {
root.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, d.destinationPosition)
}
active = false
}
@@ -89,6 +101,7 @@ Column {
active = true
}
}
onActiveChanged: d.destinationPosition = -1
StatusChatListItem {
id: statusChatListItem
@@ -104,7 +117,7 @@ Column {
hasUnreadMessages: model.hasUnreadMessages
notificationsCount: model.notificationsCount
highlightWhenCreated: !!model.highlight
selected: (model.active && statusChatList.highlightItem)
selected: (model.active && root.highlightItem)
icon.emoji: model.emoji
icon.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
@@ -113,10 +126,26 @@ Column {
ringSettings.ringSpecModel: model.colorHash
sensor.cursorShape: dragSensor.cursorShape
Connections {
target: statusChatListItem
enabled: root.draggableItems
function onOriginalOrderChanged() {
Qt.callLater(() => {
if (!delegateModel)
return
delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
})
}
}
onClicked: {
highlightWhenCreated = false
if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
if (mouse.button === Qt.RightButton && !!root.popupMenu) {
statusChatListItem.highlighted = true
let originalOpenHandler = popupMenuSlot.item.openHandler
@@ -137,17 +166,17 @@ Column {
}
}
let p = statusChatListItem.mapToItem(statusChatList, mouse.x, mouse.y)
let p = statusChatListItem.mapToItem(root, mouse.x, mouse.y)
popupMenuSlot.item.popup(p.x + 4, p.y + 6)
popupMenuSlot.item.openHandler = originalOpenHandler
return
}
if (!statusChatListItem.selected) {
statusChatList.chatItemSelected(model.parentItemId, model.itemId)
root.chatItemSelected(model.parentItemId, model.itemId)
}
}
onUnmute: statusChatList.chatItemUnmuted(model.itemId)
onUnmute: root.chatItemUnmuted(model.itemId)
}
}
@@ -158,7 +187,6 @@ Column {
keys: ["chat-item-category-" + statusChatListItem.categoryId]
onEntered: reorderDelay.start()
onDropped: statusChatList.chatItemReordered(statusChatListItem.chatId, drag.source.originalOrder, statusChatListItem.DelegateModel.itemsIndex)
Timer {
id: reorderDelay
@@ -166,7 +194,7 @@ Column {
repeat: false
onTriggered: {
if (dropArea.containsDrag) {
dropArea.drag.source.chatListItem.originalOrder = statusChatListItem.originalOrder
d.destinationPosition = delegateModel.model.get(draggable.DelegateModel.itemsIndex).position
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
}
}
@@ -210,11 +238,12 @@ Column {
Repeater {
id: statusChatListItems
objectName: "chatListItems"
model: delegateModel
}
Loader {
id: popupMenuSlot
active: !!statusChatList.popupMenu
active: !!root.popupMenu
}
}
@@ -7,8 +7,10 @@ import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Core 0.1
import SortFilterProxyModel 0.2
Item {
id: statusChatListAndCategories
id: root
implicitHeight: chatListsAndCategories.height
implicitWidth: chatListsAndCategories.width
@@ -51,11 +53,11 @@ Item {
MouseArea {
id: sensor
anchors.top: parent.top
width: statusChatListAndCategories.width
height: statusChatListAndCategories.height
width: root.width
height: root.height
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton && showPopupMenu && !!statusChatListAndCategories.popupMenu) {
if (mouse.button === Qt.RightButton && showPopupMenu && !!root.popupMenu) {
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6)
return
}
@@ -71,20 +73,44 @@ Item {
StatusChatList {
id: statusChatList
visible: statusChatList.model.count > 0
onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
onChatItemReordered: statusChatListAndCategories.chatItemReordered(categoryId, id, from, to)
draggableItems: statusChatListAndCategories.draggableItems
model: statusChatListAndCategories.model
filterFn: function (model) {
return !model.isCategory
onChatItemSelected: root.chatItemSelected(categoryId, id)
onChatItemUnmuted: root.chatItemUnmuted(id)
onChatItemReordered: root.chatItemReordered(categoryId, id, from, to)
draggableItems: root.draggableItems
model: SortFilterProxyModel {
sourceModel: root.model
filters: ValueFilter { roleName: "isCategory"; value: false }
sorters: RoleSorter { roleName: "position" }
}
popupMenu: statusChatListAndCategories.chatListPopupMenu
popupMenu: root.chatListPopupMenu
}
DelegateModel {
id: delegateModel
model: statusChatListAndCategories.model
property int destinationPosition: -1
model: SortFilterProxyModel {
sourceModel: root.model
filters: ValueFilter { roleName: "isCategory"; value: true }
sorters: RoleSorter { roleName: "position" }
}
items.includeByDefault: false
groups: DelegateModelGroup {
id: unsortedItems
name: "unsorted"
includeByDefault: true
onChanged: Utils.delegateModelSort(unsortedItems, delegateModel.items,
(a, b) => a.position < b.position)
}
delegate: Item {
id: draggable
width: statusChatListCategory.width
@@ -104,13 +130,13 @@ Item {
dragSensor.drag.threshold: 0.1
dragSensor.drag.filterChildren: true
dragSensor.onPressAndHold: {
if (statusChatListAndCategories.draggableCategories) {
if (root.draggableCategories) {
dragActive = true
}
}
dragSensor.onReleased: {
if (dragActive) {
statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, statusChatListCategory.originalOrder)
if (dragActive && delegateModel.destinationPosition !== -1 && statusChatListCategory.originalOrder !== delegateModel.destinationPosition) {
root.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, delegateModel.destinationPosition)
}
dragActive = false
}
@@ -120,38 +146,44 @@ Item {
startX = dragSensor.mouseX
}
dragSensor.onMouseYChanged: {
if (statusChatListAndCategories.draggableCategories && (Math.abs(startY - dragSensor.mouseY) > 1) && dragSensor.pressed) {
if (root.draggableCategories && (Math.abs(startY - dragSensor.mouseY) > 1) && dragSensor.pressed) {
dragActive = true
}
}
dragSensor.onMouseXChanged: {
if (statusChatListAndCategories.draggableCategories && (Math.abs(startX - dragSensor.mouseX) > 1) && dragSensor.pressed) {
if (root.draggableCategories && (Math.abs(startX - dragSensor.mouseX) > 1) && dragSensor.pressed) {
dragActive = true
}
}
onDragActiveChanged: delegateModel.destinationPosition = -1
addButton.tooltip: statusChatListAndCategories.categoryAddButtonToolTip
menuButton.tooltip: statusChatListAndCategories.categoryMenuButtonToolTip
addButton.tooltip: root.categoryAddButtonToolTip
menuButton.tooltip: root.categoryMenuButtonToolTip
originalOrder: model.position
categoryId: model.itemId
name: model.name
showActionButtons: statusChatListAndCategories.showCategoryActionButtons
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.itemId)
chatList.model: model.subItems
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: statusChatListAndCategories.draggableItems
showActionButtons: root.showCategoryActionButtons
addButton.onClicked: root.categoryAddButtonClicked(model.itemId)
popupMenu: statusChatListAndCategories.categoryPopupMenu
chatListPopupMenu: statusChatListAndCategories.chatListPopupMenu
chatList.model: SortFilterProxyModel {
sourceModel: model.subItems
sorters: RoleSorter { roleName: "position" }
}
chatList.onChatItemSelected: root.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: root.chatItemUnmuted(id)
chatList.onChatItemReordered: root.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: root.draggableItems
popupMenu: root.categoryPopupMenu
chatListPopupMenu: root.chatListPopupMenu
// Used to set the initial value of "opened" when the
// model is bound/changed.
opened: {
let openedState = statusChatListAndCategories.openedCategoryState[model.itemId]
let openedState = root.openedCategoryState[model.itemId]
return openedState !== undefined ? openedState : true // defaults to open
}
@@ -160,7 +192,18 @@ Item {
// as the state would be lost each time the model is
// changed.
onOpenedChanged: {
statusChatListAndCategories.openedCategoryState[model.itemId] = statusChatListCategory.opened
root.openedCategoryState[model.itemId] = statusChatListCategory.opened
}
Connections {
function onOriginalOrderChanged() {
Qt.callLater(() => {
if (!delegateModel)
return
delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
})
}
}
}
@@ -171,7 +214,6 @@ Item {
keys: ["chat-category"]
onEntered: reorderDelay.start()
onDropped: statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, drag.source.originalOrder, statusChatListCategory.DelegateModel.itemsIndex)
Timer {
id: reorderDelay
@@ -179,7 +221,7 @@ Item {
repeat: false
onTriggered: {
if (dropArea.containsDrag) {
dropArea.drag.source.chatListCategory.originalOrder = statusChatListCategory.originalOrder
delegateModel.destinationPosition = delegateModel.model.get(draggable.DelegateModel.itemsIndex).position
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
}
}
@@ -225,6 +267,6 @@ Item {
Loader {
id: popupMenuSlot
active: !!statusChatListAndCategories.popupMenu
active: !!root.popupMenu
}
}
@@ -35,7 +35,6 @@ Column {
StatusChatListCategoryItem {
id: statusChatListCategoryItem
title: statusChatListCategory.name
visible: model.isCategory
opened: statusChatListCategory.opened
sensor.pressAndHoldInterval: 150
@@ -66,9 +65,6 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
visible: statusChatListCategory.opened
categoryId: statusChatListCategory.categoryId
filterFn: function (model) {
return !!model.parentItemId && model.parentItemId === statusChatList.categoryId
}
popupMenu: statusChatListCategory.chatListPopupMenu
}
+12 -10
View File
@@ -13,21 +13,23 @@ Item {
property alias model: repeater.model
property alias contentWidth: flow.width
readonly property int itemsWidth: {
let result = 0;
for (let i = 0; i < repeater.count; ++i) {
result += flow.spacing + repeater.itemAt(i).width;
}
return result;
}
signal clicked(var item)
implicitWidth: flow.implicitWidth
implicitHeight: flow.implicitHeight
implicitWidth: itemsWidth
implicitHeight: flow.height
Flow {
id: flow
anchors.centerIn: parent
width: {
let itemsWidth = 0;
for (let i = 0; i < repeater.count; ++i) {
itemsWidth += spacing + repeater.itemAt(i).width;
}
return Math.min(parent.width, itemsWidth);
}
width: Math.min(parent.width, root.itemsWidth);
spacing: 10
Repeater {
@@ -38,7 +40,7 @@ Item {
name: model.name
visible: (root.showOnlySelected ? model.selected : !model.selected) &&
(filterString == 0 || name.toUpperCase().indexOf(filterString.toUpperCase()) !== -1)
width: visible ? implicitWidth : -10
width: visible ? implicitWidth : -flow.spacing
height: visible ? implicitHeight : 0
removable: root.showOnlySelected && root.active
onClicked: root.clicked(model)
+184
View File
@@ -0,0 +1,184 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import Qt.labs.calendar 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusDatePicker
\inherits StatusQ.Controls.StatusComboBox
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief Displays a date picker based on a combobox with a calendar popup
The \c StatusDatePicker displays a date picker based on a combobox with a calendar popup.
The property \p selectedDate reflects the currently chosen date (defaults to today).
For a list of components available see StatusQ.
*/
StatusComboBox {
id: root
/*!
\qmlproperty string StatusDatePicker::dateFormat
This property specifies how the selected date will be displayed to the user.
By default it is current locale's short date format. For a list of available types
and formatting characters, see https://doc.qt.io/qt-5/qdate.html#toString-2
*/
property string dateFormat: Qt.locale().dateFormat(Locale.ShortFormat)
/*!
\qmlproperty date StatusDatePicker::selectedDate
This property holds the currently selected date.
\sa QtQml.Date
*/
property alias selectedDate: d.selectedDate
QtObject {
id: d
property date selectedDate: new Date()
}
control.delegate: null
control.displayText: root.selectedDate.toLocaleDateString(Qt.locale(), root.dateFormat)
control.popup.horizontalPadding: 8
control.popup.onAboutToShow: {
// always open the popup showing the last (currently) selected date
grid.year = d.selectedDate.getFullYear()
grid.month = d.selectedDate.getMonth()
}
control.popup.contentItem: Item {
property alias grid: grid
GridLayout {
anchors.fill: parent
columns: 2
RowLayout {
Layout.fillWidth: true
Layout.columnSpan: 2
spacing: 0
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: "<<"
onClicked: grid.year = grid.year - 1
StatusToolTip {
text: qsTr("Previous year")
visible: parent.hovered
}
}
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: "<"
onClicked: {
// switch to previous month (and optionally prev year in January)
const date = new Date(grid.year, grid.month)
date.setMonth(date.getMonth() - 1)
grid.month = date.getMonth()
grid.year = date.getFullYear()
}
StatusToolTip {
text: qsTr("Previous month")
visible: parent.hovered
}
}
StatusFlatButton {
Layout.fillWidth: true
text: grid.title
font.pixelSize: 18
font.weight: Font.Medium
onClicked: {
const date = new Date()
grid.month = date.getMonth()
grid.year = date.getFullYear()
}
StatusToolTip {
text: qsTr("Show current month")
visible: parent.hovered
}
}
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: ">"
onClicked: {
// switch to next month (and optionally next year in December)
const date = new Date(grid.year, grid.month)
date.setMonth(date.getMonth() + 1)
grid.month = date.getMonth()
grid.year = date.getFullYear()
}
StatusToolTip {
text: qsTr("Next month")
visible: parent.hovered
}
}
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: ">>"
onClicked: grid.year = grid.year + 1
StatusToolTip {
text: qsTr("Next year")
visible: parent.hovered
}
}
}
DayOfWeekRow {
Layout.row: 1
Layout.column: 1
Layout.fillWidth: true
delegate: StatusBaseText {
text: model.shortName
color: Theme.palette.directColor3
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
WeekNumberColumn {
id: weekColumn
month: grid.month
year: grid.year
Layout.fillHeight: true
delegate: StatusBaseText {
text: model.weekNumber
color: Theme.palette.directColor3
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
MonthGrid {
id: grid
month: d.selectedDate.getMonth()
year: d.selectedDate.getFullYear()
Layout.fillWidth: true
Layout.fillHeight: true
delegate: StatusFlatButton {
readonly property bool selected: d.selectedDate.getFullYear() === model.year &&
d.selectedDate.getMonth() === model.month &&
d.selectedDate.getDate() === model.day
opacity: model.month === grid.month ? 1 : 0.5
text: model.day
textColor: selected ? Theme.palette.primaryColor1 : Theme.palette.directColor1
font.bold: selected || model.today
onClicked: {
d.selectedDate = model.date
root.control.popup.close()
}
}
}
}
}
}
@@ -3,6 +3,7 @@ import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusImageCropPanel
@@ -127,12 +128,15 @@ Item {
id: mainLayout
anchors.fill: parent
spacing: 1
Item {
id: cropSpaceItem
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 10
Layout.rightMargin: 10
clip: true
@@ -142,6 +146,7 @@ Item {
anchors.top: parent.top
anchors.right: cropEditor.left
anchors.bottom: parent.bottom
anchors.bottomMargin: -1
color: wallColor
opacity: wallTransparency
z: cropEditor.z + 1
@@ -160,8 +165,9 @@ Item {
StatusImageCrop {
id: cropEditor
anchors.centerIn: parent
width: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height * aspectRatio : cropSpaceItem.width - root.margins * 2
height: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height - root.margins * 2 : cropSpaceItem.width / aspectRatio
readonly property bool cropARSmall: aspectRatio < cropSpaceItem.width/cropSpaceItem.height
width: cropARSmall ? cropSpaceItem.height * aspectRatio : cropSpaceItem.width - root.margins * 2
height: cropARSmall ? cropSpaceItem.height - root.margins * 2 : cropSpaceItem.width / aspectRatio
}
Rectangle {
@@ -170,6 +176,7 @@ Item {
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: -1
color: wallColor
opacity: wallTransparency
z: cropEditor.z + 1
@@ -181,6 +188,7 @@ Item {
anchors.top: cropEditor.bottom
anchors.right: rightOverlay.left
anchors.bottom: parent.bottom
anchors.bottomMargin: -1
color: wallColor
opacity: wallTransparency
z: cropEditor.z + 1
@@ -190,6 +198,7 @@ Item {
Canvas {
visible: root.enableCheckers
anchors.fill: parent
anchors.bottomMargin: -1
onPaint: {
var ctx = getContext("2d")
for(let xI = 0; xI < Math.ceil(width/10); xI++) {
@@ -238,17 +247,20 @@ Item {
RowLayout {
visible: root.interactive
spacing: 10
StatusIcon {
icon: "remove-circle"
color: Theme.palette.baseColor1
Layout.preferredWidth: 20
Layout.preferredHeight: 20
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 24
Layout.preferredHeight: 24
}
StatusSlider {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 25
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.alignment: Qt.AlignVCenter
enabled: root.interactive
@@ -261,9 +273,11 @@ Item {
}
StatusIcon {
icon: "add-circle"
color: Theme.palette.baseColor1
Layout.preferredWidth: 20
Layout.preferredHeight: 20
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 24
Layout.preferredHeight: 24
}
}
}
@@ -284,6 +284,7 @@ Rectangle {
StatusBaseText {
id: statusListItemSubTitle
objectName: "statusListItemSubTitle"
anchors.top: statusListItemTitle.bottom
width: parent.width
text: statusListItem.subTitle
+68 -91
View File
@@ -6,6 +6,8 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import SortFilterProxyModel 0.2
/*!
\qmltype StatusListPicker
\inherits Item
@@ -15,7 +17,7 @@ import StatusQ.Controls 0.1
The \c StatusListPicker is populated with a data model. The data model is commonly a JavaScript array or a ListModel object.
StatusListPicker can be made as a single or multiple options picker by setting its StatusListPicker::multiSelection property properly or will be auto-set if the model contains / provides more than one selected items.
StatusListPicker can be made as a single or multiple options picker by setting its StatusListPicker::multiSelection property properly.
The StatusPickerButton text holds the text of the current item selected in the list picker. If there is more than one item selected, a string composed will be displayed.
The drop-down list incorporates a searcher by the following model roles: `name` or / and `shortName`.
@@ -44,6 +46,7 @@ Item {
This property holds the data that will be populated in the list picker.
NOTE: This model property should not change so it is an in / out property where the selected role will be dynamically changed according to user actions.
NOTE: Be sure provided model is compatible with StatusListPicker::multiSelection property.
Here an example of the model roles expected:
\qml
@@ -69,7 +72,9 @@ Item {
}
\endqml
*/
property ListModel inputList: ListModel { }
property var inputList: ListModel { }
readonly property StatusListPickerProxies proxy: StatusListPickerProxies {}
/*!
\qmlproperty string StatusListPicker::searchText
@@ -151,93 +156,65 @@ Item {
QtObject {
id: d
property var filteredModel: ListModel { }
// Used to set up component and the needed private properties
function initialize() {
if(filteredModel.count === 0) {
// It is necessary to load the model, not loaded yet!
var selected = 0
var selectionText = ""
for(var i = 0; i < root.inputList.count; i++) {
var item = root.inputList.get(i)
d.filteredModel.append(item)
if(item.selected) selected++;
}
// If the given model has more than one selected elements, the behaviour of the list picker will be as a multiple selector with checkboxes although it is
// set in the radiobutton mode. Radiobutton mode is only for mutial-exclusion.
if(selected > 1)
multiSelection = true
// Update selected items text:
d.getSelectedItemsText()
readonly property SortFilterProxyModel selectedItems: SortFilterProxyModel {
sourceModel: root.inputList
// NOTE: ValueFilter would crash if source model does not contain given role
// FIXME: use ValueFilter when its fixed
filters: ExpressionFilter {
expression: root.proxy.selected(model)
}
}
// Used to update model elements given a specific text by filtering them for its `name` and / or `shortName`.
function applyFilter(text) {
const input = text.toLowerCase()
filteredModel.clear()
for(var i = 0; i < root.inputList.count; i++) {
let item = root.inputList.get(i)
if(item.name.toLowerCase().includes(input) || item.shortName.toLowerCase().includes(input))
filteredModel.append(item)
readonly property string selectedItemsText: {
function formatSymbolShortNameText(symbol, shortName) {
var formattedText = ""
if(root.printSymbol && symbol)
formattedText = symbol + shortName
else
formattedText = shortName
return formattedText
}
}
function formatSymbolShortNameText(symbol, shortName) {
var formattedText = ""
if(root.printSymbol && symbol)
formattedText = symbol + shortName
else
formattedText = shortName
return formattedText
}
function getSelectedItemsText() {
var res = ""
for(var i = 0; i < root.inputList.count; i++) {
var item = root.inputList.get(i)
if(item.selected) {
if(res != "")
res += ", "
res += d.formatSymbolShortNameText(item.symbol, item.shortName)
}
for(var i = 0; i < selectedItems.count; i++) {
var item = selectedItems.get(i)
if(res != "")
res += ", "
res += formatSymbolShortNameText(root.proxy.symbol(item), root.proxy.shortName(item))
}
return res
}
// Used to update the base input list model with the new selected property
function updateInputListModel(key, selected, isSingleSelection) {
// If it is a single selection we must ensure that when a new key is selected others are cleared.
// It must be done manually because as there is the option of filterning, the model visualized changes
// and it could be possible to have a filtered list without an element selected (but in the base model
// it is) so, the binding to not selected will not be executed, as in the current filtered model
// there are no changes to update, just only the selected one.
for(var i = 0; i < root.inputList.count; i++) {
if(root.inputList.get(i).key === key) {
root.inputList.get(i).selected = selected
}
else if(isSingleSelection && selected) {
// Clear all the list
root.inputList.get(i).selected = false
}
}
}
}
width: 110
height: 38
Component.onCompleted: d.initialize()
Repeater {
// Used to update the base input list model with the new selected property
// If it is a single selection we must ensure that when a new key is selected others are cleared.
id: itemsSelectorHelper
signal selectItem(var key, bool checked)
model: root.inputList
delegate: Item {
Connections {
target: itemsSelectorHelper
function onSelectItem(key, checked) {
if (root.proxy.key(model) === key) root.proxy.setSelected(model, checked)
else if (!root.multiSelection && checked) root.proxy.setSelected(model, false)
}
}
}
}
StatusPickerButton {
id: btn
anchors.fill: parent
bgColor: Theme.palette.primaryColor3
contentColor: Theme.palette.primaryColor1
text: picker.selectedItemsText
text: d.selectedItemsText
font.pixelSize: 13
type: StatusPickerButton.Type.Down
@@ -253,8 +230,6 @@ Item {
Rectangle {
id: picker
property string selectedItemsText: ""
width: content.itemWidth
height: Math.min(content.contentHeight + content.anchors.topMargin + content.anchors.bottomMargin, root.maxPickerHeight)
anchors.left: root.menuAlignment === StatusListPicker.MenuAlignment.Left ? btn.left : undefined
@@ -277,12 +252,23 @@ Item {
}
ListView {
id: content
id: content
property int itemHeight: 40
property int itemWidth: 360
model: d.filteredModel
model: SortFilterProxyModel {
sourceModel: root.inputList
delayed: true
filters: ExpressionFilter {
expression: {
root.searchText // ensure expression is reevaluated when searchText changes
return root.proxy.name(model).toLowerCase().includes(root.searchText.toLowerCase()) ||
root.proxy.shortName(model).toLowerCase().includes(root.searchText.toLowerCase())
}
}
}
width: itemWidth
anchors.top: parent.top
anchors.topMargin: 8
@@ -310,10 +296,7 @@ Item {
text: root.searchText
input.icon.name: "search"
onTextChanged: {
d.applyFilter(text)
root.searchText = text
}
onTextChanged: root.searchText = text
}
}// End of search input item
delegate: StatusItemPicker {
@@ -321,30 +304,24 @@ Item {
height: content.itemHeight
color: mouseArea.containsMouse ? Theme.palette.baseColor4 : "transparent"
image: StatusImageSettings {
source: model.imageSource ? model.imageSource : ""
source: root.proxy.imageSource(model) ? root.proxy.imageSource(model) : ""
width: 15
height: 15
isIdenticon: false
}
name: model.name
shortName: model.shortName
name: root.proxy.name(model)
shortName: root.proxy.shortName(model)
selectorType: root.multiSelection ? StatusItemPicker.SelectorType.CheckBox : StatusItemPicker.SelectorType.RadioButton
selected: model.selected
selected: root.proxy.selected(model)
radioGroup: radioBtnGroup
onCheckedChanged: {
d.updateInputListModel(model.key, checked, selectorType === StatusItemPicker.SelectorType.RadioButton)
if(selectorType === StatusItemPicker.SelectorType.RadioButton && checked) {
// Update selected item text
picker.selectedItemsText = d.formatSymbolShortNameText(model.symbol, model.shortName)
}
else {
// Update selected items text (multiple selection, text chain).
picker.selectedItemsText = d.getSelectedItemsText()
if (checked !== root.proxy.selected(model)) {
itemsSelectorHelper.selectItem(root.proxy.key(model), checked)
}
// Used to notify selected property changes in the specific item picker.
itemPickerChanged(model.key, checked)
itemPickerChanged(root.proxy.key(model), checked)
}
MouseArea {
@@ -386,7 +363,7 @@ Item {
// Not visual element to control mutual-exclusion of radiobuttons that are not sharing the same parent (inside list view)
ButtonGroup {
id: radioBtnGroup
}
}// End of Content
}
}// End of Content
}// End of Rectangle picker
}
@@ -0,0 +1,30 @@
import QtQuick 2.14
/*!
Enables StatusListPicker to work with incompatible models.
\qml
StatusListPicker {
id: currencyPicker
inputList: ListModel {
ListElement { incompatibleA: 0 ... incomatibleZ: false }
ListElement { incompatibleA: 1 ... incomatibleZ: false }
ListElement { incompatibleA: 2 ... incomatibleZ: false }
}
proxy { // StatusListPickerProxies
key: (model) => model.incompatibleA
...
selected: (model) => model.incompatibleZ
}
}
\endqml
*/
QtObject {
property var key: (model) => model.key
property var name: (model) => model.name
property var shortName: (model) => model.shortName
property var symbol: (model) => model.symbol
property var imageSource: (model) => model.imageSource
property var category: (model) => model.category
property var selected: (model) => model.selected
property var setSelected: (model, val) => model.selected = val
}
@@ -79,6 +79,7 @@ Loader {
Component {
id: letterIdenticon
StatusLetterIdenticon {
objectName: "statusSmartIdenticonLetter"
width: statusSmartIdenticon.icon.width
height: statusSmartIdenticon.icon.height
color: statusSmartIdenticon.icon.color
@@ -378,6 +378,7 @@ Item {
}
contentItem: ListView {
id: userListView
objectName: "tagSelectorUserList"
anchors {
fill: parent
topMargin: 16
@@ -28,7 +28,7 @@ Item {
width: editText.width
placeholderText: ""
input.text: msgText
input.implicitHeight: 40
maximumHeight: 40
}
}
RowLayout {
+2
View File
@@ -1,6 +1,7 @@
module StatusQ.Components
StatusAddress 0.1 StatusAddress.qml
StatusAddressPanel 0.1 StatusAddressPanel.qml
StatusBadge 0.1 StatusBadge.qml
StatusChatInfoToolBar 0.1 StatusChatInfoToolBar.qml
StatusChatList 0.1 StatusChatList.qml
@@ -39,3 +40,4 @@ StatusCommunityCard 0.1 StatusCommunityCard.qml
StatusCommunityTags 0.1 StatusCommunityTags.qml
StatusItemSelector 0.1 StatusItemSelector.qml
StatusCard 0.1 StatusCard.qml
StatusDatePicker 0.1 StatusDatePicker.qml
+134 -125
View File
@@ -8,17 +8,17 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import SortFilterProxyModel 0.2
Item {
id: root
property string label: "Choose account"
property bool showAccountDetails: !!selectedAccount
property var accounts
property var selectedAccount
property string currency: "usd"
property alias selectField: select
implicitWidth: 448
height: select.height +
(selectedAccountDetails.visible ? selectedAccountDetails.height + selectedAccountDetails.anchors.topMargin : 0)
// set to asset symbol to display asset's balance top right
// NOTE: if this asset is not selected as a wallet token in the UI, then
// nothing will be displayed
@@ -27,10 +27,10 @@ Item {
property double minRequiredAssetBalance: 0
property int dropdownWidth: width
property int chainId: 0
property alias dropdownAlignment: select.menuAlignment
property bool isValid: true
property bool readOnly: false
property var assetBalanceTextFn: function (foundValue) {
return "Balance: " + (parseFloat(foundValue) === 0.0 ? "0" : Utils.stripTrailingZeros(foundValue))
}
@@ -51,18 +51,23 @@ Item {
return root.isValid
}
implicitWidth: 448
implicitHeight: comboBox.height +
(selectedAccountDetails.visible ? selectedAccountDetails.height + selectedAccountDetails.anchors.topMargin
: 0)
onSelectedAccountChanged: {
if (!selectedAccount) {
return
}
if (selectedAccount.color) {
selectedIconImg.color = Utils.getThemeAccountColor(selectedAccount.color, Theme.palette.userCustomizationColors) || Theme.palette.userCustomizationColors[0]
d.selectedIconColor = Utils.getThemeAccountColor(selectedAccount.color, Theme.palette.userCustomizationColors) || Theme.palette.userCustomizationColors[0]
}
if (selectedAccount.name) {
selectedTextField.text = selectedAccount.name
d.selectedText = selectedAccount.name
}
if (selectedAccount.address) {
textSelectedAddress.text = selectedAccount.address + " •"
textSelectedAddress.text = selectedAccount.address
}
if (selectedAccount.currencyBalance) {
textSelectedAddressFiatBalance.text = selectedAccount.currencyBalance + " " + currency.toUpperCase()
@@ -87,14 +92,20 @@ Item {
txtAssetSymbol.text = " " + assetFound.symbol
}
QtObject {
id: d
property color selectedIconColor: "transparent"
property string selectedText: ""
}
StatusBaseText {
id: txtAssetBalance
visible: root.assetFound !== undefined
anchors.bottom: select.top
anchors.bottom: comboBox.top
anchors.bottomMargin: -18
anchors.right: txtAssetSymbol.left
anchors.left: select.left
anchors.leftMargin: select.width / 2.5
anchors.left: comboBox.left
anchors.leftMargin: comboBox.width / 2.5
color: !root.isValid ? Theme.palette.dangerColor1 : Theme.palette.baseColor1
elide: Text.ElideRight
@@ -116,6 +127,7 @@ Item {
onExited: assetTooltip.visible = false
}
}
StatusBaseText {
id: txtAssetSymbol
visible: txtAssetBalance.visible
@@ -126,152 +138,149 @@ Item {
font.pixelSize: 13
height: txtAssetBalance.height
}
StatusSelect {
id: select
StatusComboBox {
id: comboBox
label: root.label
model: root.accounts
width: parent.width
menuAlignment: StatusSelect.MenuAlignment.Left
selectMenu.delegate: menuItem
selectMenu.width: dropdownWidth
selectedItemComponent: Item {
anchors.fill: parent
model: SortFilterProxyModel {
sourceModel: root.accounts
filters: [
ValueFilter {
roleName: "walletType"
value: root.watchWalletType
inverted: true
}
]
}
contentItem: RowLayout {
spacing: 8
StatusIcon {
id: selectedIconImg
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
width: 20
height: 20
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 20
Layout.preferredHeight: 20
icon: "filled-account"
color: d.selectedIconColor
}
StatusBaseText {
id: selectedTextField
elide: Text.ElideRight
anchors.left: selectedIconImg.right
anchors.leftMargin: 8
anchors.right: parent.right
anchors.rightMargin: select.selectedItemRightMargin
anchors.verticalCenter: parent.verticalCenter
Layout.fillWidth: true
Layout.fillHeight: true
font.pixelSize: 15
verticalAlignment: Text.AlignVCenter
height: 22
color: Theme.palette.directColor1
text: d.selectedText
}
}
delegate: StatusItemDelegate {
highlighted: index === comboBox.control.highlightedIndex
width: comboBox.width
padding: 16
onClicked: {
// WARNING: Settings comboBox value from delegate is wrong.
// ComboBox must have a single role as "value"
// This should be refactored later. Probably roleValue should be 'address'.
// All other needed values should be retrived from model by the user of component.
root.selectedAccount = { address, name, color: model.color, assets, currencyBalance };
}
Component.onCompleted: {
// WARNING: Same here, this is wrong, check comment above.
if (!root.selectedAccount && index === 0) {
root.selectedAccount = { address, name, color: model.color, assets, currencyBalance }
}
}
contentItem: RowLayout {
spacing: 0
StatusIcon {
id: iconImg
Layout.preferredWidth: 20
Layout.preferredHeight: 20
icon: "filled-account"
color: Utils.getThemeAccountColor(model.color, Theme.palette.userCustomizationColors) ||
Theme.palette.userCustomizationColors[0]
}
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.leftMargin: 14
Layout.rightMargin: 8
spacing: 0
StatusBaseText {
id: accountName
Layout.fillWidth: true
text: model.name
elide: Text.ElideRight
font.pixelSize: 15
color: Theme.palette.directColor1
}
StatusBaseText {
id: accountAddress
Layout.fillWidth: true
Layout.maximumWidth: 80
text: address
elide: Text.ElideMiddle
color: Theme.palette.baseColor1
font.pixelSize: 12
}
}
StatusBaseText {
id: txtFiatBalance
Layout.rightMargin: 4
font.pixelSize: 15
text: currencyBalance
color: Theme.palette.directColor1
}
StatusBaseText {
id: fiatCurrencySymbol
font.pixelSize: 15
color: Theme.palette.baseColor1
text: root.currency.toUpperCase()
}
}
}
}
Row {
RowLayout {
id: selectedAccountDetails
visible: root.showAccountDetails
anchors.top: select.bottom
anchors.top: comboBox.bottom
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 2
anchors.right: parent.right
anchors.rightMargin: 4
spacing: 2
StatusBaseText {
id: textSelectedAddress
Layout.maximumWidth: 80
font.pixelSize: 12
elide: Text.ElideMiddle
width: 90
color: Theme.palette.baseColor1
}
StatusBaseText {
id: textSelectedAddressFiatBalance
font.pixelSize: 12
color: Theme.palette.baseColor1
text: "•"
}
}
Component {
id: menuItem
MenuItem {
id: itemContainer
visible: walletType !== root.watchWalletType
property bool isFirstItem: index === 0
property bool isLastItem: index === accounts.rowCount() - 1
Component.onCompleted: {
if (!root.selectedAccount && isFirstItem) {
root.selectedAccount = { address, name, color: model.color, assets, currencyBalance }
}
}
height: walletType === root.watchWalletType ? 0 : (accountName.height + 14 + accountAddress.height + 14)
StatusIcon {
id: iconImg
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
width: 20
height: 20
icon: "filled-account"
color: Utils.getThemeAccountColor(model.color, Theme.palette.userCustomizationColors) || Theme.palette.userCustomizationColors[0]
}
Column {
id: column
anchors.left: iconImg.right
anchors.leftMargin: 14
anchors.right: txtFiatBalance.left
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
StatusBaseText {
id: accountName
text: model.name
elide: Text.ElideRight
font.pixelSize: 15
anchors.left: parent.left
anchors.right: parent.right
height: 22
color: Theme.palette.directColor1
}
StatusBaseText {
id: accountAddress
text: address
elide: Text.ElideMiddle
width: 80
color: Theme.palette.baseColor1
font.pixelSize: 12
height: 16
}
}
StatusBaseText {
id: txtFiatBalance
anchors.right: fiatCurrencySymbol.left
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
height: 22
text: currencyBalance
color: Theme.palette.directColor1
}
StatusBaseText {
id: fiatCurrencySymbol
anchors.right: parent.right
anchors.rightMargin: 16
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
height: 22
color: Theme.palette.baseColor1
text: root.currency.toUpperCase()
}
background: Rectangle {
color: itemContainer.highlighted ? Theme.palette.statusSelect.menuItemHoverBackgroundColor : Theme.palette.statusSelect.menuItemBackgroundColor
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: itemContainer
onClicked: {
root.selectedAccount = { address, name, color: model.color, assets, currencyBalance }
select.selectMenu.close()
}
}
StatusBaseText {
id: textSelectedAddressFiatBalance
Layout.fillWidth: true
font.pixelSize: 12
color: Theme.palette.baseColor1
}
}
}
@@ -1,158 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
Item {
id: root
property var assets
property var selectedAsset
property string defaultToken: ""
property string userSelectedToken: ""
property var tokenAssetSourceFn: function (symbol) {
return ""
}
// Define this in the usage to get balance in currency selected by user
property var getCurrencyBalanceString: function (currencyBalance) { return "" }
implicitWidth: 106
implicitHeight: 32
function resetInternal() {
assets = null
selectedAsset = null
}
onSelectedAssetChanged: {
if (selectedAsset && selectedAsset.symbol) {
iconImg.image.source = tokenAssetSourceFn(selectedAsset.symbol.toUpperCase())
selectedTextField.text = selectedAsset.symbol.toUpperCase()
}
}
StatusSelect {
id: select
width: parent.width
bgColor: "transparent"
bgColorHover: Theme.palette.directColor8
model: root.assets
caretRightMargin: 0
select.radius: 6
select.height: root.height
selectMenu.width: 342
selectedItemComponent: Item {
anchors.fill: parent
StatusRoundedImage {
id: iconImg
anchors.left: parent.left
anchors.leftMargin: 4
width: 24
height: 24
anchors.verticalCenter: parent.verticalCenter
image.onStatusChanged: {
if (iconImg.image.status === Image.Error) {
iconImg.image.source = defaultToken
}
}
}
StatusBaseText {
id: selectedTextField
anchors.left: iconImg.right
anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
height: 22
width: 50
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
color: Theme.palette.directColor1
}
}
selectMenu.delegate: menuItem
}
Component {
id: menuItem
MenuItem {
id: itemContainer
property bool isFirstItem: index === 0
property bool isLastItem: index === assets.rowCount() - 1
width: parent.width
height: 72
StatusRoundedImage {
id: iconImg
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
image.source: root.tokenAssetSourceFn(symbol.toUpperCase())
image.onStatusChanged: {
if (iconImg.image.status === Image.Error) {
iconImg.image.source = defaultToken
}
}
}
Column {
anchors.left: iconImg.right
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
StatusBaseText {
text: symbol.toUpperCase()
font.pixelSize: 15
color: Theme.palette.directColor1
}
StatusBaseText {
text: name
color: Theme.palette.baseColor1
font.pixelSize: 15
}
}
Column {
anchors.right: parent.right
anchors.rightMargin: 16
anchors.verticalCenter: parent.verticalCenter
StatusBaseText {
font.pixelSize: 15
text: parseFloat(totalBalance).toFixed(4) + " " + symbol
}
StatusBaseText {
font.pixelSize: 15
anchors.right: parent.right
text: getCurrencyBalanceString(totalCurrencyBalance)
color: Theme.palette.baseColor1
}
}
background: Rectangle {
color: itemContainer.highlighted ? Theme.palette.statusSelect.menuItemHoverBackgroundColor : Theme.palette.statusSelect.menuItemBackgroundColor
}
// To-do move this out of StatusQ, this involves dependency on BE code
Component.onCompleted: {
if(userSelectedToken === "") {
if(index === 0) {
selectedAsset = { name: name, symbol: symbol, totalBalance: totalBalance, totalCurrencyBalance: totalCurrencyBalance, balances: balances}
}
} else {
if(symbol === userSelectedToken) {
selectedAsset = { name: name, symbol: symbol, totalBalance: totalBalance, totalCurrencyBalance: totalCurrencyBalance, balances: balances}
}
}
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: itemContainer
onClicked: {
userSelectedToken = symbol
// To-do move this out of StatusQ, this involves dependency on BE code
selectedAsset = {name: name, symbol: symbol, totalBalance: totalBalance, totalCurrencyBalance: totalCurrencyBalance, balances: balances}
select.selectMenu.close()
}
}
}
}
}
@@ -0,0 +1,6 @@
import QtQuick 2.14
import StatusQ.Controls 0.1
StatusRoundButton {
icon.name: "arrow-left"
}
+3 -3
View File
@@ -15,7 +15,8 @@ Rectangle {
enum Type {
Normal,
Danger
Danger,
Primary
}
property StatusIconSettings icon: StatusIconSettings {
@@ -145,7 +146,7 @@ Rectangle {
color: d.textColor
} // Text
} // Ro
} // Row
onPressed: {
@@ -172,5 +173,4 @@ Rectangle {
}
}
} // Sensor
}
+2
View File
@@ -327,6 +327,7 @@ Item {
id: flick
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: !!leftComponentLoader.item ? 8 : 0
Layout.topMargin: root.topPadding
Layout.bottomMargin: root.bottomPadding
contentWidth: edit.paintedWidth
@@ -416,6 +417,7 @@ Item {
anchors.fill: parent
verticalAlignment: parent.verticalAlignment
font.pixelSize: 15
wrapMode: root.multiline ? Text.WordWrap : Text.NoWrap
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name
color: root.enabled ? Theme.palette.baseColor1 : Theme.palette.directColor6
+11 -6
View File
@@ -5,13 +5,18 @@ import StatusQ.Core.Theme 0.1
StatusBaseButton {
id: statusButton
normalColor: type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor3
: Theme.palette.dangerColor3
hoverColor: type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor2
: Theme.palette.dangerColor2
normalColor: type === StatusBaseButton.Type.Primary ? Theme.palette.primaryColor1 :
type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor3
: Theme.palette.dangerColor3
hoverColor: type === StatusBaseButton.Type.Primary ? Theme.palette.hoverColor(normalColor) :
type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor2
: Theme.palette.dangerColor2
disaledColor: Theme.palette.baseColor2
textColor: type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor1
: Theme.palette.dangerColor1
textColor: type === StatusBaseButton.Type.Primary ? Theme.palette.white :
type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor1
: Theme.palette.dangerColor1
disabledTextColor: Theme.palette.baseColor1
font.weight: type === StatusBaseButton.Type.Primary ? Font.Medium : Font.Normal
}
@@ -6,6 +6,7 @@ import StatusQ.Components 0.1
Rectangle {
id: statusChatInfoButton
objectName: "chatInfoButton"
implicitWidth: identicon.width +
Math.max(
@@ -8,19 +8,21 @@ RadioButton {
property string radioButtonColor: ""
property string selectionColor: StatusColors.colors['white']
property int diameter: 48
property int selectorDiameter: 20
implicitWidth: 48
implicitHeight: 48
indicator: Rectangle {
implicitWidth: 48
implicitHeight: 48
implicitWidth: control.diameter
implicitHeight: control.diameter
radius: width/2
color: radioButtonColor
Rectangle {
width: 20
height: 20
width: control.selectorDiameter
height: control.selectorDiameter
radius: width/2
color: selectionColor
border.color: StatusColors.colors['grey3']
+21 -29
View File
@@ -2,36 +2,28 @@ import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Controls 0.1
Item {
id: root
property string selectedColor
property string label: "Color"
property var model
height: accountColorInput.height
implicitWidth: 448
StatusComboBox {
id: root
StatusSelect {
id: accountColorInput
bgColor: selectedColor
label: root.label
model: root.model
label: qsTr("Color")
selectMenu.delegate: Component {
MenuItem {
property bool isFirstItem: index === 0
property bool isLastItem: index === root.model.length - 1
height: 52
width: parent.width
padding: 10
onTriggered: function () {
const selectedColor = root.model[index]
root.selectedColor = selectedColor
}
background: Rectangle {
color: root.model[index] || "transparent"
}
}
}
}
control.popup.horizontalPadding: 0
contentItem: null
control.background: Rectangle {
implicitWidth: 448
radius: 8
color: root.control.currentValue
}
delegate: StatusItemDelegate {
width: parent.width
background: Rectangle {
width: parent.width
implicitHeight: 52
color: modelData
}
}
}
@@ -12,6 +12,9 @@ Column {
property alias title: title
property alias columns: grid.columns
property int diameter: 48
property int selectorDiameter: 20
property int selectedColorIndex: 0
property string selectedColor: ""
property var model:[ StatusColors.colors['black'],
@@ -46,6 +49,10 @@ Column {
Repeater {
model: root.model
delegate: StatusColorRadioButton {
implicitWidth: root.diameter
implicitHeight: root.diameter
diameter: root.diameter
selectorDiameter: root.selectorDiameter
checked: index === selectedColorIndex
radioButtonColor: root.model[index] || "transparent"
onCheckedChanged: {
+158
View File
@@ -0,0 +1,158 @@
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
import QtQuick.Templates 2.14 as T
Item {
id: root
property alias control: comboBox
property alias model: comboBox.model
property alias delegate: comboBox.delegate
property alias contentItem: comboBox.contentItem
property alias currentIndex: comboBox.currentIndex
property alias currentValue: comboBox.currentValue
property alias label: labelItem.text
property alias validationError: validationErrorItem.text
implicitWidth: layout.implicitWidth
implicitHeight: layout.implicitHeight
LayoutMirroring.childrenInherit: true
ColumnLayout {
id: layout
anchors.fill: parent
spacing: 0
StatusBaseText {
id: labelItem
Layout.fillWidth: true
visible: !!text
font.pixelSize: 15
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
}
ComboBox {
id: comboBox
property color bgColor: Theme.palette.baseColor2
property color bgColorHover: bgColor
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: labelItem.visible ? 7 : 0
enabled: root.enabled
font.family: Theme.palette.baseFont.name
font.pixelSize: 14
padding: 16
spacing: 16
background: Rectangle {
implicitHeight: 56
implicitWidth: 448
color: Theme.palette.baseColor2
radius: 8
border.width: !!root.validationError || comboBox.hovered || comboBox.down || comboBox.activeFocus ? 1 : 0
border.color: !!root.validationError
? Theme.palette.dangerColor1
: comboBox.activeFocus
? Theme.palette.primaryColor1
: comboBox.hovered
? Theme.palette.primaryColor2
: "transparent"
}
contentItem: StatusBaseText {
font: comboBox.font
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
text: comboBox.displayText
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
}
indicator: StatusIcon {
x: comboBox.mirrored ? comboBox.padding : comboBox.width - width - comboBox.padding
y: comboBox.topPadding + (comboBox.availableHeight - height) / 2
width: 24
height: 24
icon: "chevron-down"
color: Theme.palette.baseColor1
}
popup: Popup {
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
y: comboBox.height + 8
width: comboBox.width
height: Math.min(implicitContentHeight + topPadding + bottomPadding,
comboBox.Window.height - topMargin - bottomMargin)
margins: 8
padding: 1
verticalPadding: 8
background: Rectangle {
id: backgroundItem
color: Theme.palette.statusSelect.menuItemBackgroundColor
radius: 8
border.color: Theme.palette.baseColor2
layer.enabled: true
layer.effect: DropShadow {
horizontalOffset: 0
verticalOffset: 4
radius: 12
samples: 25
spread: 0.2
color: Theme.palette.dropShadow
}
}
contentItem: StatusListView {
id: listView
implicitWidth: contentWidth
implicitHeight: contentHeight
model: comboBox.popup.visible ? comboBox.delegateModel : null
currentIndex: comboBox.highlightedIndex
}
}
delegate: StatusItemDelegate {
width: comboBox.width
highlighted: comboBox.highlightedIndex === index
font: comboBox.font
text: control.textRole ? (Array.isArray(control.model)
? modelData[control.textRole]
: model[control.textRole])
: modelData
}
}
StatusBaseText {
id: validationErrorItem
Layout.fillWidth: true
Layout.topMargin: 11
visible: !!text
font.pixelSize: 12
color: Theme.palette.dangerColor1
horizontalAlignment: TextEdit.AlignRight
wrapMode: Text.WordWrap
}
}
}
+5 -1
View File
@@ -33,6 +33,8 @@ Rectangle {
anchors.centerIn: parent
StatusEmoji {
width: 18
height: 18
emojiId: root.emoji != "" ? Emoji.iconHex(root.emoji) : ""
anchors.verticalCenter: parent.verticalCenter
}
@@ -44,7 +46,9 @@ Rectangle {
StatusBaseText {
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 13
font.pixelSize: 15
font.weight: Font.DemiBold
font.capitalization: Font.AllLowercase
color: root.enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
text: root.name
}
@@ -42,6 +42,14 @@ import StatusQ.Popups 0.1
Row {
id: floatingButtons
/*!
\qmlproperty repeater
This property represents the repeater of selectable items shown to the user.
Can be used to assign objectName to the repeater
\endqml
*/
readonly property alias repeater: itemSelectionRepeater
/*!
\qmlproperty delegate
This property represents the delegate of selectable items shown to the user.
@@ -107,7 +115,8 @@ Row {
bottomPadding: 0
defaultLeftPadding: 4
defaultRightPadding: 4
normalColor: "transparent"
hoverColor: Theme.palette.statusFloatingButtonHighlight
normalColor: Theme.palette.baseColor3
icon.name: "more"
icon.background.color: "transparent"
onClicked: popupMenu.popup(parent.x, y + height + 8)
+14 -7
View File
@@ -303,8 +303,6 @@ Item {
anchors.fill: parent
layer.enabled: true
property bool widthFit: (root.width / root.aspectRatio) <= root.height
// Window width
property real wW: widthFit ? root.width : root.height * root.aspectRatio
@@ -312,22 +310,31 @@ Item {
property real wH: widthFit ? root.width / root.aspectRatio : root.height
onPaint: {
const wSize = Qt.size(wW, wH)
const contentSize = canvasSize
const clearSize = Qt.size(Math.ceil(canvasSize.width), Math.ceil(canvasSize.height))
const r = root.radius
var ctx = getContext("2d")
ctx.save()
// TODO: observed drawing artefacts at the edge. Draw one pixel more for now until root cause is found
ctx.clearRect(0, 0, width + 1, height + 1)
ctx.clearRect(0, 0, clearSize.width, clearSize.height)
// Fill all with wallColor in order to clip the window from it
ctx.fillStyle = Qt.rgba(root.wallColor.r, root.wallColor.g, root.wallColor.b, root.wallTransparency)
ctx.fillRect(0, 0, width + 1, height + 1)
ctx.fillRect(0, 0, clearSize.width, clearSize.height)
// Cut opaque new pixels from background
ctx.globalCompositeOperation = "source-out"
// Draw the window
ctx.beginPath()
const cW = Qt.rect((width - wW)/2, (height - wH)/2, wW, wH)
const cW = Qt.rect((contentSize.width - wSize.width)/2, (contentSize.height - wSize.height)/2, wSize.width, wSize.height)
if(root.windowStyle === StatusImageCrop.WindowStyle.Rounded)
ctx.ellipse(cW.x, cW.y, cW.width, cW.height)
else if(root.windowStyle === StatusImageCrop.WindowStyle.Rectangular)
ctx.roundedRect(cW.x, cW.y, cW.width, cW.height, root.radius, root.radius)
ctx.roundedRect(cW.x, cW.y, cW.width, cW.height, r, r)
ctx.fill()
ctx.restore()
}
+31 -13
View File
@@ -94,6 +94,11 @@ Item {
\qmlproperty string StatusInput::label
This property sets the label text.
*/
property int labelPadding: 8
/*!
\qmlproperty string StatusInput::label
This property sets the label text.
*/
property string label: ""
/*!
\qmlproperty string StatusInput::secondaryLabel
@@ -132,14 +137,14 @@ Item {
property alias bottomPadding: statusBaseInput.bottomPadding
/*!
\qmlproperty real StatusInput::minimumHeight
This property sets the minimum height.
This property sets the minimum height. Default value is 44px.
*/
property real minimumHeight: 0
property real minimumHeight: 44
/*!
\qmlproperty alias StatusInput::maximumHeight
This property sets the maximum height.
This property sets the maximum height. Default value is 44px.
*/
property real maximumHeight: 0
property real maximumHeight: 44
/*!
\qmlproperty list StatusBaseInput::validators
This property sets the list of validators to be considered.
@@ -249,9 +254,8 @@ Item {
\qmlmethod
This function validates the text input's text.
*/
function validate() {
if (!statusBaseInput.dirty && validationMode === StatusInput.ValidationMode.OnlyWhenDirty) {
function validate(force) {
if (!force && !statusBaseInput.dirty && validationMode === StatusInput.ValidationMode.OnlyWhenDirty) {
return
}
statusBaseInput.valid = true
@@ -348,7 +352,7 @@ Item {
}
implicitWidth: 448
implicitHeight: (internal.inputHeight + topRow.height + errorMessage.height + (2*inputLayout.spacing))
implicitHeight: inputLayout.implicitHeight
Component.onCompleted: {
validate()
@@ -357,11 +361,13 @@ Item {
ColumnLayout {
id: inputLayout
anchors.fill: parent
spacing: ((topRow.height > 0) || (errorMessage.height > 0)) ? 8 : 0
spacing: 0
RowLayout {
id: topRow
Layout.fillWidth: true
Layout.preferredHeight: (!!root.label || !!root.secondaryLabel || root.charLimit > 0) ? 22 :0
Layout.preferredHeight: (!!root.label || !!root.secondaryLabel || root.charLimit > 0) ? 22 : 0
StatusBaseText {
id: label
visible: !!text
@@ -401,6 +407,8 @@ Item {
id: statusBaseInput
implicitWidth: parent.width
implicitHeight: internal.inputHeight
Layout.alignment: Qt.AlignTop
Layout.topMargin: (topRow.height > 0) ? labelPadding : 0
maximumLength: root.charLimit
onTextChanged: root.validate()
Keys.forwardTo: [root]
@@ -415,12 +423,22 @@ Item {
StatusBaseText {
id: errorMessage
visible: !!text && !statusBaseInput.valid
height: visible ? contentHeight : 0
visible: {
if (!text)
return false;
if ((root.validationMode == StatusInput.ValidationMode.OnlyWhenDirty && statusBaseInput.dirty) ||
root.validationMode == StatusInput.ValidationMode.Always)
return !statusBaseInput.valid;
return false;
}
font.pixelSize: 12
color: Theme.palette.dangerColor1
Layout.alignment: Qt.AlignVCenter
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignRight
Layout.topMargin: 8
Layout.fillWidth: true
}
}
}
@@ -0,0 +1,49 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
ItemDelegate {
id: root
padding: 8
spacing: 8
icon.width: 16
icon.height: 16
contentItem: RowLayout {
spacing: root.spacing
StatusIcon {
id: iconItem
Layout.alignment: Qt.AlignVCenter
visible: !!icon
icon: root.icon.name
color: root.enabled ? root.icon.color : Theme.palette.baseColor1
width: root.icon.width
height: root.icon.height
}
StatusBaseText {
id: textItem
Layout.fillWidth: true
Layout.fillHeight: true
font: root.font
text: root.text
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
}
}
background: Rectangle {
color: root.highlighted
? Theme.palette.statusPopupMenu.hoverBackgroundColor
: "transparent"
}
}
@@ -99,7 +99,6 @@ Item {
signal editClicked()
function setWord(word) {
seedWordInput.ignoreTextChange = true
seedWordInput.input.edit.text = word
}
@@ -110,11 +109,11 @@ Item {
}
StatusInput {
property bool ignoreTextChange: false
id: seedWordInput
implicitWidth: parent.width
input.leftComponent: StatusBaseText {
rightPadding: 6
text: root.leftComponentText
color: seedWordInput.input.edit.activeFocus ?
Theme.palette.primaryColor1 : Theme.palette.baseColor1
@@ -122,10 +121,6 @@ Item {
}
input.acceptReturn: true
onTextChanged: {
if (ignoreTextChange) {
ignoreTextChange = false
return
}
filteredList.clear();
let textToCheck = text.trim()
if (textToCheck !== "") {
+9 -3
View File
@@ -8,11 +8,14 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
Item {
id: root
enum MenuAlignment {
Left,
Right,
Center
}
property string label: ""
readonly property bool hasLabel: label !== ""
property color bgColor: Theme.palette.baseColor2
@@ -21,6 +24,7 @@ Item {
property alias selectMenu: selectMenu
property color bgColorHover: bgColor
property alias selectedItemComponent: selectedItemContainer.children
property bool caretVisible: true
property int caretRightMargin: 16
property alias select: inputRectangle
property int menuAlignment: StatusSelect.MenuAlignment.Right
@@ -28,10 +32,12 @@ Item {
property string validationError: ""
property alias validationErrorAlignment: validationErrorText.horizontalAlignment
property int validationErrorTopMargin: 11
implicitWidth: 448
id: root
height: inputRectangle.height + (hasLabel ? inputLabel.height + labelMargin : 0) + (!!validationError ? (validationErrorText.height + validationErrorTopMargin) : 0)
implicitHeight: inputRectangle.height +
(hasLabel ? inputLabel.height + labelMargin : 0) +
(!!validationError ? (validationErrorText.height + validationErrorTopMargin) : 0)
StatusBaseText {
id: inputLabel
@@ -72,6 +78,7 @@ Item {
height: 24
icon: "chevron-down"
color: Theme.palette.baseColor1
visible: caretVisible
}
}
@@ -99,7 +106,6 @@ Item {
id: selectMenu
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
width: parent.width
clip: true
Repeater {
id: menuItems
+4 -3
View File
@@ -25,13 +25,14 @@ Slider {
implicitHeight: Math.max(handle.implicitHeight,
background.implicitHeight + decorationContainer.height)
leftPadding: 0
horizontalPadding: 0
background: Rectangle {
id: bgRect
x: root.leftPadding
y: root.topPadding
anchors.verticalCenter: root.verticalCenter
implicitWidth: 100
implicitHeight: bgHeight
width: root.availableWidth
@@ -54,7 +55,7 @@ Slider {
} // background
handle: Rectangle {
x: root.leftPadding + root.visualPosition * (root.availableWidth - width / 2)
x: root.leftPadding + root.visualPosition * (root.availableWidth - width)
anchors.verticalCenter: bgRect.verticalCenter
color: root.handleColor
implicitWidth: root.handleSize
+1 -1
View File
@@ -34,7 +34,7 @@ TabButton {
contentItem: Item {
implicitWidth: contentItemGrid.implicitWidth
implicitHeight: contentItemGrid.implicitHeight + 11
implicitHeight: contentItemGrid.implicitHeight + 15
RowLayout {
id: contentItemGrid
+111
View File
@@ -0,0 +1,111 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusTextArea
\inherits Item
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief Displays a multi line text input component.
Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-controls2-textarea.html}{QQC.TextArea}.
The \c StatusTextArea displays a styled TextArea for users to type multiple lines of text.
For example:
\qml
StatusTextArea {
width: parent.width
placeholderText: qsTr("Search")
}
\endqml
Note: if you want to alter the TAB key behavior, just override it like this:
\qml
StatusTextArea {
width: parent.width
KeyNavigation.tab: otherItemThatAcceptsFocus
}
\endqml
Note 2: if scrolling is required, just wrap the StatusTextArea inside a StatusScrollView, e.g.:
\qml
StatusScrollView {
padding: 0 // use our own (StatusTextArea) padding
width: parent.width
height: 120
TextArea.flickable: longTextArea
StatusTextArea {
id: longTextArea
text: "Very\nlong\ntext\nwith\nmany\nlinebreaks"
}
}
\endqml
For a list of components available see StatusQ.
*/
TextArea {
id: root
/*!
\qmlproperty bool StatusTextArea::valid
This property sets the valid state. Default value is true.
*/
property bool valid: true
implicitWidth: 448 // by design
implicitHeight: 108
leftPadding: 16
rightPadding: 16
topPadding: 10
bottomPadding: 10
color: Theme.palette.directColor1
selectedTextColor: color
selectionColor: Theme.palette.primaryColor2
placeholderTextColor: root.enabled ? Theme.palette.baseColor1 : Theme.palette.directColor9
font {
family: Theme.palette.baseFont.name
pixelSize: 15
}
selectByMouse: true
wrapMode: TextEdit.WordWrap
activeFocusOnTab: enabled
KeyNavigation.priority: KeyNavigation.BeforeItem
background: Rectangle {
radius: 8
color: root.enabled ? Theme.palette.baseColor2 : Theme.palette.baseColor4
border.width: 1
border.color: {
if (!root.valid)
return Theme.palette.dangerColor1
if (root.activeFocus)
return Theme.palette.primaryColor1
if (root.hovered)
return Theme.palette.primaryColor2
return "transparent"
}
}
cursorDelegate: Rectangle {
color: Theme.palette.primaryColor1
implicitWidth: 2
implicitHeight: 22
radius: 1
visible: root.cursorVisible
SequentialAnimation on visible {
loops: Animation.Infinite
running: root.cursorVisible
PropertyAnimation { to: false; duration: 600 }
PropertyAnimation { to: true; duration: 600 }
}
}
}
+4 -1
View File
@@ -1,7 +1,6 @@
module StatusQ.Controls
StatusAccountSelector 0.1 StatusAccountSelector.qml
StatusAssetSelector 0.1 StatusAssetSelector.qml
StatusBanner 0.1 StatusBanner.qml
StatusChatCommandButton 0.1 StatusChatCommandButton.qml
StatusChatInfoButton 0.1 StatusChatInfoButton.qml
@@ -48,3 +47,7 @@ StatusActivityCenterButton 0.1 StatusActivityCenterButton.qml
StatusDropdown 0.1 StatusDropdown.qml
StatusIconTextButton 0.1 StatusIconTextButton.qml
StatusScrollBar 0.1 StatusScrollBar.qml
StatusComboBox 0.1 StatusComboBox.qml
StatusItemDelegate 0.1 StatusItemDelegate.qml
StatusTextArea 0.1 StatusTextArea.qml
StatusBackButton 0.1 StatusBackButton.qml
+3
View File
@@ -31,6 +31,9 @@ import StatusQ.Controls 0.1
ListView {
id: root
readonly property int availableWidth: width - leftMargin - rightMargin
readonly property int availableHeight: height - topMargin - bottomMargin
clip: true
boundsBehavior: Flickable.StopAtBounds
maximumFlickVelocity: 2000
-8
View File
@@ -37,17 +37,9 @@ Flickable {
property int leftPadding: padding
property int rightPadding: padding
property Item background: null
readonly property int availableWidth: width - leftPadding - rightPadding
readonly property int availableHeight: height - topPadding - bottomPadding
onBackgroundChanged: {
if (background) {
background.anchors.fill = root;
}
}
// NOTE: in Qt6 clip true will be default
clip: true
topMargin: topPadding
+3 -1
View File
@@ -62,7 +62,9 @@ QtObject {
'violet': '#D37EF4',
'yellow': '#FFCA0F',
'yellow2': '#EAD27B'
'yellow2': '#EAD27B',
'blueHijab': '#CDF2FB'
}
}
+3 -89
View File
@@ -4,95 +4,7 @@ ThemePalette {
name: "dark"
property QtObject baseFont: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Regular.otf"
}
property QtObject baseFontThin: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Thin.otf"
}
property QtObject baseFontExtraLight: FontLoader {
source: "../../../assets/fonts/Inter/Inter-ExtraLight.otf"
}
property QtObject baseFontLight: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Light.otf"
}
property QtObject baseFontMedium: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Medium.otf"
}
property QtObject baseFontBold: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Bold.otf"
}
property QtObject baseFontExtraBold: FontLoader {
source: "../../../assets/fonts/Inter/Inter-ExtraBold.otf"
}
property QtObject baseFontBlack: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Black.otf"
}
property QtObject monoFont: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Regular.otf"
}
property QtObject monoFontThin: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Thin.otf"
}
property QtObject monoFontExtraLight: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-ExtraLight.otf"
}
property QtObject monoFontLight: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Light.otf"
}
property QtObject monoFontMedium: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Medium.otf"
}
property QtObject monoFontBold: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Bold.otf"
}
property QtObject monoFontExtraBold: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-ExtraBold.otf"
}
property QtObject monoFontBlack: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Black.otf"
}
property QtObject codeFont: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Regular.ttf"
}
property QtObject codeFontThin: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Thin.ttf"
}
property QtObject codeFontExtraLight: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-ExtraLight.ttf"
}
property QtObject codeFontLight: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Light.ttf"
}
property QtObject codeFontMedium: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Medium.ttf"
}
property QtObject codeFontBold: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Bold.ttf"
}
property color dropShadow: getColor('black', 0.08)
dropShadow: getColor('black', 0.08)
baseColor1: getColor('graphite5')
baseColor2: getColor('graphite4')
@@ -147,6 +59,8 @@ ThemePalette {
miscColor11: getColor('yellow2')
miscColor12: getColor('green6')
statusFloatingButtonHighlight: getColor('blue4', 0.3)
userCustomizationColors: [
"#AAC6FF",
"#887AF9",
+2 -88
View File
@@ -4,94 +4,6 @@ ThemePalette {
name: "light"
property QtObject baseFont: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Regular.otf"
}
property QtObject baseFontThin: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Thin.otf"
}
property QtObject baseFontExtraLight: FontLoader {
source: "../../../assets/fonts/Inter/Inter-ExtraLight.otf"
}
property QtObject baseFontLight: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Light.otf"
}
property QtObject baseFontMedium: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Medium.otf"
}
property QtObject baseFontBold: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Bold.otf"
}
property QtObject baseFontExtraBold: FontLoader {
source: "../../../assets/fonts/Inter/Inter-ExtraBold.otf"
}
property QtObject baseFontBlack: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Black.otf"
}
property QtObject monoFont: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Regular.otf"
}
property QtObject monoFontThin: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Thin.otf"
}
property QtObject monoFontExtraLight: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-ExtraLight.otf"
}
property QtObject monoFontLight: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Light.otf"
}
property QtObject monoFontMedium: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Medium.otf"
}
property QtObject monoFontBold: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Bold.otf"
}
property QtObject monoFontExtraBold: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-ExtraBold.otf"
}
property QtObject monoFontBlack: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Black.otf"
}
property QtObject codeFont: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Regular.ttf"
}
property QtObject codeFontThin: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Thin.ttf"
}
property QtObject codeFontExtraLight: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-ExtraLight.ttf"
}
property QtObject codeFontLight: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Light.ttf"
}
property QtObject codeFontMedium: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Medium.ttf"
}
property QtObject codeFontBold: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Bold.ttf"
}
baseColor1: getColor('grey5')
baseColor2: getColor('grey4')
baseColor3: getColor('grey3')
@@ -145,6 +57,8 @@ ThemePalette {
miscColor11: getColor('brown2')
miscColor12: getColor('green5')
statusFloatingButtonHighlight: getColor('blueHijab')
userCustomizationColors: [
"#2946C4",
"#887AF9",
-2
View File
@@ -10,5 +10,3 @@ QtObject {
palette = theme
}
}
+91 -22
View File
@@ -6,30 +6,93 @@ QtObject {
property string name
property FontLoader baseFont
property FontLoader baseFontThin
property FontLoader baseFontExtraLight
property FontLoader baseFontLight
property FontLoader baseFontMedium
property FontLoader baseFontBold
property FontLoader baseFontExtraBold
property FontLoader baseFontBlack
property var baseFont: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Regular.otf"
}
property FontLoader monoFont
property FontLoader monoFontThin
property FontLoader monoFontExtraLight
property FontLoader monoFontLight
property FontLoader monoFontMedium
property FontLoader monoFontBold
property FontLoader monoFontExtraBold
property FontLoader monoFontBlack
property var baseFontThin: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Thin.otf"
}
property FontLoader codeFont
property FontLoader codeFontThin
property FontLoader codeFontExtraLight
property FontLoader codeFontLight
property FontLoader codeFontMedium
property FontLoader codeFontBold
property var baseFontExtraLight: FontLoader {
source: "../../../assets/fonts/Inter/Inter-ExtraLight.otf"
}
property var baseFontLight: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Light.otf"
}
property var baseFontMedium: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Medium.otf"
}
property var baseFontBold: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Bold.otf"
}
property var baseFontExtraBold: FontLoader {
source: "../../../assets/fonts/Inter/Inter-ExtraBold.otf"
}
property var baseFontBlack: FontLoader {
source: "../../../assets/fonts/Inter/Inter-Black.otf"
}
property var monoFont: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Regular.otf"
}
property var monoFontThin: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Thin.otf"
}
property var monoFontExtraLight: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-ExtraLight.otf"
}
property var monoFontLight: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Light.otf"
}
property var monoFontMedium: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Medium.otf"
}
property var monoFontBold: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Bold.otf"
}
property var monoFontExtraBold: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-ExtraBold.otf"
}
property var monoFontBlack: FontLoader {
source: "../../../assets/fonts/InterStatus/InterStatus-Black.otf"
}
property var codeFont: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Regular.ttf"
}
property var codeFontThin: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Thin.ttf"
}
property var codeFontExtraLight: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-ExtraLight.ttf"
}
property var codeFontLight: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Light.ttf"
}
property var codeFontMedium: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Medium.ttf"
}
property var codeFontBold: FontLoader {
source: "../../../assets/fonts/RobotoMono/RobotoMono-Bold.ttf"
}
property color black: getColor('black')
property color white: getColor('white')
@@ -37,6 +100,10 @@ QtObject {
property color dropShadow: getColor('black', 0.12)
property color backdropColor: getColor('black', 0.4)
function hoverColor(normalColor) {
return theme.name === "light" ? Qt.darker(normalColor, 1.1) : Qt.lighter(normalColor, 1.1)
}
property color baseColor1
property color baseColor2
property color baseColor3
@@ -90,6 +157,8 @@ QtObject {
property color miscColor11
property color miscColor12
property color statusFloatingButtonHighlight
property var userCustomizationColors: []
property var identiconRingColors: []
+6 -1
View File
@@ -19,7 +19,7 @@ QtObject {
"svg": "svg"
}
property string base: Qt.resolvedUrl("../../../assets/twemoji/")
property var emojiJSON: EmojiJSON
function parse(text, renderSize = size.small, renderFormat = format.svg) {
const renderSizes = renderSize.split("x");
if (!renderSize.includes("x") || renderSizes.length !== 2) {
@@ -43,6 +43,11 @@ QtObject {
}
})
}
function iconSource(text) {
const parsed = parse(text);
const match = parsed.match('src="(.*\.svg).*"');
return (match && match.length >= 2) ? match[1] : undefined;
}
function iconId(text) {
const parsed = parse(text);
const match = parsed.match('src=".*\/(.+?).svg');
+23
View File
@@ -150,6 +150,29 @@ QtObject {
context.stroke();
}
}
function delegateModelSort(srcGroup, dstGroup, lessThan) {
const insertPosition = (lessThan, item) => {
let lower = 0
let upper = dstGroup.count
while (lower < upper) {
const middle = Math.floor(lower + (upper - lower) / 2)
const result = lessThan(item.model, dstGroup.get(middle).model);
if (result)
upper = middle
else
lower = middle + 1
}
return lower
}
while (srcGroup.count > 0) {
const item = srcGroup.get(0)
const index = insertPosition(lessThan, item)
item.groups = dstGroup.name
dstGroup.move(item.itemsIndex, index)
}
}
}
-1
View File
@@ -1,5 +1,4 @@
module StatusQ.Core.Utils
EmojiJSON 1.0 emojiList.js
singleton Utils 0.1 Utils.qml
singleton Emoji 0.1 Emoji.qml
+19 -1
View File
@@ -21,6 +21,7 @@ Rectangle {
property int communityTypeValue: -1
property int navBarButtonSpacing: 12
property StatusNavBarTabButton navBarCameraButton
property StatusNavBarTabButton navBarProfileButton
property Component regularNavBarButton
property Component communityNavBarButton
@@ -37,6 +38,12 @@ Rectangle {
}
}
onNavBarCameraButtonChanged: {
if (!!navBarCameraButton) {
navBarCameraButton.parent = navBarCameraButtonSlot
}
}
function triggerUpdate(){
navBarModel.update()
}
@@ -162,6 +169,17 @@ Rectangle {
model: navBarModel
}
Item {
id: navBarCameraButtonSlot
anchors.horizontalCenter: parent.horizontalCenter
height: visible? statusAppNavBar.navBarProfileButton.height : 0
width: visible? statusAppNavBar.navBarProfileButton.width : 0
visible: !!statusAppNavBar.navBarCameraButton
anchors.bottom: navBarProfileButtonSlot.visible ? navBarProfileButtonSlot.top : parent.bottom
anchors.bottomMargin: visible ? 12 : 0
}
Item {
id: navBarProfileButtonSlot
anchors.horizontalCenter: parent.horizontalCenter
@@ -169,6 +187,6 @@ Rectangle {
width: visible? statusAppNavBar.navBarProfileButton.width : 0
visible: !!statusAppNavBar.navBarProfileButton
anchors.bottom: parent.bottom
anchors.bottomMargin: visible ? 32 : 0
anchors.bottomMargin: visible ? 24 : 0
}
}
@@ -5,7 +5,7 @@ import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
FocusScope {
id: statusAppTwoPanelLayout
implicitWidth: 822
+1 -4
View File
@@ -22,10 +22,7 @@ Dialog {
color: Theme.palette.backdropColor
}
background: Rectangle {
color: Theme.palette.statusModal.backgroundColor
radius: 8
}
background: StatusDialogBackground {}
header: StatusDialogHeader {
visible: root.title
@@ -0,0 +1,7 @@
import QtQuick 2.14
import StatusQ.Core.Theme 0.1
Rectangle {
color: Theme.palette.statusModal.backgroundColor
radius: 8
}
+1
View File
@@ -6,3 +6,4 @@ StatusDialogFooter 0.1 StatusDialogFooter.qml
StatusDialogHeader 0.1 StatusDialogHeader.qml
StatusHeaderActions 0.1 StatusHeaderActions.qml
StatusTitleSubtitle 0.1 StatusTitleSubtitle.qml
StatusDialogBackground 0.1 StatusDialogBackground.qml
+9 -1
View File
@@ -9,19 +9,27 @@ Action {
Normal,
Danger
}
icon.color: "transparent"
property int type: StatusMenuItem.Type.Normal
property real iconRotation: 0
// TODO: Rename to "imageSettings"
property StatusImageSettings image: StatusImageSettings {
height: 16
width: 16
isIdenticon: false
}
property StatusIconSettings iconSettings: StatusIconSettings {
width: 18
height: 18
rotation: 0
isLetterIdenticon: false
background: StatusIconBackgroundSettings {}
color: "transparent"
}
property StatusFontSettings fontSettings: StatusFontSettings {}
icon.color: "transparent"
}
+118 -126
View File
@@ -7,140 +7,139 @@ import StatusQ.Components 0.1
import StatusQ.Popups 0.1
MenuItem {
id: statusPopupMenuItem
id: root
implicitWidth: parent ? parent.width : 0
implicitHeight: action.enabled ? 38 : 0
objectName: action.objectName
implicitHeight: menu.hideDisabledItems && !enabled ? 0 : 38
objectName: action ? action.objectName : "StatusMenuItemDelegate"
property int subMenuIndex
property var statusPopupMenu: null
// property int subMenuIndex
// property var statusPopupMenu: null
Component.onCompleted: {
if (!!subMenu) {
subMenuIndex = statusPopupMenu.menuItemCount
statusPopupMenu.menuItemCount += 1
}
}
readonly property string logObjectName: "StatusMenuItemDelegate [%1, %2]".arg(this).arg(text)
// Component.onCompleted: {
// console.log("<---", logObjectName, " completed:", statusPopupMenu, menu, subMenu, action)
// }
// onMenuChanged: console.log("<--- ", logObjectName, " menu changed: ", menu)
// onActionChanged: console.log("<--- ", logObjectName, " action changed: ", action, action.text, text)
action: StatusMenuItem {
onTriggered: { statusPopupMenu.menuItemClicked(statusPopupMenuItem.subMenuIndex); }
// onTriggered: { statusPopupMenu.menuItemClicked(root.subMenuIndex); }
}
QtObject {
id: d
readonly property bool isSubMenu: !!root.subMenu
readonly property bool isStatusSubMenu: isSubMenu && (root.subMenu instanceof StatusPopupMenu)
readonly property bool hasAction: !!root.action
readonly property bool isStatusAction: d.hasAction && (root.action instanceof StatusMenuItem)
readonly property bool isDangerIcon: d.isStatusAction && root.action.type === StatusMenuItem.Type.Danger
readonly property StatusImageSettings imageSettings: d.isStatusSubMenu
? root.subMenu.imageSettings
: d.isStatusAction ? root.action.image : d.defaultImage
readonly property StatusIconSettings iconSettings: {
console.log("<<<--- Calling iconSettings", root.logObjectName)
return d.isStatusSubMenu
? root.subMenu.iconSettings
: d.isStatusAction ? root.action.iconSettings : d.defaultIcon
}
readonly property StatusFontSettings fontSettings: d.isStatusSubMenu
? root.subMenu.fontSettings
: d.isStatusAction ? root.action.fontSettings : d.defaultFontSettings
readonly property StatusImageSettings defaultImage: StatusImageSettings {
width: 16
height: 16
}
readonly property StatusIconSettings defaultIcon: StatusIconSettings {
width: 18
height: 18
rotation: 0
}
readonly property StatusFontSettings defaultFontSettings: StatusFontSettings {
pixelSize: 13
bold: false
italic: false
}
}
Component {
id: indicatorComponent
Item {
implicitWidth: 24
implicitHeight: 24
StatusIcon {
anchors.centerIn: parent
width: {
let width = statusPopupMenuItem.action && statusPopupMenuItem.action.icon.width ||
statusPopupMenuItem.action.iconSettings && statusPopupMenuItem.action.iconSettings.width
return !!width ? width : 18
}
rotation: !!statusPopupMenuItem.action.iconRotation ? statusPopupMenuItem.action.iconRotation : 0
icon: {
if (statusPopupMenuItem.subMenu && !!statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex] &&
statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex].icon.toString() !== "") {
return statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex].icon;
} else if (!!statusPopupMenuItem.action && statusPopupMenuItem.action.icon.name !== "") {
return statusPopupMenuItem.action.icon.name;
} else if (!!statusPopupMenuItem.action.iconSettings && statusPopupMenuItem.action.iconSettings.name !== "") {
return statusPopupMenuItem.action.iconSettings.name;
} else {
return "";
}
}
color: {
let c = !!statusPopupMenuItem.action.iconSettings && statusPopupMenuItem.action.iconSettings.color ||
!!statusPopupMenuItem.action && statusPopupMenuItem.action.icon.color
id: indicatorIcon
if (!Qt.colorEqual(c, "transparent")) {
return c
}
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
default:
return Theme.palette.primaryColor1
}
}
StatusIcon {
width: d.iconSettings.width // TODO: Also process action.icon.width?
height: d.iconSettings.height // TODO: Also process action.icon.height?
rotation: d.iconSettings.rotation // TODO: Also process action.icon.rotation? // !!root.action.iconRotation ? root.action.iconRotation : 0
icon: d.iconSettings.name // TODO: Also process action.icon?
color: {
const c = d.iconSettings.color;
if (!Qt.colorEqual(c, "transparent"))
return c;
if (d.isDangerIcon)
return Theme.palette.dangerColor1;
return Theme.palette.primaryColor1;
}
}
}
Component {
id: statusLetterIdenticonCmp
Item {
implicitWidth: 24
implicitHeight: 24
id: indicatorLetterIdenticon
StatusLetterIdenticon {
anchors.centerIn: parent
width: 16
height: 16
color: {
let subMenuItemIcon = statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex]
return subMenuItemIcon && subMenuItemIcon.color ? subMenuItemIcon.color : statusPopupMenuItem.action.iconSettings.background.color
}
name: statusPopupMenuItem.text
letterSize: 11
}
StatusLetterIdenticon {
width: d.imageSettings.width
height: d.imageSettings.height
color: d.iconSettings.color
name: root.text
letterSize: 11
}
}
Component {
id: statusRoundImageCmp
id: indicatorImage
Item {
implicitWidth: 24
implicitHeight: 24
StatusRoundedImage {
anchors.centerIn: parent
width: statusPopupMenuItem.action.image.width
height: statusPopupMenuItem.action.image.height
image.source: statusPopupMenuItem.subMenu ?
statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex].source :
statusPopupMenuItem.action.image.source
border.width: (statusPopupMenuItem.subMenu && statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex].isIdenticon) ||
statusPopupMenuItem.action.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
StatusRoundedImage {
width: d.imageSettings.width
height: d.imageSettings.height
image.source: d.imageSettings.source
border.width: d.isSubMenu && d.imageSettings.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
}
indicator: Loader {
sourceComponent: {
let subMenuItemIcon = statusPopupMenu.subMenuItemIcons && statusPopupMenu.subMenuItemIcons[parent.subMenuIndex]
if ((parent.subMenu && subMenuItemIcon && subMenuItemIcon.source) ||
statusPopupMenuItem.action.image && !!statusPopupMenuItem.action.image.source.toString()) {
return statusRoundImageCmp
}
indicator: Item {
implicitWidth: 24
implicitHeight: 24
Loader {
anchors.centerIn: parent
// sourceComponent: {
// if (!!d.imageSettings.source.toString())
// return indicatorImage;
// if (d.iconSettings.isLetterIdenticon)
// return indicatorLetterIdenticon;
// return indicatorIcon;
// }
return (parent.subMenu && subMenuItemIcon && subMenuItemIcon.isLetterIdenticon) ||
(statusPopupMenuItem.action.iconsSettings && statusPopupMenuItem.action.iconSettings.isLetterIdenticon) ?
statusLetterIdenticonCmp : indicatorComponent
// sourceComponent: indicatorIcon
// sourceComponent: indicatorLetterIdenticon
// sourceComponent: indicatorImage
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
// active: enabled // TODO: Also process action.icon.name ?
// && (d.iconSettings.isLetterIdenticon
// || !!d.iconSettings.name
// || !!d.imageSettings.source.toString())
}
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
active: {
if (enabled) {
let hasIconSettings = !!statusPopupMenuItem.action.icon.name ||
(statusPopupMenuItem.action.iconSettings &&
(!!statusPopupMenuItem.action.iconSettings.name || !!statusPopupMenuItem.action.iconSettings.isLetterIdenticon))
let hasImageSettings = statusPopupMenuItem.action.image && !!statusPopupMenuItem.action.image.source.toString()
return enabled && (parent.subMenu && !!statusPopupMenu.subMenuItemIcons[parent.subMenuIndex]) || hasIconSettings || hasImageSettings
}
return false
}
}
contentItem: StatusBaseText {
anchors.left: statusPopupMenuItem.indicator.right
anchors.left: root.indicator.right
anchors.right: arrowIcon.visible ? arrowIcon.left : arrowIcon.right
anchors.rightMargin: 8
anchors.leftMargin: 4
@@ -148,20 +147,13 @@ MenuItem {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: statusPopupMenuItem.text
color: {
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
default:
return Theme.palette.directColor1
}
}
font.pixelSize: !!statusPopupMenuItem.action.fontSettings ? statusPopupMenuItem.action.fontSettings.pixelSize : 13
font.bold: !!statusPopupMenuItem.action.fontSettings ? statusPopupMenuItem.action.fontSettings.bold : false
font.italic: !!statusPopupMenuItem.action.fontSettings ? statusPopupMenuItem.action.fontSettings.italic : false
text: root.text
color: d.isDangerIcon ? Theme.palette.dangerColor1 : Theme.palette.directColor1
font.pixelSize: d.fontSettings.pixelSize // !!root.action.fontSettings ? root.action.fontSettings.pixelSize : 13
font.bold: d.fontSettings.bold // !!root.action.fontSettings ? root.action.fontSettings.bold : false
font.italic: d.fontSettings.italic // !!root.action.fontSettings ? root.action.fontSettings.italic : false
elide: Text.ElideRight
visible: statusPopupMenuItem.action.enabled
visible: true // hideDisabledItems ? root.enabled : true
}
arrow: StatusIcon {
@@ -170,25 +162,25 @@ MenuItem {
anchors.right: parent.right
anchors.rightMargin: 8
height: 16
visible: statusPopupMenuItem.subMenu
visible: d.isSubMenu
icon: "next"
color: Theme.palette.directColor1
}
background: Rectangle {
color: {
if (statusPopupMenuItem.hovered) {
return statusPopupMenuItem.action.type === StatusMenuItem.Type.Danger ? Theme.palette.dangerColor3 : Theme.palette.statusPopupMenu.hoverBackgroundColor
}
return "transparent"
if (!root.hovered)
return "transparent"
if (root.action.type === StatusMenuItem.Type.Danger)
return Theme.palette.dangerColor3;
return Theme.palette.statusPopupMenu.hoverBackgroundColor;
}
}
MouseArea {
id: sensor
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: statusPopupMenuItem.action.enabled
hoverEnabled: root.enabled // WARNING: use root.enabled ?
onPressed: mouse.accepted = false
}
}
+16 -23
View File
@@ -33,8 +33,7 @@ import "statusModal" as Spares
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
icon.name: "arrow-left"
}
]
rightButtons: [
@@ -54,20 +53,18 @@ import "statusModal" as Spares
// Deprecation annotations come with Qt6.2
// @Deprecated { reason: "Use StatusDialog instead, see reasoning: https://github.com/status-im/StatusQ/issues/720" }
QC.Popup {
id: statusModal
id: root
/*!
\qmlproperty advancedHeader
This property represents the item loaded in header loader.
Can be used to read values from the component assigned to the loader.
\endqml
*/
property alias advancedHeader: advancedHeader.item
/*!
\qmlproperty advancedHeader
This property represents the item loaded in footer loader.
Can be used to read values from the component assigned to the loader.
\endqml
*/
property alias advancedFooter: advancedFooter.item
/*!
@@ -130,7 +127,6 @@ QC.Popup {
\qmlproperty headerActionButton
This property lets the user add a button to the header of the Modal.
This does not apply to the advanced header!
\endqml
*/
property alias headerActionButton: headerImpl.actionButton
@@ -138,63 +134,59 @@ QC.Popup {
\qmlproperty header
type: StatusModalHeaderSettings
This property exposes the different properties of the standard header.
\endqml
*/
property StatusModalHeaderSettings header: StatusModalHeaderSettings {}
/*!
\qmlproperty rightButtons
This property helps user assign the right buttons on the footer.
This doesn't not apply to the advanced footer!
\endqml
*/
property alias rightButtons: footerImpl.rightButtons
/*!
\qmlproperty rightButtons
This property helps user assign the left buttons on the footer.
This doesn't not apply to the advanced footer!
\endqml
*/
property alias leftButtons: footerImpl.leftButtons
/*!
\qmlproperty showHeader
This property to decides whether the standard header is shown.
default value is true
\endqml
*/
property bool showHeader: true
/*!
\qmlproperty showHeader
This property to decides whether the standard footer is shown.
default value is true
\endqml
*/
property bool showFooter: true
/*!
\qmlproperty showAdvancedHeader
This property to decides whether the advanced header is shown.
default value is false.
\endqml
*/
property bool showAdvancedHeader: false
/*!
\qmlproperty showAdvancedFooter
This property decides whether the advanced footer is shown.
default value is false.
\endqml
*/
property bool showAdvancedFooter: false
/*!
\qmlproperty hasCloseButton
This property decides whether the standard header has a close button.s
\endqml
*/
property alias hasCloseButton: headerImpl.hasCloseButton
/*!
\qmlproperty hasFloatingButtons
This property decides whether the advanced header has floating buttons on top of the Modal
\endqml
*/
property bool hasFloatingButtons: false
/*!
\qmlproperty color backgroundColor
This property decides the modal background color
*/
property string backgroundColor: Theme.palette.statusModal.backgroundColor
signal editButtonClicked()
signal headerImageClicked()
@@ -219,7 +211,7 @@ QC.Popup {
}
background: Rectangle {
color: Theme.palette.statusModal.backgroundColor
color: root.backgroundColor
radius: 8
Spares.StatusModalHeader {
@@ -227,7 +219,7 @@ QC.Popup {
anchors.top: parent.top
width: visible ? parent.width : 0
visible: statusModal.showHeader
visible: root.showHeader
title: header.title
titleElide: header.titleElide
subTitle: header.subTitle
@@ -238,9 +230,9 @@ QC.Popup {
headerImageEditable: header.headerImageEditable
editable: header.editable
onEditButtonClicked: statusModal.editButtonClicked()
onHeaderImageClicked: statusModal.headerImageClicked()
onClose: statusModal.close()
onEditButtonClicked: root.editButtonClicked()
onHeaderImageClicked: root.headerImageClicked()
onClose: root.close()
}
Loader {
@@ -248,21 +240,22 @@ QC.Popup {
anchors.top: parent.top
anchors.topMargin: hasFloatingButtons ? -18 - height : 0
width: visible ? parent.width : 0
active: statusModal.showAdvancedHeader
active: root.showAdvancedHeader
}
Spares.StatusModalFooter {
id: footerImpl
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
showFooter: statusModal.showFooter
showFooter: root.showFooter
visible: root.showFooter
}
Loader {
id: advancedFooter
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
active: statusModal.showAdvancedFooter
active: root.showAdvancedFooter
}
}
}
+41 -5
View File
@@ -10,20 +10,56 @@ import StatusQ.Popups 0.1
Menu {
id: root
// Component.onCompleted: {
// let parents = "";
// let p = parent;
// while (p) {
// parents += " <- " + p;
// p = p.parent;
// }
//// console.log("<-- StatusPopupMenu created", this, parents);
// }
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
topPadding: 8
bottomPadding: 8
property int menuItemCount: 0
property var subMenuItemIcons: []
// property int menuItemCount: 0
// property var subMenuItemIcons: []
// source: model.imageSource, // -> StatusRoundedImage.image.source
// icon: model.iconName, // -> StatusIcon.icon
// isIdenticon: model.isIdenticon, // -> StatusRoundImage.border.width
// color: model.iconColor, // -> StatusLetterIdenticon.color,
// isLetterIdenticon: !model.imageSource && !model.iconName // -> decide indicator component
property StatusImageSettings imageSettings: StatusImageSettings {
height: 16
width: 16
isIdenticon: false
}
property StatusIconSettings iconSettings: StatusIconSettings {
width: 18
height: 18
rotation: 0
isLetterIdenticon: false
background: StatusIconBackgroundSettings {}
color: "transparent"
}
property StatusFontSettings fontSettings: StatusFontSettings {}
property bool hideDisabledItems: false
property var openHandler
property var closeHandler
dim: false
signal menuItemClicked(int menuIndex)
dim: false
onOpened: {
if (typeof openHandler === "function") {
openHandler()
@@ -37,7 +73,7 @@ Menu {
}
delegate: StatusMenuItemDelegate {
statusPopupMenu: root
// statusPopupMenu: root
}
background: Item {
@@ -28,6 +28,8 @@ StatusPopupMenu {
MenuItem { implicitHeight: 0.00001 }
Instantiator {
model: root.locationModel
// NOTE: Use DelegateChooser here
delegate: Loader {
sourceComponent: (!!model.subItems && model.subItems.count > 0) ? subMenus : subMenuItemComponent
onLoaded: {
@@ -38,13 +40,20 @@ StatusPopupMenu {
item.parentIconName = model.iconName;
item.parentImageSource = model.imageSource;
item.parentIdenticonColor = !!model.iconColor ? model.iconColor : Theme.palette.primaryColor1;
root.subMenuItemIcons.push({
source: model.imageSource,
icon: model.iconName,
isIdenticon: model.isIdenticon,
color: model.iconColor,
isLetterIdenticon: !model.imageSource && !model.iconName
});
item.imageSettings.source = model.imageSource;
item.imageSettings.isIdenticon = model.isIdenticon;
item.iconSettings.name = model.iconName;
item.iconSettings.color = model.iconColor;
item.iconSettings.isLetterIdenticon = !model.imageSource && !model.iconName;
// root.subMenuItemIcons.push({
// source: model.imageSource, // -> StatusRoundedImage.image.source
// icon: model.iconName, // -> StatusIcon.icon
// isIdenticon: model.isIdenticon, // -> StatusRoundImage.border.width
// color: model.iconColor, // -> StatusLetterIdenticon.color,
// isLetterIdenticon: !model.imageSource && !model.iconName // -> decide indicator component
// });
root.insertMenu(index + numDefaultItems, item);
} else {
item.value = model.value
+3 -2
View File
@@ -30,6 +30,7 @@ StatusModal {
signal resultItemClicked(string itemId)
signal resultItemTitleClicked(string titleId)
signal resetSearchLocationClicked()
property var formatTimestampFn: function (ts) {
return ts
@@ -60,7 +61,7 @@ StatusModal {
}
function forceActiveFocus() {
contentItem.searchInput.edit.forceActiveFocus()
contentItem.searchInput.input.edit.forceActiveFocus()
}
onOpened: {
@@ -248,7 +249,7 @@ StatusModal {
type: StatusFlatRoundButton.Type.Secondary
icon.name: "close"
icon.color: Theme.palette.directColor1
onClicked: { root.resetSearchSelection(); }
onClicked: { root.resetSearchLocationClicked(); }
}
}
StatusMenuSeparator {
+2 -6
View File
@@ -52,12 +52,8 @@ StatusModal {
? replaceLoader.item.title : stackTitle
padding: 16
leftButtons: StatusRoundButton {
leftButtons: StatusBackButton {
id: backButton
icon.name: "arrow-right"
icon.width: 20
icon.height: 16
rotation: 180
visible: replaceItem || stackLayout.currentIndex > 0
onClicked: {
if (replaceItem) {
@@ -94,7 +90,7 @@ StatusModal {
anchors.top: subHeaderLoader.bottom
anchors.topMargin: subHeaderLoader.item && subHeaderLoader.item.visible ? root.subHeaderPadding : 0
anchors.bottom: parent.bottom
width: parent.width
width: root.availableWidth
visible: !replaceItem
clip: true
}
+7
View File
@@ -0,0 +1,7 @@
<svg width="24" height="20" viewBox="0 0 24 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.754547 10C0.754547 9.58579 1.09033 9.25 1.50455 9.25H22.4954C22.9096 9.25 23.2454 9.58579 23.2454 10C23.2454 10.4142 22.9096 10.75 22.4954 10.75H1.50455C1.09033 10.75 0.754547 10.4142 0.754547 10Z" fill="#939BA1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.75317C2 2.12982 4.12665 0.00317383 6.75 0.00317383H8.75C9.16421 0.00317383 9.5 0.33896 9.5 0.753174C9.5 1.16739 9.16421 1.50317 8.75 1.50317H6.75C4.95507 1.50317 3.5 2.95825 3.5 4.75317V6.54037C3.5 6.95458 3.16421 7.29037 2.75 7.29037C2.33579 7.29037 2 6.95458 2 6.54037V4.75317Z" fill="#939BA1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 15.25C2 17.8734 4.12665 20 6.75 20H8.75C9.16421 20 9.5 19.6642 9.5 19.25C9.5 18.8358 9.16421 18.5 8.75 18.5H6.75C4.95507 18.5 3.5 17.0449 3.5 15.25V13.4628C3.5 13.0486 3.16421 12.7128 2.75 12.7128C2.33579 12.7128 2 13.0486 2 13.4628V15.25Z" fill="#939BA1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 4.75317C22 2.12982 19.8734 0.00317383 17.25 0.00317383H15.25C14.8358 0.00317383 14.5 0.33896 14.5 0.753174C14.5 1.16739 14.8358 1.50317 15.25 1.50317H17.25C19.0449 1.50317 20.5 2.95825 20.5 4.75317V6.54037C20.5 6.95458 20.8358 7.29037 21.25 7.29037C21.6642 7.29037 22 6.95458 22 6.54037V4.75317Z" fill="#939BA1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 15.25C22 17.8734 19.8734 20 17.25 20H15.25C14.8358 20 14.5 19.6642 14.5 19.25C14.5 18.8358 14.8358 18.5 15.25 18.5H17.25C19.0449 18.5 20.5 17.0449 20.5 15.25V13.4628C20.5 13.0486 20.8358 12.7128 21.25 12.7128C21.6642 12.7128 22 13.0486 22 13.4628V15.25Z" fill="#939BA1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+4 -1
View File
@@ -15,6 +15,7 @@
<file>StatusQ/Components/private/statusMessage/StatusTimeStampLabel.qml</file>
<file>StatusQ/Components/qmldir</file>
<file>StatusQ/Components/StatusAddress.qml</file>
<file>StatusQ/Components/StatusAddressPanel.qml</file>
<file>StatusQ/Components/StatusBadge.qml</file>
<file>StatusQ/Components/StatusCard.qml</file>
<file>StatusQ/Components/StatusChatInfoToolBar.qml</file>
@@ -29,6 +30,7 @@
<file>StatusQ/Components/StatusCommunityTags.qml</file>
<file>StatusQ/Components/StatusContactRequestsIndicatorListItem.qml</file>
<file>StatusQ/Components/StatusContactVerificationIcons.qml</file>
<file>StatusQ/Components/StatusDatePicker.qml</file>
<file>StatusQ/Components/StatusDescriptionListItem.qml</file>
<file>StatusQ/Components/StatusEmoji.qml</file>
<file>StatusQ/Components/StatusExpandableItem.qml</file>
@@ -66,7 +68,6 @@
<file>StatusQ/Controls/qmldir</file>
<file>StatusQ/Controls/StatusAccountSelector.qml</file>
<file>StatusQ/Controls/StatusActivityCenterButton.qml</file>
<file>StatusQ/Controls/StatusAssetSelector.qml</file>
<file>StatusQ/Controls/StatusBanner.qml</file>
<file>StatusQ/Controls/StatusBaseButton.qml</file>
<file>StatusQ/Controls/StatusBaseInput.qml</file>
@@ -113,6 +114,7 @@
<file>StatusQ/Controls/StatusToolTip.qml</file>
<file>StatusQ/Controls/StatusWalletColorButton.qml</file>
<file>StatusQ/Controls/StatusWalletColorSelect.qml</file>
<file>StatusQ/Controls/StatusTextArea.qml</file>
<file>StatusQ/Core/Backpressure/Backpressure.qml</file>
<file>StatusQ/Core/Backpressure/LICENSE</file>
<file>StatusQ/Core/Backpressure/qmldir</file>
@@ -174,5 +176,6 @@
<file>StatusQ/Popups/StatusSpellcheckingMenuItems.qml</file>
<file>StatusQ/Popups/StatusStackModal.qml</file>
<file>StatusQ/qmldir</file>
<file>StatusQ/Components/StatusListPickerProxies.qml</file>
</qresource>
</RCC>
+6
View File
@@ -2,8 +2,14 @@ cmake_minimum_required(VERSION 3.5)
project(TestStatusQ LANGUAGES CXX)
# The current StatusQ builds with Qt 5.14 which doesn't support the apple silicon.
# Therefore force the intel architecture for MacOS platforms.
set(CMAKE_OSX_ARCHITECTURES "x86_64")
enable_testing()
set(CMAKE_AUTOMOC ON)
# TODO: Workaround until we make StatusQ a CMake library
list(APPEND QML_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../src/")
set(QML_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator extra qml import paths")