Compare commits

...
Author SHA1 Message Date
Pascal Precht 99b9e4f4f2 chore: cut 0.16.0 release 2021-11-01 10:49:14 +01:00
Pascal Precht da9dc2f46a fix(StatusModal): render footer correctly based on showFooter flag 2021-11-01 10:48:06 +01:00
Pascal Precht d301b94c70 feat(StatusQ.Platform): introduce StatusMacNotification component 2021-10-29 10:38:51 +02:00
Pascal Precht ea9a560277 feat(StatusQ.Controls): introduce StatusWalletColorSelect control
Usage:

```qml
StatusWalletColorSelect {
    model: Theme.palette.accountColors
}

```

Closes #467
2021-10-28 09:15:40 +02:00
Pascal Precht eb4aae4060 fix(StatusRoundButton): ensure disabled state uses correct background color 2021-10-27 18:00:11 +02:00
Pascal Precht 597ae19242 feat(StatusQ.Controls): introduce StatusWalletColorButton component
Usage:

```qml
StatusWalletColorButton {
    icon.color: Theme.palette.miscColor1
    selected: true
}
```

Closes #466
2021-10-27 17:59:50 +02:00
Pascal Precht 7e02a32f48 chore: release 0.15.0 2021-10-26 14:29:48 +02:00
Pascal Precht 4cc0d2bbca feat(StatusQ.Controls): introduce StatusChatCommandButton
Usage:

```qml
StatusChatCommandButton {
    icon.name: "send"
    icon.color: Theme.palette.miscColor2
    text: "Send transaction"
}
```

Closes #429
2021-10-26 14:26:42 +02:00
Pascal Precht 4bcd89b38a feat(StatusQ.Controls): introduce StatusTabBarIconButton component
Usage:

```qml
StatusTabBarIconButton {
    icon.name: "travel-and-places"
}
```

Closes #428
2021-10-26 14:26:30 +02:00
Pascal Precht 64b2a51c09 chore: cut 0.14.0 release 2021-10-25 12:00:59 +02:00
B.Melnik ab9ab2497b fix(Spellchecking): Add check for hunspell existence 2021-10-25 11:59:50 +02:00
Alexandra Betouni 98dab4ff82 fix(Popups/StatusMenuItemDelegate) adding checks to avoid undefined errors 2021-10-25 11:59:35 +02:00
Khushboo Mehta 1452748331 feat(StatusSmartIdenticon): Created a new StatusQ componnent to accomodate:
1. A StatusRoundedImage
2. StatusRoundIcon
3. LetterIdenticon

Fallback in case of an error in loading Image to the LetterIdenticon
2021-10-22 11:02:05 +02:00
Pascal Precht 074dc22ba5 fix(StatusModal): ensure onEditButtonClicked signal is emitted
Closes #454
2021-10-21 12:36:16 +02:00
Pascal Precht 9c5f79a695 fix(StatusModal): expose header.editable property
Fixes #452
2021-10-21 12:36:16 +02:00
Anastasiya S 6114c99311 chore(StatusChatInfoButton): add object name for pin counter for testing purposes 2021-10-20 09:22:35 +02:00
Anastasiya S 86f50edfdc chore(StatusChatInfoButton): add object name for testing purposes 2021-10-19 15:06:13 +02:00
Pascal Precht e945577e3c chore: cut 0.13.0 release 2021-10-19 09:49:21 +02:00
B.Melnik 8360d3e415 chore(ForTests): Add ojectName's for modals 2021-10-19 08:04:16 +02:00
Khushboo Mehta 71fbdef164 feat(StatusFlatRoundButton): Update the StatusFlatRoundButton to take over button behaviour from StatusIconButton under ui/shared/status
1. Added icon disabledColor property under StatusIconSettings
2. Added Tertiary and Quaternary type to accomodate hovered behavior needed in many buttons
3. Added a missing gif icon.
2021-10-19 08:04:00 +02:00
Pascal Precht 8aba017c24 fix: use proper double checkmark icon 2021-10-18 16:52:32 +02:00
Pascal Precht a37489204c fix(StatusBaseButton): introduce missing highlighted property 2021-10-18 16:47:51 +02:00
Pascal Precht dab12dc7c8 chore: cut 0.12.0 release 2021-10-18 10:17:15 +02:00
Pascal Precht 409c2ccafa chore: ignore cache files 2021-10-18 10:15:16 +02:00
B.Melnik e1b0f2dc9a feat: Resolve StatusQ modules highlighting and add qml compiler for detecting coompile time errors 2021-10-18 09:46:22 +02:00
Pascal Precht bdd699557d feat(StatusQ.Controls): introduce StatusColorSelector component
This is a select component to pick from various supplied colors.

Usage:

```qml
import StatusQ.Controls 0.1

StatusColorSelector {
    model: ["red", "blue", "green"]
}

```

Closes #444
2021-10-15 11:04:22 +02:00
Pascal Precht 9fdc9aeaa3 feat(StatusQ.Controls): introduce StatusAssetSelector component
This is used for a more complex amount and asset selector component.

Usage:

```qml
import StatusQ.Controls 0.1

StatusAssetSelector {
    assets: ListModel {
        ListElement {
            address: "0x1234"
            name: "Status Network Token"
            value: "20"
            symbol: "SNT"
            fiatBalance: "9992.01"
            fiatBalanceDisplay: "9992.01"
        }
        ListElement {
            address: "0x1234"
            name: "DAI Token"
            value: "20"
            symbol: "DAI"
            fiatBalance: "20"
            fiatBalanceDisplay: "20"
        }
    }
}
```

Closes #442
2021-10-15 11:03:31 +02:00
Pascal Precht 6789446df3 feat(StatusQ.Components): introduce StatusAddress component
This introduces a `StatusAddress` component which renders an address
and can be made `expandable` by applying a `width`:

```qml
import StatusQ.Components 0.1

// Simple case
StatusAddress {
    text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
}

// Expandable case
Item {
    width: 200
    height: childrenRect.height
    StatusAddress {
        text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
        expandable: true
        width: parent.width
    }
}

```

Closes #430
2021-10-15 11:02:41 +02:00
Pascal Precht 5e15cc49f6 feat(StatusQ.Controls): introduce StatusAccountSelector component
This commit moves the original `AccountSelector` into StatusQ and makes it
a `StatusAccountSelector`. The API has been preserved. The only difference is
that it's internally relying completely on `StatusQ.Core.Theme` and `StatusQ.Controls`
components instead.

Usage:

```qml
import StatusQ.Controls 0.1

StatusAccountSelector {
    accounts: ListModel {
        ListElement {
            name: "Pascal"
            address: "0x1234567891011"
            iconColor: "red"
            balance: "0"
            walletType: "generated"
            assets: []
            fiatBalance: "1199.02"
        }
        ListElement {
            name: "Boris"
            address: "0x123"
            iconColor: "red"
            balance: "0"
            walletType: "generated"
            assets: []
            fiatBalance: "0"
        }
        ListElement {
            name: "Alexandra"
            address: "0x123"
            iconColor: "yellow"
            balance: "0"
            walletType: "generated"
            assets: []
            fiatBalance: "0"
        }
        ListElement {
            name: "Khushboo"
            address: "0x123"
            iconColor: "blue"
            balance: "0"
            walletType: "generated"
            assets: []
            fiatBalance: "0"
        }
    }
}
```

Closes #435
2021-10-15 11:02:28 +02:00
Pascal Precht 6e10959e40 feat(StatusQ.Controls): introduce StatusSelect
This introduces a new `StatusSelect` component which is a select form control.
The `model` property can be used to apply a `ListModel` for dynamic data.
To give users full control over what the menu items look like, `StatusSelect`
exposes a `selectMenu.delegate` property.

Most of the time this should be a `StatusMenuItemDelegate` to get access to the
comple `MenuItem` component (remember that `StatusMenuItem` is merely an `Action`
type).

`StatusMenuItemDelegate` derives most of its behaviour by its applied `action`,
so the easiest way to construct a dynamic select with StatusQ menu item look and feel
is a combination of `StatusMenuItemDelegate` and `StatusMenuItem` as shown below.

Further more, because `StatusSelect` can't know what the `delegate` is going to look like
it also can't decide what data goes into a `selectedItem`. Therefore, it offers another API,
the `selectedItemComponent` which can be any component. This component can then be accessed
by menu item actions to set corresponding properties.

Usage:

```qml
import StatusQ.Controls 0.1

StatusSelect {
    label: "Some label"
    model: ListModel {
        ListElement {
            name: "Pascal"
        }
        ListElement {
            name: "Khushboo"
        }
        ListElement {
            name: "Alexandra"
        }
        ListElement {
            name: "Eric"
        }
    }

    selectMenu.delegate: StatusMenuItemDelegate {
        statusPopupMenu: select
        action: StatusMenuItem {
            iconSettings.name: "filled-account"
            text: name
            onTriggered: {
                selectedItem.text = name
            }
        }
    }

    selectedItemComponent: Item {
        id: selectedItem
        anchors.fill: parent
        property string text: ""

        StatusBaseText {
            text: selectedItem.text
            anchors.centerIn: parent
            color: Theme.palette.directColor1
        }
    }
}
```

Closes #436
2021-10-15 11:00:30 +02:00
Pascal Precht 0764e25a58 feat(StatusQ.Popups): introduce StatusMenuItemDelegate
This extracts the `MenuItem` delegate used in `StatusPopupMenu` into its
own component so it can be easily reused for cases where simply supplying the
popup menu with `StatusMenuItem` (which is of type `Action`) isn't enough.

Ideally, the `StatusMenuItemDelegate` would be called `StatusMenuItem` but that
would be a breaking change.

Usage:

```qml

StatusPopupMenu {
    delegate: StatusMenuItemDelegate {
        ...
    }
}
2021-10-15 11:00:18 +02:00
B.Melnik 5043b0b625 feat(StatusModal): Add edit avatar button
Part of https://github.com/status-im/status-desktop/issues/3734
2021-10-15 10:49:40 +02:00
Pascal Precht 694a4ca1ec chore: cut 0.11.1 release 2021-10-12 11:34:25 +02:00
Khushboo Mehta c276a90e73 fix(StatusChatInfoButton): StatusChatInfoButton takes up entire available width
fixes #432
2021-10-08 08:37:20 +02:00
Khushboo Mehta dce45c2ff3 fix: Sandbox doesn't build on Linux machines
fixes #423
2021-10-08 08:37:01 +02:00
Khushboo-dev-cpp d9da5bdc1d feature(StatusSelectableText): Added a selectable text component (#431)
Features:
1. Select text and copy it
2. Custom highlight on selection
3. Highlight on links
4. Support for multiline text
2021-09-29 15:22:23 -04:00
Pascal Precht b6a6e220f7 chore: cut v0.11.0 release 2021-09-27 10:52:07 +02:00
B.Melnik 478177f25e fix(StatusSpellcheckingMenuItems): Exact menu items order 2021-09-27 10:48:18 +02:00
Pascal Precht 654bd9f284 fix(StatusSearchPopup): use correct theme color for search result text
This used `Theme.palette.black` before which doesn't work across differen themes.
`Theme.palette.directColor1` is the correct one to use here.
2021-09-27 10:48:02 +02:00
Pascal Precht a2e3659d99 fix(StatusChatList): ensure right click popup opens in correct position
This broke because the emitted `mouse` coordinates where no longer correct
after we've moved the chat list item into a delegate model.
2021-09-27 10:47:38 +02:00
Eric Mastro 5c3267f7e6 feat: add star icons (#422) 2021-09-23 15:00:04 -04:00
Eric Mastro 0631d500e1 fix: track category opened state
Category `opened` state is tracked and restored on model change.

Previously, when the model data for categories and channels was changed, all unexpanded, or collapsed categories would automatically expand. This was due to the default state of the category `opened` property being restored (which was set to true) when the model data changed.

With this change in place, the opened state of each category is tracked in the parent component (`StatusChatListAndCategories`), and on each model change, the opened state is restored.

NOTE: it was tempting to the put the changes inside of the `StatusChatListCategory` component, however this would not work as the component is used as a delegate, and all state is wiped on each model change.
2021-09-23 15:05:17 +02:00
Pascal Precht 8f8cb336c2 chore: cut 0.10.0 release 2021-09-20 08:53:01 +02:00
B.Melnik 3e24b71075 feat(StatusSpellcheckingMenuItems): Add spellchecking menu
Closes: #398
2021-09-20 08:52:06 +02:00
Pascal Precht 40c0e48b04 feat(StatusChatList): expose statusChatListItems Repeater
Ever since we've moved to `DelegateModel` which is passed to the `Repeater`
which was previously aliased as `chatListItems`, we no longer get access to the
`model.itemAt` method. This is because `DelegateModel` doesn't have such a method.

So in order to restore that access, we have to expose `Repeater` additionally.

The reason this method is needed, is so that apps like Status Desktop can update
individual chat list items based on `Connection` events
2021-09-20 08:51:55 +02:00
Pascal Precht 8820cd89be feat(StatusInput): add support for asynchronous validators
Allows asynchronous validation, with the ability to track the validated value for use in the StatusInput as a value that is separate from the entered text.

Async operations are debounced internally to the StatusAsyncValidator.

- `validate`: the input value to this function is the value sent to `asyncComplete`, which must be called by the validator. Return true when the value from the async operation is valid.
- `asyncComplete`: signal to be called by the validator after the async operation has completed. It should contain the value returned by the async operation that should be validated in `validate`.
- `validatedValue`: This is the valid value returned from the async operation. It it tracked separately so that the input text on the `StatusInput` can remain as entered by the user. Use this property and the `onValidatedValueChanged` signal handler for the “real” value to be used by other components.

Closes #395
2021-09-20 08:49:36 +02:00
77 changed files with 3209 additions and 528 deletions
+1
View File
@@ -12,3 +12,4 @@ Makefile
.qmake.stash
*_qml.cpp
*_qmlcache.qrc
sandbox/qmlcache_loader.cpp
+137
View File
@@ -1,3 +1,140 @@
<a name=""></a>
## Version 0.16.0 (2021-11-01)
#### Bug Fixes
* **StatusModal:** render footer correctly based on `showFooter` flag ([da9dc2f4](da9dc2f4))
* **StatusRoundButton:** ensure disabled state uses correct background color ([eb4aae40](eb4aae40))
#### Features
* **StatusQ.Controls:**
* introduce `StatusWalletColorSelect` control ([ea9a5602](ea9a5602), closes [#467](467))
* introduce `StatusWalletColorButton` component ([597ae192](597ae192), closes [#466](466))
* **StatusQ.Platform:** introduce StatusMacNotification component ([d301b94c](d301b94c))
<a name=""></a>
## Version 0.15.0 (2021-10-26)
#### Features
* **StatusQ.Controls:**
* introduce StatusChatCommandButton ([4cc0d2bb](4cc0d2bb), closes [#429](429))
* introduce `StatusTabBarIconButton` component ([4bcd89b3](4bcd89b3), closes [#428](428))
<a name=""></a>
## Version 0.14.0 (2021-10-25)
#### Bug Fixes
* **Spellchecking:** Add check for hunspell existence ([ab9ab249](ab9ab249))
* **StatusModal:**
* ensure `onEditButtonClicked` signal is emitted ([074dc22b](074dc22b), closes [#454](454))
* expose `header.editable` property ([9c5f79a6](9c5f79a6), closes [#452](452))
#### Features
* **StatusSmartIdenticon:** Created a new StatusQ componnent to accomodate: ([14527483](14527483))
<a name=""></a>
## Version 0.13.0 (2021-10-19)
#### Bug Fixes
* use proper double checkmark icon ([8aba017c](8aba017c))
* **StatusBaseButton:** introduce missing `highlighted` property ([a3748920](a3748920))
#### Features
* **StatusFlatRoundButton:** Update the StatusFlatRoundButton to take over button behaviour from StatusIconButton under ui/shared/status ([71fbdef1](71fbdef1))
<a name=""></a>
## Version 0.12.0 (2021-10-18)
#### Features
* Resolve StatusQ modules highlighting and add qml compiler for detecting coompile time errors ([e1b0f2dc](e1b0f2dc))
* **StatusModal:** Add edit avatar button ([5043b0b6](5043b0b6))
* **StatusQ.Components:** introduce `StatusAddress` component ([6789446d](6789446d), closes [#430](430))
* **StatusQ.Controls:**
* introduce StatusColorSelector component ([bdd69955](bdd69955), closes [#444](444))
* introduce `StatusAssetSelector` component ([9fdc9aea](9fdc9aea), closes [#442](442))
* introduce `StatusAccountSelector` component ([5e15cc49](5e15cc49), closes [#435](435))
* introduce `StatusSelect` ([6e10959e](6e10959e), closes [#436](436))
* **StatusQ.Popups:** introduce `StatusMenuItemDelegate` ([0764e25a](0764e25a))
#### Breaking Changes
* **StatusQ.Popups:** introduce `StatusMenuItemDelegate` ([0764e25a](0764e25a))
<a name=""></a>
## Version 0.11.1(2021-10-12)
#### Bug Fixes
* Sandbox doesn't build on Linux machines ([dce45c2f](dce45c2f))
* **StatusChatInfoButton:** StatusChatInfoButton takes up entire available width ([c276a90e](c276a90e))
<a name=""></a>
## v0.11.0 (2021-09-27)
#### Bug Fixes
* track category opened state ([0631d500](0631d500))
* **StatusChatList:** ensure right click popup opens in correct position ([a2e3659d](a2e3659d))
* **StatusSearchPopup:** use correct theme color for search result text ([654bd9f2](654bd9f2))
* **StatusSpellcheckingMenuItems:** Exact menu items order ([478177f2](478177f2))
#### Features
* add star icons (#422) ([5c3267f7](5c3267f7))
<a name=""></a>
## v0.10.0 (2021-09-20)
#### Bug Fixes
* **StatusChatInfoToolBar:** Right anchored title in StatusChatInfoToolBar ([6e8a36be](6e8a36be))
* **StatusChatListCategoryItem:** Disable sensor when chevron clicked ([c83641d2](c83641d2))
* **StatusQ.Controls.Validators:** fix bug that addressOrEns validator isn't properly exposed in QML ([1374c193](1374c193))
#### Features
* **Spellchecker:** Add Spellchecker class ([c65f80d2](c65f80d2))
* **Spellchecking:**
* Add dictionaries ([1d12d222](1d12d222))
* Add huspell dependency ([f9457ef3](f9457ef3))
* **StatusChatList:** expose `statusChatListItems` Repeater ([40c0e48b](40c0e48b))
* **StatusExpandableItem:** Correct placement of expandable region in tertiary type ([1f244f62](1f244f62))
* **StatusInput:**
* add support for asynchronous validators ([8820cd89](8820cd89), closes [#395](395))
* introduce `leftPadding` and `rightPadding` properties ([13dc8ae3](13dc8ae3))
* introduce `reset` API ([a2ad08e4](a2ad08e4))
* **StatusSpellcheckingMenuItems:** Add spellchecking menu ([3e24b710](3e24b710))
<a name=""></a>
## v0.9.0 (2021-09-13)
+57
View File
@@ -240,6 +240,63 @@ Column {
loading: true
size: StatusBaseButton.Size.Small
}
// Tertiary
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Tertiary
icon.name: "gif"
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Tertiary
icon.name: "gif"
enabled: false
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Tertiary
icon.name: "gif"
loading: true
}
// No background Tertiary
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Tertiary
color: "transparent"
icon.name: "gif"
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Tertiary
icon.name: "gif"
color: "transparent"
enabled: false
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Tertiary
icon.name: "gif"
color: "transparent"
loading: true
}
// Quartenery
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Quaternary
icon.name: "gif"
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Quaternary
icon.name: "gif"
enabled: false
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Quaternary
icon.name: "gif"
loading: true
}
}
StatusPickerButton {
+15
View File
@@ -12,6 +12,21 @@ GridLayout {
columnSpacing: 5
rowSpacing: 5
StatusSelectableText {
color: Theme.palette.baseColor1
text: "This is a multiline paragraph that can be selected and copied. A paragraph is a group of words put together to form a group that is usually longer than a sentence. Paragraphs are often made up of several sentences. There are usually between three and eight sentences. Paragraphs can begin with an indentation (about five spaces), or by missing a line out, and then starting again."
font.pixelSize: 15
width: 300
multiline: true
}
StatusSelectableText {
color: Theme.palette.baseColor1
text: "<p>This is a selectable link in rich text format to test <a href='www.google.com'>www.google.com</a></p>"
font.pixelSize: 15
width: 200
}
StatusIconTabButton {
icon.name: "chat"
}
+1 -1
View File
@@ -286,7 +286,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
icon.isLetterIdenticon: true
icon.background.color: "orange"
icon.color: "orange"
}
StatusListItem {
+43
View File
@@ -53,6 +53,11 @@ Column {
onClicked: modalWithIdenticon.open()
}
StatusButton {
text: "Modal with editable identicon"
onClicked: modalWithEditableIdenticon.open()
}
StatusButton {
text: "Modal with long titles"
onClicked: modalWithLongTitles.open()
@@ -63,6 +68,11 @@ Column {
onClicked: modalWithHeaderPopupMenu.open()
}
StatusButton {
text: "Spellchecking menu"
onClicked: spellMenu.open()
}
StatusModal {
id: simpleModal
anchors.centerIn: parent
@@ -254,6 +264,33 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
]
}
StatusModal {
id: modalWithEditableIdenticon
anchors.centerIn: parent
header.title: "Header"
header.subTitle: "SubTitle"
header.headerImageEditable: true
header.image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.image.isIdenticon: true
contentItem: StatusBaseText {
anchors.centerIn: parent
text: "Some text content"
font.pixelSize: 15
color: Theme.palette.directColor1
}
rightButtons: [
StatusButton {
text: "Change text"
onClicked: {
modalWithIdenticon.contentItem.text = "Changed!"
}
}
]
}
StatusModal {
id: modalWithLongTitles
anchors.centerIn: parent
@@ -309,4 +346,10 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
ListElement{name: "Account 1"; iconName: "filled-account"}
ListElement{name: "Account 2"; iconName: "filled-account"}
}
StatusSpellcheckingMenuItems {
id: spellMenu
anchors.centerIn: parent
suggestions: ["suggestion1", "suggestion2", "suggestion3", "suggestion4"]
}
}
+55
View File
@@ -0,0 +1,55 @@
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
StatusAccountSelector {
accounts: ListModel {
ListElement {
name: "Pascal"
address: "0x1234567891011"
iconColor: "red"
balance: "0"
walletType: "generated"
assets: []
fiatBalance: "1199.02"
}
ListElement {
name: "Boris"
address: "0x123"
iconColor: "red"
balance: "0"
walletType: "generated"
assets: []
fiatBalance: "0"
}
ListElement {
name: "Alexandra"
address: "0x123"
iconColor: "yellow"
balance: "0"
walletType: "generated"
assets: []
fiatBalance: "0"
}
ListElement {
name: "Khushboo"
address: "0x123"
iconColor: "blue"
balance: "0"
walletType: "generated"
assets: []
fiatBalance: "0"
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Components 0.1
import Sandbox 0.1
Column {
spacing: 8
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
}
Item {
width: 200
height: childrenRect.height
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
expandable: true
width: parent.width
}
}
}
+36
View File
@@ -0,0 +1,36 @@
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 {
assets: ListModel {
ListElement {
address: "0x1234"
name: "Status Network Token"
value: "20"
symbol: "SNT"
fiatBalance: "9992.01"
fiatBalanceDisplay: "9992.01"
}
ListElement {
address: "0x1234"
name: "DAI Token"
value: "20"
symbol: "DAI"
fiatBalance: "20"
fiatBalanceDisplay: "20"
}
}
}
}
+26
View File
@@ -0,0 +1,26 @@
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 Sandbox 0.1
Column {
spacing: 8
StatusChatCommandButton {
icon.name: "send"
icon.color: Theme.palette.miscColor2
text: "Send transaction"
}
StatusChatCommandButton {
icon.name: "send"
icon.rotation: 180
icon.color: Theme.palette.miscColor8
text: "Receive transaction"
}
}
+17
View File
@@ -0,0 +1,17 @@
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 Sandbox 0.1
Column {
spacing: 8
StatusColorSelector {
model: ["red", "blue", "green"]
}
}
+16
View File
@@ -0,0 +1,16 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Platform 0.1
import Sandbox 0.1
Column {
spacing: 8
StatusMacNotification {
name: "Some name"
message: "Some message here"
}
}
+54
View File
@@ -0,0 +1,54 @@
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
StatusSelect {
id: select
label: "Some label"
model: ListModel {
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
selectMenu.delegate: StatusMenuItemDelegate {
statusPopupMenu: select
action: StatusMenuItem {
iconSettings.name: "filled-account"
text: name
onTriggered: {
selectedItem.text = name
}
}
}
selectedItemComponent: Item {
id: selectedItem
anchors.fill: parent
property string text: ""
StatusBaseText {
text: selectedItem.text
anchors.centerIn: parent
color: Theme.palette.directColor1
}
}
}
}
+50
View File
@@ -0,0 +1,50 @@
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 Sandbox 0.1
Column {
spacing: 8
Row {
StatusTabBarIconButton {
icon.name: "smileys-and-people"
onClicked: highlighted = !highlighted
}
StatusTabBarIconButton {
icon.name: "animals-and-nature"
onClicked: highlighted = !highlighted
}
StatusTabBarIconButton {
icon.name: "activity"
onClicked: highlighted = !highlighted
}
StatusTabBarIconButton {
icon.name: "travel-and-places"
onClicked: highlighted = !highlighted
}
StatusTabBarIconButton {
icon.name: "objects"
onClicked: highlighted = !highlighted
}
StatusTabBarIconButton {
icon.name: "symbols"
onClicked: highlighted = !highlighted
}
StatusTabBarIconButton {
icon.name: "flags"
onClicked: highlighted = !highlighted
}
}
}
+38
View File
@@ -0,0 +1,38 @@
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 Sandbox 0.1
Column {
spacing: 8
Row {
spacing: 4
StatusWalletColorButton {
icon.color: Theme.palette.miscColor1
selected: true
}
StatusWalletColorButton {
icon.color: Theme.palette.miscColor2
}
StatusWalletColorButton {
icon.color: Theme.palette.miscColor3
}
StatusWalletColorButton {
icon.color: Theme.palette.miscColor4
}
StatusWalletColorButton {
icon.color: Theme.palette.miscColor5
}
StatusWalletColorButton {
icon.color: Theme.palette.miscColor6
}
StatusWalletColorButton {
icon.color: Theme.palette.miscColor7
}
}
}
+17
View File
@@ -0,0 +1,17 @@
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 Sandbox 0.1
Column {
spacing: 8
StatusWalletColorSelect {
model: Theme.palette.accountColors
}
}
+101
View File
@@ -143,17 +143,62 @@ StatusWindow {
selected: page.sourceComponent == statusTabSwitchesComponent
onClicked: page.sourceComponent = statusTabSwitchesComponent
}
StatusNavigationListItem {
title: "StatusChatCommandButton"
selected: page.sourceComponent == statusChatCommandButtonPageComponent
onClicked: page.sourceComponent = statusChatCommandButtonPageComponent
}
StatusNavigationListItem {
title: "Controls"
selected: page.sourceComponent == controlsComponent
onClicked: page.sourceComponent = controlsComponent
}
StatusNavigationListItem {
title: "StatusTabBarIconButton"
selected: page.sourceComponent == statusTabBarIconButtonPageComponent
onClicked: page.sourceComponent = statusTabBarIconButtonPageComponent
}
StatusNavigationListItem {
title: "StatusInput"
selected: page.sourceComponent == statusInputPageComponent
onClicked: page.sourceComponent = statusInputPageComponent
}
StatusNavigationListItem {
title: "StatusSelect"
selected: page.sourceComponent == statusSelectPageComponent
onClicked: page.sourceComponent = statusSelectPageComponent
}
StatusNavigationListItem {
title: "StatusAccountSelector"
selected: page.sourceComponent == statusAccountSelectorPageComponent
onClicked: page.sourceComponent = statusAccountSelectorPageComponent
}
StatusNavigationListItem {
title: "StatusAssetSelector"
selected: page.sourceComponent == statusAssetSelectorPageComponent
onClicked: page.sourceComponent = statusAssetSelectorPageComponent
}
StatusNavigationListItem {
title: "StatusColorSelector"
selected: page.sourceComponent == statusColorSelectorPageComponent
onClicked: page.sourceComponent = statusColorSelectorPageComponent
}
StatusNavigationListItem {
title: "StatusWalletColorButton"
selected: page.sourceComponent == statusWalletColorButtonPageComponent
onClicked: page.sourceComponent = statusWalletColorButtonPageComponent
}
StatusNavigationListItem {
title: "StatusWalletColorSelect"
selected: page.sourceComponent == statusWalletColorSelectPageComponent
onClicked: page.sourceComponent = statusWalletColorSelectPageComponent
}
StatusListSectionHeadline { text: "StatusQ.Components" }
StatusNavigationListItem {
title: "StatusAddress"
selected: page.sourceComponent == statusAddressPageComponent
onClicked: page.sourceComponent = statusAddressPageComponent
}
StatusNavigationListItem {
title: "List Items"
selected: page.sourceComponent == listItemsComponent
@@ -186,6 +231,12 @@ StatusWindow {
selected: page.sourceComponent == statusModalComponent
onClicked: page.sourceComponent = statusModalComponent
}
StatusListSectionHeadline { text: "StatusQ.Platform" }
StatusNavigationListItem {
title: "StatusMacNotification"
selected: page.sourceComponent == notificationComponent
onClicked: page.sourceComponent = notificationComponent
}
}
}
}
@@ -256,11 +307,51 @@ StatusWindow {
StatusInputPage {}
}
Component {
id: statusSelectPageComponent
StatusSelectPage {}
}
Component {
id: statusAccountSelectorPageComponent
StatusAccountSelectorPage {}
}
Component {
id: statusAssetSelectorPageComponent
StatusAssetSelectorPage {}
}
Component {
id: statusColorSelectorPageComponent
StatusColorSelectorPage {}
}
Component {
id: statusTabBarIconButtonPageComponent
StatusTabBarIconButtonPage {}
}
Component {
id: statusWalletColorButtonPageComponent
StatusWalletColorButtonPage {}
}
Component {
id: statusWalletColorSelectPageComponent
StatusWalletColorSelectPage {}
}
Component {
id: listItemsComponent
ListItems {}
}
Component {
id: statusAddressPageComponent
StatusAddressPage {}
}
Component {
id: layoutComponent
Layout {}
@@ -276,6 +367,11 @@ StatusWindow {
Buttons {}
}
Component {
id: statusChatCommandButtonPageComponent
StatusChatCommandButtonPage {}
}
Component {
id: popupMenuComponent
StatusPopupMenuPage {}
@@ -301,6 +397,11 @@ StatusWindow {
StatusExpandableSettingsItemPage{}
}
Component {
id: notificationComponent
StatusMacNotificationPage {}
}
Component {
id: demoAppCmp
+9 -4
View File
@@ -1,6 +1,8 @@
QT += quick svg
CONFIG += c++11 warn_on
CONFIG += c++11 warn_on qtquickcompiler
QML_IMPORT_PATH= $$PWD/../src
DEFINES += QT_DEPRECATED_WARNINGS
@@ -30,9 +32,12 @@ macx {
hunspellTarget.commands = brew install hunspell
QMAKE_EXTRA_TARGETS += hunspellTarget
LIBS += -L"/usr/local/lib" -lhunspell-1.7
INCLUDEPATH += /usr/local/include/hunspell
exists (/usr/local/lib/libhunspell-1.7.a) {
LIBS += -L"/usr/local/lib" -lhunspell-1.7
INCLUDEPATH += /usr/local/include/hunspell
DEFINES += USE_HUNSPELL
message("hunspell exists in /usr/local/lib")
}
}
ios {
+14 -7
View File
@@ -1,6 +1,8 @@
#include "spellchecker.h"
#ifdef USE_HUNSPELL
#include "hunspell.hxx"
#endif
#include <QTextCodec>
#include <QFile>
#include <QDebug>
@@ -12,22 +14,24 @@
SpellChecker::SpellChecker(QObject *parent)
: QObject(parent)
, m_hunspell(nullptr)
, m_userDict("userDict_")
#ifdef USE_HUNSPELL
, m_hunspell(nullptr)
#endif
{
}
SpellChecker::~SpellChecker()
{
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
delete m_hunspell;
#endif
}
bool SpellChecker::spell(const QString &word)
{
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
return m_hunspell->spell(m_codec->fromUnicode(word).toStdString());
#else
return true;
@@ -36,12 +40,15 @@ bool SpellChecker::spell(const QString &word)
bool SpellChecker::isInit() const
{
#ifdef USE_HUNSPELL
return !m_hunspell;
#endif
return false;
}
void SpellChecker::initHunspell()
{
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
if (m_hunspell) {
delete m_hunspell;
}
@@ -102,7 +109,7 @@ QVariantList SpellChecker::suggest(const QString &word)
{
int numSuggestions = 0;
QVariantList suggestions;
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
std::vector<std::string> wordlist;
wordlist = m_hunspell->suggest(m_codec->fromUnicode(word).toStdString());
@@ -121,14 +128,14 @@ QVariantList SpellChecker::suggest(const QString &word)
void SpellChecker::ignoreWord(const QString &word)
{
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
m_hunspell->add(m_codec->fromUnicode(word).constData());
#endif
}
void SpellChecker::addToUserWordlist(const QString &word)
{
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
QString userDict = m_userDict + m_lang + ".txt";
if (!userDict.isEmpty()) {
QFile userDictonaryFile(userDict);
+2 -2
View File
@@ -6,7 +6,7 @@
#include <QQuickTextDocument>
#include <QSyntaxHighlighter>
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
class Hunspell;
#endif
class QTextCodec;
@@ -45,7 +45,7 @@ private:
QString m_userDict;
QQuickTextDocument *m_document;
#ifdef Q_OS_MACOS
#ifdef USE_HUNSPELL
Hunspell *m_hunspell;
#endif
QTextCodec *m_codec;
+39
View File
@@ -0,0 +1,39 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
StatusBaseText {
id: root
property bool expandable: false
property bool expanded: false
readonly property real actualWidth: implicitWidth
property real maxWidth: width
font.family: Theme.palette.monoFont.name
font.pixelSize: 13
elide: Text.ElideMiddle
color: Theme.palette.baseColor1
Component.onCompleted: {
maxWidth = width
expanded = actualWidth <= maxWidth
}
MouseArea {
anchors.fill: parent
cursorShape: root.expandable ? Qt.PointingHandCursor : Qt.arrowCursor
enabled: root.expandable
onClicked: {
if (root.expanded) {
width = root.width = root.maxWidth
} else {
width = root.width = root.actualWidth
}
root.expanded = !root.expanded
}
}
}
+5 -1
View File
@@ -19,6 +19,8 @@ Column {
property alias chatListItems: delegateModel
property bool draggableItems: false
property alias statusChatListItems: statusChatListItems
property Component popupMenu
property var filterFn
@@ -143,7 +145,9 @@ Column {
}
}
popupMenuSlot.item.popup(mouse.x + 4, statusChatListItem.y + mouse.y + 6)
let p = statusChatListItem.mapToItem(statusChatList, mouse.x, mouse.y)
popupMenuSlot.item.popup(p.x + 4, p.y + 6)
popupMenuSlot.item.openHandler = originalOpenHandler
return
}
@@ -28,6 +28,9 @@ Item {
property alias sensor: sensor
property bool draggableItems: false
property bool draggableCategories: false
// Keeps track of expanded category state. Should only be modified
// internally at runtime.
property var openedCategoryState: new Object({})
property Component categoryPopupMenu
property Component chatListPopupMenu
@@ -147,6 +150,21 @@ Item {
popupMenu: statusChatListAndCategories.categoryPopupMenu
chatListPopupMenu: statusChatListAndCategories.chatListPopupMenu
// Used to set the initial value of "opened" when the
// model is bound/changed.
opened: {
let openedState = statusChatListAndCategories.openedCategoryState[model.categoryId]
return openedState !== undefined ? openedState : true // defaults to open
}
// Used to track the internal changes of the `opened`
// property. This cannot be brought inside the component
// as the state would be lost each time the model is
// changed.
onOpenedChanged: {
statusChatListAndCategories.openedCategoryState[model.categoryId] = statusChatListCategory.opened
}
}
DropArea {
+11 -41
View File
@@ -20,9 +20,15 @@ Rectangle {
property bool hasUnreadMessages: false
property bool hasMention: false
property bool muted: false
property StatusImageSettings image: StatusImageSettings {}
property StatusImageSettings image: StatusImageSettings {
width: 24
height: 24
}
property StatusIconSettings icon: StatusIconSettings {
width: 24
height: 24
color: Theme.palette.miscColor5
letterSize: 15
}
property int type: StatusChatListItem.Type.PublicChat
property bool highlighted: false
@@ -67,50 +73,14 @@ Rectangle {
onClicked: statusChatListItem.clicked(mouse)
Loader {
StatusSmartIdenticon {
id: identicon
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
sourceComponent: !!statusChatListItem.image.source.toString() ?
statusRoundedImageCmp : statusLetterIdenticonCmp
}
Component {
id: statusLetterIdenticonCmp
StatusLetterIdenticon {
height: 24
width: 24
name: statusChatListItem.name
letterSize: 15
color: statusChatListItem.icon.color
}
}
Component {
id: statusRoundedImageCmp
Item {
height: 24
width: 24
StatusRoundedImage {
id: statusRoundedImage
width: parent.width
height: parent.height
image.source: statusChatListItem.image.source
showLoadingIndicator: true
color: statusChatListItem.image.isIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
border.width: statusChatListItem.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
Loader {
sourceComponent: statusLetterIdenticonCmp
active: statusRoundedImage.image.status === Image.Error
}
}
image: statusChatListItem.image
icon: statusChatListItem.icon
name: statusChatListItem.name
}
StatusIcon {
@@ -18,6 +18,8 @@ Rectangle {
property bool expanded: false
property StatusIconSettings icon: StatusIconSettings {
width: !!statusExpandableItem.icon.name.toString() ? 24 : 40
height: !!statusExpandableItem.icon.name.toString() ? 24 : 40
color: Theme.palette.directColor1
background: StatusIconBackgroundSettings {
width: 32
@@ -55,44 +57,17 @@ Rectangle {
visible: (statusExpandableItem.type === StatusExpandableItem.Type.Tertiary)
}
Loader {
StatusSmartIdenticon {
id: identicon
anchors.top: parent.top
anchors.topMargin: 25
anchors.left: parent.left
anchors.leftMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Secondary) ? 0 : 11
image: statusExpandableItem.image
icon: statusExpandableItem.icon
name: primaryText.text
active: (statusExpandableItem.type !== StatusExpandableItem.Type.Tertiary)
sourceComponent: !!statusExpandableItem.image.source.toString() ? roundedImage :
!!statusExpandableItem.icon.name.toString() ? roundedIcon : letterIdenticon
}
Component {
id: roundedImage
StatusRoundedImage {
image.source: statusExpandableItem.image.source
}
}
Component {
id: roundedIcon
StatusRoundIcon {
icon.background.width: statusExpandableItem.icon.background.width
icon.background.height: statusExpandableItem.icon.background.height
icon.background.color: statusExpandableItem.icon.background.color
icon.color: statusExpandableItem.icon.color
icon.name: statusExpandableItem.icon.name
}
}
Component {
id: letterIdenticon
StatusLetterIdenticon {
height: 40
width: 40
name: primaryText.text
letterSize: 20
color: Theme.palette.miscColor5
}
}
StatusBaseText {
+8 -49
View File
@@ -47,11 +47,12 @@ Rectangle {
property real rightPadding: 16
property bool enabled: true
property StatusIconSettings icon: StatusIconSettings {
height: 20
width: 20
height: isLetterIdenticon ? 40 : 20
width: isLetterIdenticon ? 40 : 20
rotation: 0
isLetterIdenticon: false
color: type === StatusListItem.Type.Danger ?
letterSize: 21
color: isLetterIdenticon ? background.color : type === StatusListItem.Type.Danger ?
Theme.palette.dangerColor1 : Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
width: 40
@@ -110,62 +111,20 @@ Rectangle {
statusListItem.clicked(statusListItem.itemId)
}
Loader {
StatusSmartIdenticon {
id: iconOrImage
anchors.left: parent.left
anchors.leftMargin: statusListItem.leftPadding
anchors.top: parent.top
anchors.topMargin: 12
sourceComponent: {
if (statusListItem.icon.isLetterIdenticon) {
return statusLetterIdenticon
}
return !!statusListItem.icon.name ? statusRoundedIcon : statusRoundedImage
}
image: statusListItem.image
icon: statusListItem.icon
name: statusListItem.title
active: statusListItem.icon.isLetterIdenticon ||
!!statusListItem.icon.name ||
!!statusListItem.image.source.toString()
}
Component {
id: statusRoundedIcon
StatusRoundIcon {
icon.width: statusListItem.icon.width
icon.height: statusListItem.icon.height
icon.name: statusListItem.icon.name
icon.rotation: statusListItem.icon.rotation
icon.color: statusListItem.icon.color
color: statusListItem.icon.background.color
width: statusListItem.icon.background.width
height: statusListItem.icon.background.height
}
}
Component {
id: statusRoundedImage
StatusRoundedImage {
image.source: statusListItem.image.source
image.height: statusListItem.image.height
image.width: statusListItem.image.width
color: statusListItem.image.isIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
border.width: statusListItem.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
}
Component {
id: statusLetterIdenticon
StatusLetterIdenticon {
width: statusListItem.icon.background.width
height: statusListItem.icon.background.height
color: statusListItem.icon.background.color
name: statusListItem.title
}
}
Item {
id: statusListItemTitleArea
anchors.left: iconOrImage.active ? iconOrImage.right : parent.left
@@ -0,0 +1,78 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Loader {
id: statusSmartIdenticon
property string name: ""
property StatusIconSettings icon: StatusIconSettings {
width: 40
height: 40
}
property StatusImageSettings image: StatusImageSettings {
width: 40
height: 40
}
sourceComponent: statusSmartIdenticon.icon.isLetterIdenticon ? letterIdenticon :
!!statusSmartIdenticon.image.source.toString() ? roundedImage :
!!statusSmartIdenticon.icon.name.toString() ? roundedIcon : letterIdenticon
Component {
id: roundedImage
Item {
width: statusSmartIdenticon.image.width
height: statusSmartIdenticon.image.height
StatusRoundedImage {
id: statusRoundImage
width: parent.width
height: parent.height
image.source: statusSmartIdenticon.image.source
showLoadingIndicator: true
border.width: statusSmartIdenticon.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
color: statusSmartIdenticon.image.isIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
}
Loader {
anchors.centerIn: parent
active: statusRoundImage.image.status === Image.Error
sourceComponent: letterIdenticon
onLoaded: {
item.color = Theme.palette.miscColor5
item.width = statusSmartIdenticon.image.width
item.height = statusSmartIdenticon.image.height
}
}
}
}
Component {
id: roundedIcon
StatusRoundIcon {
icon.background.width: statusSmartIdenticon.icon.background.width
icon.background.height: statusSmartIdenticon.icon.background.height
icon.background.color: statusSmartIdenticon.icon.background.color
icon.width: statusSmartIdenticon.icon.width
icon.height: statusSmartIdenticon.icon.height
icon.name: statusSmartIdenticon.icon.name
icon.rotation: statusSmartIdenticon.icon.rotation
icon.color: statusSmartIdenticon.icon.color
}
}
Component {
id: letterIdenticon
StatusLetterIdenticon {
width: statusSmartIdenticon.icon.width
height: statusSmartIdenticon.icon.height
color: statusSmartIdenticon.icon.color
name: statusSmartIdenticon.name
letterSize: statusSmartIdenticon.icon.letterSize
}
}
}
+2
View File
@@ -1,5 +1,6 @@
module StatusQ.Components
StatusAddress 0.1 StatusAddress.qml
StatusBadge 0.1 StatusBadge.qml
StatusChatInfoToolBar 0.1 StatusChatInfoToolBar.qml
StatusChatList 0.1 StatusChatList.qml
@@ -21,3 +22,4 @@ StatusRoundedImage 0.1 StatusRoundedImage.qml
StatusMacWindowButtons 0.1 StatusMacWindowButtons.qml
StatusListItemBadge 0.1 StatusListItemBadge.qml
StatusExpandableItem 0.1 StatusExpandableItem.qml
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
@@ -0,0 +1,277 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQml.Models 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
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
property string showBalanceForAssetSymbol: ""
property var assetFound
property double minRequiredAssetBalance: 0
property int dropdownWidth: width
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))
}
readonly property string watchWalletType: "watch"
enum Type {
Address,
Contact,
Account
}
function validate() {
if (showBalanceForAssetSymbol == "" || minRequiredAssetBalance == 0 || !assetFound) {
return root.isValid
}
root.isValid = assetFound.value >= minRequiredAssetBalance
return root.isValid
}
onSelectedAccountChanged: {
if (!selectedAccount) {
return
}
if (selectedAccount.iconColor) {
selectedIconImg.color = Utils.getThemeAccountColor(selectedAccount.iconColor, Theme.palette.accountColors) || Theme.palette.accountColors[0]
}
if (selectedAccount.name) {
selectedTextField.text = selectedAccount.name
}
if (selectedAccount.address) {
textSelectedAddress.text = selectedAccount.address + " •"
}
if (selectedAccount.fiatBalance) {
textSelectedAddressFiatBalance.text = selectedAccount.fiatBalance + " " + currency.toUpperCase()
}
if (selectedAccount.assets && showBalanceForAssetSymbol) {
assetFound = Utils.findAssetBySymbol(selectedAccount.assets, showBalanceForAssetSymbol)
if (!assetFound) {
console.warn("Cannot find asset '", showBalanceForAssetSymbol, "'. Ensure this asset has been added to the token list.")
}
}
if (!selectedAccount.type) {
selectedAccount.type = StatusAccountSelector.Type.Account
}
validate()
}
onAssetFoundChanged: {
if (!assetFound) {
return
}
txtAssetBalance.text = root.assetBalanceTextFn(assetFound.value)
txtAssetSymbol.text = " " + assetFound.symbol
}
StatusBaseText {
id: txtAssetBalance
visible: root.assetFound !== undefined
anchors.bottom: select.top
anchors.bottomMargin: -18
anchors.right: txtAssetSymbol.left
anchors.left: select.left
anchors.leftMargin: select.width / 2.5
color: !root.isValid ? Theme.palette.dangerColor1 : Theme.palette.baseColor1
elide: Text.ElideRight
font.pixelSize: 13
horizontalAlignment: Text.AlignRight
height: 18
StatusToolTip {
enabled: txtAssetBalance.truncated
id: assetTooltip
text: txtAssetBalance.text
}
MouseArea {
enabled: txtAssetBalance.truncated
anchors.fill: parent
hoverEnabled: enabled
onEntered: assetTooltip.visible = true
onExited: assetTooltip.visible = false
}
}
StatusBaseText {
id: txtAssetSymbol
visible: txtAssetBalance.visible
anchors.top: txtAssetBalance.top
anchors.right: parent.right
color: txtAssetBalance.color
font.pixelSize: 13
height: txtAssetBalance.height
}
StatusSelect {
id: select
label: root.label
model: root.accounts
width: parent.width
menuAlignment: StatusSelect.MenuAlignment.Left
selectMenu.delegate: menuItem
selectMenu.width: dropdownWidth
selectedItemComponent: Item {
anchors.fill: parent
StatusIcon {
id: selectedIconImg
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
width: 20
height: 20
icon: "filled-account"
}
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
font.pixelSize: 15
verticalAlignment: Text.AlignVCenter
height: 22
color: Theme.palette.directColor1
}
}
}
Row {
id: selectedAccountDetails
visible: root.showAccountDetails
anchors.top: select.bottom
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 2
StatusBaseText {
id: textSelectedAddress
font.pixelSize: 12
elide: Text.ElideMiddle
width: 90
color: Theme.palette.baseColor1
}
StatusBaseText {
id: textSelectedAddressFiatBalance
font.pixelSize: 12
color: Theme.palette.baseColor1
}
}
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, iconColor, assets, fiatBalance }
}
}
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(iconColor, Theme.palette.accountColors) || Theme.palette.accountColors[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: 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: fiatBalance
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, iconColor, assets, fiatBalance }
select.selectMenu.close()
}
}
}
}
}
@@ -0,0 +1,150 @@
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 var tokenAssetSourceFn: function (symbol) {
return ""
}
property var assetGetterFn: function (index, field) {
// This is merely to make the component work with nim model data
// as well as static QML ListModel data
if (typeof assets.get === "function") {
return assets.get(index)[field]
}
return assets.rowData(index, field)
}
implicitWidth: 86
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()
}
}
onAssetsChanged: {
if (!assets) {
return
}
selectedAsset = {
name: assetGetterFn(0, "name"),
symbol: assetGetterFn(0, "symbol"),
value: assetGetterFn(0, "value"),
fiatBalanceDisplay: assetGetterFn(0, "fiatBalanceDisplay"),
address: assetGetterFn(0, "address"),
fiatBalance: assetGetterFn(0, "fiatBalance")
}
}
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
}
StatusBaseText {
id: selectedTextField
anchors.left: iconImg.right
anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
height: 22
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())
}
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(value).toFixed(4) + " " + symbol
}
StatusBaseText {
font.pixelSize: 15
anchors.right: parent.right
text: fiatBalanceDisplay.toUpperCase()
color: Theme.palette.baseColor1
}
}
background: Rectangle {
color: itemContainer.highlighted ? Theme.palette.statusSelect.menuItemHoverBackgroundColor : Theme.palette.statusSelect.menuItemBackgroundColor
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: itemContainer
onClicked: {
root.selectedAsset = { address, name, value, symbol, fiatBalance, fiatBalanceDisplay }
select.selectMenu.close()
}
}
}
}
}
+2 -1
View File
@@ -54,6 +54,7 @@ Rectangle {
signal clicked(var mouse)
signal pressAndHold(var mouse)
property bool highlighted: false
/// Implementation
@@ -65,7 +66,7 @@ Rectangle {
color: {
if (statusBaseButton.enabled) {
return sensor.containsMouse ? hoverColor
return sensor.containsMouse || highlighted ? hoverColor
: normalColor
} else {
return disaledColor
+1
View File
@@ -47,6 +47,7 @@ Item {
property bool valid: true
property bool pristine: true
property bool dirty: false
property bool pending: false
property bool leftIcon: true
property StatusIconSettings icon: StatusIconSettings {
@@ -0,0 +1,71 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
Rectangle {
id: root
implicitWidth: 168
implicitHeight: 95
property string text: ""
property bool highlighted: false
property bool enabled: true
signal clicked(var mouse)
property StatusIconSettings icon: StatusIconSettings {
width: 24
height: 24
background: StatusIconBackgroundSettings {}
}
color: {
let actualColor = Qt.darker(root.icon.color, 1)
actualColor.a = sensor.containsMouse && enabled ? 0.3 : 0.2
return actualColor
}
radius: 16
MouseArea {
id: sensor
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
anchors.fill: parent
hoverEnabled: true
onClicked: function (mouse) {
root.clicked(mouse)
}
StatusRoundIcon {
icon.name: root.icon.name
icon.width: root.icon.width
icon.height: root.icon.height
icon.rotation: root.icon.rotation
icon.color: Theme.palette.white
icon.background.width: 40
icon.background.height: 40
icon.background.color: root.icon.color
anchors.top: parent.top
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 8
}
StatusBaseText {
text: root.text
anchors.left: parent.left
anchors.leftMargin: 8
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
font.pixelSize: 13
font.weight: Font.Medium
color: Theme.palette.white
}
}
}
+18 -46
View File
@@ -18,8 +18,15 @@ Rectangle {
property string subTitle: ""
property bool muted: false
property int pinnedMessagesCount: 0
property StatusImageSettings image: StatusImageSettings {}
property StatusIconSettings icon: StatusIconSettings {}
property StatusImageSettings image: StatusImageSettings {
width: 36
height: 36
}
property StatusIconSettings icon: StatusIconSettings {
width: 36
height: 36
letterSize: 20
}
property int type: StatusChatInfoButton.Type.PublicChat
property alias tooltip: statusToolTip
property alias sensor: sensor
@@ -27,6 +34,7 @@ Rectangle {
signal clicked(var mouse)
signal pinnedMessagesCountClicked(var mouse)
signal unmute()
signal linkActivated(string link)
enum Type {
Unknown0, // 0
@@ -49,51 +57,14 @@ Rectangle {
onClicked: statusChatInfoButton.clicked(mouse)
Loader {
StatusSmartIdenticon {
id: identicon
anchors.left: parent.left
anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter
sourceComponent: !!statusChatInfoButton.image.source.toString() ?
statusRoundImageComponent :
statusLetterIdenticonComponent
}
Component {
id: statusRoundImageComponent
Item {
width: 36
height: 36
StatusRoundedImage {
id: statusRoundImage
width: parent.width
height: parent.height
image.source: statusChatInfoButton.image.source
showLoadingIndicator: true
border.width: statusChatInfoButton.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
Loader {
sourceComponent: statusLetterIdenticonComponent
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
active: statusRoundImage.image.status === Image.Error
}
}
}
Component {
id: statusLetterIdenticonComponent
StatusLetterIdenticon {
width: 36
height: 36
name: statusChatInfoButton.title
color: statusChatInfoButton.icon.color
}
image: statusChatInfoButton.image
icon: statusChatInfoButton.icon
name: statusChatInfoButton.title
}
Item {
@@ -161,6 +132,7 @@ Rectangle {
}
StatusIcon {
objectName: "mutedIcon"
id: mutedIcon
anchors.left: chatName.right
anchors.leftMargin: 4
@@ -206,15 +178,14 @@ Rectangle {
+ divider.width + divider.anchors.leftMargin
: 0
StatusBaseText {
StatusSelectableText {
id: chatType
text: statusChatInfoButton.subTitle
color: Theme.palette.baseColor1
font.pixelSize: 12
elide: Text.ElideRight
width: Math.min(parent.width - (pinIcon.visible ? divider.width + divider.anchors.leftMargin + pinIcon.width + pinIcon.anchors.leftMargin : 0),
implicitWidth)
onLinkActivated: statusChatInfoButton.linkActivated(link)
}
Rectangle {
@@ -253,6 +224,7 @@ Rectangle {
color: pinCountSensor.containsMouse ? Theme.palette.directColor1 : Theme.palette.baseColor1
MouseArea {
objectName: "pinMessagesCounterSensor"
id: pinCountSensor
anchors.fill: parent
hoverEnabled: true
@@ -0,0 +1,37 @@
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
StatusSelect {
id: accountColorInput
bgColor: selectedColor
label: root.label
model: root.model
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"
}
}
}
}
}
+20 -3
View File
@@ -18,14 +18,19 @@ Rectangle {
return Theme.palette.directColor1;
case StatusFlatRoundButton.Type.Primary:
return Theme.palette.primaryColor1;
case StatusFlatRoundButton.Type.Tertiary:
return hovered ? Theme.palette.primaryColor1: Theme.palette.baseColor1;
case StatusFlatRoundButton.Type.Quaternary:
return hovered ? Theme.palette.primaryColor1: Theme.palette.directColor1;
}
}
property color disabledColor: {
disabledColor: {
switch(statusFlatRoundButton.type) {
case StatusFlatRoundButton.Type.Secondary:
return Theme.palette.baseColor1;
case StatusFlatRoundButton.Type.Primary:
case StatusFlatRoundButton.Type.Tertiary:
case StatusFlatRoundButton.Type.Quaternary:
return Theme.palette.baseColor1;
}
}
@@ -35,6 +40,7 @@ Rectangle {
property alias hovered: sensor.containsMouse
property alias tooltip: statusToolTip
property alias backgroundHoverColor: backgroundSettings.hoverColor
property bool highlighted: false
@@ -47,7 +53,9 @@ Rectangle {
enum Type {
Primary,
Secondary
Secondary,
Tertiary,
Quaternary
}
/// Implementation
@@ -59,6 +67,8 @@ Rectangle {
switch(statusFlatRoundButton.type) {
case StatusFlatRoundButton.Type.Primary:
case StatusFlatRoundButton.Type.Secondary:
case StatusFlatRoundButton.Type.Tertiary:
case StatusFlatRoundButton.Type.Quaternary:
return "transparent";
}
}
@@ -68,6 +78,8 @@ Rectangle {
case StatusFlatRoundButton.Type.Primary:
return Theme.palette.primaryColor3;
case StatusFlatRoundButton.Type.Secondary:
case StatusFlatRoundButton.Type.Tertiary:
case StatusFlatRoundButton.Type.Quaternary:
return Theme.palette.baseColor2;
}
}
@@ -76,6 +88,8 @@ Rectangle {
switch(statusFlatRoundButton.type) {
case StatusFlatRoundButton.Type.Primary:
case StatusFlatRoundButton.Type.Secondary:
case StatusFlatRoundButton.Type.Tertiary:
case StatusFlatRoundButton.Type.Quaternary:
return "transparent";
}
}
@@ -85,6 +99,8 @@ Rectangle {
case StatusFlatRoundButton.Type.Primary:
return Theme.palette.primaryColor3;
case StatusFlatRoundButton.Type.Secondary:
case StatusFlatRoundButton.Type.Tertiary:
case StatusFlatRoundButton.Type.Quaternary:
return Theme.palette.baseColor4;
}
}
@@ -120,6 +136,7 @@ Rectangle {
visible: !loading
icon: statusFlatRoundButton.icon.name
source: statusFlatRoundButton.icon.source
rotation: statusFlatRoundButton.icon.rotation
width: statusFlatRoundButton.icon.width
+12 -48
View File
@@ -20,56 +20,20 @@ TabButton {
contentItem: Item {
anchors.fill: parent
Loader {
active: true
StatusSmartIdenticon {
id: identicon
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
sourceComponent: statusIconTabButton.name !== "" && !icon.source.toString() ? letterIdenticon :
!!icon.source.toString() ? imageIcon : defaultIcon
}
Component {
id: defaultIcon
StatusIcon {
icon: statusIconTabButton.icon.name
height: statusIconTabButton.icon.height
width: statusIconTabButton.icon.width
color: (statusIconTabButton.hovered || highlighted || statusIconTabButton.checked) ? Theme.palette.primaryColor1 : statusIconTabButton.icon.color
}
}
Component {
id: imageIcon
Item {
width: 28
height: 28
StatusRoundedImage {
id: statusRoundImage
showLoadingIndicator: true
width: parent.width
height: parent.height
image.source: icon.source
}
Loader {
sourceComponent:letterIdenticon
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
active: statusRoundImage.image.status === Image.Error
}
}
}
Component {
id: letterIdenticon
StatusLetterIdenticon {
width: 26
height: 26
letterSize: 15
name: statusIconTabButton.name
color: (statusIconTabButton.hovered || highlighted || statusIconTabButton.checked) ? Theme.palette.primaryColor1 : statusIconTabButton.icon.color
}
image.source: statusIconTabButton.icon.source
image.width: 28
image.height: 28
icon.height: statusIconTabButton.icon.height
icon.width: statusIconTabButton.icon.width
icon.name: statusIconTabButton.icon.name
icon.color: (statusIconTabButton.hovered || highlighted || statusIconTabButton.checked) ? Theme.palette.primaryColor1 : statusIconTabButton.icon.color
icon.isLetterIdenticon: statusIconTabButton.name !== "" && !statusIconTabButton.icon.source.toString()
icon.letterSize: 15
name: statusIconTabButton.name
}
}
+46 -1
View File
@@ -1,6 +1,7 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Backpressure 1.0
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
@@ -24,6 +25,7 @@ Item {
property alias input: statusBaseInput
property alias valid: statusBaseInput.valid
property alias pending: statusBaseInput.pending
property alias text: statusBaseInput.text
property string label: ""
property string secondaryLabel: ""
@@ -32,19 +34,25 @@ Item {
property real leftPadding: 16
property real rightPadding: 16
property list<StatusValidator> validators
property list<StatusAsyncValidator> asyncValidators
property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty
property string validatedValue
property var pendingValidators: []
enum ValidationMode {
OnlyWhenDirty, // validates input only after it has become dirty
Always // validates input even before it has become dirty
}
property var errors: ({})
property var asyncErrors: ({})
function reset() {
statusBaseInput.valid = false
statusBaseInput.pristine = true
statusBaseInput.text = ""
errorMessage = ""
root.errorMessage = ""
}
function validate() {
@@ -78,6 +86,43 @@ Item {
}
}
}
if (asyncValidators.length && !Object.values(errors).length) {
for (let idx in asyncValidators) {
let asyncValidator = asyncValidators[idx]
asyncValidator.validationComplete.connect(function (value, valid) {
updateAsyncValidity(asyncValidator.name, value, valid)
})
root.pending = true
pendingValidators.push(asyncValidator.name)
asyncValidator.asyncOperationInternal(statusBaseInput.text)
}
} else if (!asyncValidators.length && !Object.values(errors).length) {
root.validatedValue = root.text
}
}
function updateAsyncValidity(validatorName, value, result) {
if (!asyncErrors) {
asyncErrors = {}
}
if (typeof result === "boolean" && result) {
if (asyncErrors[validatorName] !== undefined) {
delete asyncErrors[validatorName]
}
errorMessage.text = ""
root.validatedValue = value
} else {
asyncErrors[validatorName] = result
for (let idx in asyncValidators) {
errorMessage.text = asyncValidators[idx].errorMessage || root.errorMessage
break;
}
}
pendingValidators = pendingValidators.filter(v => v !== validatorName)
root.pending = pendingValidators.length > 0
root.valid = Object.values(asyncErrors).length == 0
}
Component.onCompleted: validate()
+2 -2
View File
@@ -21,7 +21,7 @@ Rectangle {
}
}
property color disabledColor: {
disabledColor: {
switch(statusRoundButton.type) {
case StatusRoundButton.Type.Primary:
return Theme.palette.baseColor1;
@@ -77,7 +77,7 @@ Rectangle {
property color disabledColor: {
switch(statusRoundButton.type) {
case StatusRoundButton.Type.Primary:
return Theme.palette.indirectColor1;
return Theme.palette.baseColor2;
case StatusRoundButton.Type.Secondary:
return Theme.palette.baseColor1;
}
+175
View File
@@ -0,0 +1,175 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
Item {
enum MenuAlignment {
Left,
Right,
Center
}
property string label: ""
readonly property bool hasLabel: label !== ""
property color bgColor: Theme.palette.baseColor2
readonly property int labelMargin: 7
property var model
property alias selectMenu: selectMenu
property color bgColorHover: bgColor
property alias selectedItemComponent: selectedItemContainer.children
property int caretRightMargin: 16
property alias select: inputRectangle
property int menuAlignment: StatusSelect.MenuAlignment.Right
property Item zeroItemsView: 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)
StatusBaseText {
id: inputLabel
visible: hasLabel
text: root.label
anchors.left: parent.left
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
font.pixelSize: 15
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
}
Rectangle {
property bool hovered: false
id: inputRectangle
height: 56
color: hovered ? bgColorHover : bgColor
radius: 8
anchors.top: root.hasLabel ? inputLabel.bottom : parent.top
anchors.topMargin: root.hasLabel ? root.labelMargin : 0
anchors.right: parent.right
anchors.left: parent.left
border.width: !!validationError ? 1 : 0
border.color: Theme.palette.dangerColor1
Item {
id: selectedItemContainer
anchors.fill: parent
}
StatusIcon {
id: caret
anchors.right: parent.right
anchors.rightMargin: caretRightMargin
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
icon: "chevron-down"
color: Theme.palette.baseColor1
}
}
Rectangle {
width: selectMenu.width
height: selectMenu.height
x: selectMenu.x
y: selectMenu.y
visible: selectMenu.opened
color: Theme.palette.statusSelect.menuItemBackgroundColor
radius: 8
border.color: Theme.palette.baseColor2
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 3
radius: 8
samples: 15
fast: true
cached: true
color: Theme.palette.dropShadow
}
}
StatusPopupMenu {
id: selectMenu
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
width: parent.width
clip: true
Repeater {
id: menuItems
model: root.model
property int zeroItemsViewHeight
delegate: selectMenu.delegate
onItemAdded: {
root.zeroItemsView.visible = false
root.zeroItemsView.height = 0
}
onItemRemoved: {
if (count === 0) {
root.zeroItemsView.visible = true
root.zeroItemsView.height = zeroItemsViewHeight
}
}
Component.onCompleted: {
zeroItemsViewHeight = root.zeroItemsView.height
root.zeroItemsView.visible = count === 0
root.zeroItemsView.height = count !== 0 ? 0 : root.zeroItemsView.height
selectMenu.insertItem(0, root.zeroItemsView)
}
}
}
StatusBaseText {
id: validationErrorText
visible: !!validationError
text: validationError
anchors.top: inputRectangle.bottom
anchors.topMargin: validationErrorTopMargin
anchors.right: parent.right
anchors.left: parent.left
font.pixelSize: 12
height: visible ? implicitHeight : 0
color: Theme.palette.dangerColor1
horizontalAlignment: TextEdit.AlignRight
wrapMode: Text.WordWrap
}
MouseArea {
id: mouseArea
anchors.fill: inputRectangle
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: {
inputRectangle.hovered = true
}
onExited: {
inputRectangle.hovered = false
}
onClicked: {
if (selectMenu.opened) {
selectMenu.close()
} else {
const rightOffset = inputRectangle.width - selectMenu.width
let offset = rightOffset
switch (root.menuAlignment) {
case StatusSelect.MenuAlignment.Left:
offset = 0
break
case StatusSelect.MenuAlignment.Right:
offset = rightOffset
break
case StatusSelect.MenuAlignment.Center:
offset = rightOffset / 2
}
selectMenu.popup(inputRectangle.x + offset, inputRectangle.y + inputRectangle.height + 8)
}
}
}
}
@@ -0,0 +1,105 @@
import QtQuick 2.14
import QtQuick.Controls 2.14 as QC
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: statusSelectableText
property bool multiline: false
property string text: ""
property string hoveredLinkColor: Theme.palette.directColor1
property alias selectedText: edit.selectedText
property alias selectedTextColor: edit.selectedTextColor
property alias selectionStart: edit.selectionStart
property alias selectionEnd: edit.selectionEnd
property alias cursorPosition: edit.cursorPosition
property alias hoveredLink: edit.hoveredLink
property alias color: edit.color
property alias font: edit.font
property alias focussed: edit.activeFocus
property alias verticalAlignmet: edit.verticalAlignment
property alias horizontalAlignment: edit.horizontalAlignment
signal linkActivated(string link)
implicitWidth: multiline ? 0 : edit.implicitWidth
implicitHeight: edit.implicitHeight
clip:true
MouseArea {
id: sensor
enabled: !edit.activeFocus
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: {
edit.forceActiveFocus()
}
onExited: {
flick.contentX = 0
flick.contentY = 0
}
Flickable {
id: flick
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
contentWidth: edit.paintedWidth
contentHeight: edit.paintedHeight
boundsBehavior: Flickable.StopAtBounds
QC.ScrollBar.vertical: QC.ScrollBar { interactive: multiline; enabled: multiline }
function ensureVisible(r) {
if (width-contentX >= r.x) {
contentX = 0;
}
else if (contentX+width <= r.x+r.width) {
contentX = r.x+r.width-width;
}
if (contentY >= r.y)
contentY = r.y;
else if (contentY+height <= r.y+r.height)
contentY = r.y+r.height-height;
}
TextEdit {
id: edit
width: flick.width
height: flick.height
verticalAlignment: Text.AlignVCenter
readOnly: true
selectByMouse: true
selectionColor: Theme.palette.primaryColor2
selectedTextColor: color
focus: true
font.pixelSize: 15
font.family: Theme.palette.baseFont.name
color: Theme.palette.directColor1
textFormat: Text.RichText
onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
wrapMode: statusSelectableText.multiline ? Text.WrapAtWordBoundaryOrAnywhere : TextEdit.NoWrap
Keys.forwardTo: [statusSelectableText]
onFocusChanged: {
if(!focus) {
flick.contentX = 0
flick.contentY = 0
}
}
onLinkActivated: statusSelectableText.linkActivated(link)
text: "<style>a:link { color: " + (!!hoveredLink ? statusSelectableText.hoveredLinkColor : Theme.palette.baseColor1) + "; }</style>" + statusSelectableText.text
}
}
}
}
@@ -0,0 +1,53 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
property StatusIconSettings icon: StatusIconSettings {
width: 24
height: 24
name: ""
}
property bool highlighted: false
property bool enabled: true
signal clicked(var mouse)
implicitWidth: 40
implicitHeight: 40
MouseArea {
id: sensor
enabled: root.enabled
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
anchors.fill: parent
hoverEnabled: true
onClicked: function (mouse) {
root.clicked(mouse)
}
StatusIcon {
id: statusIcon
width: root.icon.width
height: root.icon.height
icon: root.icon.name
color: root.highlighted || sensor.containsMouse ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
anchors.centerIn: parent
}
Rectangle {
visible: root.highlighted || sensor.containsMouse
width: statusIcon.width
anchors.horizontalCenter: parent.horizontalCenter
height: 2
radius: 1
color: Theme.palette.primaryColor1
anchors.bottom: parent.bottom
}
}
}
@@ -0,0 +1,41 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
StatusFlatRoundButton {
id: control
property bool selected: false
icon.name: "filled-account"
icon.width: 36
icon.height: 36
Rectangle {
anchors.fill: parent
color: control.hovered ? control.icon.color : "transparent"
opacity: 0.1
radius: 8
}
Rectangle {
width: 16
height: 16
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
anchors.rightMargin: 2
visible: control.selected
radius: width / 2
color: Theme.palette.successColor1
StatusIcon {
icon: "tiny/checkmark"
height: 12
color: Theme.palette.white
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
}
@@ -0,0 +1,61 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Item {
id: control
property string selectedColor
property string label: "Account color"
property var model
property bool enabled: true
height: childrenRect.height
implicitWidth: 480
StatusBaseText {
id: label
text: control.label
anchors.left: parent.left
anchors.top: parent.top
font.pixelSize: 15
color: control.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
}
RowLayout {
id: colors
spacing: 6
anchors.top: label.bottom
anchors.topMargin: 8
anchors.left: parent.left
anchors.right: parent.right
Repeater {
model: control.model
StatusWalletColorButton {
id: colorBtn
icon.color: modelData
selected: {
const upperCaseColor = control.selectedColor.toUpperCase()
const upperCaseModelDataColor = modelData.toString().toUpperCase()
if (upperCaseColor === upperCaseModelDataColor) {
return true
}
// Check the colors in the other theme
const currentColor = Utils.getThemeAccountColor(upperCaseColor, Theme.palette.accountColors)
if (!currentColor) {
return false
}
return currentColor === upperCaseModelDataColor
}
onClicked: {
control.selectedColor = modelData.toUpperCase()
}
}
}
}
}
@@ -0,0 +1,15 @@
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1
StatusAsyncValidator {
readonly property string uuid: Utils.uuid()
name: "asyncEns"
errorMessage: "ENS name could not be resolved in to an address"
validate: function (asyncResult) {
return Utils.isValidAddress(asyncResult)
}
}
@@ -0,0 +1,32 @@
import QtQuick 2.13
import StatusQ.Core.Backpressure 1.0
Item {
id: statusAsyncValidator
property string name: ""
property string errorMessage: "invalid input"
signal asyncComplete(var result)
signal validationComplete(var value, bool valid)
// Prevents firing async operations before time has elapsed. If multiple
// calls are attempted, the timer resets each time.
property int debounceTime: 600
property var validate: function (value) {
return value === "async result"
}
property var asyncOperation: function(inputText) {
// Do something with the input text. Once completed, fire the
// `asyncComplete` signal
asyncComplete("async result")
}
readonly property var asyncOperationInternal: Backpressure.debounce(statusAsyncValidator, debounceTime, function(inputText) {
statusAsyncValidator.asyncOperation(inputText)
})
onAsyncComplete: function(result) {
validationComplete(result, validate(result))
}
}
@@ -1,4 +1,5 @@
import QtQuick 2.13
import StatusQ.Controls 0.1
QtObject {
id: statusValidator
+3 -1
View File
@@ -2,6 +2,8 @@ module StatusQ.Controls.Validators
StatusAddressValidator 0.1 StatusAddressValidator.qml
StatusAddressOrEnsValidator 0.1 StatusAddressOrEnsValidator.qml
StatusValidator 0.1 StatusValidator.qml
StatusAsyncValidator 0.1 StatusAsyncValidator.qml
StatusAsyncEnsValidator 0.1 StatusAsyncEnsValidator.qml
StatusMinLengthValidator 0.1 StatusMinLengthValidator.qml
StatusMaxLengthValidator 0.1 StatusMaxLengthValidator.qml
StatusValidator 0.1 StatusValidator.qml
+9
View File
@@ -1,9 +1,14 @@
module StatusQ.Controls
StatusAccountSelector 0.1 StatusAccountSelector.qml
StatusAssetSelector 0.1 StatusAssetSelector.qml
StatusChatCommandButton 0.1 StatusChatCommandButton.qml
StatusChatInfoButton 0.1 StatusChatInfoButton.qml
StatusChatListCategoryItemButton 0.1 StatusChatListCategoryItemButton.qml
StatusColorSelector 0.1 StatusColorSelector.qml
StatusIconTabButton 0.1 StatusIconTabButton.qml
StatusNavBarTabButton 0.1 StatusNavBarTabButton.qml
StatusTabBarIconButton 0.1 StatusTabBarIconButton.qml
StatusToolTip 0.1 StatusToolTip.qml
StatusBaseButton 0.1 StatusBaseButton.qml
StatusButton 0.1 StatusButton.qml
@@ -14,8 +19,12 @@ StatusSwitch 0.1 StatusSwitch.qml
StatusRadioButton 0.1 StatusRadioButton.qml
StatusCheckBox 0.1 StatusCheckBox.qml
StatusSlider 0.1 StatusSlider.qml
StatusSelect 0.1 StatusSelect.qml
StatusBaseInput 0.1 StatusBaseInput.qml
StatusInput 0.1 StatusInput.qml
StatusPickerButton 0.1 StatusPickerButton.qml
StatusSwitchTabButton 0.1 StatusSwitchTabButton.qml
StatusSwitchTabBar 0.1 StatusSwitchTabBar.qml
StatusSelectableText 0.1 StatusSelectableText.qml
StatusWalletColorButton 0.1 StatusWalletColorButton.qml
StatusWalletColorSelect 0.1 StatusWalletColorSelect.qml
@@ -0,0 +1,123 @@
pragma Singleton
import QtQuick 2.0
Item {
id: backpressure
property var _timers: ({})
property int _nextId: 0
function setTimeout(owner, timeout, callback) {
var tid = ++_nextId;
var cleanup = function() {
if (tid !== null) {
clearTimeout(tid);
}
}
if (!owner) {
owner = backpressure;
}
owner.Component.destruction.connect(cleanup);
var obj = Qt.createQmlObject('import QtQuick 2.0; Timer {running: false; repeat: false; interval: ' + timeout + '}', backpressure, "setTimeout");
obj.triggered.connect(function() {
callback();
obj.destroy();
owner.Component.destruction.disconnect(cleanup);
delete _timers[tid];
});
obj.running = true;
_timers[tid] = obj;
return tid;
}
function clearTimeout(timerId) {
if (!_timers.hasOwnProperty(timerId)) {
return;
}
var timer = _timers[timerId];
timer.stop();
timer.destroy();
delete _timers[timerId];
}
function oneInTime(owner, duration, callback) {
var pending = false;
var timerId = null;
return function() {
if (pending) {
return;
}
pending = true;
var args = arguments;
callback.apply(null, args);
timerId = setTimeout(owner, duration , function() {
pending = false;
}, duration);
}
}
function promisedOneInTime(owner, callback) {
var q = priv.loadPromiseLib();
var promise = null;
return function() {
var args = arguments;
if (promise !== null) {
return q.rejected();
}
promise = q.promise(function(fulfill, reject) {
fulfill(callback.apply(null, args));
});
promise.then(function() {
promise = null;
}, function() {
promise = null;
});
return promise;
};
}
function debounce(owner, duration, callback) {
var timerId = null;
return function() {
var args = arguments;
if (timerId !== null) {
clearTimeout(timerId);
}
timerId = setTimeout(owner, duration, function() {
timerId = null;
callback.apply(null, args);
});
}
}
QtObject {
id: priv
property var q: null
function loadPromiseLib() {
if (q !== null) {
return q.q;
}
q = Qt.createQmlObject('import QtQuick 2.0; import QuickPromise 1.0; Item { property var q: Q;}', backpressure);
if (q.hasOwnProperty("qmlErrors")) {
console.error("Backpressure: Failed to load QuickPromise. Please check your installation.");
}
return q.q;
}
}
}
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+80
View File
@@ -0,0 +1,80 @@
[![Build Status](https://www.travis-ci.org/e-fever/backpressure.svg?branch=master)](https://www.travis-ci.org/e-fever/backpressure)
[![Build status](https://ci.appveyor.com/api/projects/status/knt6r7gra9dm0oui?svg=true)](https://ci.appveyor.com/project/benlau/backpressure)
Backpressure
============
Backpressure happens on a stream of data where you are not fast enough to process.
This library is designed to provide a few mechanism to handle it.
Installation
============
qpm install net.efever.backpressure
API
===
```
import Backpressure 1.0
```
**Backpressure.oneInTime(owner, duration, callback)**
It will create a wrapper function of the callback. Whatever you have invoked the wrapper function, it will execute the callback immediately. Then it will be blocked within duration period. It could prevent to process the same event twice within the duration period.
Example:
```
Item {
id : item
property var processClick : Backpressure.oneInTime(item, 500, function(value) {
/* Callback */
});
MouseArea {
onClicked: {
processClick(value);
}
}
}
```
If the owner is destroyed, the callback will no longer be able to access.
**Backpressure.debounce(owner, duration, callback)**
If will create a wrapper function of the callback. Whatever you have invoked the wrapper function, it won't execute the callback until the duration period finished. If user invoked the wrapper function again within the period, then the previous call will be dropped, and the timer is restarted.
It will guarantee only the last function call and parameter will be passed to the callback.
Reference: [ReactiveX - Debounce operator](http://reactivex.io/documentation/operators/debounce.html)
**Backpressure.promisedOneInTime(owner, callback)**
This function is similar to oneInTime that will create a wrapper of the callback. But it does not take a timeout value as an argument of the construction function.
Instead, it will convert the return from the callback to a promise object. Then blocks successively calls until the promise is resolved/rejected.
The wrapper function returns a promise represents the result of the callback. If that is blocked, it will simply a rejected promise.
You must install QuickPromise in order to use this funciton.
Example
```
var timeout = Backpressure.promisedOneInTime(anyItem, function(delay) {
return Q.promise(function(fulfill, reject) {
Q.setTimeout(function() {
fulfill();
}, delay);
});
});
var promise1 = timeout(1000); // Pending
var promise2 = timeout(1000); // Rejected
```
+3
View File
@@ -0,0 +1,3 @@
module StatusQ.Core.Backpressure
singleton Backpressure 1.0 Backpressure.qml
+2
View File
@@ -8,8 +8,10 @@ QtObject {
property real width
property real height
property color color
property color disabledColor
property url source
property int rotation
property bool isLetterIdenticon
property int letterSize
property StatusIconBackgroundSettings background: StatusIconBackgroundSettings {}
}
@@ -5,6 +5,8 @@ QtObject {
property string subTitle
property int titleElide: Text.ElideRight
property int subTitleElide: Text.ElideRight
property bool headerImageEditable: false
property bool editable: false
property Component popupMenu
property StatusImageSettings image: StatusImageSettings {
width: 40
@@ -146,6 +146,17 @@ ThemePalette {
miscColor10: getColor('brown3')
miscColor11: getColor('yellow2')
accountColors: [
getColor('blue5'),
getColor('yellow2'),
"#E6ABFC",
getColor('moss2'),
"#FB8383",
getColor('green4'),
"#ADA3FF",
getColor('brown3')
]
property QtObject statusAppLayout: QtObject {
property color backgroundColor: baseColor3
property color rightPanelBackgroundColor: baseColor3
@@ -205,5 +216,10 @@ ThemePalette {
property QtObject statusSwitchTab: QtObject {
property color backgroundColor: baseColor3
}
property QtObject statusSelect: QtObject {
property color menuItemBackgroundColor: baseColor2
property color menuItemHoverBackgroundColor: directColor7
}
}
@@ -144,6 +144,17 @@ ThemePalette {
miscColor10: getColor('brown')
miscColor11: getColor('brown2')
accountColors: [
getColor('blue'),
getColor('brown2'),
getColor('violet'),
"#1D806F",
getColor('red2'),
getColor('green2'),
getColor('purple'),
getColor('brown')
]
property QtObject statusAppLayout: QtObject {
property color backgroundColor: white
property color rightPanelBackgroundColor: white
@@ -203,5 +214,10 @@ ThemePalette {
property QtObject statusSwitchTab: QtObject {
property color backgroundColor: white
}
property QtObject statusSelect: QtObject {
property color menuItemBackgroundColor: white
property color menuItemHoverBackgroundColor: baseColor2
}
}
+7
View File
@@ -89,6 +89,8 @@ QtObject {
property color miscColor10
property color miscColor11
property var accountColors: []
property QtObject statusAppLayout: QtObject {
property color backgroundColor
property color rightPanelBackgroundColor
@@ -150,6 +152,11 @@ QtObject {
property color backgroundColor
}
property QtObject statusSelect: QtObject {
property color menuItemBackgroundColor
property color menuItemHoeverBackgroundColor
}
function alphaColor(color, alpha) {
let actualColor = Qt.darker(color, 1)
actualColor.a = alpha
+41
View File
@@ -26,6 +26,47 @@ QtObject {
const isDomain = /(?:(?:(?<thld>[\w\-]*)(?:\.))?(?<sld>[\w\-]*))\.(?<tld>[\w\-]*)/.test(inputValue)
return isEmail || isDomain || (inputValue.startsWith("@") && inputValue.length > 1)
}
function uuid() {
return Date.now().toString(36) + Math.random().toString(36).substr(2, 5)
}
function getThemeAccountColor(c, accountColors) {
const upperCaseColor = c.toUpperCase()
let colorIndex = accountColors.indexOf(upperCaseColor)
if (colorIndex > -1) {
return upperCaseColor
}
return false
}
function findAssetBySymbol(assets, symbolToFind) {
for(var i=0; i<assets.rowCount(); i++) {
const symbol = assets.rowData(i, "symbol")
if (symbol.toLowerCase() === symbolToFind.toLowerCase()) {
return {
name: assets.rowData(i, "name"),
symbol,
value: assets.rowData(i, "value"),
fiatBalanceDisplay: assets.rowData(i, "fiatBalanceDisplay"),
address: assets.rowData(i, "address"),
fiatBalance: assets.rowData(i, "fiatBalance")
}
}
}
}
function stripTrailingZeros(strNumber) {
if (!(typeof strNumber === "string")) {
try {
strNumber = strNumber.toString()
} catch(e) {
throw "[Utils.stripTrailingZeros] input parameter must be a string"
}
}
return strNumber.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1')
}
}
@@ -0,0 +1,129 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
Rectangle {
id: root
property string chatId: ""
property string name: "channelName"
property string message: "My latest message\n with a return"
property string identicon: ""
// TODO: what about dark theme?
color: "#F7F7F7"
width: 366
height: 75
radius: 8
Loader {
id: identicon
sourceComponent: root.identicon === "" ? statusIdenticon : userOrChannelIdenticon
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
height: 40
width: 40
}
Component {
id: userOrChannelIdenticon
StatusSmartIdenticon {
id: contactImage
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
image: StatusImageSettings {
width: 40
height: 40
source: root.identicon
isIdenticon: true
}
icon: StatusIconSettings {
width: 40
height: 40
letterSize: 15
color: Theme.palette.miscColor5
}
name: root.name
}
}
Component {
id: statusIdenticon
Image {
source: "../../assets/img/status-logo-icon.svg"
width: 40
height: 40
sourceSize.width: width * 2
sourceSize.height: height * 2
cache: true
fillMode: Image.PreserveAspectFit
}
/* SVGImage { */
/* source: Style.svg("status-logo-icon") */
/* width: 40 */
/* height: 40 */
/* } */
}
StatusBaseText {
id: name
anchors.bottom: messagePreview.top
anchors.bottomMargin: 2
anchors.left: identicon.right
anchors.leftMargin: 8
anchors.right: openButton.left
anchors.rightMargin: 8
elide: Text.ElideRight
text: root.name
font.weight: Font.Medium
font.pixelSize: 15
color: "#4b4b4b"
}
StatusBaseText {
id: messagePreview
anchors.bottom: identicon.bottom
anchors.bottomMargin: 2
anchors.left: identicon.right
anchors.leftMargin: 8
anchors.right: openButton.left
anchors.rightMargin: 16
elide: Text.ElideRight
clip: true // This is needed because emojis don't ellide correctly
font.pixelSize: 14
color: "#4b4b4b"
text: root.message
}
Rectangle {
id: openButton
anchors.right: parent.right
height: parent.height
width: 85
color: "transparent"
Rectangle {
height: parent.height
width: 1.2
anchors.left: parent.left
color: "#D9D9D9"
}
StatusBaseText {
font.weight: Font.Medium
font.pixelSize: 14
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
text: "Open"
color: "black"
}
}
}
+1
View File
@@ -1,5 +1,6 @@
module StatusQ.Platform
StatusMacTrafficLights 0.1 StatusMacTrafficLights.qml
StatusMacNotification 0.1 StatusMacNotification.qml
StatusWindowsTitleBar 0.1 StatusWindowsTitleBar.qml
@@ -0,0 +1,193 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
MenuItem {
id: statusPopupMenuItem
implicitWidth: parent ? parent.width : 0
implicitHeight: action.enabled ? 38 : 0
property int subMenuIndex
property var statusPopupMenu: null
Component.onCompleted: {
if (!!subMenu) {
subMenuIndex = statusPopupMenu.menuItemCount
statusPopupMenu.menuItemCount += 1
}
}
action: StatusMenuItem {
onTriggered: { statusPopupMenu.menuItemClicked(statusPopupMenuItem.subMenuIndex); }
}
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
if (!Qt.colorEqual(c, "transparent")) {
return c
}
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
break;
default:
return Theme.palette.primaryColor1
}
}
}
}
}
Component {
id: statusLetterIdenticonCmp
Item {
implicitWidth: 24
implicitHeight: 24
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
}
}
}
Component {
id: statusRoundImageCmp
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
}
}
}
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
}
return (parent.subMenu && subMenuItemIcon && subMenuItemIcon.isLetterIdenticon) ||
(statusPopupMenuItem.action.iconsSettings && statusPopupMenuItem.action.iconSettings.isLetterIdenticon) ?
statusLetterIdenticonCmp : indicatorComponent
}
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.right: arrowIcon.visible ? arrowIcon.left : arrowIcon.right
anchors.rightMargin: 8
anchors.leftMargin: 4
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: statusPopupMenuItem.text
color: {
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
break;
default:
return Theme.palette.directColor1
}
}
font.pixelSize: 13
elide: Text.ElideRight
visible: statusPopupMenuItem.action.enabled
}
arrow: StatusIcon {
id: arrowIcon
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 8
height: 16
visible: statusPopupMenuItem.subMenu
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"
}
}
MouseArea {
id: sensor
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: statusPopupMenuItem.action.enabled
onPressed: mouse.accepted = false
}
}
+5 -1
View File
@@ -20,6 +20,7 @@ QC.Popup {
property bool showFooter: true
signal editButtonClicked()
signal headerImageClicked()
parent: QC.Overlay.overlay
@@ -54,8 +55,11 @@ QC.Popup {
image: header.image
icon: header.icon
popupMenu: header.popupMenu
headerImageEditable: header.headerImageEditable
editable: header.editable
onEditButtonClicked: statusModal.editButtonClicked()
onHeaderImageClicked: statusModal.headerImageClicked()
onClose: statusModal.close()
}
@@ -63,7 +67,7 @@ QC.Popup {
id: footerImpl
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
visible: statusModal.showFooter
showFooter: statusModal.showFooter
}
}
}
+3 -185
View File
@@ -9,7 +9,7 @@ import StatusQ.Popups 0.1
Menu {
id: statusPopupMenu
id: root
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
topPadding: 8
bottomPadding: 8
@@ -38,190 +38,8 @@ Menu {
}
}
delegate: MenuItem {
id: statusPopupMenuItem
implicitWidth: parent ? parent.width : 0
implicitHeight: action.enabled ? 38 : 0
property int subMenuIndex
Component.onCompleted: {
if (!!subMenu) {
subMenuIndex = statusPopupMenu.menuItemCount
statusPopupMenu.menuItemCount += 1
}
}
action: StatusMenuItem {
onTriggered: { statusPopupMenu.menuItemClicked(statusPopupMenuItem.subMenuIndex); }
}
Component {
id: indicatorComponent
Item {
implicitWidth: 24
implicitHeight: 24
StatusIcon {
anchors.centerIn: parent
width: {
let width = statusPopupMenuItem.action.icon.width ||
statusPopupMenuItem.action.iconSettings.width
return !!width ? width : 18
}
rotation: statusPopupMenuItem.action.iconRotation
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.name !== "") {
return statusPopupMenuItem.action.iconSettings.name;
} else {
return "";
}
}
color: {
let c = statusPopupMenuItem.action.iconSettings.color ||
statusPopupMenuItem.action.icon.color
if (!Qt.colorEqual(c, "transparent")) {
return c
}
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
break;
default:
return Theme.palette.primaryColor1
}
}
}
}
}
Component {
id: statusLetterIdenticonCmp
Item {
implicitWidth: 24
implicitHeight: 24
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
}
}
}
Component {
id: statusRoundImageCmp
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
}
}
}
indicator: Loader {
sourceComponent: {
let subMenuItemIcon = statusPopupMenu.subMenuItemIcons[parent.subMenuIndex]
if ((parent.subMenu && subMenuItemIcon && subMenuItemIcon.source) ||
statusPopupMenuItem.action.image && !!statusPopupMenuItem.action.image.source.toString()) {
return statusRoundImageCmp
}
return (parent.subMenu && subMenuItemIcon && subMenuItemIcon.isLetterIdenticon) ||
(statusPopupMenuItem.action.iconsSettings && statusPopupMenuItem.action.iconSettings.isLetterIdenticon) ?
statusLetterIdenticonCmp : indicatorComponent
}
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.right: arrowIcon.visible ? arrowIcon.left : arrowIcon.right
anchors.rightMargin: 8
anchors.leftMargin: 4
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: statusPopupMenuItem.text
color: {
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
break;
default:
return Theme.palette.directColor1
}
}
font.pixelSize: 13
elide: Text.ElideRight
visible: statusPopupMenuItem.action.enabled
}
arrow: StatusIcon {
id: arrowIcon
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 8
height: 16
visible: statusPopupMenuItem.subMenu
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"
}
}
MouseArea {
id: sensor
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: statusPopupMenuItem.action.enabled
onPressed: mouse.accepted = false
}
delegate: StatusMenuItemDelegate {
statusPopupMenu: root
}
background: Item {
+11 -56
View File
@@ -113,11 +113,16 @@ StatusModal {
property string primaryText: ""
property string secondaryText: ""
property StatusIconSettings iconSettings: StatusIconSettings {
width: 16
height: 16
name: ""
isLetterIdenticon: false
letterSize: 11
}
property StatusImageSettings image: StatusImageSettings {
width: 16
height: 16
source: ""
isIdenticon: false
}
@@ -155,67 +160,17 @@ StatusModal {
font.weight: Font.Medium
}
Loader {
StatusSmartIdenticon {
id: identicon
Layout.preferredWidth: active ? 16 : 0
Layout.preferredHeight: 16
image: searchOptionsMenuButton.image
icon: searchOptionsMenuButton.iconSettings
name: searchOptionsMenuButton.primaryText
active: searchOptionsMenuButton.primaryText !== defaultSearchLocationText &&
(searchOptionsMenuButton.iconSettings.name ||
searchOptionsMenuButton.iconSettings.isLetterIdenticon ||
!!searchOptionsMenuButton.image.source.toString())
sourceComponent: {
if (!!searchOptionsMenuButton.image.source.toString()) {
return statusRoundedImageCmp
}
if (!!searchOptionsMenuButton.iconSettings.isLetterIdenticon || !searchOptionsMenuButton.iconSettings.name) {
return statusLetterIdenticonCmp
}
return statusIconCmp
}
}
Component {
id: statusIconCmp
StatusIcon {
width: 16
icon: searchOptionsMenuButton.iconSettings.name
color: searchOptionsMenuButton.iconSettings.color
}
}
Component {
id: statusRoundedImageCmp
Item {
width: 16
height: 16
StatusRoundedImage {
id: statusRoundedImage
implicitWidth: parent.width
implicitHeight: parent.height
image.source: searchOptionsMenuButton.image.source
color: searchOptionsMenuButton.image.isIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
border.width: searchOptionsMenuButton.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
Loader {
sourceComponent: statusLetterIdenticonCmp
active: statusRoundedImage.image.status === Image.Error
}
}
}
Component {
id: statusLetterIdenticonCmp
StatusLetterIdenticon {
implicitWidth: 16
implicitHeight: 16
letterSize: 11
color: searchOptionsMenuButton.iconSettings.color
name: searchOptionsMenuButton.primaryText
}
}
StatusBaseText {
@@ -301,7 +256,7 @@ StatusModal {
radius: 0
statusListItemSubTitle.height: model.content !== "" ? 20 : 0
statusListItemSubTitle.elide: Text.ElideRight
statusListItemSubTitle.color: Theme.palette.black
statusListItemSubTitle.color: Theme.palette.directColor1
icon.isLetterIdenticon: (model.image === "")
icon.background.color: model.color
titleAsideText: root.formatTimestampFn(model.time)
@@ -22,7 +22,8 @@ MenuItem {
isLetterIdenticon: (root.image.source.toString() === ""
&& root.iconSettings.name.toString() === "")
background: StatusIconBackgroundSettings {}
color: "transparent"
color: (name === "channel") ? Theme.palette.directColor1 : "transparent"
letterSize: 11
}
background: Rectangle {
@@ -32,30 +33,17 @@ MenuItem {
contentItem: RowLayout {
anchors.left: parent.left
anchors.leftMargin: 12
StatusIcon {
Layout.preferredWidth: visible ? root.iconSettings.width : 0
Layout.preferredHeight: visible ? root.iconSettings.height : 0
Item {
Layout.preferredWidth: root.iconSettings.width
Layout.preferredHeight: root.iconSettings.height
Layout.alignment: Qt.AlignVCenter
visible: !!root.iconSettings.name && !root.image.source.toString()
icon: root.iconSettings.name
color: (icon === "channel")? Theme.palette.directColor1 : root.iconSettings.color
}
StatusRoundedImage {
Layout.preferredWidth: visible ? root.image.width : 0
Layout.preferredHeight: visible ? root.image.height : 0
Layout.alignment: Qt.AlignVCenter
visible: root.image.source.toString() !== ""
image.source: root.image.source
border.width: root.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
StatusLetterIdenticon {
Layout.preferredWidth: visible ? root.iconSettings.width : 0
Layout.preferredHeight: visible ? root.iconSettings.height : 0
visible: root.iconSettings.isLetterIdenticon && !root.iconSettings.name && !root.image.source.toString()
color: root.iconSettings.color
name: root.text
letterSize: 11
StatusSmartIdenticon {
id: identicon
anchors.centerIn: parent
image: root.image
icon: root.iconSettings
name: root.text
}
}
StatusBaseText {
Layout.fillWidth: true
@@ -0,0 +1,107 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
StatusPopupMenu {
id: root
property alias suggestions: suggestionsMenu.model
signal addToUserDict()
signal disableSpellchecking()
Column {
Repeater {
id: suggestionsMenu
delegate: MenuItem {
id: variants
implicitWidth: parent ? parent.width : 0
implicitHeight: 38
contentItem: StatusBaseText {
rightPadding: 8
leftPadding: 4
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: modelData
color: Theme.palette.directColor1
font.pixelSize: 13
elide: Text.ElideRight
}
background: Rectangle {
color: variants.hovered ? Theme.palette.statusPopupMenu.hoverBackgroundColor
: "transparent"
}
onTriggered: {
root.menuItemClicked(index)
}
}
}
StatusMenuSeparator { visible: !!suggestionsMenu.model && suggestionsMenu.model.length !== 0}
MenuItem {
id: ignoreWord
implicitWidth: parent ? parent.width : 0
implicitHeight: 38
contentItem: StatusBaseText {
rightPadding: 8
leftPadding: 4
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: qsTr("Add to dictionary")
color: Theme.palette.directColor1
font.pixelSize: 13
elide: Text.ElideRight
}
background: Rectangle {
color: ignoreWord.hovered ? Theme.palette.statusPopupMenu.hoverBackgroundColor
: "transparent"
}
onTriggered: {
root.addToUserDict()
}
}
MenuItem {
id: disableSpellchecking
implicitWidth: parent ? parent.width : 0
implicitHeight: 38
contentItem: StatusBaseText {
rightPadding: 8
leftPadding: 4
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: qsTr("Disable Spellchecking")
color: Theme.palette.directColor1
font.pixelSize: 13
elide: Text.ElideRight
}
background: Rectangle {
color: disableSpellchecking.hovered ? Theme.palette.statusPopupMenu.hoverBackgroundColor
: "transparent"
}
onTriggered: {
root.disableSpellchecking()
}
}
}
}
+2
View File
@@ -3,9 +3,11 @@ module StatusQ.Popups
StatusMenuSeparator 0.1 StatusMenuSeparator.qml
StatusPopupMenu 0.1 StatusPopupMenu.qml
StatusMenuItem 0.1 StatusMenuItem.qml
StatusMenuItemDelegate 0.1 StatusMenuItemDelegate.qml
StatusMenuHeadline 0.1 StatusMenuHeadline.qml
StatusModal 0.1 StatusModal.qml
StatusSearchPopup 0.1 StatusSearchPopup.qml
StatusModalDivider 0.1 StatusModalDivider.qml
StatusSearchPopupMenuItem 0.1 StatusSearchPopupMenuItem.qml
StatusSearchLocationMenu 0.1 StatusSearchLocationMenu.qml
StatusSpellcheckingMenuItems 0.1 StatusSpellcheckingMenuItems.qml
@@ -12,8 +12,10 @@ Row {
property int titleElide: Text.ElideRight
property int subTitleElide: Text.ElideRight
property bool editable: false
property bool headerImageEditable: false
signal editButtonClicked
signal headerImageClicked
property StatusImageSettings image: StatusImageSettings {
width: 40
@@ -39,7 +41,7 @@ Row {
}
return statusRoundedImageCmp
}
active: statusImageWithTitle.icon.isLetterIdenticon ||
active: statusImageWithTitle.icon.isLetterIdenticon ||
!!statusImageWithTitle.image.source.toString()
}
@@ -60,16 +62,56 @@ Row {
height: statusImageWithTitle.image.height
StatusRoundedImage {
id: statusRoundedImage
objectName: "headerImage"
image.source: statusImageWithTitle.image.source
width: statusImageWithTitle.image.width
height: statusImageWithTitle.image.height
color: statusImageWithTitle.image.isIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
border.width: statusImageWithTitle.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
showLoadingIndicator: true
}
Rectangle {
id: editAvatarIcon
objectName: "editAvatarImage"
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: -3
anchors.rightMargin: -2
width: 18
height: 18
radius: width / 2
visible: statusImageWithTitle.headerImageEditable
color: Theme.palette.primaryColor1;
border.color: Theme.palette.indirectColor1
border.width: Theme.palette.name === "light" ? 1 : 0
StatusIcon {
anchors.centerIn: parent
width: 11
color: Theme.palette.indirectColor1
icon: "tiny/edit"
}
}
MouseArea {
anchors.fill: parent
cursorShape: enabled ? Qt.PointingHandCursor
: Qt.ArrowCursor
enabled: statusImageWithTitle.headerImageEditable
onClicked: {
statusImageWithTitle.headerImageClicked()
}
}
Loader {
sourceComponent: statusLetterIdenticon
active: statusRoundedImage.image.status === Image.Error
@@ -80,23 +122,25 @@ Row {
Column {
id: textLayout
width: !iconOrImage.active ? parent.width :
parent.width - iconOrImage.width - parent.spacing
parent.width - iconOrImage.width - parent.spacing
Row {
id: headerTitleRow
width: parent.width
spacing: 4
StatusBaseText {
id: headerTitle
objectName: "headerTitle"
font.family: Theme.palette.baseFont.name
font.pixelSize: 17
font.bold: true
elide: statusImageWithTitle.titleElide
color: Theme.palette.directColor1
width: !editButton.visible ? parent.width :
parent.width - editButton.width - parent.spacing
width: !editButton.visible ? parent.width :
parent.width - editButton.width - parent.spacing
}
StatusFlatRoundButton {
id: editButton
objectName: "editAvatarbButton"
visible: statusImageWithTitle.editable
anchors.bottom: headerTitle.bottom
anchors.bottomMargin: -1
@@ -114,6 +158,7 @@ Row {
StatusBaseText {
id: headerSubTitle
objectName: "headerSubTitle"
font.family: Theme.palette.baseFont.name
font.pixelSize: 15
color:Theme.palette.baseColor1
@@ -13,6 +13,7 @@ Rectangle {
property list<Item> leftButtons
property list<StatusBaseButton> rightButtons
property bool showFooter: true
radius: 8
@@ -30,7 +31,7 @@ Rectangle {
}
}
implicitHeight: visible ? rootLayout.implicitHeight + 30 : 0
implicitHeight: rootLayout.implicitHeight + 30
RowLayout {
id: rootLayout
@@ -43,6 +44,7 @@ Rectangle {
Row {
id: leftButtonsLayout
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
visible: statusModalFooter.showFooter
spacing: 16
}
@@ -55,9 +57,9 @@ Rectangle {
Row {
id: rightButtonsLayout
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
visible: statusModalFooter.showFooter
spacing: 16
}
}
@@ -18,9 +18,11 @@ Rectangle {
property alias image: imageWithTitle.image
property alias icon: imageWithTitle.icon
property bool editable: false
property alias headerImageEditable: imageWithTitle.headerImageEditable
property Component popupMenu
signal editButtonClicked
signal headerImageClicked
signal close
implicitHeight: visible? Math.max(closeButton.height, imageWithTitle.implicitHeight) + 32 : 0
@@ -36,6 +38,18 @@ Rectangle {
}
}
Rectangle {
anchors.bottom: parent.bottom
width: parent.width
height: parent.radius
color: parent.color
StatusModalDivider {
anchors.bottom: parent.bottom
width: parent.width
}
}
StatusImageWithTitle {
id: imageWithTitle
anchors.verticalCenter: parent.verticalCenter
@@ -46,6 +60,7 @@ Rectangle {
editable: statusModalHeader.editable
titleElide: statusModalHeader.titleElide
subTitleElide: statusModalHeader.subTitleElide
onHeaderImageClicked: statusModalHeader.headerImageClicked()
onEditButtonClicked: statusModalHeader.editButtonClicked()
}
@@ -60,6 +75,7 @@ Rectangle {
Loader {
id: actionButtonLoader
objectName: "actionButtonloader"
anchors.right: closeButton.left
anchors.rightMargin: 8
anchors.top: parent.top
@@ -68,6 +84,7 @@ Rectangle {
StatusFlatRoundButton {
id: closeButton
objectName: "headerClosebutton"
anchors.right: parent.right
anchors.rightMargin: 20
anchors.top: parent.top
@@ -83,18 +100,6 @@ Rectangle {
onClicked: statusModalHeader.close()
}
Rectangle {
anchors.bottom: parent.bottom
width: parent.width
height: parent.radius
color: parent.color
StatusModalDivider {
anchors.bottom: parent.bottom
width: parent.width
}
}
Loader {
id: popupMenuSlot
active: !!statusModalHeader.popupMenu
+4 -3
View File
@@ -1,4 +1,5 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.76413 10.1901L8.32479 4.77888C8.70676 4.40717 9.32476 4.40591 9.71111 4.78187C10.0948 5.15523 10.0968 5.75861 9.71418 6.13093L3.45575 12.2211C3.26582 12.406 3.01753 12.4992 2.76838 12.5C2.51183 12.4981 2.26284 12.4063 2.07584 12.2244L0.284232 10.5078C-0.0959013 10.1379 -0.0957078 9.53795 0.290638 9.16199C0.674309 8.78863 1.29863 8.79084 1.67363 9.15576L2.76413 10.1901Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.76413 10.1901L14.3248 4.77888C14.7068 4.40717 15.3248 4.40591 15.7111 4.78187C16.0948 5.15523 16.0968 5.75861 15.7142 6.13093L9.45576 12.2211C9.26582 12.406 9.01753 12.4992 8.76838 12.5C8.51183 12.4981 8.26284 12.4063 8.07584 12.2244L6.28423 10.5078L7.67363 9.15576L8.76413 10.1901Z" fill="black"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.8641 4.42199C23.2087 4.65176 23.3019 5.11741 23.0721 5.46206L13.1981 19.4222C13.0734 19.6091 12.8715 19.7303 12.6479 19.7525C12.4243 19.7746 12.2026 19.6953 12.0437 19.5365L6.04369 13.5365C5.7508 13.2436 5.7508 12.7687 6.04369 12.4758C6.33658 12.1829 6.81146 12.1829 7.10435 12.4758L12.4575 17.8289L21.824 4.63C22.0538 4.28536 22.5194 4.19223 22.8641 4.42199Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.8556 4.38365C18.1927 4.6244 18.2707 5.09281 18.03 5.42988L12.0525 13.7986C11.8117 14.1357 11.3433 14.2137 11.0063 13.973C10.6692 13.7322 10.5911 13.2638 10.8319 12.9268L16.8094 4.55803C17.0501 4.22097 17.5185 4.1429 17.8556 4.38365Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.0194 12.4798C1.3111 12.1857 1.78597 12.1838 2.08005 12.4755L8.09766 18.4444C8.39174 18.7361 8.39367 19.211 8.10197 19.505C7.81027 19.7991 7.3354 19.801 7.04132 19.5093L1.02371 13.5404C0.729628 13.2487 0.727699 12.7738 1.0194 12.4798Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 894 B

After

Width:  |  Height:  |  Size: 1.1 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 1.5H4C2.61929 1.5 1.5 2.61929 1.5 4V16C1.5 17.3807 2.61929 18.5 4 18.5H16C17.3807 18.5 18.5 17.3807 18.5 16V4C18.5 2.61929 17.3807 1.5 16 1.5ZM4 0C1.79086 0 0 1.79086 0 4V16C0 18.2091 1.79086 20 4 20H16C18.2091 20 20 18.2091 20 16V4C20 1.79086 18.2091 0 16 0H4Z" fill="#939BA1"/>
<path d="M8.72261 11.4868V10.4133C8.72261 9.99528 8.38061 9.65328 7.96261 9.65328H6.22411C5.90111 9.65328 5.64461 9.90978 5.64461 10.2328C5.64461 10.5748 5.90111 10.8313 6.22411 10.8313H7.37361V11.5913C7.11711 11.8288 6.58511 12.0758 6.02461 12.0758C4.87511 12.0758 4.03911 11.1923 4.03911 9.99528C4.03911 8.79828 4.87511 7.91478 6.02461 7.91478C6.50911 7.91478 6.98411 8.12378 7.34511 8.47528C7.46861 8.59878 7.63961 8.66528 7.80111 8.66528C8.13361 8.66528 8.43761 8.38978 8.43761 8.05728C8.43761 7.91478 8.38061 7.76278 8.27611 7.64878C7.78211 7.11678 7.05061 6.71778 6.02461 6.71778C4.17211 6.71778 2.65211 7.99078 2.65211 9.99528C2.65211 11.9903 4.17211 13.2823 6.02461 13.2823C7.30711 13.2823 8.72261 12.6363 8.72261 11.4868Z" fill="#939BA1"/>
<path d="M11.4392 12.5603V7.43978C11.4392 7.07878 11.1352 6.77478 10.7742 6.77478C10.3942 6.77478 10.0902 7.07878 10.0902 7.43978V12.5603C10.0902 12.9213 10.3942 13.2253 10.7552 13.2253C11.1352 13.2253 11.4392 12.9213 11.4392 12.5603Z" fill="#939BA1"/>
<path d="M17.3479 7.43029C17.3479 7.09778 17.0819 6.83179 16.7684 6.83179H13.5669C13.1489 6.83179 12.8069 7.17379 12.8069 7.59179V12.5603C12.8069 12.9213 13.1109 13.2253 13.4719 13.2253C13.8519 13.2253 14.1559 12.9213 14.1559 12.5603V11.0463C14.1559 10.7701 14.3797 10.5463 14.6559 10.5463H16.2425C16.556 10.5463 16.822 10.2803 16.822 9.95728C16.822 9.62478 16.556 9.35879 16.2425 9.35879H14.6559C14.3797 9.35879 14.1559 9.13493 14.1559 8.85879V8.51929C14.1559 8.24314 14.3797 8.01929 14.6559 8.01929H16.7684C17.0819 8.01929 17.3479 7.75329 17.3479 7.43029Z" fill="#939BA1"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,3 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.85145 4.58361L7.3077 0.871991C7.19383 0.598227 6.80602 0.598227 6.69215 0.871991L5.1484 4.58361L1.1414 4.90485C0.845844 4.92854 0.726003 5.29738 0.951182 5.49027L4.0041 8.10542L3.07138 12.0156C3.00259 12.304 3.31634 12.5319 3.56937 12.3774L6.99993 10.282L10.4305 12.3774C10.6835 12.5319 10.9973 12.304 10.9285 12.0156L9.99575 8.10542L13.0487 5.49027C13.2738 5.29738 13.154 4.92854 12.8585 4.90485L8.85145 4.58361ZM10.8765 6.03425C10.9891 5.93781 10.9292 5.75339 10.7814 5.74154L8.77154 5.58041C8.39775 5.55045 8.07214 5.31388 7.92813 4.96764L7.15381 3.10596C7.09688 2.96908 6.90297 2.96908 6.84604 3.10596L6.07172 4.96764C5.92771 5.31388 5.6021 5.55045 5.22831 5.58041L3.21848 5.74154C3.0707 5.75339 3.01078 5.93781 3.12337 6.03425L4.65465 7.34596C4.93944 7.58991 5.06381 7.97269 4.97681 8.33744L4.50897 10.2987C4.47458 10.4429 4.63145 10.5569 4.75797 10.4796L6.47867 9.42861C6.79869 9.23315 7.20116 9.23315 7.52118 9.42861L9.24188 10.4796C9.3684 10.5569 9.52527 10.4429 9.49088 10.2987L9.02304 8.33744C8.93604 7.97269 9.06041 7.58991 9.3452 7.34596L10.8765 6.03425Z" fill="#FFCA0F"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.85169 4.58361L7.30794 0.871991C7.19408 0.598227 6.80626 0.598227 6.6924 0.871991L5.14865 4.58361L1.14164 4.90485C0.846088 4.92854 0.726247 5.29738 0.951426 5.49027L4.00434 8.10542L3.07163 12.0156C3.00283 12.304 3.31658 12.5319 3.56961 12.3774L7.00017 10.282L10.4307 12.3774C10.6838 12.5319 10.9975 12.304 10.9287 12.0156L9.996 8.10542L13.0489 5.49027C13.2741 5.29738 13.1543 4.92854 12.8587 4.90485L8.85169 4.58361Z" fill="#FFCA0F"/>
</svg>

After

Width:  |  Height:  |  Size: 589 B

+107
View File
@@ -0,0 +1,107 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M924 356.628C924 346.845 924.004 337.062 923.944 327.279C923.895 319.039 923.8 310.8 923.576 302.562C923.092 284.61 922.033 266.503 918.84 248.75C915.602 230.741 910.314 213.98 901.981 197.617C893.789 181.534 883.088 166.817 870.32 154.057C857.555 141.298 842.834 130.605 826.746 122.417C810.366 114.083 793.587 108.796 775.558 105.56C757.803 102.371 739.691 101.314 721.738 100.829C713.495 100.607 705.253 100.512 697.008 100.461C687.22 100.402 677.432 100.406 667.644 100.406L553.997 100H468.997L357.361 100.407C347.554 100.407 337.747 100.402 327.94 100.461C319.679 100.512 311.42 100.607 303.161 100.829C285.167 101.315 267.014 102.373 249.217 105.564C231.164 108.801 214.36 114.085 197.958 122.414C181.835 130.601 167.083 141.296 154.291 154.057C141.501 166.816 130.78 181.529 122.573 197.61C114.218 213.981 108.919 230.751 105.673 248.771C102.477 266.516 101.418 284.618 100.931 302.562C100.709 310.801 100.613 319.039 100.563 327.279C100.503 337.063 100 349.217 100 359L100.003 469.09L100 555L100.508 667.428C100.508 677.224 100.504 687.02 100.563 696.816C100.613 705.069 100.709 713.319 100.932 721.568C101.418 739.544 102.479 757.676 105.678 775.454C108.923 793.487 114.22 810.271 122.569 826.656C130.777 842.761 141.5 857.498 154.291 870.275C167.082 883.051 181.83 893.759 197.95 901.959C214.362 910.304 231.174 915.597 249.238 918.838C267.027 922.032 285.174 923.09 303.161 923.576C311.42 923.798 319.679 923.893 327.941 923.944C337.748 924.003 347.554 924 357.361 924L470.006 924.003H555.217L667.644 923.999C677.432 923.999 687.22 924.003 697.008 923.944C705.253 923.893 713.495 923.798 721.738 923.576C739.698 923.089 757.816 922.03 775.579 918.835C793.597 915.593 810.368 910.302 826.739 901.961C842.831 893.763 857.554 883.053 870.32 870.275C883.086 857.5 893.786 842.765 901.978 826.663C910.316 810.27 915.604 793.477 918.844 775.432C922.034 757.663 923.092 739.537 923.577 721.568C923.8 713.318 923.895 705.068 923.944 696.816C924.005 687.02 924 677.224 924 667.428C924 667.428 923.994 556.985 923.994 555V469C923.994 467.534 924 356.628 924 356.628Z" fill="#3B59DE"/>
</g>
<g clip-path="url(#clip0)">
<g filter="url(#filter1_f)">
<circle cx="512" cy="100" r="521" fill="white" fill-opacity="0.1"/>
</g>
</g>
<g filter="url(#filter2_ddiii)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M429.746 739.525C365.19 743.172 300.676 704.222 297.172 641.018C293.727 578.889 342.227 537.325 422.283 532.812C481.376 529.482 518.419 542.937 577.513 539.598C592.165 538.795 606.72 536.719 621.015 533.395C612.306 640.178 534.949 733.597 429.746 739.525Z" fill="url(#paint0_radial)"/>
</g>
<g filter="url(#filter3_ddiii)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M595.412 506.135C533.72 509.69 495.058 495.319 433.357 498.883C418.055 499.742 402.858 501.96 387.946 505.51C397.053 391.409 477.806 291.595 587.616 285.251C655.003 281.362 722.357 322.968 726.01 390.51C729.605 456.894 678.988 501.306 595.42 506.127L595.412 506.135Z" fill="url(#paint1_radial)"/>
</g>
<defs>
<filter id="filter0_d" x="89" y="89.0002" width="854" height="854.003" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dx="4" dy="4"/>
<feGaussianBlur stdDeviation="7.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<filter id="filter1_f" x="-213" y="-625" width="1450" height="1450" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="102" result="effect1_foregroundBlur"/>
</filter>
<filter id="filter2_ddiii" x="222" y="487.277" width="474.015" height="357.483" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="30"/>
<feGaussianBlur stdDeviation="37.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="13"/>
<feGaussianBlur stdDeviation="13.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="effect1_dropShadow" result="effect2_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-38"/>
<feGaussianBlur stdDeviation="61"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="shape" result="effect3_innerShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-10" dy="-33"/>
<feGaussianBlur stdDeviation="20"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.262745 0 0 0 0 0.376471 0 0 0 0 0.87451 0 0 0 0.17 0"/>
<feBlend mode="normal" in2="effect3_innerShadow" result="effect4_innerShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="10" dy="24"/>
<feGaussianBlur stdDeviation="32"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect4_innerShadow" result="effect5_innerShadow"/>
</filter>
<filter id="filter3_ddiii" x="312.946" y="240" width="488.244" height="371.705" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="30"/>
<feGaussianBlur stdDeviation="37.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="13"/>
<feGaussianBlur stdDeviation="13.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="effect1_dropShadow" result="effect2_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-38"/>
<feGaussianBlur stdDeviation="61"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="shape" result="effect3_innerShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-10" dy="-33"/>
<feGaussianBlur stdDeviation="20"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.262745 0 0 0 0 0.376471 0 0 0 0 0.87451 0 0 0 0.17 0"/>
<feBlend mode="normal" in2="effect3_innerShadow" result="effect4_innerShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="10" dy="24"/>
<feGaussianBlur stdDeviation="32"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect4_innerShadow" result="effect5_innerShadow"/>
</filter>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(360.545 542.122) rotate(45.3201) scale(237.198 346.271)">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0.8"/>
</radialGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(454.281 295.52) rotate(45.988) scale(250.586 365.62)">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0.8"/>
</radialGradient>
<clipPath id="clip0">
<rect x="100" y="100" width="824" height="824.003" rx="184" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 9.2 KiB

+47
View File
@@ -18,8 +18,10 @@
<file>src/StatusQ/Popups/StatusMenuSeparator.qml</file>
<file>src/StatusQ/Popups/StatusMenuHeadline.qml</file>
<file>src/StatusQ/Popups/StatusMenuItem.qml</file>
<file>src/StatusQ/Popups/StatusMenuItemDelegate.qml</file>
<file>src/StatusQ/Popups/StatusModalDivider.qml</file>
<file>src/StatusQ/Components/qmldir</file>
<file>src/StatusQ/Components/StatusAddress.qml</file>
<file>src/StatusQ/Components/StatusChatListItem.qml</file>
<file>src/StatusQ/Components/StatusChatListAndCategories.qml</file>
<file>src/StatusQ/Components/StatusChatInfoToolBar.qml</file>
@@ -37,9 +39,12 @@
<file>src/StatusQ/Components/StatusLoadingIndicator.qml</file>
<file>src/StatusQ/Platform/qmldir</file>
<file>src/StatusQ/Platform/StatusMacTrafficLights.qml</file>
<file>src/StatusQ/Controls/StatusAssetSelector.qml</file>
<file>src/StatusQ/Controls/StatusIconTabButton.qml</file>
<file>src/StatusQ/Controls/StatusChatInfoButton.qml</file>
<file>src/StatusQ/Controls/StatusColorSelector.qml</file>
<file>src/StatusQ/Controls/qmldir</file>
<file>src/StatusQ/Controls/StatusAccountSelector.qml</file>
<file>src/StatusQ/Controls/StatusSlider.qml</file>
<file>src/StatusQ/Controls/StatusRoundButton.qml</file>
<file>src/StatusQ/Controls/StatusNavBarTabButton.qml</file>
@@ -50,6 +55,7 @@
<file>src/StatusQ/Controls/StatusSwitch.qml</file>
<file>src/StatusQ/Controls/StatusCheckBox.qml</file>
<file>src/StatusQ/Controls/StatusButton.qml</file>
<file>src/StatusQ/Controls/StatusSelect.qml</file>
<file>src/StatusQ/Controls/StatusToolTip.qml</file>
<file>src/StatusQ/Controls/Validators/StatusValidator.qml</file>
<file>src/StatusQ/Controls/Validators/StatusMinLengthValidator.qml</file>
@@ -268,5 +274,46 @@
<file>src/StatusQ/Controls/StatusSwitchTabBar.qml</file>
<file>src/StatusQ/Components/StatusExpandableItem.qml</file>
<file>src/assets/img/icons/snt.svg</file>
<file>src/StatusQ/Popups/StatusSpellcheckingMenuItems.qml</file>
<file>src/StatusQ/Controls/StatusSelectableText.qml</file>
<file>src/assets/img/icons/tiny/add.svg</file>
<file>src/assets/img/icons/tiny/arrow-down.svg</file>
<file>src/assets/img/icons/tiny/channel-white.svg</file>
<file>src/assets/img/icons/tiny/channel.svg</file>
<file>src/assets/img/icons/tiny/chat.svg</file>
<file>src/assets/img/icons/tiny/chatbot.svg</file>
<file>src/assets/img/icons/tiny/checkmark.svg</file>
<file>src/assets/img/icons/tiny/chevron-down.svg</file>
<file>src/assets/img/icons/tiny/chevron-left.svg</file>
<file>src/assets/img/icons/tiny/chevron-right.svg</file>
<file>src/assets/img/icons/tiny/chevron-up.svg</file>
<file>src/assets/img/icons/tiny/clear.svg</file>
<file>src/assets/img/icons/tiny/community-1.svg</file>
<file>src/assets/img/icons/tiny/community.svg</file>
<file>src/assets/img/icons/tiny/contact.svg</file>
<file>src/assets/img/icons/tiny/double-checkmark.svg</file>
<file>src/assets/img/icons/tiny/edit.svg</file>
<file>src/assets/img/icons/tiny/external.svg</file>
<file>src/assets/img/icons/tiny/group-white.svg</file>
<file>src/assets/img/icons/tiny/group.svg</file>
<file>src/assets/img/icons/tiny/more.svg</file>
<file>src/assets/img/icons/tiny/message/delivered.svg</file>
<file>src/assets/img/icons/tiny/message/pending.svg</file>
<file>src/assets/img/icons/tiny/message/sent.svg</file>
<file>src/assets/img/icons/tiny/message/warning.svg</file>
<file>src/assets/img/icons/tiny/muted-white.svg</file>
<file>src/assets/img/icons/tiny/muted.svg</file>
<file>src/assets/img/icons/tiny/not-secure.svg</file>
<file>src/assets/img/icons/tiny/pending.svg</file>
<file>src/assets/img/icons/tiny/pin.svg</file>
<file>src/assets/img/icons/tiny/public-chat-white.svg</file>
<file>src/assets/img/icons/tiny/public-chat.svg</file>
<file>src/assets/img/icons/tiny/reply.svg</file>
<file>src/assets/img/icons/tiny/secure.svg</file>
<file>src/assets/img/icons/tiny/settings.svg</file>
<file>src/assets/img/icons/tiny/SNT.svg</file>
<file>src/assets/img/icons/tiny/time.svg</file>
<file>src/assets/img/icons/tiny/tribute-to-talk.svg</file>
<file>src/assets/img/icons/tiny/warning.svg</file>
</qresource>
</RCC>