Compare commits

..
Author SHA1 Message Date
Khushboo Mehta 2a1c11eb15 feat(StatusListItem): Add tags model under subtitle in a list item 2022-03-29 22:29:32 +02:00
Noelia a99e5e0201 fix(StatusChatListCategory): Selecting the category menu should not toggle the category itself
Closes `status-desktop` issue https://github.com/status-im/status-desktop/issues/4914
2022-03-29 19:23:46 +02:00
Stefan 8d780bb5b9 tests(StatusInput): add regression test to check for qml output
Also improves on the test structure
2022-03-29 19:23:46 +02:00
Michał Iskierko b0c00fd60d fix(StatusSearchPopup): Fix cutting text with big font (#604)
Decreasing padding.
Setting loading property default to false.

Fix #5197
2022-03-29 19:23:45 +02:00
Patryk Osmaczko 99659b2589 fix(StatusInput): add implicitHeight
It makes it work with layouts correctly.
2022-03-29 19:23:45 +02:00
Patryk Osmaczko ac3abff16f fix(StatusBaseInput): fix default padding when leftComponent is loaded 2022-03-29 19:23:45 +02:00
Alexandra Betouni cf0ba3f7a1 fix(StatusSeedPhraseInput): Increased suggestion match chars to 4 2022-03-29 19:23:45 +02:00
Alexandra Betouni 3c2e97c5e2 fix(StatusSeedPhraseInput): exposed touch/keys pressed events
Exposed keys.onPressed signal, mouse on clicked signal
as well as tabNavItem to be set in KeyNavigation.tab
when needed

Needed for task https://github.com/status-im/status-desktop/issues/4955
2022-03-26 00:29:04 +02:00
Khushboo Mehta b9aa49853a fix(StatusInput): Added mising documentation of new properties to StatusInput and StatusModal
Moved the StatusInputWithCursor out of StatusQ as it not needed under StatusQ.
2022-03-25 14:51:53 +01:00
Khushboo Mehta 03eb6302d5 fix(StatusModal): Added support for advanced footer and header as seen in new designs.
It is also backward compatible and is not a breaking change.
2022-03-25 14:51:53 +01:00
Khushboo Mehta 5f8f798cf2 feat(StatusInput): Expose errorMessage so that its placement can be controlled from outside 2022-03-25 14:51:53 +01:00
Khushboo Mehta bbc0177a66 fix(StatusListItemTag): Fix for allignment in StatusListItemTag and option to make close button invisible 2022-03-25 14:51:53 +01:00
Khushboo Mehta 6ce9f9bd86 feat: Added new icon fees 2022-03-25 14:51:53 +01:00
Khushboo Mehta 46254f79c4 feat(StatusFloatValidator): Used to validate a float variable for
1. Is a valid number
2. Is greater than bottom value
3. Is less than top value
2022-03-25 14:51:53 +01:00
Khushboo Mehta ad659a5dc2 feat(StatusInputWithCursor): Extended the StatusInput to support an Input with no background and a blinking custom cursor 2022-03-25 14:51:53 +01:00
Alexandra Betouni 41f67b59e9 fix(StatusTagSelector): move suggestions popup inside component (#598)
Closes #531
2022-03-24 18:03:36 -04:00
r4bbit.eth aa91a88be7 chore: add check for dark and light theme to PR template (#597) 2022-03-24 07:03:31 +01:00
Boris Melnik f299c9df3a fix(StatusQ.Popups): Replace TextEdit to StatusBaseInput for SearchPopup
Closes: https://github.com/status-im/status-desktop/issues/5059
2022-03-23 17:16:52 +01:00
Patryk Osmaczko b6c3231e30 feat(StatusQ.Controls): add StatusTokenInlineSelector
Closes: status-im/status-desktop#4937
2022-03-23 11:00:57 +01:00
Jonathan Rainville 496ad05247 fix(StatusLetterIdenticon): fix emoji positioning
The emoji wasn't centered correctly on Windows
Fixes #5045
2022-03-23 07:29:34 +01:00
Patryk Osmaczko 93f9214aad fix(StatusBaseInput): apply changes required by StatusSeedPhraseInput 2022-03-22 19:45:52 +01:00
Patryk Osmaczko 22bbf9b177 refactor(StatusBaseInput): use RowLayout for position management 2022-03-22 19:45:52 +01:00
Noelia 7301323ed7 fix(StatusPasswordStrengthIndicator): Added new onValueChanged condition
Added new `onValueChanged` condition if bar value is 0 --> Strength.None.
2022-03-22 10:21:48 +01:00
Alexandra Betouni c6e4cf627c fix(SeedPhraseInput): Fixing SeedPhraseInput control height
The suggestion list should be showing up to 5 seed
word entries
2022-03-22 09:20:13 +01:00
Alexandra Betouni 5c1c9852ae fix(SeedPhraseInput): fix lost focus after typing one character
Relates to: https://github.com/status-im/status-desktop/issues/4955
2022-03-22 09:17:18 +01:00
osmaczko be2b2c3df7 ci: add pull request template 2022-03-21 14:19:57 +01:00
Jonathan Rainville 1362a94448 fix(StatusChatListItem): add missing import (#585) 2022-03-18 12:15:38 -04:00
Jonathan Rainville 189f66225c fix(StatusIconSettings): set charactersLen to 1 by default (#581)
This caused a breaking change where components that used to imply 1 charactersLen now showed no character at all because it defaulted to 0.
2022-03-17 15:08:51 -04:00
Jonathan Rainville 40d8b9c2f6 feat(StatusIconSetting): add emojiSize setting for icons (#579) 2022-03-17 14:14:39 -04:00
Jonathan Rainville 8af7028efc fix(StatusContactRequestIndicatorListItem): hide badge when value is 0 (#580)
* fix(StatusContactRequestIndicatorListItem): hide badge when value is 0

* feat(icons): add edit pencil icon
2022-03-17 11:56:44 -04:00
Alexandra Betouni f1eff6700a feat(StatusQ/Controls): Adding StatusSeedPhraseInput control
Also added an example in Inputs page

Closes #567
2022-03-17 11:24:36 +01:00
Stefan 082bb8ef45 docs(StatusInput): Initial basic docs plus validationMode 2022-03-14 02:43:01 -07:00
Stefan 7609450068 test(StatusInput): Add initial basic tests 2022-03-14 02:43:01 -07:00
Stefan 6570275176 fix(dev): silence qml warnings 2022-03-14 02:43:01 -07:00
Stefan 4b579cddbe feat(StatusInput): add mode to ingnore unvalidated content
Add optional feature to StatusInput not to allow typing characters
that are not validated

updates #4961
2022-03-14 02:43:01 -07:00
osmaczko a84026d74d Add various of changes required by emojiHash and identiconRing integration (#577)
* chore(StatusIdenticonRing): make ringSpecModel accept array of objects

* chore(StatusLetterIdenticon): add charactersLen and textColor settings
2022-03-13 09:00:55 -04:00
Khushboo-dev-cpp 428b165198 feat: Add emoji support (#575)
* feat: Add emoji support
1. StatusChatListItem (only updated parts already done by Jo)
2. StatusListItem
3. StatusInput

* feat(StatusColorSelectorGrid): Added new widget for color selection as needed in wallet

* fix(StatusInput): on reset, valid should be set to true else error mode is shown even though the user hasnt entered a value

* fix(StatusLetterIdenticon): Removed the clicked event out from the LetterIdenticon and added it to the StatusBaseInput as other places that use the letterIdenticon dont need the mouse area is not needed
2022-03-11 14:34:21 -05:00
Jonathan Rainville 56b2663e4d fix(StatusQ.Validators): fix regular expression test in validator 2022-03-10 17:10:15 +01:00
Anthony Laibe 9dbb7ec53f fix(@StatusListItem): Use tags model 2022-03-10 15:14:14 +01:00
Alexandra Betouni 7e9c7a52fd feat(StatusLetterIdenticon): Added charCount property in StatusLetterIdenticon
For desktop task #4956 the letter identicon displayed inside
the StatusSmartIdenticon should be of 2 characters and not 1.
2022-03-10 10:06:07 +01:00
Noelia 2e33fb9f81 feat(StatusPasswordStrengthIndicator): Add new Strength type None
Add new Strength type None and its corresponding state.
2022-03-09 13:17:58 +01:00
Pascal Precht 208825807b chore: cut v0.25.0 release 2022-03-07 19:11:38 +01:00
Anthony Laibe 381150a7b5 feat(@StatusListItem): add option for tags 2022-03-07 13:29:26 +01:00
Jonathan Rainville 5fac8774f4 feat(StatusChatListItem): enable assigning emoji to chat item 2022-03-07 10:19:43 +01:00
Anthony Laibe e9f20be15a feat(StatusQ.Core): add new arrow-left icon 2022-03-03 10:53:50 +01:00
Anthony Laibe 9d06aae1f4 fix(build): fix linux build
Fixes #413
2022-03-03 10:50:45 +01:00
Anthony Laibe f574e39012 fix(@StatusListItem): fix left padding
When there is an icon, take it into account when calculating the left
padding
2022-03-02 19:01:12 +01:00
Jonathan Rainville 8495fae8a5 fix(StatusListItem): add propagateTitleClicks property to StatusListItem
Makes it possible disable the propagation of the mouse event when it's not wanted, for example in the search popup, where if the user clicks the title, we want to show the profile popup, but not navigate to the channel
2022-02-23 09:49:59 +01:00
Alexandra Betouni 07a5dc09ac fix(StatusTagSelector): Updates and fixes in the component
Moved `remove` function below remove contact signal
also removed online status badge from CreateChatView

Fixed as well name tags to be adapting on parent's
width and scrolling the list to the end when this is
bigger than the available width. Switcehd to use
nameCountLimit property where needed
2022-02-22 11:27:35 +01:00
Boris Melnik 9e6fbe955a feat(StatusChatList): Highlight chat item at creation time
Part of: https://github.com/status-im/status-desktop/issues/4767
2022-02-21 08:46:20 +01:00
Noelia 1217771fd0 feat(StatusPinInput): Introduce StatusPinInput control
It creates `StatusPinInput` control that allows customzing its circle diameter, circle spacing and pin length. It contains a `TextInput` object that will provide the component, input text management like validation rules.

It incorporates a blinking animation when the control is focused and feedback (mouse shape changed) when hovering it.

It adds new page in sandbox to play with `StatusPinInput` control.

It adds component documentation.

Also it creates 2 new `StatusValidator` controls with their corresponding documentation:
- `StatusRegularExpressionValidator` which wraps a QML type `RegularExpressionValidator`.

- `StatusIntValidator` which wraps a QML type `IntValidator`.

Closes #524
2022-02-18 09:25:05 +01:00
Noelia 3b86d13a96 feat(StatusSmartIdenticon): Add support for color rings in StatusSmartIdenticon (#553)
Created new control `StatusIdenticonRing` and used in `StatusSmartIdenticon` component.

Added property assignments in sandbox models to display the `StatusIdenticonRing` when needed.

Added first documentation approach for `StatusIdenticonRing` and `StatusIdenticonRingSettings`.

Closes #517
2022-02-17 09:20:17 +01:00
Noelia c0f825c690 feat(StatusContactVerificationIcons): Create new row control that includes mutual connect and trust indicator icons (#559)
Create `StatusContactVerificationIcons` row component.

Refactor in `StatusMemberListItem`. It now uses `StatusContactVerificationIcons` component.

Refactor in `StatusListItem`. It now contains a Loader for dynamically decide if a row icons component is defined aside the title.

Refactor in `StatusMessageHeader` and `StatusMessage`. They now use `StatusContactVerificationIcons` component.

Closes #542

BREAKING CHANGES:

Removed `titleIcon1Visible` and `titleIcon1Visible` from `StatusListItem`.

Removed `ContactType` enumeration in `StatusMessage`. Now, contact verification type is managed by enum `TrustedType` in `StatusContactVerificationIcons` component.
2022-02-16 11:37:48 +01:00
Alexandra Betouni 825999b151 feat(StatusQ): Moving docs outside sandbox
To generate docs, from doc folder run
/path/to/Qt/installation/bin/qdoc statusq.qdocconf

A folder named "html" will be generated under doc,
open the statusq-index.html to get to the home page.
2022-02-15 08:43:33 +01:00
Alexandra Betouni cdf51fefbd fix(sandbox): Fix results popup component position
Fixed alignment when results are being filtered.
If the x position that the popup should be aligned
goes off the screen, the popup appears back on
position 0. Also fixed result list item was not
vertically centered.
2022-02-15 08:40:19 +01:00
Alexandra Betouni 665141f81d fix(StatusQ.Popups): removed overlay setting (#557)
A MouseArea was set as an Overlay to the PopupMenu
consuming all clicks outside the component until it
was closed. Removed it as it's not necessary anymore.

Closes https://github.com/status-im/status-desktop/issues/3599
2022-02-15 05:08:15 +02:00
Pascal Precht 9cbd19d658 chore: release v0.24.0 2022-02-14 10:02:02 +01:00
Alexandra Betouni 0e00fd24ab feat(StatusQ) Adding qdoc related files (#555)
Added qdoc conf & source files for each
StatusQ module. Documented StatusBaseText
from StatusQ.Core as an example

To generate docs, from sandbox/docs run
/path/to/Qt/installation/bin/qdoc statusq.qdocconf

A folder named "html" will be generated under sandbox/doc,
open the statusq-index.html to get to the home page.

Closes #550
2022-02-11 09:55:44 -05:00
Patryk Osmaczko 5780f183c7 feat(StatusListItem): add highlighted property 2022-02-09 10:00:41 +01:00
Alexandra Betouni b7d6554b80 feat(StatusQ.Components): Adding StatusWizardSteper component
Added StatusWizardStepper component

Also added corresponding page in API documentation

Closes #522
2022-02-09 09:21:46 +01:00
Pascal Precht 0fabd92d61 chore: cut 0.23.0 release 2022-02-08 09:40:35 +01:00
Alexandra Betouni 7b290ddd56 feat(StatusQ.Components): Adding StatusToastMessage
Added StatusToastMessage component, an example page
as well as a demonstration in chat view

Closes #521
2022-02-08 09:36:38 +01:00
Alexandra Betouni 094dee4928 feat(StatusQ.Components): Adding StatusTagSelector component
Added StatusTagSelector component needed for
creating new chat channels, either ono on
one or group based on updated designs on
Figma

Also added corresponding page in API Documentation

Closes #526
2022-02-02 10:26:45 +01:00
Noelia 5497bb3f5f chore(demoApp): restore DemoApp to have the latest changes from both master and base_bc
Updated DemoApp, main and Models to have the
latest changes from both master and base_bc
2022-02-02 10:18:03 +01:00
Richard Ramos d85ed4c3ed refactor: fix empty categories handling (#544)
* feat(StatusChatListCategory): display item if the model is a category
* fix(StatusChatListAndCategories): do not display categories in StatusChatList
2022-02-01 11:10:09 +01:00
Sale Djenic 77b89edbdb refactor(StatusAppNavBar): triggerUpdate function added 2022-02-01 11:10:09 +01:00
Sale Djenic 80396841f1 refactor(StatusChatToolBar): open/close handlers get called if they are set for popupMenu of StatusChatToolBar component 2022-02-01 11:10:09 +01:00
Sale Djenic c2e075178c fix(StatusChatList): unexisting property name for chat item fixed
`StatusChatList` component is able to display:
- chats for Chat section
- channels for Community section
- channels from a category from Community section

in cases 1. and 2. displayed items do not have `parentItemId` property and
it's not used in these cases.
This commit fixes that console error.
2022-02-01 11:10:09 +01:00
Sale Djenic e0f34a3e1d refactor(StatusChatList): categoryId parameter added to chatItemSelected signal 2022-02-01 11:10:09 +01:00
Sale Djenic c2bab872be refactor(StatusChatList): updates due to chat & communities models refactored
Updated Models.qml for chats and communities models to reflect changes due to
refactor in the actual backend.`StatusChatList` and `StatusChatListAndCategories`
components updated accordingly.
2022-02-01 11:10:09 +01:00
Alexandra Betouni 491f7d5d15 refactor(sandbox): remove obsolete timeline demo code
This feature is deprecated and shall be removed

Relates to #4177
2022-02-01 11:10:09 +01:00
Sale Djenic c6893b0c7f refactor(StatusAppNavBar): profile nav bar button added
Profile button of type `StatusNavBarTabButton` added to `StatusAppNavBar`
and exposed so it can be optionally set from outside of the component.
2022-02-01 11:10:09 +01:00
Sale Djenic 2ee91475e5 refactor(StatusAppNavBar): navigation bar displays buttons based on set model
`StatusAppNavBar` component is refactored in order to meet new changes we
have on the backend in the desktop app.
2022-02-01 11:10:09 +01:00
10188 changed files with 26038 additions and 1132 deletions
+17
View File
@@ -0,0 +1,17 @@
### Checklist
- [ ] follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)
- the scope should be the component's name e.g: `feat(StatusListItem): ... `
- when adding new components, the scope is the module e.g: `feat(StatusQ.Controls): ...`
- [ ] add documentation if necessary (new component, new feature)
- [ ] update sandbox app
- in case of new component, add new component page
- in case of new features, add variation to existing component page
- nice to have: add it to the demo application as well
- [ ] test changes in both light and dark theme?
- [ ] is this a breaking change?
- [ ] use the dedicated `BREAKING CHANGE` commit message section
- [ ] resolve breaking changes in [status-desktop](https://github.com/status-im/status-desktop)
- [ ] (pre-merge) adapt code to breaking changes
- [ ] (post-merge) update StatusQ submodule pointer
- [ ] test changes in [status-desktop](https://github.com/status-im/status-desktop)
+4
View File
@@ -13,3 +13,7 @@ Makefile
*_qml.cpp
*_qmlcache.qrc
sandbox/qmlcache_loader.cpp
doc/html
CMakeLists.txt.user
.vscode
build/
+57
View File
@@ -1,3 +1,60 @@
<a name=""></a>
## 0.25.0 (2022-03-07)
#### Bug Fixes
* **@StatusListItem:** fix left padding ([f574e390](f574e390))
* **StatusListItem:** add propagateTitleClicks property to StatusListItem ([8495fae8](8495fae8))
* **StatusQ.Popups:** removed overlay setting (#557) ([665141f8](665141f8))
* **StatusTagSelector:** Updates and fixes in the component ([07a5dc09](07a5dc09))
* **build:** fix linux build ([9d06aae1](9d06aae1), closes [#413](413))
* **sandbox:** Fix results popup component position ([cdf51fef](cdf51fef))
#### Features
* **@StatusListItem:** add option for tags ([381150a7](381150a7))
* **StatusChatList:** Highlight chat item at creation time ([9e6fbe95](9e6fbe95))
* **StatusChatListItem:** enable assigning emoji to chat item ([5fac8774](5fac8774))
* **StatusContactVerificationIcons:** Create new row control that includes mutual connect and trust indicator icons (#559) ([c0f825c6](c0f825c6), closes [#542](542))
* **StatusQ:** Moving docs outside sandbox ([825999b1](825999b1))
* **StatusQ.Core:** add new arrow-left icon ([e9f20be1](e9f20be1))
* **StatusSmartIdenticon:** Add support for color rings in StatusSmartIdenticon (#553) ([3b86d13a](3b86d13a), closes [#517](517))
#### Breaking Changes
* **StatusContactVerificationIcons:** Create new row control that includes mutual connect and trust indicator icons (#559) ([c0f825c6](c0f825c6), closes [#542](542))
<a name=""></a>
## 0.24.0 (2022-02-14)
#### Features
* **StatusListItem:** add highlighted property ([5780f183](5780f183))
* **StatusQ.Components:** Adding StatusWizardSteper component ([b7d6554b](b7d6554b), closes [#522](522))
<a name=""></a>
## Version 0.23.0 (2022-02-08)
#### Bug Fixes
* Icon components had wrong color in sandbox app ([b632c712](b632c712), closes [#538](538))
* **StatusChatList:** unexisting property name for chat item fixed ([c2e07517](c2e07517))
#### Features
* **StatusQ.Components:**
* Adding StatusToastMessage ([7b290ddd](7b290ddd), closes [#521](521))
* Adding StatusTagSelector component ([094dee49](094dee49), closes [#526](526))
<a name=""></a>
## Version 0.22.0 (2022-01-31)
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

+19
View File
@@ -0,0 +1,19 @@
/*!
\page statusq-index.html
\title StatusQ
\brief A components library for Status desktop client.
StatusQ provides a collection of components....
StatusQ - Components and Interfaces
\list
\li \l{StatusQ Components}{Components}
\li \l{StatusQ Controls}{Controls}
\li \l{StatusQ Core}{Core}
\li \l{StatusQ Layout}{Layout}
\li \l{StatusQ Platform}{Platform}
\li \l{StatusQ Popups}{Popups}
\endlist
*/
+41
View File
@@ -0,0 +1,41 @@
/*!
\qmlmodule StatusQ.Components 0.1
\title StatusQ Components
\brief Basic set of Components StatusQ components
This is a listing of all Components components.
This module is part of the \l{StatusQ}{StatusQ} project.
\list
\li \l{StatusAddress}
\li \l{StatusBadge}
\li \l{StatusChatInfoToolBar}
\li \l{StatusChatList}
\li \l{StatusChatListItem}
\li \l{StatusImageSettings}
\li \l{StatusChatListCategory}
\li \l{StatusChatListCategoryItem}
\li \l{StatusChatListAndCategories}
\li \l{StatusChatToolBar}
\li \l{StatusContactRequestsIndicatorListItem}
\li \l{StatusDescriptionListItem}
\li \l{StatusLetterIdenticon}
\li \l{StatusListItem}
\li \l{StatusListSectionHeadline}
\li \l{StatusLoadingIndicator}
\li \l{StatusMemberListItem}
\li \l{StatusNavigationListItem}
\li \l{StatusNavigationPanelHeadline}
\li \l{StatusRoundIcon}
\li \l{StatusRoundedImage}
\li \l{StatusMacWindowButtons}
\li \l{StatusListItemBadge}
\li \l{StatusExpandableItem}
\li \l{StatusSmartIdenticon}
\li \l{StatusMessage}
\li \l{StatusMessageDetails}
\li \l{StatusTagSelector}
\li \l{StatusToastMessage}
\endlist
*/
+47
View File
@@ -0,0 +1,47 @@
/*!
\qmlmodule StatusQ.Controls 0.1
\title StatusQ Controls
\brief Basic set of Controls StatusQ components
This is a listing of all Controls components.
This module is part of the \l{StatusQ}{StatusQ} project.
\list
\li \l{StatusAccountSelector}
\li \l{StatusAssetSelector}
\li \l{StatusBanner}
\li \l{StatusChatCommandButton}
\li \l{StatusChatInfoButton}
\li \l{StatusChatListCategoryItemButton}
\li \l{StatusColorSelector}
\li \l{StatusIconTabButton}
\li \l{StatusNavBarTabButton}
\li \l{StatusTabBarIconButton}
\li \l{StatusToolTip}
\li \l{StatusBaseButton}
\li \l{StatusButton}
\li \l{StatusFlatButton}
\li \l{StatusRoundButton}
\li \l{StatusFlatRoundButton}
\li \l{StatusSwitch}
\li \l{StatusRadioButton}
\li \l{StatusCheckBox}
\li \l{StatusSlider}
\li \l{StatusSelect}
\li \l{StatusBaseInput}
\li \l{StatusIdenticonRing}
\li \l{StatusInput}
\li \l{StatusPickerButton}
\li \l{StatusPinInput}
\li \l{StatusProgressBar}
\li \l{StatusPasswordStrengthIndicator}
\li \l{StatusSwitchTabButton}
\li \l{StatusSwitchTabBar}
\li \l{StatusSelectableText}
\li \l{StatusWalletColorButton}
\li \l{StatusWalletColorSelect}
\li \l{StatusRegularExpressionValidator}
\li \l{StatusIntValidator}
\endlist
*/
+23
View File
@@ -0,0 +1,23 @@
/*!
\qmlmodule StatusQ.Core 0.1
\title StatusQ Core
\brief Basic set of Core StatusQ components
This is a listing of all Core components. These
files are available for general import and they are based off the \l{https://doc.qt.io/qt-5/qtquick-qmlmodule.html}{Qt
Quick Primitives} and \l{https://doc.qt.io/archives/qt-5.11/qtquick-controls2-qmlmodule.html}{Qt Quick Controls 2}.
This module is part of the \l{StatusQ}{StatusQ} project.
\list
\li \l{StatusAppNavBarFilterModel}
\li \l{StatusBaseText}
\li \l{StatusIcon}
\li \l{StatusIconBackgroundSettings}
\li \l{StatusIconSettings}
\li \l{StatusIdenticonRingSettings}
\li \l{StatusImageSettings}
\li \l{StatusModalHeaderSettings}
\li \l{StatusTooltipSettings}
\endlist
*/
+16
View File
@@ -0,0 +1,16 @@
/*!
\qmlmodule StatusQ.Layout 0.1
\title StatusQ Layout
\brief Basic set of Layout StatusQ components
This is a listing of all Layout components.
This module is part of the \l{StatusQ}{StatusQ} project.
\list
\li \l{StatusAppLayout}
\li \l{StatusAppNavBar}
\li \l{StatusAppTwoPanelLayout}
\li \l{StatusAppThreePanelLayout}
\endlist
*/
+15
View File
@@ -0,0 +1,15 @@
/*!
\qmlmodule StatusQ.Platform 0.1
\title StatusQ Platform
\brief Basic set of Platform StatusQ components
This is a listing of all Platform components.
This module is part of the \l{StatusQ}{StatusQ} project.
\list
\li \l{StatusMacTrafficLights}
\li \l{StatusMacNotification}
\li \l{StatusWindowsTitleBar}
\endlist
*/
+22
View File
@@ -0,0 +1,22 @@
/*!
\qmlmodule StatusQ.Popups 0.1
\title StatusQ Popups
\brief Basic set of Popups StatusQ components
This is a listing of all Popups components.
This module is part of the \l{StatusQ}{StatusQ} project.
\list
\li \l{StatusMenuSeparator}
\li \l{StatusPopupMenu}
\li \l{StatusMenuItem}
\li \l{StatusMenuItemDelegate}
\li \l{StatusModal}
\li \l{StatusSearchPopup}
\li \l{StatusModalDivider}
\li \l{StatusSearchPopupMenuItem}
\li \l{StatusSearchLocationMenu}
\li \l{StatusSpellcheckingMenuItems}
\endlist
*/
+36
View File
@@ -0,0 +1,36 @@
project = StatusQ
version = 0.1
description = StatusQ Project
url = https://github.com/status-im/StatusQ
#These are set implictly by qdoc as well, but only with these the module header can be found
includepaths = -I . \
-I $PWD/../src/StatusQ
imagedirs = src/images
sourcedirs += src \
$PWD/../src/StatusQ/Components \
$PWD/../src/StatusQ/Controls \
$PWD/../src/StatusQ/Core \
$PWD/../src/StatusQ/Layout \
$PWD/../src/StatusQ/Platform \
$PWD/../src/StatusQ/Popups \
sources.fileextensions = "*.cpp *.qdoc *.qml"
depends += qtcore \
qtquick \
qtqml \
qtgui \
qtdoc \
qtquickcontrols2
navigation.homepage = "StatusQ"
outputdir = $PWD/html
outputformats = HTML
HTML.stylesheets = style.css
HTML.headerstyles = "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\"/>\n"
HTML.postheader = "<p class=\"header\"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/>"
HTML.footer = "<hr/><div class=\"footer\"><p><acronym title=\"Copyright\">&copy;</acronym> 2022 Status. All rights reserved. <a href=\"https://status.im\" target=\"_blank\"><small>status.im</a></small></p></div>"
+41
View File
@@ -0,0 +1,41 @@
body {
font-family: "Verdana";
font-size: 14px;
max-width: 80%;
margin: auto;
}
h1, h2, h3 {
color: #4360DF;
}
div.sidebar {
float: right;
}
pre {
padding: 15px;
}
div.qmlproto {
padding-left: 15px;
padding-right: 15px;
}
pre, div.qmlproto {
font-family: "Courier New";
font-size: 20px;
margin-left: 2em;
background-color: #F0F2F5;
}
hr {
margin-top: 2em;
margin-bottom: 2em;
}
p.header {
margin-bottom: -1em;
}
p.footer {
text-align: right;
margin-top: -1em;
}
+91 -53
View File
@@ -1,12 +1,16 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Layout 0.1
import StatusQ.Popups 0.1
import StatusQ.Platform 0.1
import "demoapp"
import "demoapp/data" 1.0
Rectangle {
id: demoApp
@@ -17,6 +21,31 @@ Rectangle {
property string titleStyle: "osx"
QtObject {
id: appSectionType
readonly property int chat: 0
readonly property int community: 1
readonly property int wallet: 2
readonly property int browser: 3
readonly property int nodeManagement: 4
readonly property int profileSettings: 5
readonly property int apiDocumentation: 100
readonly property int demoApp: 101
}
function setActiveItem(sectionId) {
for (var i = 0; i < Models.demoAppSectionsModel.count; i++) {
let item = Models.demoAppSectionsModel.get(i)
if (item.sectionId !== sectionId)
{
Models.demoAppSectionsModel.setProperty(i, "active", false)
continue
}
Models.demoAppSectionsModel.setProperty(i, "active", true);
}
}
StatusMacTrafficLights {
anchors.left: parent.left
anchors.top: parent.top
@@ -47,32 +76,74 @@ Rectangle {
id: navBar
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
tooltip.text: "Chat"
checked: appView.sourceComponent == statusAppChatView
onClicked: {
appView.sourceComponent = statusAppChatView
}
communityTypeRole: "sectionType"
communityTypeValue: appSectionType.community
sectionModel: Models.demoAppSectionsModel
property bool communityAdded: false
onAboutToUpdateFilteredRegularModel: {
communityAdded = false
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Status Community"
tooltipText: "Status Community"
}
filterRegularItem: function(item) {
if(item.sectionType === appSectionType.community)
if(communityAdded)
return false
else
communityAdded = true
return true
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
id: communityBtn
filterCommunityItem: function(item) {
return item.sectionType === appSectionType.community
}
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.name
tooltip.text: model.tooltipText
icon.color: Theme.palette.miscColor6
icon.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
checked: appView.sourceComponent == statusAppCommunityView
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
onClicked: {
appView.sourceComponent = statusAppCommunityView
if(model.sectionType === appSectionType.chat)
{
appView.sourceComponent = statusAppChatView
demoApp.setActiveItem(model.sectionId)
}
else if(model.sectionType === appSectionType.profileSettings)
{
appView.sourceComponent = statusAppProfileSettingsView
demoApp.setActiveItem(model.sectionId)
}
}
}
communityNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
onClicked: {
if(model.sectionType === appSectionType.community)
{
appView.sourceComponent = statusAppCommunityView
demoApp.setActiveItem(model.sectionId)
}
}
popupMenu: StatusPopupMenu {
@@ -103,40 +174,7 @@ Rectangle {
type: StatusMenuItem.Type.Danger
}
}
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "bigger/browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "bigger/status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
id: profileNavButton
icon.name: "bigger/settings"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusAppNavBar.backgroundColor
badge.border.width: 2
tooltip.text: "Profile"
checked: appView.sourceComponent == statusAppProfileSettingsView
onClicked: {
appView.sourceComponent = statusAppProfileSettingsView
}
}
]
}
appView: Loader {
+348 -200
View File
@@ -7,6 +7,7 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Layout 0.1
import StatusQ.Popups 0.1
Column {
spacing: 5
@@ -49,247 +50,394 @@ Column {
}
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
tooltip.text: "Chat"
}
QtObject {
id: appSectionType
readonly property int chat: 0
readonly property int community: 1
readonly property int wallet: 2
readonly property int browser: 3
readonly property int nodeManagement: 4
readonly property int profileSettings: 5
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
tooltip.text: "Chat"
sectionModel: ListModel {
ListElement {sectionId: "chat"; sectionType: 0; name: "Chat"; active: true; image: ""; icon: "chat"; color: ""; hasNotification: true; notificationsCount: 12}
}
navBarCommunityTabButtons.model: ListModel {
id: buttons
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
icon.name: "profile"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
tooltip.text: "Profile"
}
]
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
communityTypeRole: "sectionType"
communityTypeValue: appSectionType.community
sectionModel: ListModel {
ListElement {sectionId: "chat"; sectionType: 0; name: "Chat"; active: true; image: ""; icon: "chat"; color: ""; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "0x0001"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "wallet"; sectionType: 2; name: "Wallet"; active: false; image: ""; icon: "wallet"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "browser"; sectionType: 3; name: "Browser"; active: false; image: ""; icon: "bigger/browser"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "profile"; sectionType: 5; name: "Profile"; active: false; image: ""; icon: "bigger/settings"; color: ""; hasNotification: true; notificationsCount: 0}
}
property bool communityAdded: false
filterRegularItem: function(item) {
if(item.sectionType === appSectionType.community)
if(communityAdded)
return false
else
communityAdded = true
return true
}
filterCommunityItem: function(item) {
return item.sectionType === appSectionType.community
}
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
communityNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
}
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
popupMenu: StatusPopupMenu {
StatusMenuItem {
text: qsTr("Invite People")
icon.name: "share-ios"
}
StatusMenuItem {
text: qsTr("View Community")
icon.name: "group"
}
StatusMenuItem {
text: qsTr("Edit Community")
icon.name: "edit"
enabled: false
}
StatusMenuSeparator {}
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
type: StatusMenuItem.Type.Danger
}
}
]
}
}
StatusAppNavBar {
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
communityTypeRole: "sectionType"
communityTypeValue: appSectionType.community
sectionModel: ListModel {
ListElement {sectionId: "chat"; sectionType: 0; name: "Chat"; active: true; image: ""; icon: "chat"; color: ""; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "0x0001"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "wallet"; sectionType: 2; name: "Wallet"; active: false; image: ""; icon: "wallet"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "browser"; sectionType: 3; name: "Browser"; active: false; image: ""; icon: "bigger/browser"; color: ""; hasNotification: false; notificationsCount: 0}
}
property bool communityAdded: false
filterRegularItem: function(item) {
if(item.sectionType === appSectionType.community)
if(communityAdded)
return false
else
communityAdded = true
return true
}
filterCommunityItem: function(item) {
return item.sectionType === appSectionType.community
}
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
communityNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
popupMenu: StatusPopupMenu {
StatusMenuItem {
text: qsTr("Invite People")
icon.name: "share-ios"
}
StatusMenuItem {
text: qsTr("View Community")
icon.name: "group"
}
StatusMenuItem {
text: qsTr("Edit Community")
icon.name: "edit"
enabled: false
}
StatusMenuSeparator {}
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
type: StatusMenuItem.Type.Danger
}
}
}
}
StatusAppNavBar {
communityTypeRole: "sectionType"
communityTypeValue: appSectionType.community
sectionModel: ListModel {
ListElement {sectionId: "chat"; sectionType: 0; name: "Chat"; active: true; image: ""; icon: "chat"; color: ""; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "0x0001"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "0x0002"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "0x0003"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "0x0004"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 0}
ListElement {sectionId: "wallet"; sectionType: 2; name: "Wallet"; active: false; image: ""; icon: "wallet"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "browser"; sectionType: 3; name: "Browser"; active: false; image: ""; icon: "bigger/browser"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "profile"; sectionType: 5; name: "Profile"; active: false; image: ""; icon: "bigger/settings"; color: ""; hasNotification: false; notificationsCount: 0}
}
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
icon.name: "profile"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
property bool communityAdded: false
tooltip.text: "Profile"
filterRegularItem: function(item) {
if(item.sectionType === appSectionType.community)
if(communityAdded)
return false
else
communityAdded = true
return true
}
filterCommunityItem: function(item) {
return item.sectionType === appSectionType.community
}
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
}
communityNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
popupMenu: StatusPopupMenu {
StatusMenuItem {
text: qsTr("Invite People")
icon.name: "share-ios"
}
StatusMenuItem {
text: qsTr("View Community")
icon.name: "group"
}
StatusMenuItem {
text: qsTr("Edit Community")
icon.name: "edit"
enabled: false
}
StatusMenuSeparator {}
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
type: StatusMenuItem.Type.Danger
}
}
]
}
}
StatusAppNavBar {
id: test
navBarChatButton: StatusNavBarTabButton {
icon.name: "chat"
badge.value: 33
badge.visible: true
communityTypeRole: "sectionType"
communityTypeValue: appSectionType.community
sectionModel: ListModel {
ListElement {sectionId: "chat"; sectionType: 0; name: "Chat"; active: true; image: ""; icon: "chat"; color: ""; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "0x0001"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 12}
ListElement {sectionId: "0x0002"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "0x0003"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 0}
ListElement {sectionId: "0x0004"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 1}
ListElement {sectionId: "0x0005"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "0x0006"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 3}
ListElement {sectionId: "0x0007"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 5}
ListElement {sectionId: "0x0008"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 0}
ListElement {sectionId: "0x0009"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "0x0010"; sectionType: 1; name: "Test Community"; active: false; image: ""; icon: ""; color: "#00ff00"; hasNotification: true; notificationsCount: 11}
ListElement {sectionId: "wallet"; sectionType: 2; name: "Wallet"; active: false; image: ""; icon: "wallet"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "browser"; sectionType: 3; name: "Browser"; active: false; image: ""; icon: "bigger/browser"; color: ""; hasNotification: false; notificationsCount: 0}
ListElement {sectionId: "profile"; sectionType: 5; name: "Profile"; active: false; image: ""; icon: "bigger/settings"; color: ""; hasNotification: true; notificationsCount: 0}
}
property bool communityAdded: false
filterRegularItem: function(item) {
if(item.sectionType === appSectionType.community)
if(communityAdded)
return false
else
communityAdded = true
return true
}
filterCommunityItem: function(item) {
return item.sectionType === appSectionType.community
}
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
tooltip.text: "Chat"
}
navBarCommunityTabButtons.model: ListModel {
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
ListElement {
name: "Test community"
tooltipText: "Test Community"
}
}
navBarCommunityTabButtons.delegate: StatusNavBarTabButton {
name: model.name
tooltip.text: model.name
communityNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
}
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
navBarTabButtons: [
StatusNavBarTabButton {
icon.name: "wallet"
tooltip.text: "Wallet"
},
StatusNavBarTabButton {
icon.name: "browser"
tooltip.text: "Browser"
},
StatusNavBarTabButton {
icon.name: "status-update"
tooltip.text: "Timeline"
},
StatusNavBarTabButton {
icon.name: "profile"
badge.visible: true
badge.anchors.rightMargin: 4
badge.anchors.topMargin: 5
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
popupMenu: StatusPopupMenu {
tooltip.text: "Profile"
StatusMenuItem {
text: qsTr("Invite People")
icon.name: "share-ios"
}
StatusMenuItem {
text: qsTr("View Community")
icon.name: "group"
}
StatusMenuItem {
text: qsTr("Edit Community")
icon.name: "edit"
enabled: false
}
StatusMenuSeparator {}
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
type: StatusMenuItem.Type.Danger
}
}
]
}
}
}
}
+61 -5
View File
@@ -4,6 +4,7 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1
GridLayout {
columns: 1
@@ -64,6 +65,12 @@ GridLayout {
type: StatusChatListItem.Type.CommunityChat
}
StatusChatListItem {
name: "community-channel-emoji"
type: StatusChatListItem.Type.CommunityChat
icon.emoji: "😁"
}
StatusChatListItem {
name: "community-channel-with-image"
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
@@ -85,7 +92,8 @@ GridLayout {
StatusChatListItem {
name: "has-mentions"
type: StatusChatListItem.Type.PublicChat
badge.value: 1
hasUnreadMessages: true
notificationsCount: 1
}
StatusChatListItem {
@@ -100,7 +108,7 @@ GridLayout {
type: StatusChatListItem.Type.PublicChat
muted: true
hasUnreadMessages: true
badge.value: 1
notificationsCount: 1
}
StatusChatListItem {
@@ -130,7 +138,7 @@ GridLayout {
selected: true
muted: true
hasUnreadMessages: true
badge.value: 1
notificationsCount: 1
}
@@ -321,6 +329,43 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
badge.icon.isLetterIdenticon: true
}
StatusListItem {
title: "List Item with Tags"
icon.isLetterIdenticon: true
bottomModel: 3
bottomDelegate: StatusListItemTag {
title: "tag"
icon.isLetterIdenticon: true
}
}
StatusListItem {
title: "List Item with Inline Tags"
icon.isLetterIdenticon: true
tagsModel : 2
tagsDelegate: StatusListItemTag {
color: "blue"
height: 24
radius: 6
closeButtonVisible: false
icon.emoji: "😁"
icon.emojiSize: Emoji.size.verySmall
icon.isLetterIdenticon: true
title: "helloworld.eth"
titleText.font.pixelSize: 12
titleText.color: Theme.palette.indirectColor1
}
}
StatusListItem {
title: "List Item with Emoji"
subTitle: "Emoji"
icon.emoji: "😁"
icon.color: "yellow"
icon.letterSize: 14
icon.isLetterIdenticon: true
}
StatusDescriptionListItem {
title: "Title"
subTitle: "Subtitle"
@@ -350,18 +395,29 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
nickName: "This is an example"
userName: "annabelle"
chatKey: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
trustIndicator: StatusMemberListItem.TrustedType.Verified
trustIndicator: StatusContactVerificationIcons.TrustedType.Verified
isMutualContact: true
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
isOnline: true
ringSettings.ringSpecModel:
ListModel {
ListElement {colorId: 13; segmentLength: 5}
ListElement {colorId: 31; segmentLength: 5}
ListElement {colorId: 10; segmentLength: 1}
ListElement {colorId: 2; segmentLength: 5}
ListElement {colorId: 26; segmentLength: 2}
ListElement {colorId: 19; segmentLength: 4}
ListElement {colorId: 28; segmentLength: 3}
}
ringSettings.distinctiveColors: Theme.palette.identiconRingColors
}
StatusMemberListItem {
nickName: "carmen.eth"
isOnline: false
trustIndicator: StatusMemberListItem.TrustedType.Untrustworthy
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
}
StatusMemberListItem {
+41
View File
@@ -78,6 +78,11 @@ Column {
onClicked: editTitleModal.open()
}
StatusButton {
text: "Modal with Advanced Header/Footer"
onClicked: advancedHeaderFooterModal.open()
}
StatusModal {
id: simpleModal
anchors.centerIn: parent
@@ -353,6 +358,42 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
header.editable: true
}
StatusModal {
id: advancedHeaderFooterModal
anchors.centerIn: parent
showHeader: false
showFooter: false
showAdvancedHeader: true
showAdvancedFooter: true
height: 200
advancedHeaderComponent: Rectangle {
width: parent.width
height: 50
color: Theme.palette.baseColor1
border.width: 1
StatusBaseText {
anchors.centerIn: parent
text: "Add any header here"
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
advancedFooterComponent: Rectangle {
width: parent.width
height: 50
color: Theme.palette.baseColor1
border.width: 1
StatusBaseText {
anchors.centerIn: parent
text: "Add any footer here"
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
}
ListModel {
id: dummyAccountsModel
ListElement{name: "Account 1"; iconName: "filled-account"}
+104
View File
@@ -0,0 +1,104 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQml.Models 2.2
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
ListView {
id: messageList
anchors.fill: parent
anchors.margins: 15
clip: true
delegate: StatusMessage {
id: delegate
width: parent.width
audioMessageInfoText: "Audio Message"
cancelButtonText: "Cancel"
saveButtonText: "Save"
loadingImageText: "Loading image..."
errorLoadingImageText: "Error loading the image"
resendText: "Resend"
pinnedMsgInfoText: "Pinned by"
messageDetails: StatusMessageDetails {
contentType: model.contentType
messageContent: model.messageContent
amISender: model.amIsender
displayName: model.userName
secondaryName: model.localName !== "" && model.ensName.startsWith("@") ? model.ensName: ""
chatID: model.chatKey
profileImage: StatusImageSettings {
width: 40
height: 40
source: model.profileImage
isIdenticon: model.isIdenticon
}
messageText: model.message
hasMention: model.hasMention
isMutualContact: model.isMutualContact
trustIndicator: model.trustIndicator
isPinned: model.isPinned
pinnedBy: model.pinnedBy
hasExpired: model.hasExpired
}
timestamp.text: "10:00 am"
timestamp.tooltip.text: "10:01 am"
// reply related data
isAReply: model.isReply
replyDetails: StatusMessageDetails {
amISender: model.isReply ? model.replyAmISender : ""
displayName: model.isReply ? model.replySenderName: ""
profileImage: StatusImageSettings {
width: 20
height: 20
source: model.isReply ? model.replyProfileImage: ""
isIdenticon: model.isReply ? model.replyIsIdenticon: ""
}
messageText: model.isReply ? model.replyMessageText: ""
contentType: model.replyContentType
messageContent: model.replyMessageContent
}
quickActions: [
StatusFlatRoundButton {
id: emojiBtn
width: 32
height: 32
icon.name: "reaction-b"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "Add reaction"
},
StatusFlatRoundButton {
id: replyBtn
width: 32
height: 32
icon.name: "reply"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "Reply"
},
StatusFlatRoundButton {
width: 32
height: 32
icon.name: "tiny/edit"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "Edit"
onClicked: {
delegate.editMode = !delegate.editMode
}
},
StatusFlatRoundButton {
id: otherBtn
width: 32
height: 32
icon.name: "more"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "More"
}
]
}
}
+68
View File
@@ -0,0 +1,68 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Page {
id: root
anchors.fill: parent
anchors.margins: 16
property ListModel contactsModel: null
background: null
header: RowLayout {
id: headerRow
width: parent.width
height: tagSelector.height
anchors.right: parent.right
anchors.rightMargin: 8
StatusTagSelector {
id: tagSelector
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: 17
maxHeight: root.height
toLabelText: qsTr("To: ")
warningText: qsTr("USER LIMIT REACHED")
listLabel: qsTr("Contacts")
onTextChanged: {
sortModel(root.contactsModel);
}
Component.onCompleted: { sortModel(root.contactsModel); }
}
StatusButton {
implicitHeight: 44
Layout.alignment: Qt.AlignTop
enabled: (tagSelector.namesModel.count > 0)
text: "Confirm"
}
}
contentItem: Item {
anchors.fill: parent
anchors.topMargin: 68
StatusBaseText {
visible: (contactsModel.count === 0)
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 15
color: Theme.palette.baseColor1
text: qsTr("You can only send direct messages to your Contacts. \n\n
Send a contact request to the person you would like to chat with, you will be\n able to
chat with them once they have accepted your contact request.")
Component.onCompleted: {
if (visible) {
tagSelector.enabled = false;
}
}
}
}
}
+38 -192
View File
@@ -1,4 +1,5 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
@@ -11,6 +12,7 @@ import "data" 1.0
StatusAppThreePanelLayout {
id: root
property bool createChat: false
leftPanel: Item {
anchors.fill: parent
@@ -23,113 +25,35 @@ StatusAppThreePanelLayout {
text: "Chat"
}
Item {
RowLayout {
id: searchInputWrapper
anchors.top: headline.bottom
anchors.topMargin: 16
width: parent.width
height: searchInput.height
anchors.top: headline.bottom
anchors.topMargin: 16
anchors.right: parent.right
anchors.rightMargin: 8
StatusBaseInput {
id: searchInput
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: actionButton.left
anchors.leftMargin: 16
anchors.rightMargin: 16
height: 36
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: 17
implicitHeight: 36
topPadding: 8
bottomPadding: 0
placeholderText: "Search"
icon.name: "search"
}
StatusRoundButton {
id: actionButton
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 8
width: 32
height: 32
StatusIconTabButton {
icon.name: "public-chat"
}
type: StatusRoundButton.Type.Secondary
icon.name: "add"
state: "default"
onClicked: chatContextMenu.popup(actionButton.width-chatContextMenu.width, actionButton.height + 4)
states: [
State {
name: "default"
PropertyChanges {
target: actionButton
icon.rotation: 0
highlighted: false
}
},
State {
name: "pressed"
PropertyChanges {
target: actionButton
icon.rotation: 45
highlighted: true
}
}
]
transitions: [
Transition {
from: "default"
to: "pressed"
RotationAnimation {
duration: 150
direction: RotationAnimation.Clockwise
easing.type: Easing.InCubic
}
},
Transition {
from: "pressed"
to: "default"
RotationAnimation {
duration: 150
direction: RotationAnimation.Counterclockwise
easing.type: Easing.OutCubic
}
}
]
StatusPopupMenu {
id: chatContextMenu
onOpened: {
actionButton.state = "pressed"
}
onClosed: {
actionButton.state = "default"
}
StatusMenuItem {
text: "Start new chat"
icon.name: "private-chat"
}
StatusMenuItem {
text: "Start group chat"
icon.name: "group-chat"
}
StatusMenuItem {
text: "Join public chat"
icon.name: "public-chat"
}
StatusMenuItem {
text: "Communities"
icon.name: "communities"
}
StatusIconTabButton {
icon.name: "edit"
onClicked: {
root.createChat = !root.createChat;
}
}
}
@@ -149,10 +73,7 @@ StatusAppThreePanelLayout {
StatusChatList {
anchors.horizontalCenter: parent.horizontalCenter
chatListItems.model: Models.demoChatListItems
selectedChatId: "0"
onChatItemSelected: selectedChatId = id
model: Models.demoChatListItems
onChatItemUnmuted: {
for (var i = 0; i < Models.demoChatListItems.count; i++) {
let item = Models.demoChatListItems.get(i);
@@ -204,6 +125,25 @@ StatusAppThreePanelLayout {
}
}
centerPanel: Loader {
anchors.fill: parent
sourceComponent: root.createChat ? createChatView : chatChannelView
}
Component {
id: createChatView
CreateChatView {
contactsModel: Models.dummyContactsModel
}
}
Component {
id: chatChannelView
ChatChannelView {
model: Models.chatMessagesModel
}
}
rightPanel: Item {
anchors.fill: parent
@@ -251,98 +191,4 @@ StatusAppThreePanelLayout {
}
}
}
centerPanel: ListView {
id: messageList
anchors.fill: parent
anchors.margins: 15
clip: true
model: Models.chatMessagesModel
delegate: StatusMessage {
id: delegate
width: parent.width
audioMessageInfoText: "Audio Message"
cancelButtonText: "Cancel"
saveButtonText: "Save"
loadingImageText: "Loading image..."
errorLoadingImageText: "Error loading the image"
resendText: "Resend"
pinnedMsgInfoText: "Pinned by"
messageDetails: StatusMessageDetails {
contentType: model.contentType
messageContent: model.messageContent
amISender: model.amIsender
displayName: model.userName
secondaryName: model.localName !== "" && model.ensName.startsWith("@") ? model.ensName: ""
chatID: model.chatKey
profileImage: StatusImageSettings {
width: 40
height: 40
source: model.profileImage
isIdenticon: model.isIdenticon
}
messageText: model.message
hasMention: model.hasMention
contactType: model.contactType
isPinned: model.isPinned
pinnedBy: model.pinnedBy
hasExpired: model.hasExpired
}
timestamp.text: "10:00 am"
timestamp.tooltip.text: "10:01 am"
// reply related data
isAReply: model.isReply
replyDetails: StatusMessageDetails {
amISender: model.isReply ? model.replyAmISender : ""
displayName: model.isReply ? model.replySenderName: ""
profileImage: StatusImageSettings {
width: 20
height: 20
source: model.isReply ? model.replyProfileImage: ""
isIdenticon: model.isReply ? model.replyIsIdenticon: ""
}
messageText: model.isReply ? model.replyMessageText: ""
contentType: model.replyContentType
messageContent: model.replyMessageContent
}
quickActions: [
StatusFlatRoundButton {
id: emojiBtn
width: 32
height: 32
icon.name: "reaction-b"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "Add reaction"
},
StatusFlatRoundButton {
id: replyBtn
width: 32
height: 32
icon.name: "reply"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "Reply"
},
StatusFlatRoundButton {
width: 32
height: 32
icon.name: "tiny/edit"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "Edit"
onClicked: {
delegate.editMode = !delegate.editMode
}
},
StatusFlatRoundButton {
id: otherBtn
width: 32
height: 32
icon.name: "more"
type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: "More"
}
]
}
}
}
+3 -3
View File
@@ -77,11 +77,9 @@ StatusAppThreePanelLayout {
draggableItems: true
draggableCategories: false
chatList.model: Models.demoCommunityChatListItems
categoryList.model: Models.demoCommunityCategoryItems
model: Models.demoCommunityChatListItems
showCategoryActionButtons: true
onChatItemSelected: selectedChatId = id
categoryPopupMenu: StatusPopupMenu {
@@ -268,6 +266,8 @@ StatusAppThreePanelLayout {
image.source: model.source
image.isIdenticon: model.isIdenticon
isOnline: model.isOnline
ringSettings.ringSpecModel: model.ringSpecModel
ringSettings.distinctiveColors: Theme.palette.identiconRingColors
}
}
}
+384 -101
View File
@@ -4,122 +4,268 @@ import StatusQ.Components 0.1
QtObject {
property ListModel demoChatListItems: ListModel {
property ListModel dummyContactsModel: ListModel {
ListElement {
publicId: "0x0"
name: "Maria"
icon: ""
isIdenticon: false
onlineStatus: 3
}
ListElement {
publicId: "0x1"
name: "James"
icon: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
isIdenticon: false
onlineStatus: 1
}
ListElement {
publicId: "0x2"
name: "Paul"
icon: ""
isIdenticon: false
onlineStatus: 2
}
ListElement {
publicId: "0x3"
name: "Tracy"
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
onlineStatus: 3
}
ListElement {
publicId: "0x4"
name: "Nick"
icon: ""
isIdenticon: false
onlineStatus: 3
}
ListElement {
publicId: "0x5"
name: "Steven"
icon: ""
isIdenticon: false
onlineStatus: 2
}
ListElement {
publicId: "0x6"
name: "Helen"
icon: ""
isIdenticon: false
onlineStatus: 3
}
}
property var demoChatListItems: ListModel {
id: demoChatListItems
ListElement {
chatId: "0"
itemId: "x012340000"
name: "#status"
chatType: StatusChatListItem.Type.PublicChat
muted: false
unreadMessagesCount: 0
mentionsCount: 0
icon: ""
isIdenticon: false
color: "blue"
description: ""
type: StatusChatListItem.Type.PublicChat
hasUnreadMessages: true
notificationsCount: 0
muted: false
active: false
position: 0
isCategory: false
subItems: []
}
ListElement {
chatId: "1"
itemId: "x012340001"
name: "status-desktop"
chatType: StatusChatListItem.Type.PublicChat
muted: false
icon: ""
isIdenticon: false
color: "red"
unreadMessagesCount: 1
mentionsCount: 1
description: ""
type: StatusChatListItem.Type.PublicChat
hasUnreadMessages: true
notificationsCount: 1
muted: false
active: false
position: 1
isCategory: false
subItems: []
}
ListElement {
chatId: "2"
itemId: "x012340002"
name: "Amazing Funny Squirrel"
chatType: StatusChatListItem.Type.OneToOneChat
muted: false
color: "green"
identicon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
unreadMessagesCount: 0
position: 2
}
ListElement {
chatId: "3"
name: "Black Ops"
chatType: StatusChatListItem.Type.GroupChat
muted: false
color: "purple"
unreadMessagesCount: 0
position: 3
}
ListElement {
chatId: "4"
name: "Spectacular Growing Otter"
chatType: StatusChatListItem.Type.OneToOneChat
muted: true
color: "Orange"
unreadMessagesCount: 0
position: 4
}
ListElement {
chatId: "5"
name: "channel-with-a-super-duper-long-name"
chatType: StatusChatListItem.Type.PublicChat
muted: false
isIdenticon: true
color: "green"
unreadMessagesCount: 0
description: ""
type: StatusChatListItem.Type.OneToOneChat
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: true
position: 2
isCategory: false
subItems: []
}
ListElement {
itemId: "x012340003"
name: "Black Ops"
icon: ""
isIdenticon: false
color: "purple"
description: ""
type: StatusChatListItem.Type.OneToOneChat
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: false
position: 3
isCategory: false
subItems: []
}
ListElement {
itemId: "x012340004"
name: "Spectacular Growing Otter"
icon: ""
isIdenticon: false
color: "orange"
description: ""
type: StatusChatListItem.Type.OneToOneChat
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: false
position: 4
isCategory: false
subItems: []
}
ListElement {
itemId: "x012340005"
name: "channel-with-a-super-duper-long-name"
icon: ""
isIdenticon: false
color: "green"
description: ""
type: StatusChatListItem.Type.PublicChat
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: false
position: 5
isCategory: false
subItems: []
}
}
property var demoCommunityChatListItems: ListModel {
id: demoCommunityChatListItems
ListElement {
chatId: "0"
itemId: "x012340000"
name: "general"
chatType: StatusChatListItem.Type.CommunityChat
muted: false
unreadMessagesCount: 0
icon: ""
isIdenticon: false
color: "orange"
description: ""
type: StatusChatListItem.Type.Unknown0
hasUnreadMessages: true
notificationsCount: 0
muted: false
active: false
position: 0
isCategory: true
subItems: []
}
ListElement {
chatId: "1"
name: "random"
chatType: StatusChatListItem.Type.CommunityChat
itemId: "x0125340000"
name: "Pink Channel"
icon: ""
isIdenticon: false
color: "pink"
description: ""
type: StatusChatListItem.Type.CommunityChat
hasUnreadMessages: true
notificationsCount: 0
muted: false
unreadMessagesCount: 0
color: "orange"
categoryId: "public"
active: false
position: 0
isCategory: false
subItems: []
}
ListElement {
chatId: "2"
name: "watercooler"
chatType: StatusChatListItem.Type.CommunityChat
muted: false
unreadMessagesCount: 0
color: "orange"
categoryId: "public"
position: 1
}
ListElement {
chatId: "3"
name: "language-design"
chatType: StatusChatListItem.Type.CommunityChat
muted: false
unreadMessagesCount: 0
color: "orange"
categoryId: "dev"
position: 0
}
}
property var demoCommunityCategoryItems: ListModel {
id: demoCommunityCategoryItems
ListElement {
categoryId: "public"
itemId: "x012340001"
name: "Public"
position: 0
icon: ""
isIdenticon: false
color: "orange"
description: ""
type: StatusChatListItem.Type.Unknown0
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: true
position: 1
isCategory: true
subItems: [
ListElement {
itemId: "x012340002"
parentItemId: "x012340001"
name: "random"
icon: ""
isIdenticon: false
color: "orange"
description: ""
hasUnreadMessages: true
notificationsCount: 4
muted: false
active: false
position: 0
},
ListElement {
itemId: "x012340003"
parentItemId: "x012340001"
name: "watercooler"
icon: ""
isIdenticon: false
color: "orange"
description: ""
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: true
position: 1
}
]
}
ListElement {
categoryId: "dev"
itemId: "x012340004"
name: "Development"
position: 1
icon: ""
isIdenticon: false
color: "orange"
description: ""
type: StatusChatListItem.Type.Unknown0
hasUnreadMessages: false
notificationsCount: 0
muted: false
active: false
position: 2
isCategory: true
subItems: [
ListElement {
itemId: "x012340005"
parentItemId: "x012340004"
name: "language-design"
icon: ""
isIdenticon: false
color: "orange"
description: ""
hasUnreadMessages: false
notificationsCount: 0
muted: true
active: false
position: 0
}
]
}
}
@@ -351,7 +497,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f5789"
contactType: 2
isMutualContact: true
trustIndicator: StatusContactVerificationIcons.TrustedType.None
hasMention: false
editMode: false
isReply: false
@@ -379,7 +526,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f2333"
contactType: 3
isMutualContact: true
trustIndicator: StatusContactVerificationIcons.TrustedType.Verified
hasMention: false
editMode: false
isReply: false
@@ -406,7 +554,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAkUlEQVR4nOzYwQmDQBQG4SSkl3SQyizDyuzAavTi0cPK8sPwM9/Rw8rw4KH7eZUwhMYQGkNoDKGpCfmmDl63/bh7vvx/78T7aiZiCI0hNMMbJL2FZs+vmYghNIbQTG+cp9smtf1qJmIIjSEKqZmIITSG0Azfa6W/qfxDvBhCY4hCaiZiCI0hNIbQGEJzBgAA///3pSBjX42sYAAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f2333"
contactType: 3
isMutualContact: true
trustIndicator: StatusContactVerificationIcons.TrustedType.Verified
hasMention: false
editMode: false
isReply: false
@@ -433,7 +582,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f6789"
contactType: 4
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: false
editMode: false
isReply: false
@@ -461,7 +611,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: true
trustIndicator: StatusContactVerificationIcons.TrustedType.None
hasMention: false
editMode: false
isReply: false
@@ -489,7 +640,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: false
editMode: false
isReply: false
@@ -517,7 +669,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: true
editMode: false
isReply: false
@@ -546,7 +699,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: false
editMode: false
isReply: true
@@ -575,7 +729,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: false
editMode: false
isReply: true
@@ -604,7 +759,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: false
editMode: false
isReply: true
@@ -633,7 +789,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
hasMention: false
editMode: false
isReply: true
@@ -661,7 +818,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: false
trustIndicator: StatusContactVerificationIcons.TrustedType.Verified
hasMention: false
editMode: false
isReply: false
@@ -688,7 +846,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: true
trustIndicator: StatusContactVerificationIcons.TrustedType.None
hasMention: false
editMode: false
isReply: false
@@ -715,7 +874,8 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
profileImage: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDKExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
chatKey: "0x04d1bed19c523299cbd07ddec7b8949ad7dd923819a68e0b733c9c0bc38cde276bd256f098e755f8f028395c2c91f438a22adaff6caded060b7cc0ef3f470f1234"
contactType: 0
isMutualContact: true
trustIndicator: StatusContactVerificationIcons.TrustedType.None
hasMention: false
editMode: false
isReply: false
@@ -737,36 +897,159 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
nickName: "This is an example"
userName: "annabelle"
chatKey: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
trustIndicator: StatusMemberListItem.TrustedType.Verified
trustIndicator: StatusContactVerificationIcons.TrustedType.Verified
isMutualContact: true
isOnline: true
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
ringSpecModel: [ ListElement {colorId: 13; segmentLength: 5},
ListElement {colorId: 31; segmentLength: 5},
ListElement {colorId: 10; segmentLength: 1},
ListElement {colorId: 2; segmentLength: 5},
ListElement {colorId: 26; segmentLength: 2},
ListElement {colorId: 19; segmentLength: 4},
ListElement {colorId: 28; segmentLength: 3} ]
}
ListElement {
nickName: "carmen.eth"
trustIndicator: StatusMemberListItem.TrustedType.Untrustworthy
userName: ""
chatKey: ""
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
isMutualContact: false
isOnline: false
source: ""
isIdenticon: false
}
ListElement {
nickName: "This girl I know from work"
userName: "annabelle"
chatKey: ""
trustIndicator: StatusContactVerificationIcons.TrustedType.None
isMutualContact: false
isOnline: true
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDK
ExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
ringSpecModel: [ ListElement {colorId: 11; segmentLength: 1},
ListElement {colorId: 23; segmentLength: 5},
ListElement {colorId: 23; segmentLength: 5},
ListElement {colorId: 10; segmentLength: 4},
ListElement {colorId: 15; segmentLength: 3},
ListElement {colorId: 26; segmentLength: 2},
ListElement {colorId: 29; segmentLength: 5} ]
}
ListElement {
nickName: "Mark Cuban"
userName: "annabelle"
chatKey: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
trustIndicator: StatusMemberListItem.TrustedType.Untrustworthy
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
isMutualContact: true
isOnline: false
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
source: ""
isIdenticon: false
ringSpecModel: [ ListElement {colorId: 0; segmentLength: 1},
ListElement {colorId: 28; segmentLength: 1},
ListElement {colorId: 31; segmentLength: 1},
ListElement {colorId: 22; segmentLength: 4},
ListElement {colorId: 28; segmentLength: 3},
ListElement {colorId: 27; segmentLength: 5},
ListElement {colorId: 7; segmentLength: 5},
ListElement {colorId: 13; segmentLength: 1},
ListElement {colorId: 25; segmentLength: 4}]
}
}
// App Section Types:
// chat: 0
// community: 1
// wallet: 2
// browser: 3
// nodeManagement: 4
// profileSettings: 5
// apiDocumentation: 100
// demoApp: 101
property ListModel mainAppSectionsModel: ListModel {
ListElement {
sectionId: "mainApp"
sectionType: 100
name: "API Documentation"
active: true
image: ""
icon: "edit"
color: ""
hasNotification: false
notificationsCount: 0
}
ListElement {
sectionId: "demoApp"
sectionType: 101
name: "Demo Application"
active: false
image: ""
icon: "status"
color: ""
hasNotification: false
notificationsCount: 0
}
}
property ListModel demoAppSectionsModel: ListModel {
ListElement {
sectionId: "chat"
sectionType: 0
name: "Chat"
active: true
image: ""
icon: "chat"
color: ""
hasNotification: false
notificationsCount: 0
}
ListElement {
sectionId: "0x123456789"
sectionType: 1
name: "Status Community"
active: false
image: "https://assets.brandfetch.io/51a495de903c46a.png"
icon: ""
color: ""
hasNotification: false
notificationsCount: 0
}
ListElement {
sectionId: "wallet"
sectionType: 2
name: "Wallet"
active: false
image: ""
icon: "wallet"
color: ""
hasNotification: false
notificationsCount: 0
}
ListElement {
sectionId: "browser"
sectionType: 3
name: "Browser"
active: false
image: ""
icon: "bigger/browser"
color: ""
hasNotification: false
notificationsCount: 0
}
ListElement {
sectionId: "profile"
sectionType: 6
name: "Profile"
active: false
image: ""
icon: "bigger/settings"
color: ""
hasNotification: true
notificationsCount: 0
}
}
}
+76 -29
View File
@@ -12,6 +12,8 @@ import StatusQ.Components 0.1
import StatusQ.Layout 0.1
import StatusQ.Platform 0.1
import "demoapp/data" 1.0
StatusWindow {
id: rootWindow
width: Qt.platform.os == "ios" || Qt.platform.os == "android" ? Screen.width
@@ -31,11 +33,33 @@ StatusWindow {
Component.onCompleted: {
Theme.palette = lightTheme
apiDocsButton.checked = true
rootWindow.updatePosition();
}
QtObject {
id: appSectionType
readonly property int chat: 0
readonly property int community: 1
readonly property int wallet: 2
readonly property int browser: 3
readonly property int nodeManagement: 4
readonly property int profileSettings: 5
readonly property int apiDocumentation: 100
readonly property int demoApp: 101
}
function setActiveItem(sectionId) {
for (var i = 0; i < Models.mainAppSectionsModel.count; i++) {
let item = Models.mainAppSectionsModel.get(i)
if (item.sectionId !== sectionId) {
Models.mainAppSectionsModel.setProperty(i, "active", false);
continue
}
Models.mainAppSectionsModel.setProperty(i, "active", true);
}
}
StatusAppLayout {
id: appLayout
anchors.fill: parent
@@ -43,37 +67,36 @@ StatusWindow {
appNavBar: StatusAppNavBar {
height: rootWindow.height
navBarChatButton: StatusNavBarTabButton {
icon.name: "refresh"
tooltip.text: "Reload App"
onClicked: app.restartQml()
}
communityTypeRole: "sectionType"
communityTypeValue: appSectionType.community
sectionModel: Models.mainAppSectionsModel
navBarTabButtons: [
StatusNavBarTabButton {
id: apiDocsButton
icon.name: "edit"
tooltip.text: "API Documentation"
onClicked: {
stackView.clear()
regularNavBarButton: StatusNavBarTabButton {
anchors.horizontalCenter: parent.horizontalCenter
name: model.icon.length > 0? "" : model.name
icon.name: model.icon
icon.source: model.image
tooltip.text: model.name
autoExclusive: true
checked: model.active
badge.value: model.notificationsCount
badge.visible: model.hasNotification
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
badge.border.width: 2
onClicked: {
stackView.clear()
if(model.sectionType === appSectionType.apiDocumentation)
{
stackView.push(libraryDocumentationCmp)
checked = !checked
demoAppButton.checked = false
rootWindow.setActiveItem(sectionId)
}
},
StatusNavBarTabButton {
id: demoAppButton
icon.name: "status"
tooltip.text: "Demo Application"
checked: stackView.currentItem == demoAppCmp
onClicked: {
stackView.clear()
else if(model.sectionType === appSectionType.demoApp)
{
stackView.push(demoAppCmp)
checked = !checked
apiDocsButton.checked = false
rootWindow.setActiveItem(model.sectionId)
}
}
]
}
}
appView: StackView {
@@ -206,6 +229,11 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusPinInput"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Components" }
StatusNavigationListItem {
title: "StatusAddress"
@@ -232,6 +260,21 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page("StatusExpandableSettingsItem");
}
StatusNavigationListItem {
title: "StatusTagSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusToastMessage"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWizardStepper"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Popup" }
StatusNavigationListItem {
title: "StatusPopupMenu"
@@ -250,6 +293,11 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusColorSelectorGrid"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
}
}
}
@@ -347,8 +395,7 @@ StatusWindow {
}
DemoApp {
id: demoApp
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.centerIn: parent
}
DropShadow {
anchors.fill: demoApp
@@ -0,0 +1,36 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
width: 800
height: 100
Row {
id: selectedColor
anchors.top: parent.top
anchors.left: colorSelectionGrid.left
spacing: 10
StatusBaseText {
text: "SelectedColor is"
}
Rectangle {
width: 100
height: 20
radius: width/2
color: colorSelectionGrid.selectedColor
}
}
StatusColorSelectorGrid {
id: colorSelectionGrid
anchors.top: selectedColor.bottom
anchors.topMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
titleText: "COLOR"
selectedColorIndex: 2
}
}
+83 -1
View File
@@ -57,6 +57,33 @@ Column {
input.clearable: true
}
Item {
implicitWidth: 480
implicitHeight: 102
z: 100000
StatusSeedPhraseInput {
id: statusSeedInput
anchors.left: parent.left
anchors.right: parent.right
textEdit.input.anchors.leftMargin: 16
textEdit.input.anchors.rightMargin: 16
textEdit.input.anchors.topMargin: 11
textEdit.label: "Input with drop down selection list"
leftComponentText: "1"
inputList: ListModel {
ListElement {
seedWord: "panda"
}
ListElement {
seedWord: "posible"
}
ListElement {
seedWord: "wing"
}
}
}
}
StatusInput {
label: "Label"
charLimit: 30
@@ -102,10 +129,24 @@ Column {
]
}
StatusInput {
label: "Input with <i>StatusRegularExpressionValidator</i>"
charLimit: 30
input.placeholderText: `Must match regex(${validators[0].regularExpression.toString()}) and <= 30 chars`
validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
validators: [
StatusRegularExpressionValidator {
regularExpression: /^[0-9A-Za-z_\$-\s]*$/
errorMessage: "Bad input!"
}
]
}
StatusInput {
label: "Label"
input.placeholderText: "Input width component (right side)"
input.component: StatusIcon {
input.rightComponent: StatusIcon {
icon: "cancel"
height: 16
color: Theme.palette.dangerColor1
@@ -130,4 +171,45 @@ Column {
input.minimumHeight: 80
input.maximumHeight: 200
}
StatusInput {
property bool toggled: true
label: "Input with emoji icon"
input.placeholderText: "Enter Name"
input.icon.emoji: toggled ? "😁" : "🧸"
input.icon.color: "blue"
input.isIconSelectable: true
onIconClicked: {
toggled = !toggled
}
}
StatusInput {
property bool toggled: true
label: "Input with selectable icon which is not an emoji"
input.placeholderText: "Enter Name"
input.icon.emoji: ""
input.icon.name: toggled ? "filled-account" : "image"
input.icon.color: "blue"
input.isIconSelectable: true
onIconClicked: {
toggled = !toggled
}
}
StatusInput {
label: "Input with inline token selector"
input.leftComponent: StatusTokenInlineSelector {
tokens: [{amount: 0.1, token: "ETH"},
{amount: 10, token: "SNT"},
{amount: 15, token: "MANA"}]
StatusToolTip {
id: toolTip
text: "posted"
}
onTriggered: toolTip.visible = true
}
input.edit.readOnly: true
}
}
+75
View File
@@ -0,0 +1,75 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
Column {
id: root
spacing: 25
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// PIN input that accepts only numbers
StatusBaseText {
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.directColor1
text: "Enter Keycard PIN"
font.pixelSize: 30
font.bold: true
}
StatusPinInput {
id: numbersPinInput
anchors.horizontalCenter: parent.horizontalCenter
validator: StatusIntValidator{bottom: 0; top: 999999;}
}
StatusBaseText {
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.dangerColor1
text: "Only numbers allowed"
font.pixelSize: 16
}
StatusBaseText {
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.directColor1
text: "Introduced PIN: " + numbersPinInput.pinInput
font.pixelSize: 12
}
// PIN input that accepts input depending on the regular expression definition
StatusBaseText {
topPadding: 100
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.directColor1
text: "Enter another Keycard PIN"
font.pixelSize: 30
font.bold: true
}
StatusPinInput {
id: regexPinInput
anchors.horizontalCenter: parent.horizontalCenter
validator: StatusRegularExpressionValidator { regularExpression: /[0-9A-Za-z@]+/ }
circleDiameter: 22
circleSpacing: 22
pinLen: 7
}
StatusBaseText {
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.dangerColor1
text: "Only alphanumeric characters and '@' allowed"
font.pixelSize: 16
}
StatusBaseText {
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.directColor1
text: "Introduced PIN: " + regexPinInput.pinInput
font.pixelSize: 12
}
}
+56
View File
@@ -0,0 +1,56 @@
import QtQuick 2.14
import StatusQ.Components 0.1
Item {
id: root
anchors.fill: parent
property ListModel asortedContacts: ListModel {
ListElement {
publicId: "0x0"
name: "Maria"
icon: ""
isIdenticon: false
onlineStatus: 3
}
ListElement {
publicId: "0x1"
name: "James"
icon: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
isIdenticon: false
onlineStatus: 1
}
ListElement {
publicId: "0x2"
name: "Paul"
icon: ""
isIdenticon: false
onlineStatus: 2
}
ListElement {
publicId: "0x3"
name: "Tracy"
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
onlineStatus: 3
}
ListElement {
publicId: "0x4"
name: "Nick"
icon: ""
isIdenticon: false
onlineStatus: 3
}
}
StatusTagSelector {
id: tagSelector
width: 650
height: 44
anchors.centerIn: parent
namesModel: root.asortedContacts
toLabelText: qsTr("To: ")
warningText: qsTr("USER LIMIT REACHED")
}
}
+40
View File
@@ -0,0 +1,40 @@
import QtQuick 2.14
import StatusQ.Components 0.1
Item {
id: root
anchors.fill: parent
Column {
id: toastArea
anchors.centerIn: parent
spacing: 8
Repeater {
id: toastRepeater
width: parent.width
height: childrenRect.height
model: [
{"title":"anna.eth wants to verify your identity", "subTitle":"Provide the code in the letter I sent to you on February 1st.", "icon":"contact", "loading":false, "type":0,"url":""},
{"title":"Verification Request Sent", "subTitle":"", "icon":"checkmark-circle", "loading":false, "type":1,"url":""},
{"title":"Collectible is being minted...", "subTitle":"View on Etherscan", "icon":"", "loading":true, "type":0,"url":"http://google.com"},
{"title":"Contact request sent", "subTitle":"", "icon":"checkmark-circle", "loading":false, "type":1,"url":""}
]
delegate: StatusToastMessage {
primaryText: modelData.title
secondaryText: modelData.subTitle
icon.name: modelData.icon
loading: modelData.loading
type: modelData.type
linkUrl: modelData.url
onLinkActivated: {
Qt.openUrlExternally(link);
}
//simulate open
Component.onCompleted: {
open = true;
}
}
}
}
}
+100
View File
@@ -0,0 +1,100 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
width: 800
height: 100
//Simulate animation between steps
property bool stepsCompleted: false
function reset() {
for (var i = 0; i < stepsListModel.count; i++) {
stepsListModel.setProperty(i, "loading", false);
stepsListModel.setProperty(i, "stepCompleted", false);
step1.loadingTime = 0;
step2.loadingTime = 0;
root.stepsCompleted = false;
}
}
ListModel {
id: stepsListModel
ListElement {description:"Send Request"; loadingTime: 0; stepCompleted: false}
ListElement {description:"Receive Response"; loadingTime: 0; stepCompleted: false}
ListElement {description:"Confirm Identity"; loadingTime: 0; stepCompleted: false}
}
Shortcut {
sequence: "Ctrl+R"
onActivated: {
if (!root.stepsCompleted) {
animate.running = true;
} else {
root.reset();
}
}
}
StatusBaseText {
id: indicLabel
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.palette.directColor1
text: "Press Ctrl+R to run the animation"
font.pixelSize: 17
}
SequentialAnimation {
id: animate
ScriptAction {
id: step1
property int loadingTime: 0
Behavior on loadingTime { NumberAnimation { duration: 2000 }}
onLoadingTimeChanged: {
stepsListModel.setProperty(1, "loadingTime", step1.loadingTime);
}
script: {
step1.loadingTime = 2000;
stepsListModel.setProperty(0, "loadingTime", step1.loadingTime);
stepsListModel.setProperty(0, "stepCompleted", true);
}
}
PauseAnimation {
duration: 2100
}
ScriptAction {
id: step2
property int loadingTime: 0
Behavior on loadingTime { NumberAnimation { duration: 2000 } }
onLoadingTimeChanged: {
stepsListModel.setProperty(2, "loadingTime", step2.loadingTime);
}
script: {
step2.loadingTime = 2000;
stepsListModel.setProperty(1, "stepCompleted", true);
}
}
PauseAnimation {
duration: 2100
}
ScriptAction {
script: {
stepsListModel.setProperty(2, "stepCompleted", true);
root.stepsCompleted = true;
}
}
}
//simulation code
StatusWizardStepper {
id: wizardStepper
width: (parent.width - 50)
anchors.top: indicLabel.bottom
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
stepsModel: stepsListModel
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ SOURCES += \
handler.cpp \
main.cpp \
sandboxapp.cpp \
spellchecker.cpp
spellchecker.cpp \
!macx {
SOURCES += statuswindow.cpp
+9 -3
View File
@@ -1,4 +1,10 @@
make clean
qmake sandbox.pro -spec macx-clang CONFIG+=debug CONFIG+=x86_64 && /usr/bin/make qmake_all
make
#!/bin/bash
make clean
if [[ $OSTYPE == 'darwin'* ]]
then
qmake sandbox.pro -spec macx-clang CONFIG+=debug CONFIG+=x86_64 && /usr/bin/make qmake_all
else
qmake sandbox.pro CONFIG+=debug CONFIG+=x86_64 && /usr/bin/make qmake_all
fi
make
+24 -37
View File
@@ -15,8 +15,7 @@ Column {
width: 288
property string categoryId: ""
property string selectedChatId: ""
property alias chatListItems: delegateModel
property var model: null
property bool draggableItems: false
property alias statusChatListItems: statusChatListItems
@@ -24,10 +23,8 @@ Column {
property Component popupMenu
property var filterFn
property var profileImageFn
property var chatNameFn
signal chatItemSelected(string id)
signal chatItemSelected(string categoryId, string id)
signal chatItemUnmuted(string id)
signal chatItemReordered(string id, int from, int to)
@@ -39,17 +36,16 @@ Column {
DelegateModel {
id: delegateModel
model: statusChatList.model
delegate: Item {
id: draggable
width: statusChatListItem.width
height: statusChatListItem.height
property alias chatListItem: statusChatListItem
visible: {
if (!!statusChatList.filterFn) {
return statusChatList.filterFn(model, statusChatList.categoryId)
return statusChatList.filterFn(model)
}
return true
}
@@ -96,34 +92,26 @@ Column {
StatusChatListItem {
id: statusChatListItem
property string profileImage: ""
opacity: dragSensor.active ? 0.0 : 1.0
Component.onCompleted: {
if (typeof statusChatList.profileImageFn === "function") {
profileImage = statusChatList.profileImageFn(model.chatId || model.id) || ""
}
}
originalOrder: model.position
chatId: model.chatId || model.id
categoryId: model.categoryId || ""
name: !!statusChatList.chatNameFn ? statusChatList.chatNameFn(model) : model.name
type: model.chatType
muted: !!model.muted
hasUnreadMessages: !!model.hasUnreadMessages || model.unviewedMessagesCount > 0
hasMention: model.mentionsCount > 0
badge.value: model.chatType === StatusChatListItem.Type.OneToOneChat ?
model.unviewedMessagesCount || 0 :
model.mentionsCount || 0
selected: (model.chatId || model.id) === statusChatList.selectedChatId
icon.color: model.color || ""
image.isIdenticon: !!!profileImage && !!!model.identityImage && !!model.identicon
image.source: profileImage || model.identityImage || model.identicon || ""
chatId: model.itemId
categoryId: model.parentItemId? model.parentItemId : ""
name: model.name
icon.emoji: model.emoji
type: !!model.type ? model.type : StatusChatListItem.Type.CommunityChat
muted: model.muted
hasUnreadMessages: model.hasUnreadMessages
notificationsCount: model.notificationsCount
highlightWhenCreated: !!model.highlight
selected: model.active
icon.color: model.color
image.isIdenticon: model.isIdenticon
image.source: model.icon
sensor.cursorShape: dragSensor.cursorShape
onClicked: {
highlightWhenCreated = false
if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
statusChatListItem.highlighted = true
@@ -132,7 +120,7 @@ Column {
popupMenuSlot.item.openHandler = function () {
if (!!originalOpenHandler) {
originalOpenHandler((model.chatId || model.id))
originalOpenHandler(model.itemId)
}
}
@@ -152,10 +140,10 @@ Column {
return
}
if (!statusChatListItem.selected) {
statusChatList.chatItemSelected(model.chatId || model.id)
statusChatList.chatItemSelected(model.parentItemId, model.itemId)
}
}
onUnmute: statusChatList.chatItemUnmuted(model.chatId || model.id)
onUnmute: statusChatList.chatItemUnmuted(model.itemId)
}
}
@@ -204,9 +192,8 @@ Column {
type: draggable.chatListItem.type
muted: draggable.chatListItem.muted
dragged: true
hasUnreadMessages: draggable.chatListItem.hasUnreadMessages
hasMention: draggable.chatListItem.hasMention
badge.value: draggable.chatListItem.badge.value
hasUnreadMessages: model.hasUnreadMessages
notificationsCount: model.notificationsCount
selected: draggable.chatListItem.selected
icon.color: draggable.chatListItem.icon.color
@@ -20,11 +20,9 @@ Item {
text: "More"
}
property string selectedChatId: ""
property var model: []
property bool showCategoryActionButtons: false
property bool showPopupMenu: true
property alias chatList: statusChatList.chatListItems
property alias categoryList: delegateModel
property alias sensor: sensor
property bool draggableItems: false
property bool draggableCategories: false
@@ -36,7 +34,7 @@ Item {
property Component chatListPopupMenu
property Component popupMenu
signal chatItemSelected(string id)
signal chatItemSelected(string categoryId, string id)
signal chatItemUnmuted(string id)
signal chatItemReordered(string categoryId, string chatId, int from, int to)
signal chatListCategoryReordered(string categoryId, int from, int to)
@@ -71,26 +69,25 @@ Item {
StatusChatList {
id: statusChatList
anchors.horizontalCenter: parent.horizontalCenter
visible: chatListItems.count > 0
selectedChatId: statusChatListAndCategories.selectedChatId
onChatItemSelected: statusChatListAndCategories.chatItemSelected(id)
visible: statusChatList.model.count > 0
onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
onChatItemReordered: statusChatListAndCategories.chatItemReordered(categoryId, id, from, to)
draggableItems: statusChatListAndCategories.draggableItems
model: statusChatListAndCategories.model
filterFn: function (model) {
return !!!model.categoryId
return !model.isCategory
}
popupMenu: statusChatListAndCategories.chatListPopupMenu
}
DelegateModel {
id: delegateModel
model: statusChatListAndCategories.model
delegate: Item {
id: draggable
width: statusChatListCategory.width
height: statusChatListCategory.height
property alias chatListCategory: statusChatListCategory
StatusChatListCategory {
@@ -99,7 +96,7 @@ Item {
property bool dragActive: false
property real startY: 0
property real startX: 0
opacity: dragActive ? 0.0 : 1.0
dragSensor.drag.target: draggedListCategoryLoader.item
@@ -136,16 +133,15 @@ Item {
menuButton.tooltip: statusChatListAndCategories.categoryMenuButtonToolTip
originalOrder: model.position
categoryId: model.categoryId
categoryId: model.itemId
name: model.name
showActionButtons: statusChatListAndCategories.showCategoryActionButtons
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.categoryId)
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.itemId)
chatList.chatListItems.model: statusChatListAndCategories.chatList.model
chatList.selectedChatId: statusChatListAndCategories.selectedChatId
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(id)
chatList.model: model.subItems
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.categoryId, id, from, to)
chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: statusChatListAndCategories.draggableItems
popupMenu: statusChatListAndCategories.categoryPopupMenu
@@ -154,7 +150,7 @@ Item {
// Used to set the initial value of "opened" when the
// model is bound/changed.
opened: {
let openedState = statusChatListAndCategories.openedCategoryState[model.categoryId]
let openedState = statusChatListAndCategories.openedCategoryState[model.itemId]
return openedState !== undefined ? openedState : true // defaults to open
}
@@ -163,7 +159,7 @@ Item {
// as the state would be lost each time the model is
// changed.
onOpenedChanged: {
statusChatListAndCategories.openedCategoryState[model.categoryId] = statusChatListCategory.opened
statusChatListAndCategories.openedCategoryState[model.itemId] = statusChatListCategory.opened
}
}
@@ -212,8 +208,7 @@ Item {
name: draggable.chatListCategory.name
showActionButtons: draggable.chatListCategory.showActionButtons
chatList.chatListItems.model: draggable.chatListCategory.chatList.chatListItems.model
chatList.selectedChatId: draggable.chatListCategory.chatList.selectedChatId
chatList.model: draggable.chatListCategory.chatList.model
}
}
}
@@ -35,11 +35,11 @@ Column {
StatusChatListCategoryItem {
id: statusChatListCategoryItem
title: statusChatListCategory.name
visible: model.isCategory
opened: statusChatListCategory.opened
sensor.pressAndHoldInterval: 150
showMenuButton: showActionButtons && !!statusChatListCategory.popupMenu
highlighted: statusChatListCategory.dragged
sensor.onClicked: {
if (sensor.enabled) {
@@ -48,7 +48,6 @@ Column {
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6);
return
}
statusChatListCategory.opened = !opened;
}
}
onTitleClicked: statusChatListCategory.opened = !opened
@@ -68,7 +67,7 @@ Column {
visible: statusChatListCategory.opened
categoryId: statusChatListCategory.categoryId
filterFn: function (model) {
return !!model.categoryId && model.categoryId == statusChatList.categoryId
return !!model.parentItemId && model.parentItemId === statusChatList.categoryId
}
popupMenu: statusChatListCategory.chatListPopupMenu
+17 -9
View File
@@ -5,6 +5,7 @@ import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
@@ -18,7 +19,7 @@ Rectangle {
property string name: ""
property alias badge: statusBadge
property bool hasUnreadMessages: false
property bool hasMention: false
property int notificationsCount: 0
property bool muted: false
property StatusImageSettings image: StatusImageSettings {
width: 24
@@ -28,10 +29,14 @@ Rectangle {
width: 24
height: 24
color: Theme.palette.miscColor5
letterSize: 15
letterSize: emoji ? 11 : 15
emoji: ""
emojiSize: Emoji.size.verySmall
charactersLen: 1
}
property int type: StatusChatListItem.Type.PublicChat
property bool highlighted: false
property bool highlightWhenCreated: false
property bool selected: false
property bool dragged: false
property alias sensor: sensor
@@ -98,8 +103,8 @@ Rectangle {
if (statusChatListItem.muted && !hoverHander.hovered && !statusChatListItem.highlighted) {
return 0.4
}
return statusChatListItem.hasMention ||
statusChatListItem.hasUnreadMessages ||
return statusChatListItem.hasUnreadMessages ||
statusChatListItem.notificationsCount > 0 ||
statusChatListItem.selected ||
statusChatListItem.highlighted ||
statusBadge.visible ||
@@ -141,16 +146,18 @@ Rectangle {
if (statusChatListItem.muted && !hoverHander.hovered && !statusChatListItem.highlighted) {
return Theme.palette.directColor5
}
return statusChatListItem.hasMention ||
statusChatListItem.hasUnreadMessages ||
return statusChatListItem.hasUnreadMessages ||
statusChatListItem.notificationsCount > 0 ||
statusChatListItem.selected ||
statusChatListItem.highlighted ||
statusChatListItem.highlightWhenCreated ||
hoverHander.hovered ||
statusBadge.visible ? Theme.palette.directColor1 : Theme.palette.directColor4
}
font.weight: !statusChatListItem.muted &&
(statusChatListItem.hasMention ||
statusChatListItem.hasUnreadMessages ||
(statusChatListItem.hasUnreadMessages ||
statusChatListItem.notificationsCount > 0 ||
statusChatListItem.highlightWhenCreated ||
statusBadge.visible) ? Font.Bold : Font.Medium
font.pixelSize: 15
}
@@ -189,7 +196,8 @@ Rectangle {
color: statusChatListItem.muted ? Theme.palette.primaryColor2 : Theme.palette.primaryColor1
border.width: 4
border.color: color
visible: statusBadge.value > 0
value: statusChatListItem.notificationsCount
visible: statusChatListItem.notificationsCount > 0
}
}
}
+19 -9
View File
@@ -93,6 +93,25 @@ Rectangle {
property bool showMoreMenu: false
onClicked: {
menuButton.highlighted = true
let originalOpenHandler = popupMenuSlot.item.openHandler
let originalCloseHandler = popupMenuSlot.item.closeHandler
popupMenuSlot.item.openHandler = function () {
if (!!originalOpenHandler) {
originalOpenHandler()
}
}
popupMenuSlot.item.closeHandler = function () {
menuButton.highlighted = false
if (!!originalCloseHandler) {
originalCloseHandler()
}
}
popupMenuSlot.item.openHandler = originalOpenHandler
popupMenuSlot.item.popup(-popupMenuSlot.item.width + menuButton.width, menuButton.height + 4)
statusChatToolBar.menuButtonClicked()
}
@@ -100,15 +119,6 @@ Rectangle {
Loader {
id: popupMenuSlot
active: !!statusChatToolBar.popupMenu
onLoaded: {
popupMenuSlot.item.closeHandler = function () {
menuButton.highlighted = false
}
popupMenuSlot.item.openHandler = function () {
menuButton.highlighted = true
}
}
}
}
@@ -14,6 +14,7 @@ StatusListItem {
components: [
StatusBadge {
visible: statusContactRequestsListItem.requestsCount > 0
value: statusContactRequestsListItem.requestsCount
anchors.verticalCenter: parent.verticalCenter
border.width: 4
@@ -0,0 +1,79 @@
import QtQuick 2.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Row {
id: root
property bool isMutualContact: false
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
property StatusIconSettings mutualConnectionIcon: StatusIconSettings {
name: "tiny/tiny-contact"
color: Theme.palette.indirectColor1
width: dummyImage.width
height: dummyImage.height
background: StatusIconBackgroundSettings {
width: 10
height: 10
color: Theme.palette.primaryColor1
}
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: mutualConnectionIcon.name ? "../../assets/img/icons/" + mutualConnectionIcon.name + ".svg": ""
visible: false
}
}
property StatusIconSettings trustContactIcon: StatusIconSettings {
// None and Untrustworthy types, same aspect (Icon will not be visible in case of None type):
name: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? "tiny/tiny-checkmark" : "tiny/subtract"
color: Theme.palette.indirectColor1
width: dummyImage.width
height: dummyImage.height
background: StatusIconBackgroundSettings {
width: 10
height: 10
color: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
}
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: trustContactIcon.name ? "../../assets/img/icons/" + trustContactIcon.name + ".svg": ""
visible: false
}
}
enum TrustedType {
None, //0
Verified, //1
Untrustworthy //2
}
spacing: 4
visible: root.isMutualContact || (root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None)
StatusRoundIcon {
visible: root.isMutualContact
icon.name: root.mutualConnectionIcon.name
icon.width: root.mutualConnectionIcon.width
icon.height: root.mutualConnectionIcon.height
icon.rotation: root.mutualConnectionIcon.rotation
icon.color: root.mutualConnectionIcon.color
icon.background.color: root.mutualConnectionIcon.background.color
icon.background.width: root.mutualConnectionIcon.background.width
icon.background.height: root.mutualConnectionIcon.background.height
}
StatusRoundIcon {
visible: root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None
icon.name: root.trustContactIcon.name
icon.width: root.trustContactIcon.width
icon.height: root.trustContactIcon.height
icon.rotation: root.trustContactIcon.rotation
icon.color: root.trustContactIcon.color
icon.background.color: root.trustContactIcon.background.color
icon.background.width: root.trustContactIcon.background.width
icon.background.height: root.trustContactIcon.background.height
}
}
@@ -12,6 +12,7 @@ Rectangle {
property alias additionalText: additionalText.text
property alias button: button
property alias expandableComponent: expandableRegion.sourceComponent
property alias expandableItem: expandableRegion.item
property int type: StatusExpandableItem.Type.Primary
property bool expandable: true
@@ -185,7 +186,7 @@ Rectangle {
anchors.leftMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Primary) ? 48 : 0
anchors.right: parent.right
anchors.rightMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Primary) ? 16 : 0
active: false
visible: false
}
onExpandedChanged: {
@@ -202,13 +203,13 @@ Rectangle {
name: "EXPANDED"
PropertyChanges {target: expandImage; icon: "chevron-up"}
PropertyChanges {target: statusExpandableItem; height: 82 + expandableRegion.height + 22}
PropertyChanges {target: expandableRegion; active: true}
PropertyChanges {target: expandableRegion; visible: true}
},
State {
name: "COLLAPSED"
PropertyChanges {target: expandImage; icon: "chevron-down"}
PropertyChanges {target: statusExpandableItem; height: 82}
PropertyChanges {target: expandableRegion; active: false}
PropertyChanges {target: expandableRegion; visible: false}
}
]
@@ -1,13 +1,17 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
Rectangle {
id: statusLetterIdenticon
id: root
property alias identiconText: identiconText
property string name
property string emoji
property string emojiSize
property int letterSize: 21
property int charactersLen: 1
color: Theme.palette.miscColor5
width: 40
@@ -16,15 +20,30 @@ Rectangle {
StatusBaseText {
id: identiconText
text: ((statusLetterIdenticon.name.charAt(0) === "#")
|| (statusLetterIdenticon.name.charAt(0) === "@") ?
statusLetterIdenticon.name.charAt(1) : statusLetterIdenticon.name.charAt(0)).toUpperCase()
anchors.alignWhenCentered: false
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
height: parent.height
font.weight: Font.Bold
font.pixelSize: statusLetterIdenticon.letterSize
font.pixelSize: root.letterSize
color: Qt.rgba(255, 255, 255, 0.7)
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: {
if (emoji) {
if(Utils.isHtml(emoji))
return emoji
else
return Emoji.parse(emoji, emojiSize || undefined)
}
const shift = (root.name.charAt(0) === "#") ||
(root.name.charAt(0) === "@")
return root.name.substring(shift, shift + charactersLen).toUpperCase()
}
}
}
+81 -68
View File
@@ -13,16 +13,20 @@ Rectangle {
property string titleId: ""
property string title: ""
property string titleAsideText: ""
property bool titleIcon1Visible
property bool titleIcon2Visible
property string subTitle: ""
property string tertiaryTitle: ""
property string label: ""
property real leftPadding: 16
property real rightPadding: 16
property bool enabled: true
property bool highlighted: false
property bool propagateTitleClicks: true
property int type: StatusListItem.Type.Primary
property list<Item> components
property var bottomModel: []
property Component bottomDelegate
property var tagsModel: []
property Component tagsDelegate
property StatusIconSettings icon: StatusIconSettings {
height: isLetterIdenticon ? 40 : 20
@@ -30,6 +34,7 @@ Rectangle {
rotation: 0
isLetterIdenticon: false
letterSize: 21
charactersLen: 1
color: isLetterIdenticon ? background.color : type === StatusListItem.Type.Danger ?
Theme.palette.dangerColor1 : Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
@@ -51,31 +56,10 @@ Rectangle {
height: 40
isIdenticon: false
}
property StatusIconSettings titleIcon1: StatusIconSettings {
width: dummyImage.width
height: dummyImage.height
background: StatusIconBackgroundSettings {
width: 10
height: 10
}
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: titleIcon1.name ? "../../assets/img/icons/" + titleIcon1.name + ".svg": ""
visible: false
}
}
property StatusIconSettings titleIcon2: StatusIconSettings {
width: dummyImage.width
height: dummyImage.height
background: StatusIconBackgroundSettings {
width: 10
height: 10
}
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: titleIcon2.name ? "../../assets/img/icons/" + titleIcon2.name + ".svg": ""
visible: false
}
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: 1.5
distinctiveColors: Theme.palette.identiconRingColors
}
property alias sensor: sensor
@@ -83,10 +67,13 @@ Rectangle {
property alias statusListItemIcon: iconOrImage
property alias statusListItemTitle: statusListItemTitle
property alias statusListItemTitleAside: statusListItemTitleAsideText
property alias statusListItemTitleIcons: titleIconsRow
property alias statusListItemTitleArea: statusListItemTitleArea
property alias statusListItemSubTitle: statusListItemSubTitle
property alias statusListItemTertiaryTitle: statusListItemTertiaryTitle
property alias statusListItemComponentsSlot: statusListItemComponentsSlot
property alias statusListItemTagsSlot: statusListItemTagsSlot
property alias statusListItemInlineTagsSlot: statusListItemTagsSlotInline
signal clicked(string itemId)
signal titleClicked(string titleId)
@@ -98,9 +85,14 @@ Rectangle {
}
implicitWidth: 448
implicitHeight: Math.max(64, statusListItemTitleArea.height + 16)
implicitHeight: {
if (bottomModel.length === 0) {
return Math.max(64, statusListItemTitleArea.height + 16)
}
return Math.max(64, statusListItemTitleArea.height + 90)
}
color: {
if (sensor.containsMouse) {
if (sensor.containsMouse || statusListItem.highlighted) {
switch(type) {
case StatusListItem.Type.Primary:
return Theme.palette.baseColor2
@@ -149,16 +141,26 @@ Rectangle {
!!statusListItem.icon.name ||
!!statusListItem.image.source.toString()
badge.border.color: statusListItem.color
ringSettings: statusListItem.ringSettings
}
Item {
id: statusListItemTitleArea
function getStatusListItemTitleAnchorsRight() {
let isIconsRowVisible = false
if(titleIconsRow.item) {
isIconsRowVisible = true//titleIconsRow.item.visible
}
return !statusListItem.titleAsideText && !isIconsRowVisible ? statusListItemTitleArea.right : undefined
}
anchors.left: iconOrImage.active ? iconOrImage.right : parent.left
anchors.right: statusListItemLabel.visible ?
statusListItemLabel.left : statusListItemComponentsSlot.left
anchors.leftMargin: statusListItem.leftPadding
anchors.right: statusListItemLabel.visible ? statusListItemLabel.left : statusListItemComponentsSlot.left
anchors.leftMargin: iconOrImage.active ? 16 : statusListItem.leftPadding
anchors.rightMargin: statusListItem.rightPadding
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
height: childrenRect.height
StatusBaseText {
@@ -168,8 +170,9 @@ Rectangle {
height: visible ? contentHeight : 0
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
anchors.left: parent.left
anchors.right: !statusListItem.titleAsideText && !statusListItem.titleIcon1Visible && !statusListItem.titleIcon2Visible
? parent.right : undefined
anchors.right: !statusListItem.titleAsideText && !titleIconsRow.sourceComponent ? parent.right : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 20
color: {
if (!statusListItem.enabled) {
return Theme.palette.baseColor1
@@ -186,9 +189,10 @@ Rectangle {
MouseArea {
anchors.fill: parent
cursorShape: containsMouse? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: statusListItem.enabled
cursorShape: sensor.enabled && containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
propagateComposedEvents: true
propagateComposedEvents: statusListItem.propagateTitleClicks
onClicked: {
statusListItem.titleClicked(statusListItem.titleId)
mouse.accepted = false
@@ -201,43 +205,20 @@ Rectangle {
anchors.left: statusListItemTitle.right
anchors.leftMargin: 4
anchors.verticalCenter: statusListItemTitle.verticalCenter
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 20
text: statusListItem.titleAsideText
font.pixelSize: 10
color: Theme.palette.baseColor1
visible: !!statusListItem.titleAsideText
}
Row {
Loader {
id: titleIconsRow
spacing: 4
anchors.left: !statusListItem.titleAsideText ? statusListItemTitle.right : statusListItemTitleAsideText.right
anchors.verticalCenter: statusListItemTitle.verticalCenter
anchors.leftMargin: titleIconsRow.spacing
StatusRoundIcon {
visible: statusListItem.titleIcon1Visible
icon.name: statusListItem.titleIcon1.name
icon.width: statusListItem.titleIcon1.width
icon.height: statusListItem.titleIcon1.height
icon.rotation: statusListItem.titleIcon1.rotation
icon.color: statusListItem.titleIcon1.color
icon.background.color: statusListItem.titleIcon1.background.color
icon.background.width: statusListItem.titleIcon1.background.width
icon.background.height: statusListItem.titleIcon1.background.height
}
StatusRoundIcon {
visible: statusListItem.titleIcon2Visible
icon.name: statusListItem.titleIcon2.name
icon.width: statusListItem.titleIcon2.width
icon.height: statusListItem.titleIcon2.height
icon.rotation: statusListItem.titleIcon2.rotation
icon.color: statusListItem.titleIcon2.color
icon.background.color: statusListItem.titleIcon2.background.color
icon.background.width: statusListItem.titleIcon2.background.width
icon.background.height: statusListItem.titleIcon2.background.height
}
}
anchors.leftMargin: 4
}
StatusBaseText {
id: statusListItemSubTitle
@@ -269,11 +250,42 @@ Rectangle {
width: contentItem.width
implicitHeight: visible ? 22 : 0
}
Row {
id: statusListItemTagsSlotInline
anchors.top: statusListItemTertiaryTitle.bottom
width: parent.width
spacing: 10
clip: true
Repeater {
model: tagsModel
delegate: tagsDelegate
}
}
}
Row {
id: statusListItemTagsSlot
anchors.topMargin: 16
anchors.top: iconOrImage.bottom
anchors.left: parent.left
anchors.leftMargin: 16
width: statusListItemBadge.width
spacing: 10
anchors.verticalCenter: parent.verticalCenter
Repeater {
model: bottomModel
delegate: bottomDelegate
}
}
StatusBaseText {
id: statusListItemLabel
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 16
anchors.right: statusListItemComponentsSlot.left
anchors.rightMargin: statusListItemComponentsSlot.width > 0 ? 10 : 0
@@ -283,12 +295,13 @@ Rectangle {
visible: !!statusListItem.label
}
Row {
id: statusListItemComponentsSlot
anchors.right: parent.right
anchors.rightMargin: statusListItem.rightPadding
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 12
spacing: 10
}
}
@@ -57,6 +57,8 @@ Control {
visible: root.icon.isLetterIdenticon
color: root.icon.color
name: root.primaryText
emoji: root.icon.emoji
emojiSize: root.icon.emojiSize
}
StatusBaseText {
font.weight: Font.Medium
@@ -0,0 +1,81 @@
import QtQuick 2.13
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Rectangle {
id: root
width: layout.width
height: 30
color: Theme.palette.primaryColor3
radius: 15
property alias titleText: titleText
property string title: ""
property bool closeButtonVisible: true
signal clicked()
property StatusImageSettings image: StatusImageSettings {
width: 20
height: 20
isIdenticon: false
}
property StatusIconSettings icon: StatusIconSettings {
height: 20
width: 20
rotation: 0
isLetterIdenticon: false
letterSize: 10
color: Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
width: 15
height: 15
color: Theme.palette.primaryColor3
}
}
RowLayout {
id: layout
height: parent.height
spacing: 5
StatusSmartIdenticon {
id: iconOrImage
Layout.leftMargin: 5
image: root.image
icon: root.icon
name: root.title
active: root.icon.isLetterIdenticon ||
!!root.icon.name ||
!!root.image.source.toString()
}
StatusBaseText {
id: titleText
color: Theme.palette.primaryColor1
text: root.title
Layout.rightMargin: closeButtonVisible ? 0 : 5
}
StatusIcon {
id: closeIcon
color: Theme.palette.primaryColor1
icon: "close-circle"
visible: closeButtonVisible
Layout.rightMargin: 5
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.clicked()
}
}
}
}
}
@@ -10,15 +10,9 @@ StatusListItem {
property string userName: ""
property string chatKey: ""
property bool isMutualContact: false
property var trustIndicator: StatusMemberListItem.TrustedType.None
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
property bool isOnline: false
enum TrustedType {
None, //0
Verified, //1
Untrustworthy //2
}
// Subtitle composition:
function composeSubtitile() {
var compose = ""
@@ -42,8 +36,10 @@ StatusListItem {
// root object settings:
title: root.nickName
titleIcon1Visible: root.isMutualContact
titleIcon2Visible: root.trustIndicator !== StatusMemberListItem.TrustedType.None
statusListItemTitleIcons.sourceComponent: StatusContactVerificationIcons {
isMutualContact: root.isMutualContact
trustIndicator: root.trustIndicator
}
subTitle: composeSubtitile()
statusListItemSubTitle.font.pixelSize: 10
icon.isLetterIdenticon: !root.image.source.toString()
@@ -51,7 +47,7 @@ StatusListItem {
statusListItemIcon.badge.color: root.isOnline ? Theme.palette.successColor1 : Theme.palette.baseColor1
color: sensor.containsMouse ? Theme.palette.baseColor2 : Theme.palette.baseColor4
// Default sizes/positions by design
// Default sizes / positions by design
implicitWidth: 256
implicitHeight: Math.max(56, statusListItemTitleArea.height + leftPadding)
leftPadding: 8
@@ -64,13 +60,4 @@ StatusListItem {
statusListItemIcon.badge.border.width: 2
statusListItemIcon.badge.implicitHeight: 12 // 8 px + 2 px * 2 borders
statusListItemIcon.badge.implicitWidth: 12 // 8 px + 2 px * 2 borders
// Trusted type icons definition:
titleIcon1.name: "tiny/tiny-contact"
titleIcon1.color: Theme.palette.indirectColor1
titleIcon1.background.color: Theme.palette.primaryColor1
// None and Untrustworthy types, same aspect (Icon will not be visible in case of None type):
titleIcon2.name: trustIndicator === StatusMemberListItem.TrustedType.Verified ? "tiny/tiny-checkmark" : "tiny/subtract"
titleIcon2.color: Theme.palette.indirectColor1
titleIcon2.background.color: trustIndicator === StatusMemberListItem.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
}
+2 -13
View File
@@ -21,14 +21,6 @@ Rectangle {
Invitation = 7
}
enum ContactType {
STANDARD = 0,
RENAME = 1,
CONTACT = 2,
VERIFIED = 3,
UNTRUSTWORTHY = 4
}
property alias messageHeader: messageHeader
property alias quickActions:quickActionsPanel.quickActions
property alias statusChatInput: editComponent.inputComponent
@@ -108,11 +100,8 @@ Rectangle {
displayName: messageDetails.displayName
secondaryName: messageDetails.secondaryName
tertiaryDetail: messageDetails.chatID
icon1.name: messageDetails.contactType === StatusMessage.ContactType.CONTACT ? "tiny/tiny-contact" : ""
icon2.name: messageDetails.contactType === StatusMessage.ContactType.VERIFIED ? "tiny/tiny-checkmark" :
messageDetails.contactType === StatusMessage.ContactType.UNTRUSTWORTHY ? "tiny/subtract": ""
icon2.background.color: messageDetails.contactType === StatusMessage.ContactType.UNTRUSTWORTHY ? Theme.palette.dangerColor1 : Theme.palette.primaryColor1
icon2.color: Theme.palette.indirectColor1
isMutualContact: messageDetails.isMutualContact
trustIndicator: messageDetails.trustIndicator
resendText: statusMessage.resendText
showResendButton: messageDetails.hasExpired && messageDetails.amISender
onClicked: statusMessage.senderNameClicked()
@@ -17,12 +17,13 @@ QtObject {
property string messageText: ""
property int contentType: 0
property string messageContent: ""
property int contactType: 0
property bool isMutualContact: false
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
property bool hasMention: false
property bool isPinned: false
property string pinnedBy: ""
property bool hasExpired: false
property string timestamp: ""
property string timestamp: ""
}
@@ -1,11 +1,13 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Loader {
id: statusSmartIdenticon
property string name: ""
property int dZ: 100
// Badge color properties must be set if badgeItem.visible = true
property alias badge: statusBadge
@@ -13,6 +15,7 @@ Loader {
property StatusIconSettings icon: StatusIconSettings {
width: 40
height: 40
charactersLen: 1
}
property StatusImageSettings image: StatusImageSettings {
@@ -20,6 +23,12 @@ Loader {
height: 40
}
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: 1.5
distinctiveColors: Theme.palette.identiconRingColors
}
sourceComponent: statusSmartIdenticon.icon.isLetterIdenticon ? letterIdenticon :
!!statusSmartIdenticon.image.source.toString() ? roundedImage :
!!statusSmartIdenticon.icon.name.toString() ? roundedIcon : letterIdenticon
@@ -75,10 +84,21 @@ Loader {
height: statusSmartIdenticon.icon.height
color: statusSmartIdenticon.icon.color
name: statusSmartIdenticon.name
emoji: statusSmartIdenticon.icon.emoji
emojiSize: statusSmartIdenticon.icon.emojiSize
letterSize: statusSmartIdenticon.icon.letterSize
identiconText.color: statusSmartIdenticon.icon.textColor
charactersLen: statusSmartIdenticon.icon.charactersLen
}
}
// Next components are painted above main sourceComponent
StatusIdenticonRing {
settings: statusSmartIdenticon.ringSettings
anchors.fill: parent
z: statusSmartIdenticon.dZ/2
}
// State component
StatusBadge {
id: statusBadge
@@ -88,6 +108,6 @@ Loader {
border.width: 3
implicitHeight: 15
implicitWidth: 15
z: 100
z: statusSmartIdenticon.dZ
}
}
@@ -0,0 +1,285 @@
import QtQuick 2.14
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.14
import QtGraphicalEffects 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
implicitWidth: 448
implicitHeight: 44 + ((userListView.count > 0) ? 44 + ((((userListView.count * 64) > root.maxHeight)
? root.maxHeight : (userListView.count * 64))) :0)
property real maxHeight
property alias textEdit: edit
property alias text: edit.text
property string warningText: ""
property string toLabelText: ""
property string listLabel: ""
property int nameCountLimit: 5
property ListModel sortedList: ListModel { }
property ListModel namesModel: ListModel { }
function find(model, criteria) {
for (var i = 0; i < model.count; ++i) if (criteria(model.get(i))) return model.get(i);
return null;
}
function insertTag(name, id) {
if (!find(namesModel, function(item) { return item.publicId === id }) && namesModel.count < root.nameCountLimit) {
namesModel.insert(namesModel.count, {"name": name, "publicId": id});
addMember(id);
edit.clear();
}
}
function sortModel(inputModel) {
sortedList.clear();
if (text !== "") {
for (var i = 0; i < inputModel.count; i++ ) {
var entry = inputModel.get(i);
if (entry.name.toLowerCase().includes(text.toLowerCase())) {
sortedList.insert(sortedList.count, {"publicId": entry.publicId, "name": entry.name,
"icon": entry.icon, "isIdenticon": entry.isIdenticon,
"onlineStatus": entry.onlineStatus});
userListView.model = sortedList;
}
}
} else {
userListView.model = inputModel;
}
}
signal addMember(string memberId)
signal removeMember(string memberId)
Rectangle {
id: tagSelectorRect
width: parent.width
height: 44
radius: 8
color: Theme.palette.baseColor2
RowLayout {
anchors.fill: parent
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 8
StatusBaseText {
Layout.preferredWidth: 22
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
color: Theme.palette.baseColor1
text: root.toLabelText
}
ScrollView {
Layout.preferredWidth: (namesList.contentWidth > (parent.width - 142)) ?
(parent.width - 142) : namesList.contentWidth
implicitHeight: 30
Layout.alignment: Qt.AlignVCenter
visible: (namesList.count > 0)
contentWidth: namesList.contentWidth
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
clip: true
ListView {
id: namesList
anchors.fill: parent
model: namesModel
orientation: ListView.Horizontal
spacing: 8
onCountChanged: {
contentX = contentWidth;
}
delegate: Rectangle {
id: nameDelegate
width: (nameText.contentWidth + 34)
height: 30
color: mouseArea.containsMouse ? Theme.palette.miscColor1 : Theme.palette.primaryColor1
radius: 8
StatusBaseText {
id: nameText
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
color: Theme.palette.indirectColor1
text: name
}
StatusIcon {
anchors.left: nameText.right
anchors.verticalCenter: parent.verticalCenter
color: Theme.palette.indirectColor1
icon: "close"
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
removeMember(publicId);
namesModel.remove(index, 1);
}
}
}
}
}
TextEdit {
id: edit
Layout.fillWidth: true
Layout.preferredHeight: 44
verticalAlignment: Text.AlignVCenter
visible: (namesModel.count < 5)
enabled: visible
focus: true
font.pixelSize: 15
font.family: Theme.palette.baseFont.name
color: Theme.palette.directColor1
Keys.onPressed: {
if ((event.key === Qt.Key_Backspace || event.key === Qt.Key_Escape)
&& getText(cursorPosition, (cursorPosition-1)) === "") {
removeMember(namesModel.get(namesList.count-1).publicId);
namesModel.remove((namesList.count-1), 1);
}
}
}
StatusBaseText {
id: warningTextLabel
visible: (namesModel.count === root.nameCountLimit)
Layout.preferredWidth: 120
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
font.pixelSize: 10
color: Theme.palette.dangerColor1
text: root.nameCountLimit + " " + root.warningText
}
}
}
StatusBaseText {
id: contactsLabel
font.pixelSize: 15
anchors.left: parent.left
anchors.leftMargin: 8
anchors.top: tagSelectorRect.bottom
anchors.topMargin: 32
visible: (namesModel.count === 0)
color: Theme.palette.baseColor1
text: root.listLabel
}
Control {
id: suggestionsContainer
width: 360
anchors {
top: (root.sortedList.count > 0) ? tagSelectorRect.bottom : contactsLabel.bottom
topMargin: 8//Style.current.padding
bottom: parent.bottom
bottomMargin: 20//Style.current.bigPadding
}
visible: ((root.namesModel.count === 0) || (root.sortedList.count > 0))
x: ((root.namesModel.count > 0) && ((edit.x + 8) <= (root.width - suggestionsContainer.width)))
? (edit.x + 8) : 0
background: Rectangle {
id: bgRect
anchors.fill: parent
visible: (root.sortedList.count > 0)
color: Theme.palette.statusPopupMenu.backgroundColor
radius: 8
layer.enabled: true
layer.effect: DropShadow {
width: bgRect.width
height: bgRect.height
x: bgRect.x
source: bgRect
horizontalOffset: 0
verticalOffset: 4
radius: 12
samples: 25
spread: 0.2
color: Theme.palette.dropShadow
}
}
contentItem: ListView {
id: userListView
anchors.fill: parent
anchors.topMargin: 8
anchors.bottomMargin: 8
clip: true
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
boundsBehavior: Flickable.StopAtBounds
delegate: Item {
id: wrapper
anchors.right: parent.right
anchors.left: parent.left
height: 64
property bool hovered: false
Rectangle {
id: rectangle
anchors.fill: parent
anchors.rightMargin: 8
anchors.leftMargin: 8
radius: 8
visible: (root.sortedList.count > 0)
color: (wrapper.hovered) ? Theme.palette.baseColor2 : "transparent"
}
StatusSmartIdenticon {
id: contactImage
anchors.left: parent.left
anchors.leftMargin: 16//Style.current.padding
anchors.verticalCenter: parent.verticalCenter
name: model.name
icon: StatusIconSettings {
width: 40
height: 40
letterSize: 15
}
image: StatusImageSettings {
width: 40
height: 40
source: model.icon
isIdenticon: model.isIdenticon
}
}
StatusBaseText {
id: contactInfo
text: model.name
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: contactImage.right
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
color: Theme.palette.directColor1
font.weight: Font.Medium
font.pixelSize: 15
}
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
onEntered: {
wrapper.hovered = true;
}
onExited: {
wrapper.hovered = false;
}
onClicked: {
root.insertTag(model.name, model.publicId);
}
}
}
}
}
}
@@ -0,0 +1,182 @@
import QtQuick 2.14
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
Control {
id: root
width: 343
height: !!secondaryText ? 68 : 48
anchors.right: parent.right
property bool open: false
property string primaryText: ""
property string secondaryText: ""
property bool loading: false
property string iconName: ""
property string linkUrl: ""
property StatusIconSettings icon: StatusIconSettings {
width: 23
height: 23
}
property int type: StatusToastMessage.Type.Default
enum Type {
Default,
Success
}
function open(title, subTitle, iconName, type, loading, url) {
root.primaryText = title;
root.secondaryText = subTitle;
root.icon.name = iconName;
root.type = type;
root.loading = loading;
root.linkUrl = url;
root.open = true;
}
signal close()
signal linkActivated(var link)
states: [
State {
name: "opened"
when: root.open
PropertyChanges {
target: root
anchors.rightMargin: 0
opacity: 1.0
}
},
State {
name: "closed"
when: !root.open
PropertyChanges {
target: root
anchors.rightMargin: -width
opacity: 0.0
}
StateChangeScript {
script: { root.close(); }
}
}
]
transitions: [
Transition {
to: "*"
NumberAnimation { properties: "anchors.rightMargin,opacity"; duration: 400 }
}
]
background: Rectangle {
id: background
anchors.fill: parent
color: Theme.palette.statusToastMessage.backgroundColor
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
}
}
contentItem: Item {
anchors.left: parent.left
anchors.leftMargin: 16
anchors.right: parent.right
anchors.rightMargin: 4
height: parent.height
MouseArea {
anchors.fill: parent
onMouseXChanged: {
root.open = (mouseX < (root.width/3));
}
}
RowLayout {
anchors.fill: parent
spacing: 16
Rectangle {
implicitWidth: 32
implicitHeight: 32
Layout.alignment: Qt.AlignVCenter
radius: (root.width/2)
color: (root.type === StatusToastMessage.Type.Success) ?
Theme.palette.successColor2 : Theme.palette.primaryColor3
Loader {
anchors.centerIn: parent
sourceComponent: root.loading ? loadingInd : statusIcon
Component {
id: loadingInd
StatusLoadingIndicator {
color: (root.type === StatusToastMessage.Type.Success) ?
Theme.palette.successColor1 : Theme.palette.primaryColor1
}
}
Component {
id: statusIcon
StatusIcon {
anchors.centerIn: parent
width: root.icon.width
height: root.icon.height
color: (root.type === StatusToastMessage.Type.Success) ?
Theme.palette.successColor1 : Theme.palette.primaryColor1
icon: root.icon.name
}
}
}
}
Column {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
StatusBaseText {
width: parent.width
font.pixelSize: 13
color: Theme.palette.directColor1
elide: Text.ElideRight
text: root.primaryText
}
StatusBaseText {
width: parent.width
visible: (!root.linkUrl && !!root.secondaryText)
height: visible ? contentHeight : 0
font.pixelSize: 13
color: Theme.palette.baseColor1
text: root.secondaryText
elide: Text.ElideRight
}
StatusSelectableText {
visible: (!!root.linkUrl)
height: visible ? implicitHeight : 0
font.pixelSize: 13
hoveredLinkColor: Theme.palette.primaryColor1
text: "<p><a style=\"text-decoration:none\" href=\'" + root.linkUrl + " \'>" + root.secondaryText + "</a></p>"
onLinkActivated: {
root.linkActivated(root.linkUrl);
}
}
}
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
icon.name: "close"
icon.color: Theme.palette.directColor1
implicitWidth: 30
implicitHeight: 30
onClicked: {
root.open = false;
}
}
}
}
}
@@ -0,0 +1,78 @@
import QtQuick 2.14
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
Item {
id: wizardWrapper
width: parent.width
height: 56
property ListModel stepsModel: ListModel { }
ListView {
id: repeat
width: childrenRect.width
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
orientation: ListView.Horizontal
model: stepsModel
delegate: Item {
id: wrapperItem
width: (index === 0) ? descriptionLabel.contentWidth : (wizardWrapper.width / repeat.count)
height: 56
onXChanged: {
//as x changes while delegates are created, direct assignment doesn't work
x = (index === (repeat.count-1)) ? (width+32) : (label.width/2) + 8
}
StatusProgressBar {
id: barBorder
width: visible ? (parent.width - (label.width/2 + 24)) : 0
height: visible ? 8 : 0
visible: (index > 0)
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -12
from: 0
//TODO what is to: here?
to: 2000
value: loadingTime
backgroundColor: "transparent"
backgroundBorderColor: Theme.palette.primaryColor1
fillColor: Theme.palette.primaryColor1
}
Item {
id: label
width: descriptionLabel.contentWidth
height: 56
anchors.left: (index > 0) ? barBorder.right : parent.left
anchors.leftMargin: (index > 0) ? -((width/2) - 24) : 0
Rectangle {
width: 32
height: 32
anchors.horizontalCenter: parent.horizontalCenter
radius: width/2
color: stepCompleted ? Theme.palette.primaryColor1 : "transparent"
border.color: (stepCompleted && (barBorder.visible ? (barBorder.value === barBorder.to) : true))
? "transparent" : Theme.palette.primaryColor1
border.width: 2
StatusBaseText {
anchors.centerIn: parent
text: index+1
font.pixelSize: 17
color: (stepCompleted && (barBorder.visible ? (barBorder.value === barBorder.to) : true))
? Theme.palette.indirectColor1 : Theme.palette.primaryColor1
}
}
StatusBaseText {
id: descriptionLabel
anchors.bottom: parent.bottom
text: description
color: Theme.palette.directColor1
font.pixelSize: 13
}
}
}
}
}
@@ -19,38 +19,8 @@ Item {
property string tertiaryDetail: ""
property string resendText: ""
property bool showResendButton: false
property StatusIconSettings icon1: StatusIconSettings {
width: dummyImage.width
height: dummyImage.height
rotation: 0
color: Theme.palette.indirectColor1
background: StatusIconBackgroundSettings {
width: 10
height: 10
color: Theme.palette.primaryColor1
}
// only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: icon1.name ? "../../../../assets/img/icons/" + icon1.name + ".svg": ""
visible: false
}
}
property StatusIconSettings icon2: StatusIconSettings {
width: dummyImage.width
height: dummyImage.height
rotation: 0
color: Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
width: 10
height: 10
color: Theme.palette.indirectColor1
}
// only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: icon2.name ? "../../../../assets/img/icons/" + icon2.name + ".svg": ""
visible: false
}
}
property bool isMutualContact: false
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
signal clicked()
signal resendClicked()
@@ -83,28 +53,10 @@ Item {
}
}
Layout.alignment: Qt.AlignBottom
}
StatusRoundIcon {
icon.background.width: icon1.background.width
icon.background.height: icon1.background.height
icon.background.color: icon1.background.color
icon.width: icon1.width
icon.height: icon1.height
icon.name: icon1.name
icon.rotation: icon1.rotation
icon.color: icon1.color
visible: !!icon.name
}
StatusRoundIcon {
icon.background.width: icon2.background.width
icon.background.height: icon2.background.height
icon.background.color: icon2.background.color
icon.width: icon2.width
icon.height: icon2.height
icon.name: icon2.name
icon.rotation: icon2.rotation
icon.color: icon2.color
visible: !!icon.name
}
StatusContactVerificationIcons {
isMutualContact: statusMessageHeader.isMutualContact
trustIndicator: statusMessageHeader.trustIndicator
}
StatusBaseText {
id: secondaryDisplayName
+5
View File
@@ -10,6 +10,7 @@ StatusChatListCategoryItem 0.1 StatusChatListCategoryItem.qml
StatusChatListAndCategories 0.1 StatusChatListAndCategories.qml
StatusChatToolBar 0.1 StatusChatToolBar.qml
StatusContactRequestsIndicatorListItem 0.1 StatusContactRequestsIndicatorListItem.qml
StatusContactVerificationIcons 0.1 StatusContactVerificationIcons.qml
StatusDescriptionListItem 0.1 StatusDescriptionListItem.qml
StatusLetterIdenticon 0.1 StatusLetterIdenticon.qml
StatusListItem 0.1 StatusListItem.qml
@@ -22,7 +23,11 @@ StatusRoundIcon 0.1 StatusRoundIcon.qml
StatusRoundedImage 0.1 StatusRoundedImage.qml
StatusMacWindowButtons 0.1 StatusMacWindowButtons.qml
StatusListItemBadge 0.1 StatusListItemBadge.qml
StatusListItemTag 0.1 StatusListItemTag.qml
StatusExpandableItem 0.1 StatusExpandableItem.qml
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
StatusMessage 0.1 StatusMessage.qml
StatusMessageDetails 0.1 StatusMessageDetails.qml
StatusTagSelector 0.1 StatusTagSelector.qml
StatusToastMessage 0.1 StatusToastMessage.qml
StatusWizardStepper 0.1 StatusWizardStepper.qml
+189 -150
View File
@@ -1,14 +1,15 @@
import QtQuick 2.14
import QtQuick.Controls 2.14 as QC
import QtQuick.Layouts 1.14
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: statusBaseInput
id: root
property bool multiline: false
@@ -24,6 +25,7 @@ Item {
property alias edit: edit
property alias text: edit.text
property alias background: background
property alias color: edit.color
property alias font: edit.font
@@ -35,10 +37,11 @@ Item {
property alias placeholderTextColor: placeholder.color
property alias placeholderFont: placeholder.font
property real leftPadding: 16
property real leftPadding: leftComponentLoader.item ? 8 : 16
property real rightPadding: 16
property real topPadding: 12
property real bottomPadding: 12
property var tabNavItem: null
property real minimumHeight: 0
property real maximumHeight: 0
@@ -49,56 +52,64 @@ Item {
property bool dirty: false
property bool pending: false
property bool leftIcon: true
property bool isIconSelectable: false
property bool showBackground: true
property StatusIconSettings icon: StatusIconSettings {
width: 24
height: 24
name: ""
color: Theme.palette.baseColor1
}
property Item component
onClearableChanged: {
if (clearable && !component) {
clearButtonLoader.active = true
clearButtonLoader.parent = statusBaseInputComponentSlot
} else {
clearButtonLoader.active = false
emoji: ""
letterSize: emoji ? 11 : 14
background: StatusIconBackgroundSettings {
width: 30
height: 30
color: Theme.palette.indirectColor1
}
}
onComponentChanged: {
if (!!component) {
component.parent = statusBaseInputComponentSlot
}
}
property Component leftComponent
property Component rightComponent
signal iconClicked
signal keyPressed(var event)
signal editClicked()
implicitWidth: 448
implicitHeight: multiline ? Math.max((edit.implicitHeight + topPadding + bottomPadding), 44) : 44
implicitHeight: multiline ? Math.min(Math.max(
(edit.implicitHeight + topPadding + bottomPadding),
44, root.minimumHeight), root.maximumHeight) : 44
Rectangle {
id: background
width: parent.width
height: maximumHeight != 0 ? Math.min(
minimumHeight != 0 ? Math.max(statusBaseInput.implicitHeight, minimumHeight)
: statusBaseInput.implicitHeight, maximumHeight) : parent.height
color: Theme.palette.baseColor2
minimumHeight
!= 0 ? Math.max(
root.implicitHeight,
minimumHeight) : root.implicitHeight,
maximumHeight) : parent.height
color: root.showBackground ? Theme.palette.baseColor2
: "transparent"
radius: 8
clip: true
border.width: 1
border.color: {
if (!statusBaseInput.valid && statusBaseInput.dirty) {
return Theme.palette.dangerColor1;
if (!root.showBackground) {
return "transparent"
}
if (!root.valid && root.dirty) {
return Theme.palette.dangerColor1
}
if (edit.activeFocus) {
return Theme.palette.primaryColor1;
return Theme.palette.primaryColor1
}
return sensor.containsMouse ? Theme.palette.primaryColor2 : "transparent"
}
MouseArea {
id: sensor
enabled: !edit.activeFocus
@@ -107,146 +118,138 @@ Item {
cursorShape: Qt.IBeamCursor
onClicked: {
edit.forceActiveFocus()
root.editClicked()
}
StatusIcon {
id: statusIcon
anchors.topMargin: 10
anchors.left: statusBaseInput.leftIcon ? parent.left : undefined
anchors.right: !statusBaseInput.leftIcon ? parent.right : undefined
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
icon: statusBaseInput.icon.name
width: statusBaseInput.icon.width
height: statusBaseInput.icon.height
color: statusBaseInput.icon.color
visible: !!statusBaseInput.icon.name
}
Flickable {
id: flick
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: (statusIcon.visible && statusBaseInput.leftIcon) ?
statusIcon.right : parent.left
anchors.right: {
if (!!statusBaseInput.component) {
return statusBaseInputComponentSlot.left
}
return statusIcon.visible && !statusBaseInput.leftIcon ? statusIcon.left : parent.right
RowLayout {
anchors {
fill: parent
leftMargin: root.leftPadding
rightMargin: root.rightPadding
}
anchors.leftMargin: statusIcon.visible && statusBaseInput.leftIcon ? 8
: statusBaseInput.leftPadding
anchors.rightMargin: {
return clearable ? clearButtonLoader.width + 12 :
(statusIcon.visible && !leftIcon) || !!statusBaseInput.component ? 8 : 0
}
contentWidth: edit.paintedWidth
contentHeight: edit.paintedHeight
boundsBehavior: Flickable.StopAtBounds
QC.ScrollBar.vertical: QC.ScrollBar { interactive: multiline; enabled: multiline }
clip: true
function ensureVisible(r) {
if (contentX >= r.x)
contentX = r.x;
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;
Loader {
id: leftComponentLoader
sourceComponent: {
if (root.leftComponent) return root.leftComponent
if (!root.leftIcon) return undefined
if (root.icon.emoji) return identiconComponent
if (root.icon.name) return isIconSelectable ? identiconComponent : iconComponent
return undefined
}
}
TextEdit {
id: edit
property string previousText: text
width: flick.width
height: flick.height
verticalAlignment: Text.AlignVCenter
selectByMouse: true
selectionColor: Theme.palette.primaryColor2
selectedTextColor: color
focus: true
font.pixelSize: 15
font.family: Theme.palette.baseFont.name
color: Theme.palette.directColor1
onCursorRectangleChanged: { flick.ensureVisible(cursorRectangle); }
wrapMode: statusBaseInput.multiline ? Text.WrapAtWordBoundaryOrAnywhere : TextEdit.NoWrap
onActiveFocusChanged: {
if (statusBaseInput.pristine) {
statusBaseInput.pristine = false
}
Flickable {
id: flick
Layout.fillHeight: true
Layout.fillWidth: true
Layout.topMargin: root.topPadding
Layout.bottomMargin: root.bottomPadding
contentWidth: edit.paintedWidth
contentHeight: edit.paintedHeight
boundsBehavior: Flickable.StopAtBounds
QC.ScrollBar.vertical: QC.ScrollBar {
interactive: multiline
enabled: multiline
}
clip: true
function ensureVisible(r) {
if (contentX >= r.x)
contentX = r.x
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
}
Keys.onReturnPressed: {
if (multiline) {
event.accepted = false
} else {
event.accepted = true
}
}
TextEdit {
id: edit
Keys.onEnterPressed: {
if (multiline) {
event.accepted = false
} else {
event.accepted = true
}
}
property string previousText: text
property var keyEvent
Keys.forwardTo: [statusBaseInput]
onTextChanged: {
statusBaseInput.dirty = true
if (statusBaseInput.maximumLength > 0) {
if (text.length > statusBaseInput.maximumLength) {
var cursor = cursorPosition;
text = previousText;
if (cursor > text.length) {
cursorPosition = text.length;
} else {
cursorPosition = cursor-1;
}
}
previousText = text
}
}
StatusBaseText {
id: placeholder
visible: (edit.text.length === 0)
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: statusBaseInput.rightPadding
anchors.verticalCenter: parent.verticalCenter
width: flick.width
height: flick.height
verticalAlignment: Text.AlignVCenter
selectByMouse: true
selectionColor: Theme.palette.primaryColor2
selectedTextColor: color
focus: true
font.pixelSize: 15
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name
color: statusBaseInput.enabled ? Theme.palette.baseColor1 :
Theme.palette.directColor6
color: Theme.palette.directColor1
wrapMode: root.multiline ? Text.WrapAtWordBoundaryOrAnywhere : TextEdit.NoWrap
Keys.onReturnPressed: event.accepted = !multiline
Keys.onEnterPressed: event.accepted = !multiline
Keys.forwardTo: [root]
KeyNavigation.priority: !!root.tabNavItem ? KeyNavigation.BeforeItem : KeyNavigation.AfterItem
KeyNavigation.tab: root.tabNavItem
Keys.onPressed: {
edit.keyEvent = event.key
root.keyPressed(event);
}
onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
onActiveFocusChanged: if (root.pristine) root.pristine = false
onTextChanged: {
root.dirty = true
if (root.maximumLength > 0) {
if (text.length > root.maximumLength) {
var cursor = cursorPosition
text = previousText
if (cursor > text.length) {
cursorPosition = text.length
} else {
cursorPosition = cursor - 1
}
}
previousText = text
}
}
StatusBaseText {
id: placeholder
visible: (edit.text.length === 0)
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: root.rightPadding
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name
color: root.enabled ? Theme.palette.baseColor1 : Theme.palette.directColor6
}
}
} // Flickable
Loader {
sourceComponent: {
if (root.rightComponent) return root.rightComponent
if (root.clearable) return clearButton
if (root.leftIcon) return undefined
if (root.icon.emoji) return identiconComponent
if (root.icon.name) return isIconSelectable ? identiconComponent : iconComponent
return undefined
}
}
} // Flickable
Item {
id: statusBaseInputComponentSlot
anchors.right: parent.right
anchors.rightMargin: 12
width: childrenRect.width
height: childrenRect.height
anchors.verticalCenter: parent.verticalCenter
}
}
} // Rectangle
Loader {
id: clearButtonLoader
sourceComponent: StatusFlatRoundButton {
id: clearButton
visible: edit.text.length != 0 &&
statusBaseInput.clearable &&
!statusBaseInput.multiline &&
edit.activeFocus
Component {
id: clearButton
StatusFlatRoundButton {
visible: edit.text.length != 0 && root.clearable && !root.multiline
&& edit.activeFocus
type: StatusFlatRoundButton.Type.Secondary
width: 24
height: 24
@@ -260,5 +263,41 @@ Item {
}
}
Component {
id: identiconComponent
StatusSmartIdenticon {
id: identicon
icon.width: !root.icon.emoji ? 20 : 30
icon.height: !root.icon.emoji ? 20 : 30
icon.background: root.icon.background
icon.color: root.icon.color
icon.letterSize: root.icon.letterSize
icon.emoji: root.icon.emoji
icon.name: !root.icon.emoji ? root.icon.name : ""
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
enabled: identicon.visible
onClicked: root.iconClicked()
}
}
}
Component {
id: iconComponent
StatusIcon {
id: statusIcon
icon: root.icon.name
width: root.icon.width
height: root.icon.height
color: root.icon.color
}
}
}
@@ -0,0 +1,32 @@
import QtQuick 2.13
import QtQuick.Controls 2.14
import StatusQ.Core.Theme 0.1
RadioButton {
id: control
property string radioButtonColor: ""
property string selectionColor: StatusColors.colors['white']
implicitWidth: 48
implicitHeight: 48
indicator: Rectangle {
implicitWidth: 48
implicitHeight: 48
radius: width/2
color: radioButtonColor
Rectangle {
width: 20
height: 20
radius: width/2
color: selectionColor
border.color: StatusColors.colors['grey3']
visible: control.checked
anchors.centerIn: parent
}
}
}
@@ -0,0 +1,56 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import "./"
Column {
id: root
property alias titleText: title.text
property alias title: title
property int selectedColorIndex: 0
property string selectedColor: ""
property var model: [StatusColors.colors['black'],
StatusColors.colors['grey'],
StatusColors.colors['blue2'],
StatusColors.colors['purple'],
StatusColors.colors['cyan'],
StatusColors.colors['violet'],
StatusColors.colors['red2'],
StatusColors.colors['yellow'],
StatusColors.colors['green2'],
StatusColors.colors['moss'],
StatusColors.colors['brown'],
StatusColors.colors['brown2']]
spacing: 16
StatusBaseText {
id: title
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.baseColor1
}
Grid {
columns: 6
rowSpacing: 16
columnSpacing: 32
Repeater {
model: root.model
delegate: StatusColorRadioButton {
checked: index === selectedColorIndex
radioButtonColor: root.model[index] || "transparent"
onCheckedChanged: {
if(checked) {
selectedColorIndex = index
selectedColor = root.model[index]
}
}
}
}
}
}
@@ -0,0 +1,132 @@
import QtQuick 2.0
import QtQuick.Layouts 1.0
import StatusQ.Core 0.1
/*!
\qmltype StatusIdenticonRing
\inherits Item
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief It provides lines wrapped into a ring around another component like avatars.
The \c StatusIdenticonRing item displays lines wrapped into a ring. The line is rendered clockwise.
N segments and M distinctive colors compose identicon lines.
Example of how the component looks like:
\image status_identicon_ring.png
Example of how to use it:
\qml
StatusIdenticonRing {
anchors.fill: parent
settings: StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: 1.5
ringSpecModel: [ ListElement {colorId: 0; segmentLength: 1},
ListElement {colorId: 28; segmentLength: 1},
ListElement {colorId: 31; segmentLength: 1},
ListElement {colorId: 22; segmentLength: 4},
ListElement {colorId: 28; segmentLength: 3},
ListElement {colorId: 27; segmentLength: 5},
ListElement {colorId: 7; segmentLength: 5},
ListElement {colorId: 13; segmentLength: 1},
ListElement {colorId: 25; segmentLength: 4}]
distinctiveColors: ["#000000", "#726F6F", "#C4C4C4",
"#E7E7E7", "#FFFFFF", "#00FF00",
"#009800", "#B8FFBB", "#FFC413",
"#9F5947", "#FFFF00", "#A8AC00",
"#FFFFB0", "#FF5733", "#FF0000",
"#9A0000", "#FF9D9D", "#FF0099",
"#C80078", "#FF00FF", "#900090",
"#FFB0FF", "#9E00FF", "#0000FF",
"#000086", "#9B81FF", "#3FAEF9",
"#9A6600", "#00FFFF", "#008694",
"#C2FFFF", "#00F0B6"]
}
}
\endqml
For a list of components available see StatusQ.
*/
Item {
id: root
/*!
\qmlproperty StatusIdenticonRingSettings StatusIdenticonRing::settings
This property holds a set of settings for building the ring.
*/
property StatusIdenticonRingSettings settings: StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: 1.5
}
visible: settings.ringSpecModel !== undefined
Loader {
anchors.fill: parent
active: root.visible
sourceComponent: Canvas {
function printArcSegment(context, xPos, yPos, radius, color, startAngle, arcAngleLen, lineWidth) {
context.beginPath()
context.arc(xPos, yPos, radius, startAngle, startAngle + arcAngleLen, false/*anticlockwise*/)
context.strokeStyle = color
context.lineWidth = lineWidth
context.stroke()
}
function getSegmentsCount() {
if (typeof settings.ringSpecModel.count !== "undefined") {
return settings.ringSpecModel.count
}
return settings.ringSpecModel.length
}
function getSegment(i) {
if (typeof settings.ringSpecModel.count !== "undefined") {
return settings.ringSpecModel.get(i)
}
return settings.ringSpecModel[i]
}
function totalRingUnits() {
var units = 0
for (let i=0; i < getSegmentsCount(); i++) {
const segment = getSegment(i)
units += segment.segmentLength
}
return Math.max(1, units)
}
onPaint: {
const context = getContext("2d")
const radius = (height - settings.ringPxSize) / 2
const xPos = width / 2
const yPos = height / 2
const unitRadLen = 2 * Math.PI / totalRingUnits()
const segmentsCount = getSegmentsCount()
let arcPos = settings.initalAngleRad
context.reset()
if(settings.ringSpecModel) {
for (let i=0; i < segmentsCount; i++) {
const segment = getSegment(i)
printArcSegment(context,
xPos,
yPos,
radius,
settings.distinctiveColors[segment.colorId],
arcPos,
segment.segmentLength * unitRadLen,
settings.ringPxSize)
arcPos += segment.segmentLength * unitRadLen
}
}
}
}
}
}
+124 -15
View File
@@ -6,27 +6,71 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
/*!
\qmltype StatusInput
\inherits Item
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief The StatusInput control provides a generic user text input
Example of how to use it:
\qml
StatusInput {
label: "Label"
charLimit: 30
errorMessage: "Input doesn't match validator"
input.clearable: true
input.placeholderText: "Placeholder text"
}
\endqml
For a list of components available see StatusQ.
*/
Item {
id: root
implicitWidth: 480
height: (label.visible ?
label.anchors.topMargin +
label.height :
charLimitLabel.visible ?
charLimitLabel.anchors.topMargin +
charLimitLabel.height :
0) +
statusBaseInput.anchors.topMargin +
statusBaseInput.height +
(errorMessage.visible ?
errorMessage.anchors.topMargin +
errorMessage.height :
0) + 8
implicitHeight: (label.visible ?
label.anchors.topMargin +
label.height :
charLimitLabel.visible ?
charLimitLabel.anchors.topMargin +
charLimitLabel.height :
0) +
statusBaseInput.anchors.topMargin +
statusBaseInput.height +
(errorMessage.visible ?
errorMessage.anchors.topMargin +
errorMessage.height :
0) + 8
height: implicitHeight
width: implicitWidth
property alias input: statusBaseInput
property alias valid: statusBaseInput.valid
property alias pending: statusBaseInput.pending
property alias text: statusBaseInput.text
/*!
\qmlproperty errorMessageCmp
This property represents the errorMessage shown on statusInput in cases one of the validators fails
This can be used to control the error message's look and position from the outside.
Examples of usage
\qml
StatusInput {
errorMessageCmp.font.pixelSize: 15
errorMessageCmp.font.weight: Font.Medium
}
\endqml
*/
property alias errorMessageCmp: errorMessage
property string label: ""
property string secondaryLabel: ""
property int charLimit: 0
@@ -35,27 +79,73 @@ Item {
property real rightPadding: 16
property list<StatusValidator> validators
property list<StatusAsyncValidator> asyncValidators
/*!
\qmlproperty int (enumeration ValidationMode)
This property describes the validation mode
Note that this property should be always strictly compared with one of ValidationMode's value
Default value: StatusInput.ValidationMode.OnlyWhenDirty
Examples of usage
> To ignore invalid input
\qml
StatusInput {
validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
validators: [
StatusMinLengthValidator {
minLength: 15
}
]
}
\endqml
*/
property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty
property string validatedValue
property var pendingValidators: []
signal iconClicked()
signal keyPressed(var event)
signal editClicked()
/*!
\qmltype ValidationMode
\brief Available validation modes supported by StatusInput
Values:
- OnlyWhenDirty validates input only after it has become dirty
- Always validates input even before it has become dirty
- IgnoreInvalidInput ignore the new content if it doesn't match validators
Has no effect without at least a validator
\note that it represents a QML enumeration and can't be used as a property type, we use int instead
\see validationMode for a usage example
\see validators
*/
enum ValidationMode {
OnlyWhenDirty, // validates input only after it has become dirty
Always // validates input even before it has become dirty
Always, // validates input even before it has become dirty
IgnoreInvalidInput // ignore the new content if it doesn't match
}
property var errors: ({})
property var asyncErrors: ({})
function reset() {
statusBaseInput.valid = false
statusBaseInput.valid = true
statusBaseInput.pristine = true
statusBaseInput.text = ""
root.errorMessage = ""
}
property string _previousText: text
function validate() {
if (!statusBaseInput.dirty && validationMode === StatusInput.ValidationMode.OnlyWhenDirty) {
return
}
@@ -85,11 +175,23 @@ Item {
if (errors){
let errs = Object.values(errors)
if (errs && errs[0]) {
if(validationMode === StatusInput.ValidationMode.IgnoreInvalidInput
&& text.length > _previousText.length) {
// Undo the last input
const cursor = statusBaseInput.cursorPosition;
statusBaseInput.text = _previousText;
if (statusBaseInput.cursor > statusBaseInput.text.length) {
statusBaseInput.cursorPosition = statusBaseInput.text.length;
} else {
statusBaseInput.cursorPosition = cursor-1;
}
}
errorMessage.text = errs[0].errorMessage || root.errorMessage;
} else {
errorMessage.text = ""
}
}
_previousText = text
}
if (asyncValidators.length && !Object.values(errors).length) {
@@ -189,6 +291,13 @@ Item {
onTextChanged: root.validate()
Keys.forwardTo: [root]
onIconClicked: root.iconClicked()
onKeyPressed: {
root.keyPressed(event);
}
onEditChanged: {
root.editClicked();
}
}
StatusBaseText {
@@ -15,16 +15,23 @@ StatusProgressBar {
property string labelGreat: "Great"
enum Strength {
VeryWeak, // 0
Weak, // 1
SoSo, // 2
Good, // 3
Great // 4
None, // 0
VeryWeak, // 1
Weak, // 2
SoSo, // 3
Good, // 4
Great // 5
}
onValueChanged: if(value === 0) control.strength = StatusPasswordStrengthIndicator.Strength.None
// Behavior:
states: [
// Strength states definition:
State {
when: control.strength === StatusPasswordStrengthIndicator.Strength.None
PropertyChanges { target: control; text: ""}
},
State {
when: control.strength === StatusPasswordStrengthIndicator.Strength.VeryWeak
PropertyChanges { target: control; fillColor : Theme.palette.dangerColor1}
+234
View File
@@ -0,0 +1,234 @@
import QtQuick 2.0
import StatusQ.Core.Theme 0.1
import StatusQ.Controls.Validators 0.1
/*!
\qmltype StatusPinInput
\inherits Item
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief It allows entering an N pin length.
The \c StatusPinInput displays N visual circles corresponging with the pin length to introduce.
It runs a blinking animation when the control is focused and ready to introduce the pin, as well as, an hovering feedback when user is in the MouseArea where is able to click into the control.
This pin input control allows introducing validators.
Example of how the control looks like:
\image status_pin_input.png
Example of how to use it:
\qml
StatusPinInput {
id: regexPinInput
validator: StatusRegularExpressionValidator { regularExpression: /[0-9A-Za-z@]+/ }
circleDiameter: 22
circleSpacing: 22
pinLen: 7
}
\endqml
For a list of components available see StatusQ.
*/
Item {
id: root
/*!
\qmlproperty string StatusPinInput::pinInput
This property holds the introduced user pin.
*/
property alias pinInput: inputText.text
/*!
\qmlproperty Validator StatusPinInput::validator
This property allows you to set a validator on the StatusPinInput. When a validator is set the StatusPinInput will only accept
input which leaves the pinInput property in an acceptable state.
Currently supported validators are qml StatusIntValidator and StatusRegularExpressionValidator.
An example of using validators is shown below, which allows input of integers between 0 and 999999 into the pin input
\qml
StatusPinInput {
id: numbersPinInput
validator: StatusIntValidator{bottom: 0; top: 999999;}
}
\endqml
*/
property alias validator: d.statusValidator
/*!
\qmlproperty int StatusPinInput::pinLen
This property allows you to set a specific pin input length. The default value is 6.
*/
property int pinLen: 6
/*!
\qmlproperty int StatusPinInput::circleSpacing
This property allows you to customize spacing between pin circles. The default value is 16 pixels.
*/
property int circleSpacing: 16
/*!
\qmlproperty int StatusPinInput::circleDiameter
This property allows you to customize pin circle diameter. The default value is 16 pixels.
*/
property int circleDiameter: 16
QtObject {
id: d
property int currentPinIndex: 0
property StatusValidator statusValidator
function activateBlink () {
const currItem = repeater.itemAt(d.currentPinIndex)
if(currItem) {
if((currItem.innerState === "NEXT") && (!currItem.blinkingAnimation.running)) {
currItem.blinkingAnimation.start()
}
}
}
function deactivateBlink () {
const currItem = repeater.itemAt(d.currentPinIndex)
if(currItem) {
if((currItem.innerState === "NEXT") && (currItem.blinkingAnimation.running)) {
currItem.blinkingAnimation.stop()
// To ensure that the opacity does not remain in an intermediate state when forcing the animation to stop
currItem.innerOpacity = 1
}
}
}
}
/*
\qmlmethod StatusPinInput::statesInitialization()
Initializes pin input bringing it to its initial state.
It is directly called in Component.onCompleted slot and can be called whenever you need resetting it.
*/
function statesInitialization() {
d.currentPinIndex = 0
repeater.itemAt(d.currentPinIndex).innerState = "NEXT"
for (var i = 1; i < root.pinLen; i++) {
repeater.itemAt(i).innerState = "EMPTY"
}
}
width: (root.circleDiameter + root.circleSpacing) * root.pinLen
height: root.circleDiameter
Component.onCompleted: { statesInitialization() }
// Pin input data management object:
TextInput {
id: inputText
visible: false
focus: true
maximumLength: root.pinLen
validator: d.statusValidator.validatorObj
onTextChanged: {
// Modify state of current introduced character position:
if(text.length >= (d.currentPinIndex + 1)) {
repeater.itemAt(d.currentPinIndex).innerState = "FILLED"
// Update next:
d.currentPinIndex++
if(d.currentPinIndex < root.pinLen)
repeater.itemAt(d.currentPinIndex).innerState = "NEXT"
}
// Modify state of current removed character position:
else if (text.length <= (d.currentPinIndex + 1)) {
if(d.currentPinIndex < root.pinLen)
repeater.itemAt(d.currentPinIndex).innerState = "EMPTY"
d.currentPinIndex--
repeater.itemAt(d.currentPinIndex).innerState = "NEXT"
}
// Some component validations:
if(text.length !== d.currentPinIndex)
console.error("StatusPinInput input management error. Current pin length must be "+ text.length + "and is " + d.currentPinIndex)
}
onFocusChanged: { if(!focus) { d.deactivateBlink () } }
}
// Pin input visual objects:
Row {
spacing: root.circleSpacing
Repeater {
id: repeater
model: root.pinLen
Rectangle {
id: background
property string innerState: "EMPTY"
property alias blinkingAnimation: blinkingAnimation
property alias innerOpacity: inner.opacity
width: root.circleDiameter
height: width
color: Theme.palette.primaryColor2
radius: 0.5 * width
Rectangle {
id: inner
state: background.innerState
anchors.centerIn: parent
height: width
color: Theme.palette.primaryColor1
radius: 0.5 * width
states: [
State {
name: "NEXT"
StateChangeScript { script: { if(inputText.focus) blinkingAnimation.start() } }
PropertyChanges {target: inner; width: root.circleDiameter / 2}
},
State {
name: "FILLED"
StateChangeScript { script: if(blinkingAnimation.running) blinkingAnimation.stop() }
PropertyChanges {target: inner; width: root.circleDiameter}
PropertyChanges {target: inner; opacity: 1}
},
State {
name: "EMPTY"
StateChangeScript { script: if(blinkingAnimation.running) blinkingAnimation.stop() }
PropertyChanges {target: inner; width: 0}
PropertyChanges {target: inner; opacity: 1}
}
]
// Animation on transitions
Behavior on width { NumberAnimation { duration: 200 } }
// Animation on "cursor" blinking
SequentialAnimation {
id: blinkingAnimation
loops: Animation.Infinite
NumberAnimation { target: inner; property: "opacity"; to: 0; duration: 800 }
NumberAnimation { target: inner; property: "opacity"; to: 1; duration: 800 }
}
}
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
// MouseArea behavior:
onClicked: {
inputText.forceActiveFocus()
d.activateBlink ()
}
onContainsMouseChanged: { if(containsMouse) { cursorShape = Qt.PointingHandCursor } }
}
}
@@ -10,6 +10,7 @@ ProgressBar {
property string text
property color fillColor
property color backgroundColor: Theme.palette.directColor8
property color backgroundBorderColor: "transparent"
width: 416
height: 16
@@ -19,6 +20,7 @@ ProgressBar {
implicitWidth: parent.width
implicitHeight: parent.height
color: control.backgroundColor
border.color: control.backgroundBorderColor
radius: 5
}
contentItem: Item {
@@ -0,0 +1,141 @@
import QtQuick 2.12
import QtGraphicalEffects 1.13
import QtQuick.Controls 2.12
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
width: 162
height: 44
property alias textEdit: seedWordInput
property alias text: seedWordInput.text
property string leftComponentText: ""
property ListModel inputList: ListModel { }
property ListModel filteredList: ListModel { }
signal doneInsertingWord(string word)
signal keyPressed(var event)
signal editClicked()
onActiveFocusChanged: {
if (root.activeFocus) {
seedWordInput.input.edit.forceActiveFocus();
}
}
StatusInput {
id: seedWordInput
implicitWidth: parent.width
implicitHeight: parent.height
input.anchors.topMargin: 0
input.anchors.leftMargin: 0
input.anchors.rightMargin: 0
input.leftComponent: StatusBaseText {
text: root.leftComponentText
color: seedWordInput.input.edit.activeFocus ?
Theme.palette.primaryColor1 : Theme.palette.baseColor1
font.pixelSize: 15
}
onTextChanged: {
filteredList.clear();
if (text !== "") {
for (var i = 0; i < inputList.count;i++) {
if (inputList.get(i).seedWord.startsWith(text)) {
filteredList.insert(filteredList.count, {"seedWord": inputList.get(i).seedWord});
}
}
seedSuggestionsList.model = filteredList;
if ((text.length === 3) && (filteredList.count === 1) &&
((input.edit.keyEvent !== Qt.Key_Backspace) && (input.edit.keyEvent !== Qt.Key_Delete))) {
seedWordInput.text = filteredList.get(0).seedWord;
seedWordInput.input.edit.cursorPosition = seedWordInput.text.length;
seedSuggestionsList.model = 0;
root.doneInsertingWord(seedWordInput.text);
}
} else {
seedSuggestionsList.model = 0;
}
}
onKeyPressed: {
root.keyPressed(event);
}
onEditClicked: {
root.editClicked();
}
}
Item {
id: suggListContainer
width: seedSuggestionsList.width
height: (((seedSuggestionsList.count <= 5) ? seedSuggestionsList.count : 5) *34) + 16
anchors.left: parent.left
anchors.leftMargin: 16
anchors.top: seedWordInput.bottom
anchors.topMargin: 4
visible: ((seedSuggestionsList.count > 0) && seedWordInput.input.edit.activeFocus)
Rectangle {
id: statusPopupMenuBackgroundContent
anchors.fill: parent
color: Theme.palette.statusPopupMenu.backgroundColor
radius: 8
layer.enabled: true
layer.effect: DropShadow {
anchors.fill: parent
source: statusPopupMenuBackgroundContent
horizontalOffset: 0
verticalOffset: 4
radius: 12
samples: 25
spread: 0.2
color: Theme.palette.dropShadow
}
}
ListView {
id: seedSuggestionsList
width: ((seedSuggestionsList.contentItem.childrenRect.width + 24) > root.width) ? root.width
: (seedSuggestionsList.contentItem.childrenRect.width + 24)
anchors.top: parent.top
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
clip: true
ScrollBar.vertical: ScrollBar { }
delegate: Item {
id: txtDelegate
width: suggWord.contentWidth
height: 34
Rectangle {
width: seedSuggestionsList.width
height: parent.height
color: mouseArea.containsMouse? Theme.palette.primaryColor1 : "transparent"
}
StatusBaseText {
id: suggWord
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: seedWord
color: mouseArea.containsMouse ? Theme.palette.indirectColor1 : Theme.palette.directColor1
font.pixelSize: 13
elide: Text.ElideRight
}
MouseArea {
id: mouseArea
width: seedSuggestionsList.width
height: parent.height
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
seedWordInput.text = seedWord;
seedWordInput.input.edit.cursorPosition = seedWordInput.text.length;
root.doneInsertingWord(seedWordInput.text);
seedSuggestionsList.model = 0;
}
}
}
}
}
}
@@ -0,0 +1,170 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusTokenInlineSelector
\inherits RowLayout
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief It presents selectable tokens in inline form.
The \c StatusTokenInlineSelector is a graphical component that is meant to be used as inline text input.
Example of how the component looks like:
\image status_token_inline_selector.png
*/
RowLayout {
id: root
/*!
\qmlproperty var StatusTokenInlineSelector::tokens
This is a REQUIRED property that contains an array of objects that describes each token.
\qml
tokens: [{amount: 0.1, token: "ETH"}, {amount: 10, token: "SNT"}]
\endqml
*/
property var tokens
/*!
\qmlproperty var StatusTokenInlineSelector::tokenImageSourceGetter
This is a property function used to acquire image source for given token.
*/
property var tokenImageSourceGetter: function (token) {
return "../../assets/img/icons/%1.png".arg(token)
}
signal triggered(real amount, string token)
StatusBaseText {
text: qsTr("Hold")
color: Theme.palette.directColor6
font.pixelSize: 15
}
Repeater {
model: Math.max(0, root.tokens.length - 1)
delegate: Loader {
sourceComponent: tokenComponent
onLoaded: d.assignItemProperties(item, index, root.tokens[index])
}
}
StatusBaseText {
text: qsTr("or")
color: Theme.palette.directColor6
font.pixelSize: 15
}
Loader {
active: root.tokens.length > 1
sourceComponent: tokenComponent
onLoaded: {
const index = root.tokens.length - 1
d.assignItemProperties(item, index, root.tokens[index])
}
}
StatusBaseText {
text: qsTr("to post")
color: Theme.palette.directColor6
font.pixelSize: 15
}
QtObject {
id: d
function assignItemProperties(item, index, modelData) {
item.tokenImageSource = root.tokenImageSourceGetter(modelData.token)
item.token = modelData.token
item.amount = modelData.amount
item.backgroundColor = Qt.binding(() => index % 2 ? Theme.palette.primaryColor3 : Theme.palette.dangerColor3)
item.hoverColor = Qt.binding(() => index % 2 ? Theme.palette.primaryColor2 : Theme.palette.dangerColor2)
item.textColor = Qt.binding(() => index % 2 ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1)
}
}
Component {
id: tokenComponent
Rectangle {
property string amount
property string token
property string tokenImageSource
property color backgroundColor
property color hoverColor
property color textColor
width: content.width + 4
height: content.height + 4
radius: height/2
color: mouseArea.containsMouse ? hoverColor : backgroundColor
Behavior on color {
ColorAnimation {
}
}
RowLayout {
id: content
anchors.centerIn: parent
StatusRoundedImage {
id: roundedImage
Layout.maximumHeight: text.height + 2
Layout.maximumWidth: text.height + 2
image.source: tokenImageSource
}
StatusBaseText {
id: text
text: amount + " " + token
color: textColor
font.pixelSize: 15
}
Item {
implicitWidth: 2
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
propagateComposedEvents: true
}
Rectangle {
id: pressIndicator
height: parent.height
radius: height / 2
color: textColor
opacity: 0.1
NumberAnimation on width {
from: 0
to: parent.width
duration: 800
running: mouseArea.containsPress
onStopped: {
if (pressIndicator.width == parent.width) {
root.triggered(amount, token)
}
pressIndicator.width = 0
}
}
}
}
}
}
@@ -0,0 +1,57 @@
import QtQuick 2.14
import StatusQ.Controls 0.1
/*!
\qmltype StatusFloatValidator
\inherits StatusValidator
\inqmlmodule StatusQ.Controls.Validators
\since StatusQ.Controls.Validators 0.1
\brief The StatusFloatValidator.qml type provides a validator for float values.
The \c StatusFloatValidator type provides a validator for float values.
Example of how to use it:
\qml
StatusFloatValidator {
bottom: 0
top: 1.25
errorMessage: qsTr("This is an invalid numeric value")
}
\endqml
For a list of components available see StatusQ.
*/
StatusValidator {
id: root
/*!
\qmlproperty string StatusFloatValidator::bottom
This property holds the validator's lowest acceptable value. By default, this property's value is derived from the lowest signed float available (typically -2147483647).
*/
property real bottom
/*!
\qmlproperty string StatusFloatValidator::locale
This property holds the name of the locale used to interpret the number.
*/
property string locale
/*!
\qmlproperty string StatusFloatValidator::top
This property holds the validator's highest acceptable value. By default, this property's value is derived from the highest float available (typically 2147483647).
*/
property real top
name: "floatValidator"
errorMessage: "Please enter a valid numeric value."
validate: function (t) {
return !isNaN(t) && t > bottom && t <= top ? true : {
bottom: bottom,
top: top,
actual: t
}
}
}
@@ -0,0 +1,57 @@
import QtQuick 2.14
import StatusQ.Controls 0.1
/*!
\qmltype StatusIntValidator
\inherits StatusValidator
\inqmlmodule StatusQ.Controls.Validators
\since StatusQ.Controls.Validators 0.1
\brief The StatusIntValidator type provides a validator for integer values.
The \c StatusIntValidator type provides a validator for integer values.
It is a wrapper of QML type \l{https://doc.qt.io/qt-5/qml-qtquick-intvalidator.html}{IntValidator}.
Example of how to use it:
\qml
StatusIntValidator {
bottom: 0
top: 125
errorMessage: qsTr("This is an invalid numeric value")
}
\endqml
For a list of components available see StatusQ.
*/
StatusValidator {
id: root
/*!
\qmlproperty string StatusIntValidator::bottom
This property holds the validator's lowest acceptable value. By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
*/
property int bottom
/*!
\qmlproperty string StatusIntValidator::locale
This property holds the name of the locale used to interpret the number.
*/
property string locale
/*!
\qmlproperty string StatusIntValidator::top
This property holds the validator's highest acceptable value. By default, this property's value is derived from the highest signed integer available (typically 2147483647).
*/
property int top
name: "intValidator"
errorMessage: "Please enter a valid numeric value."
validatorObj: IntValidator { bottom: root.bottom; locale: root.locale; top: root.top }
validate: function (t) {
// Basic validation management
return root.validatorObj.validate() === IntValidator.Acceptable
}
}
@@ -0,0 +1,60 @@
import QtQuick 2.14
import StatusQ.Controls 0.1
/*!
\qmltype StatusRegularExpressionValidator
\inherits StatusValidator
\inqmlmodule StatusQ.Controls.Validators
\since StatusQ.Controls.Validators 0.1
\brief The StatusRegularExpressionValidator type provides a validator for regular expressions.
The \c StatusRegularExpressionValidator type provides a validator, that counts as valid any string which matches a specified regular expression.
It is a wrapper of QML type \l{https://doc.qt.io/qt-5/qml-qtquick-regularexpressionvalidator.html}{RegularExpressionValidator}.
Example of how to use it:
\qml
StatusRegularExpressionValidator {
regularExpression: /[0-9A-Za-z@]+/
errorMessage: qsTr("Please enter a valid regular expression.")
}
\endqml
For a list of components available see StatusQ.
*/
StatusValidator {
id: root
/*!
\qmlproperty string StatusRegularExpressionValidator::regularExpression
This property holds the regular expression used for validation.
Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression matching "a".
By default, this property contains a regular expression with the pattern .* that matches any string.
Some more examples of regular expressions:
> A list of numbers with one to three positions separated by a comma:
\qml
/\d{1,3}(?:,\d{1,3})+$/
\endqml
> An amount consisting of up to 3 numbers before the decimal point, and 1 to 2 after the decimal point:
\qml
/(\d{1,3})([.,]\d{1,2})?$/
\endqml
*/
property var regularExpression
name: "regex"
errorMessage: `Must match regex(${validatorObj.regularExpression.toString()})`
validatorObj: RegularExpressionValidator { regularExpression: root.regularExpression }
validate: function (value) {
// Basic validation management
return root.validatorObj.regularExpression.test(value)
}
}
@@ -6,6 +6,7 @@ QtObject {
property string name: ""
property string errorMessage: "invalid input"
property var validatorObj
property var validate: function (value) {
return true
+3
View File
@@ -4,7 +4,10 @@ StatusAddressValidator 0.1 StatusAddressValidator.qml
StatusAddressOrEnsValidator 0.1 StatusAddressOrEnsValidator.qml
StatusAsyncValidator 0.1 StatusAsyncValidator.qml
StatusAsyncEnsValidator 0.1 StatusAsyncEnsValidator.qml
StatusIntValidator 0.1 StatusIntValidator.qml
StatusMinLengthValidator 0.1 StatusMinLengthValidator.qml
StatusMaxLengthValidator 0.1 StatusMaxLengthValidator.qml
StatusRegularExpressionValidator 0.1 StatusRegularExpressionValidator.qml
StatusUrlValidator 0.1 StatusUrlValidator.qml
StatusValidator 0.1 StatusValidator.qml
StatusFloatValidator 0.1 StatusFloatValidator.qml
+5
View File
@@ -8,6 +8,7 @@ StatusChatInfoButton 0.1 StatusChatInfoButton.qml
StatusChatListCategoryItemButton 0.1 StatusChatListCategoryItemButton.qml
StatusColorSelector 0.1 StatusColorSelector.qml
StatusIconTabButton 0.1 StatusIconTabButton.qml
StatusIdenticonRing 0.1 StatusIdenticonRing.qml
StatusNavBarTabButton 0.1 StatusNavBarTabButton.qml
StatusTabBarIconButton 0.1 StatusTabBarIconButton.qml
StatusToolTip 0.1 StatusToolTip.qml
@@ -24,10 +25,14 @@ StatusSelect 0.1 StatusSelect.qml
StatusBaseInput 0.1 StatusBaseInput.qml
StatusInput 0.1 StatusInput.qml
StatusPickerButton 0.1 StatusPickerButton.qml
StatusPinInput 0.1 StatusPinInput.qml
StatusProgressBar 0.1 StatusProgressBar.qml
StatusPasswordStrengthIndicator 0.1 StatusPasswordStrengthIndicator.qml
StatusSwitchTabButton 0.1 StatusSwitchTabButton.qml
StatusSwitchTabBar 0.1 StatusSwitchTabBar.qml
StatusSelectableText 0.1 StatusSelectableText.qml
StatusTokenInlineSelector 0.1 StatusTokenInlineSelector.qml
StatusWalletColorButton 0.1 StatusWalletColorButton.qml
StatusWalletColorSelect 0.1 StatusWalletColorSelect.qml
StatusColorSelectorGrid 0.1 StatusColorSelectorGrid.qml
StatusSeedPhraseInput 0.1 StatusSeedPhraseInput.qml
@@ -0,0 +1,46 @@
import QtQuick 2.13
import QtQml.Models 2.13
DelegateModel {
id: delegateModel
property var filterAcceptsItem: function(item) { return true; }
signal aboutToUpdateFilteredModel()
function update() {
delegateModel.aboutToUpdateFilteredModel()
if (items.count > 0) {
items.setGroups(0, items.count, "items");
}
var visible = [];
for (var i = 0; i < items.count; ++i) {
var item = items.get(i);
if (filterAcceptsItem(item.model)) {
visible.push(item);
}
}
for (i = 0; i < visible.length; ++i) {
item = visible[i];
item.inVisible = true;
if (item.visibleIndex !== i) {
visibleItems.move(item.visibleIndex, i, 1);
}
}
}
items.onChanged: update()
onFilterAcceptsItemChanged: update()
groups: DelegateModelGroup {
id: visibleItems
name: "visible"
includeByDefault: false
}
filterOnGroup: "visible"
}
+24
View File
@@ -1,6 +1,30 @@
import QtQuick 2.13
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusBaseText
\inherits Text
\inqmlmodule StatusQ.Core
\since StatusQ.Core 0.1
\brief Displays multiple lines of text. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-text.html}{Text}.
The \c StatusBaseText item displays text.
For example:
\qml
StatusBaseText {
width: 240
text: "Hello World!"
font.pixelSize: 24
color: Theme.pallete.directColor1
}
\endqml
\image status_base_text.png
For a list of components available see StatusQ.
*/
Text {
font.family: Theme.palette.baseFont.name
}
+4
View File
@@ -8,10 +8,14 @@ QtObject {
property real width
property real height
property color color
property color textColor: Qt.rgba(255, 255, 255, 0.7)
property color disabledColor
property url source
property int rotation
property bool isLetterIdenticon
property int letterSize
property int charactersLen: 1
property string emoji
property string emojiSize
property StatusIconBackgroundSettings background: StatusIconBackgroundSettings {}
}
@@ -0,0 +1,66 @@
import QtQuick 2.13
import StatusQ.Core 0.1
/*!
\qmltype StatusIdenticonRingSettings
\inherits QtObject
\inqmlmodule StatusQ.Core
\since StatusQ.Core 0.1
\brief It describes identicon ring settings.
The \c StatusIdenticonRingSettings object is not a graphical component just an object to encapsulate identicon ring settings.
Example of how to use it:
\qml
StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: 1.5
ringSpecModel: [ {colorId: 0; segmentLength: 1},
{colorId: 5; segmentLength: 1},
{colorId: 1; segmentLength: 1},
{colorId: 1; segmentLength: 4},
{colorId: 2; segmentLength: 3} ]
distinctiveColors: ["#000000", "#726F6F", "#C4C4C4",
"#E7E7E7", "#FFFFFF", "#00FF00" ]
}
\endqml
For a list of components available see StatusQ.
*/
QtObject {
id: statusIdenticonRingSettings
/*!
\qmlproperty ListModel StatusIdenticonRingSettings::ringSpecModel
This is a REQUIRED property that contains a ListModel or array of objects that describes each ring segment color and length.
Examples:
\qml
ringSpecModel: ListModel {ListElement{colorId: 0; segmentLength: 1} ListElement{colorId: 1; segmentLength: 2}}
\endqml
\qml
ringSpecModel: [{colorId: 0, segmentLength: 1}, {colorId: 1, segmentLength: 2}]
\endqml
*/
property var ringSpecModel
/*!
\qmlproperty var StatusIdenticonRingSettings::distinctiveColors
This is a REQUIRED property that holds an string array of disctinctive segment colors.
*/
property var distinctiveColors
/*!
\qmlproperty real StatusIdenticonRingSettings::initalAngleRad
This property provides the initial angle, in radians, the identicon ring will start rendering the line.
*/
property real initalAngleRad
/*!
\qmlproperty real StatusIdenticonRingSettings::ringPxSize
This property provides the pixels size of the ring line.
*/
property real ringPxSize
}
@@ -158,6 +158,13 @@ ThemePalette {
getColor('brown3')
]
identiconRingColors: ["#000000", "#726F6F", "#C4C4C4", "#E7E7E7", "#FFFFFF", "#00FF00",
"#009800", "#B8FFBB", "#FFC413", "#9F5947", "#FFFF00", "#A8AC00",
"#FFFFB0", "#FF5733", "#FF0000", "#9A0000", "#FF9D9D", "#FF0099",
"#C80078", "#FF00FF", "#900090", "#FFB0FF", "#9E00FF", "#0000FF",
"#000086", "#9B81FF", "#3FAEF9", "#9A6600", "#00FFFF", "#008694",
"#C2FFFF", "#00F0B6"]
property QtObject statusAppLayout: QtObject {
property color backgroundColor: baseColor3
property color rightPanelBackgroundColor: baseColor3
@@ -167,6 +174,10 @@ ThemePalette {
property color backgroundColor: baseColor5
}
property QtObject statusToastMessage: QtObject {
property color backgroundColor: baseColor3
}
property QtObject statusListItem: QtObject {
property color backgroundColor: baseColor3
property color secondaryHoverBackgroundColor: primaryColor3
@@ -156,6 +156,13 @@ ThemePalette {
getColor('brown')
]
identiconRingColors: ["#000000", "#726F6F", "#C4C4C4", "#E7E7E7", "#FFFFFF", "#00FF00",
"#009800", "#B8FFBB", "#FFC413", "#9F5947", "#FFFF00", "#A8AC00",
"#FFFFB0", "#FF5733", "#FF0000", "#9A0000", "#FF9D9D", "#FF0099",
"#C80078", "#FF00FF", "#900090", "#FFB0FF", "#9E00FF", "#0000FF",
"#000086", "#9B81FF", "#3FAEF9", "#9A6600", "#00FFFF", "#008694",
"#C2FFFF", "#00F0B6"]
property QtObject statusAppLayout: QtObject {
property color backgroundColor: white
property color rightPanelBackgroundColor: white
@@ -165,6 +172,10 @@ ThemePalette {
property color backgroundColor: baseColor2
}
property QtObject statusToastMessage: QtObject {
property color backgroundColor: white
}
property QtObject statusListItem: QtObject {
property color backgroundColor: white
property color secondaryHoverBackgroundColor: getColor('blue6')
+6
View File
@@ -92,6 +92,8 @@ QtObject {
property var accountColors: []
property var identiconRingColors: []
property QtObject statusAppLayout: QtObject {
property color backgroundColor
property color rightPanelBackgroundColor
@@ -101,6 +103,10 @@ QtObject {
property color backgroundColor
}
property QtObject statusToastMessage: QtObject {
property color backgroundColor
}
property QtObject statusListItem: QtObject {
property color backgroundColor
property color secondaryHoverBackgroundColor
+120
View File
@@ -0,0 +1,120 @@
pragma Singleton
import QtQuick 2.13
//import shared.status 1.0
import "../../../assets/twemoji/twemoji.js" as Twemoji
import "./emojiList.js" as EmojiJSON
QtObject {
readonly property var size: {
"veryBig": "86x86",
"big": "72x72",
"middle": "32x32",
"small": "18x18",
"verySmall": "16x16"
}
property string base: Qt.resolvedUrl("../../../assets/twemoji/")
function parse(text, renderSize = size.small) {
const renderSizes = renderSize.split("x");
if (!renderSize.includes("x") || renderSizes.length !== 2) {
throw new Error("Invalid value for 'renderSize' parameter: ", renderSize);
}
Twemoji.twemoji.base = base
Twemoji.twemoji.ext = ".svg"
Twemoji.twemoji.size = "svg"
return Twemoji.twemoji.parse(text, {
attributes: function() {
return {
width: renderSizes[0],
height: renderSizes[1],
style: "vertical-align: top"
}
}
})
}
function fromCodePoint(value) {
return Twemoji.twemoji.convert.fromCodePoint(value)
}
function deparse(value) {
// /StatusQ/src/assets/twemoji/
return value.replace(/<img src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" alt=\"(.+?)\" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g, "$1");
}
function deparseFromParse(value) {
return value.replace(/<img class=\"emoji\" draggable=\"false\" alt=\"(.+?)\" src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g, "$1");
}
function hasEmoji(value) {
let match = value.match(/<img src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" alt=\"(.+?)\" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g)
return match && match.length > 0
}
function nbEmojis(value) {
let match = value.match(/<img src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" alt=\"(.+?)\" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g)
return match ? match.length : 0
}
function getEmojis(value) {
return value.match(/<img class=\"emoji\" draggable=\"false\" alt=\"(.+?)\" src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g, "$1");
}
function getEmojiUnicode(shortname) {
var _emoji;
EmojiJSON.emoji_json.forEach(function(emoji) {
if (emoji.shortname === shortname)
_emoji = emoji;
})
if (_emoji !== undefined)
return _emoji.unicode;
return undefined;
}
function getEmojiCodepoint(iconCodePoint) {
// Split the codepoint to get all the parts and then encode them from hex to utf8
const splitCodePoint = iconCodePoint.split('-')
let codePointParts = []
splitCodePoint.forEach(function (codePoint) {
codePointParts.push(`0x${codePoint}`)
})
return String.fromCodePoint(...codePointParts);
}
function getShortcodeFromId(emojiId) {
switch (emojiId) {
case 1: return ":heart:"
case 2: return ":thumbsup:"
case 3: return ":thumbsdown:"
case 4: return ":laughing:"
case 5: return ":cry:"
case 6: return ":angry:"
default: return undefined
}
}
function getEmojiFromId(emojiId) {
let shortcode = Emoji.getShortcodeFromId(emojiId)
let emojiUnicode = Emoji.getEmojiUnicode(shortcode)
if (emojiUnicode) {
return Emoji.fromCodePoint(emojiUnicode)
}
return undefined
}
function getRandomEmoji() {
var randomEmoji = EmojiJSON.emoji_json[Math.floor(Math.random() * EmojiJSON.emoji_json.length)]
const extenstionIndex = randomEmoji.unicode.lastIndexOf('.');
let iconCodePoint = randomEmoji.unicode
if (extenstionIndex > -1) {
iconCodePoint = iconCodePoint.substring(0, extenstionIndex)
}
// Split the unicode to get all the parts and then encode them from hex to utf8
const splitCodePoint = iconCodePoint.split('-')
let codePointParts = []
splitCodePoint.forEach(function (codePoint) {
codePointParts.push(`0x${codePoint}`)
})
const encodedIcon = String.fromCodePoint(...codePointParts);
return Emoji.parse(encodedIcon) + ' '
}
}
+4
View File
@@ -70,6 +70,10 @@ QtObject {
}
return strNumber.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1')
}
function isHtml(text) {
return (/<\/?[a-z][\s\S]*>/i.test(text))
}
}
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,4 +1,5 @@
module StatusQ.Core.Utils
EmojiJSON 1.0 emojiList.js
singleton Utils 0.1 Utils.qml
singleton Emoji 0.1 Emoji.qml
+2
View File
@@ -4,6 +4,8 @@ StatusBaseText 0.1 StatusBaseText.qml
StatusIcon 0.1 StatusIcon.qml
StatusIconSettings 0.1 StatusIconSettings.qml
StatusIconBackgroundSettings 0.1 StatusIconBackgroundSettings.qml
StatusIdenticonRingSettings 0.1 StatusIdenticonRingSettings.qml
StatusImageSettings 0.1 StatusImageSettings.qml
StatusModalHeaderSettings 0.1 StatusModalHeaderSettings.qml
StatusTooltipSettings 0.1 StatusTooltipSettings.qml
StatusAppNavBarFilterModel 0.1 StatusAppNavBarFilterModel.qml
+134 -116
View File
@@ -1,40 +1,35 @@
import QtQuick 2.13
import QtQuick.Layouts 1.13
import QtQuick.Controls 2.13
import QtQml.Models 2.13
import Qt.labs.qmlmodels 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
Rectangle {
id: statusAppNavBar
property StatusNavBarTabButton navBarChatButton
property StatusNavBarTabButton navBarProfileButton
property list<StatusNavBarTabButton> navBarTabButtons
property alias navBarCommunityTabButtons: navBarCommunityTabButtons
property int navBarContentHeight: 0
property int navBarContentHeightWithoutCommunityButtons: 0
width: 78
implicitHeight: 600
color: Theme.palette.statusAppNavBar.backgroundColor
Component.onCompleted: {
navBarContentHeightWithoutCommunityButtons = (navBarChatButtonSlot.anchors.topMargin + navBarChatButtonSlot.height) +
(separator.anchors.topMargin + separator.height) +
(navBarTabButtonsSlot.height + navBarTabButtonsSlot.anchors.topMargin + navBarTabButtonsSlot.anchors.bottomMargin)
navBarContentHeight = navBarContentHeightWithoutCommunityButtons +
(navBarCommunityTabButtonsSlot.height + navBarScrollSection.anchors.topMargin)
}
property var sectionModel: []
property string communityTypeRole: ""
property int communityTypeValue: -1
property int navBarButtonSpacing: 12
onNavBarChatButtonChanged: {
if (!!navBarChatButton) {
navBarChatButton.parent = navBarChatButtonSlot
}
}
property StatusNavBarTabButton navBarProfileButton
property Component regularNavBarButton
property Component communityNavBarButton
property var filterRegularItem: function(item) { return true; }
property var filterCommunityItem: function(item) { return true; }
signal aboutToUpdateFilteredRegularModel()
signal aboutToUpdateFilteredCommunityModel()
onNavBarProfileButtonChanged: {
if (!!navBarProfileButton) {
@@ -42,115 +37,138 @@ Rectangle {
}
}
onNavBarTabButtonsChanged: {
if (navBarTabButtons.length) {
for (let idx in navBarTabButtons) {
navBarTabButtons[idx].parent = navBarTabButtonsSlot
function triggerUpdate(){
navBarModel.update()
}
StatusAppNavBarFilterModel {
id: navBarModel
filterAcceptsItem: filterRegularItem
model: statusAppNavBar.sectionModel
onAboutToUpdateFilteredModel: {
statusAppNavBar.aboutToUpdateFilteredRegularModel()
}
DelegateChooser {
id: delegateChooser
role: communityTypeRole
DelegateChoice { roleValue: communityTypeValue; delegate: communityNavButton }
DelegateChoice { delegate: regularNavBarButton }
}
delegate: delegateChooser
}
Component {
id: communityNavButton
Item {
width: parent.width
height: (necessaryHightForCommunities > maxHightForCommunities)?
maxHightForCommunities : necessaryHightForCommunities
property int communityNavBarButtonHeight: 40
property int maxHightForCommunities: {
let numOfOtherThanCommunityBtns = navBarListView.model.count - 1
let numOfSpacingsForNavBar = navBarListView.model.count - 1
return navBarListView.height -
numOfOtherThanCommunityBtns * communityNavBarButtonHeight -
numOfSpacingsForNavBar * navBarButtonSpacing
}
property int necessaryHightForCommunities: {
let numOfSpacingsForCommunities = communityListView.model.count - 1
return communityListView.model.count * communityNavBarButtonHeight +
numOfSpacingsForCommunities * navBarButtonSpacing +
separatorBottom.height
}
StatusAppNavBarFilterModel {
id: navBarCommunityModel
filterAcceptsItem: filterCommunityItem
model: statusAppNavBar.sectionModel
delegate: communityNavBarButton
onAboutToUpdateFilteredModel: {
statusAppNavBar.aboutToUpdateFilteredCommunityModel()
}
}
Item {
id: separatorTop
width: parent.width
height: navBarButtonSpacing
anchors.top: parent.top
visible: parent.necessaryHightForCommunities > parent.maxHightForCommunities
Rectangle {
height: 1
width: 30
color: Theme.palette.directColor7
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
}
}
ListView {
id: communityListView
anchors.left: parent.left
anchors.right: parent.right
anchors.top: separatorTop.visible? separatorTop.bottom : parent.top
anchors.bottom: separatorBottom.top
clip: true
spacing: navBarButtonSpacing
model: navBarCommunityModel
}
Item {
id: separatorBottom
width: parent.width
height: navBarButtonSpacing
anchors.bottom: parent.bottom
Rectangle {
height: 1
width: 30
color: Theme.palette.directColor7
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
Item {
id: navBarChatButtonSlot
ListView {
id: navBarListView
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: 48
anchors.horizontalCenter: parent.horizontalCenter
height: visible ? statusAppNavBar.navBarChatButton.height : 0
width: visible ? statusAppNavBar.navBarChatButton.width : 0
visible: !!statusAppNavBar.navBarChatButton
}
anchors.bottom: navBarProfileButtonSlot.top
anchors.bottomMargin: navBarButtonSpacing
Rectangle {
id: separatorTop
height: 1
width: 30
color: Theme.palette.directColor7
anchors.top: navBarChatButtonSlot.bottom
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
visible: separator.anchors.topMargin === 0
}
spacing: navBarButtonSpacing
ScrollView {
id: navBarScrollSection
anchors.top: separatorTop.visible ? separatorTop.bottom : navBarChatButtonSlot.bottom
anchors.topMargin: separatorTop.visible ? 0 : 12
anchors.horizontalCenter: statusAppNavBar.horizontalCenter
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
clip: true
Component.onCompleted: {
if (navBarContentHeight > statusAppNavBar.height) {
height = statusAppNavBar.height -
statusAppNavBar.navBarContentHeightWithoutCommunityButtons -
(!!navBarTabButtonsSlot.anchors.bottom ? navBarTabButtonsSlot.anchors.bottomMargin : navBarTabButtonsSlot.anchors.topMargin) -
navBarProfileButtonSlot.height -
navBarProfileButtonSlot.anchors.bottomMargin
bottomPadding = 16
topPadding = 16
} else {
height = navBarCommunityTabButtons.count > 0 ? navBarCommunityTabButtonsSlot.implicitHeight : 0
}
}
Column {
id: navBarCommunityTabButtonsSlot
width: navBarScrollSection.width
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
spacing: 12
onImplicitHeightChanged: {
statusAppNavBar.Component.onCompleted()
navBarTabButtonsSlot.Component.onCompleted()
navBarScrollSection.Component.onCompleted()
}
Repeater {
id: navBarCommunityTabButtons
}
}
}
Rectangle {
id: separator
height: 1
width: 30
color: Theme.palette.directColor7
anchors.top: !!navBarCommunityTabButtons.model && navBarCommunityTabButtons.count > 0 ? navBarScrollSection.bottom : navBarChatButtonSlot.bottom
anchors.topMargin: navBarScrollSection.height < navBarCommunityTabButtonsSlot.implicitHeight ? 0 : 16
anchors.horizontalCenter: parent.horizontalCenter
visible: navBarChatButton !== null && navBarTabButtons.length > 0
}
Column {
id: navBarTabButtonsSlot
anchors.horizontalCenter: parent.horizontalCenter
spacing: 12
Component.onCompleted: {
if (navBarContentHeight > statusAppNavBar.height) {
anchors.top = undefined
anchors.topMargin = 0
anchors.bottom = navBarProfileButtonSlot.top
anchors.bottomMargin = 32
} else {
anchors.bottom = undefined
anchors.bottomMargin = 0
anchors.top = separator.visible ? separator.bottom : parent.top
anchors.topMargin = separator.visible ? 16 : navBarChatButtonSlot.anchors.topMargin
}
}
model: navBarModel
}
Item {
id: navBarProfileButtonSlot
anchors.horizontalCenter: parent.horizontalCenter
height: visible ? statusAppNavBar.navBarProfileButton.height : 0
width: visible ? statusAppNavBar.navBarProfileButton.width : 0
height: visible? statusAppNavBar.navBarProfileButton.height : 0
width: visible? statusAppNavBar.navBarProfileButton.width : 0
visible: !!statusAppNavBar.navBarProfileButton
anchors.bottom: parent.bottom
anchors.bottomMargin: visible ? 23 : 0
anchors.bottomMargin: visible ? 32 : 0
}
}
+183 -2
View File
@@ -5,19 +5,186 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import "statusModal" as Spares
/*!
\qmltype StatusModal
\inherits Popup
\inqmlmodule StatusQ.Popups
\since StatusQ.Popups 0.1
\brief The StatusModal provides a template for creating Modals.
Example of how to use it:
\qml
StatusModal {
anchors.centerIn: parent
header.title: "Some Title"
header.subTitle: "Subtitle"
headerActionButton: StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
width: 32
height: 32
icon.width: 20
icon.height: 20
icon.name: "info"
}
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
]
rightButtons: [
StatusButton {
text: "Button"
},
StatusButton {
text: "Button"
}
]
}
\endqml
For a list of components available see StatusQ.
*/
QC.Popup {
id: statusModal
/*!
\qmlproperty advancedHeader
This property represents the item loaded in header loader.
Can be used to read values from the component assigned to the loader.
\endqml
*/
property alias advancedHeader: advancedHeader.item
/*!
\qmlproperty advancedHeader
This property represents the item loaded in footer loader.
Can be used to read values from the component assigned to the loader.
\endqml
*/
property alias advancedFooter: advancedFooter.item
/*!
\qmlproperty advancedHeader
This property can be used to assign a Component to the advanced loader.
This was introduced to give more control to user on the Modal Header
example usage below
\qml
StatusModal {
id: advancedHeaderFooterModal
anchors.centerIn: parent
showHeader: false
showAdvancedHeader: true
advancedHeaderComponent: Rectangle {
width: parent.width
height: 50
color: Theme.palette.baseColor1
border.width: 1
StatusBaseText {
anchors.centerIn: parent
text: "Add any header here"
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
\endqml
*/
property alias advancedHeaderComponent: advancedHeader.sourceComponent
/*!
\qmlproperty advancedHeader
This property can be used to assign a Component to the advanced loader.
This was introduced to give more control to user on the Modal Footer.
example usage below
\qml
StatusModal {
id: advancedHeaderFooterModal
anchors.centerIn: parent
showFooter: false
showAdvancedFooter: true
advancedFooterComponent: Rectangle {
width: parent.width
height: 50
color: Theme.palette.baseColor1
border.width: 1
StatusBaseText {
anchors.centerIn: parent
text: "Add any footer here"
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
\endqml
*/
property alias advancedFooterComponent: advancedFooter.sourceComponent
/*!
\qmlproperty headerActionButton
This property lets the user add a button to the header of the Modal.
This does not apply to the advanced header!
\endqml
*/
property alias headerActionButton: headerImpl.actionButton
property StatusModalHeaderSettings header: StatusModalHeaderSettings {}
/*!
\qmlproperty header
type: StatusModalHeaderSettings
This property exposes the different properties of the standard header.
\endqml
*/
property StatusModalHeaderSettings header: StatusModalHeaderSettings {}
/*!
\qmlproperty rightButtons
This property helps user assign the right buttons on the footer.
This doesn't not apply to the advanced footer!
\endqml
*/
property alias rightButtons: footerImpl.rightButtons
/*!
\qmlproperty rightButtons
This property helps user assign the left buttons on the footer.
This doesn't not apply to the advanced footer!
\endqml
*/
property alias leftButtons: footerImpl.leftButtons
/*!
\qmlproperty showHeader
This property to decides whether the standard header is shown.
default value is true
\endqml
*/
property bool showHeader: true
/*!
\qmlproperty showHeader
This property to decides whether the standard footer is shown.
default value is true
\endqml
*/
property bool showFooter: true
/*!
\qmlproperty showAdvancedHeader
This property to decides whether the advanced header is shown.
default value is false.
\endqml
*/
property bool showAdvancedHeader: false
/*!
\qmlproperty showAdvancedFooter
This property decides whether the advanced footer is shown.
default value is false.
\endqml
*/
property bool showAdvancedFooter: false
/*!
\qmlproperty hasCloseButton
This property decides whether the standard header has a close button.s
\endqml
*/
property alias hasCloseButton: headerImpl.hasCloseButton
signal editButtonClicked()
@@ -64,11 +231,25 @@ QC.Popup {
onClose: statusModal.close()
}
Loader {
id: advancedHeader
anchors.top: parent.top
width: visible ? parent.width : 0
active: showAdvancedHeader
}
Spares.StatusModalFooter {
id: footerImpl
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
showFooter: statusModal.showFooter
}
Loader {
id: advancedFooter
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
active: showAdvancedFooter
}
}
}
-2
View File
@@ -21,8 +21,6 @@ Menu {
property var closeHandler
dim: true
Overlay.modeless: MouseArea {}
signal menuItemClicked(int menuIndex)
@@ -10,6 +10,7 @@ StatusPopupMenu {
property var searchPopup
property var locationModel
readonly property int numDefaultItems: 2
signal itemClicked(string firstLevelItemValue, string secondLevelItemValue)
@@ -43,7 +44,7 @@ StatusPopupMenu {
color: model.iconColor,
isLetterIdenticon: !model.imageSource && !model.iconName
});
root.insertMenu(index+2, item);
root.insertMenu(index + numDefaultItems, item);
} else {
item.value = model.value
item.text = model.title;
@@ -52,7 +53,7 @@ StatusPopupMenu {
item.iconSettings.isLetterIdenticon = !model.imageSource && !model.iconName
item.image.source = model.imageSource;
item.image.isIdenticon = model.isIdenticon;
root.insertItem(index+2, item);
root.insertItem(index + numDefaultItems, item);
}
}
}
+15 -4
View File
@@ -20,10 +20,13 @@ StatusModal {
property string searchText: contentItem.searchText
property string noResultsLabel: "No results"
property string defaultSearchLocationText: "Anywhere"
property bool loading
property bool loading: false
property Menu searchOptionsPopupMenu: Menu { }
property var searchResults: [ ]
property var searchSelectionButton
// This function is called to know if the popup accepts clicks in the title
// If it does not, the clicks on the titles mousearea will be propagated to the main body instead
property var acceptsTitleClick: function(titleId) {return true}
signal resultItemClicked(string itemId)
signal resultItemTitleClicked(string titleId)
@@ -52,7 +55,7 @@ StatusModal {
}
function forceActiveFocus() {
contentItem.searchInput.forceActiveFocus()
contentItem.searchInput.edit.forceActiveFocus()
}
onOpened: {
@@ -82,7 +85,8 @@ StatusModal {
icon: "search"
color: Theme.palette.baseColor1
}
TextEdit {
StatusBaseInput {
id: inputText
anchors.left: statusIcon.right
anchors.leftMargin: 15
@@ -91,6 +95,10 @@ StatusModal {
anchors.verticalCenter: parent.verticalCenter
focus: true
font.pixelSize: 28
topPadding: 5 //smaller padding to handle bigger font
bottomPadding: 5
clearable: true
showBackground: false
font.family: Theme.palette.baseFont.name
color: Theme.palette.directColor1
Keys.onPressed: {
@@ -275,8 +283,11 @@ StatusModal {
root.resultItemClicked(itemId)
}
propagateTitleClicks: !root.acceptsTitleClick(titleId)
onTitleClicked: {
root.resultItemTitleClicked(titleId)
if (root.acceptsTitleClick(titleId)) {
root.resultItemTitleClicked(titleId)
}
}
}
section.property: "sectionName"
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="12" height="10" viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.0203 1.35355C5.21556 1.15829 5.21556 0.841709 5.0203 0.646447C4.82504 0.451184 4.50846 0.451184 4.31319 0.646447L0.313195 4.64645C0.117933 4.84171 0.117933 5.15829 0.313195 5.35355L4.31319 9.35355C4.50846 9.54882 4.82504 9.54882 5.0203 9.35355C5.21556 9.15829 5.21556 8.84171 5.0203 8.64645L2.44289 6.06904C2.2329 5.85905 2.38162 5.5 2.67859 5.5H11.3334C11.6096 5.5 11.8334 5.27614 11.8334 5C11.8334 4.72386 11.6096 4.5 11.3334 4.5H2.67859C2.38162 4.5 2.2329 4.14095 2.44289 3.93096L5.0203 1.35355Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 632 B

+3
View File
@@ -0,0 +1,3 @@
<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="M16.187 3.24584C17.4482 1.98472 19.4928 1.98472 20.754 3.24585C22.0151 4.50697 22.0151 6.55165 20.754 7.81277L9.00225 19.5645C8.57507 19.9917 8.04607 20.3029 7.46519 20.4689L3.25755 21.6711C2.99519 21.746 2.71282 21.6729 2.51988 21.4799C2.32694 21.287 2.25377 21.0046 2.32873 20.7423L3.53092 16.5346C3.69688 15.9537 4.00815 15.4247 4.43533 14.9975L16.187 3.24584ZM19.6914 4.30837C19.0171 3.63407 17.9239 3.63407 17.2496 4.30837L5.49785 16.0601C5.25124 16.3067 5.07155 16.6121 4.97574 16.9474C4.61369 18.2146 5.78522 19.3861 7.05238 19.0241C7.38772 18.9283 7.69311 18.7486 7.93972 18.5019L19.6914 6.75024C20.3657 6.07594 20.3657 4.98268 19.6914 4.30837Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 820 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.8536 1.1484C16.6583 1.34366 16.3417 1.34366 16.1464 1.1484L15.3536 0.355507C15.1583 0.160245 14.8417 0.160244 14.6464 0.355506L13.8536 1.1484C13.6583 1.34366 13.3417 1.34366 13.1464 1.1484L12.3536 0.355507C12.1583 0.160245 11.8417 0.160244 11.6464 0.355506L10.8536 1.1484C10.6583 1.34366 10.3417 1.34366 10.1464 1.1484L9.35355 0.355507C9.15829 0.160245 8.84171 0.160244 8.64645 0.355506L7.85355 1.1484C7.65829 1.34366 7.34171 1.34366 7.14645 1.1484L6.35355 0.355507C6.15829 0.160245 5.84171 0.160244 5.64645 0.355506L4.85355 1.1484C4.65829 1.34366 4.34171 1.34366 4.14645 1.1484L3.35355 0.355507C3.15829 0.160245 2.84171 0.160244 2.64645 0.355506L1.85355 1.1484C1.65829 1.34366 1.34171 1.34366 1.14645 1.1484L0.853554 0.855507C0.538571 0.540525 0 0.763608 0 1.20906V18.7948C0 19.2403 0.538571 19.4634 0.853553 19.1484L1.14645 18.8555C1.34171 18.6602 1.65829 18.6602 1.85355 18.8555L2.64645 19.6484C2.84171 19.8437 3.15829 19.8437 3.35355 19.6484L4.14645 18.8555C4.34171 18.6602 4.65829 18.6602 4.85355 18.8555L5.64645 19.6484C5.84171 19.8437 6.15829 19.8437 6.35355 19.6484L7.14645 18.8555C7.34171 18.6602 7.65829 18.6602 7.85355 18.8555L8.64645 19.6484C8.84171 19.8437 9.15829 19.8437 9.35355 19.6484L10.1464 18.8555C10.3417 18.6602 10.6583 18.6602 10.8536 18.8555L11.6464 19.6484C11.8417 19.8437 12.1583 19.8437 12.3536 19.6484L13.1464 18.8555C13.3417 18.6602 13.6583 18.6602 13.8536 18.8555L14.6464 19.6484C14.8417 19.8437 15.1583 19.8437 15.3536 19.6484L16.1464 18.8555C16.3417 18.6602 16.6583 18.6602 16.8536 18.8555L17.1464 19.1484C17.4614 19.4634 18 19.2403 18 18.7948V1.20906C18 0.763608 17.4614 0.540524 17.1464 0.855507L16.8536 1.1484ZM16 16.592C16 16.8681 15.7761 17.092 15.5 17.092H2.5C2.22386 17.092 2 16.8681 2 16.592V3.41195C2 3.13581 2.22386 2.91195 2.5 2.91195H15.5C15.7761 2.91195 16 3.13581 16 3.41195V16.592ZM3 13.502C3 13.2258 3.22386 13.002 3.5 13.002H14.5C14.7761 13.002 15 13.2258 15 13.502V14.502C15 14.7781 14.7761 15.002 14.5 15.002H3.5C3.22386 15.002 3 14.7781 3 14.502V13.502ZM3 9.50195C3 9.22581 3.22386 9.00195 3.5 9.00195H14.5C14.7761 9.00195 15 9.22581 15 9.50195V10.502C15 10.7781 14.7761 11.002 14.5 11.002H3.5C3.22386 11.002 3 10.7781 3 10.502V9.50195ZM3 5.50195C3 5.22581 3.22386 5.00195 3.5 5.00195H14.5C14.7761 5.00195 15 5.22581 15 5.50195V6.50195C15 6.7781 14.7761 7.00195 14.5 7.00195H3.5C3.22386 7.00195 3 6.7781 3 6.50195V5.50195Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

Some files were not shown because too many files have changed in this diff Show More