Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bdc330c3f | ||
|
|
485647d1c3 | ||
|
|
e1db639340 | ||
|
|
b918897241 | ||
|
|
6ba2d8f3e6 | ||
|
|
c01f623305 | ||
|
|
6dc6ebb2fb | ||
|
|
2d031244ca | ||
|
|
9498be05ef | ||
|
|
1b25ddd2b5 | ||
|
|
9741f98b70 | ||
|
|
02923f7947 | ||
|
|
6c5957a492 | ||
|
|
eb96e5e08d | ||
|
|
457e5fe4af | ||
|
|
1c0d4b0133 | ||
|
|
ba79f62fda | ||
|
|
a9c79b0359 | ||
|
|
a668afef35 | ||
|
|
deb8b38b1f | ||
|
|
b4ebc520e1 | ||
|
|
5def2102c7 | ||
|
|
0f511ebc60 | ||
|
|
b09210cf1f | ||
|
|
3bdfc3e528 | ||
|
|
baf5948c90 | ||
|
|
4b1516c990 | ||
|
|
1a5990f24b | ||
|
|
82e1845056 | ||
|
|
75a76afcf1 | ||
|
|
0922cf507a | ||
|
|
32c5f7f8df | ||
|
|
148505ba6b | ||
|
|
d960c6dcec | ||
|
|
bb9f08155f | ||
|
|
934db52126 | ||
|
|
dcef08f3b3 | ||
|
|
20e7b345e1 | ||
|
|
5f8453659d | ||
|
|
c7ff011649 | ||
|
|
2b71ccf50f | ||
|
|
310be728a3 | ||
|
|
e2728285e1 | ||
|
|
1d9abf8e95 | ||
|
|
31e90c2d47 | ||
|
|
ae1e72fb23 | ||
|
|
7710470559 | ||
|
|
2069399979 | ||
|
|
29dd4da2e4 | ||
|
|
394040a039 | ||
|
|
a8e1ed863c | ||
|
|
d7b1ae9fbc | ||
|
|
f0c7d950ea | ||
|
|
1e5d389b53 | ||
|
|
1cda85fc0e | ||
|
|
4999368dfe | ||
|
|
7e4d69be05 | ||
|
|
3abbd3d4cd | ||
|
|
8fc5276090 | ||
|
|
cf4b092112 | ||
|
|
ddf4a8d4f1 | ||
|
|
9c1edc80db | ||
|
|
20bf5b07a6 | ||
|
|
ade6bd2d0d | ||
|
|
125760b934 | ||
|
|
e231c0a6cb | ||
|
|
a16bc6bb6e | ||
|
|
51989c0f5d | ||
|
|
88b7f6eab8 | ||
|
|
2df3c0a03e | ||
|
|
1e9cc07e2d | ||
|
|
6221c0a540 | ||
|
|
ddbffa7f28 | ||
|
|
555ad8bea8 | ||
|
|
a561a3fff8 | ||
|
|
70ec009edd | ||
|
|
31a1c60eb1 | ||
|
|
0a2cf6ab6e | ||
|
|
07fa2a1b0c | ||
|
|
43b8e43303 | ||
|
|
2cec51ff8d | ||
|
|
684f45cc08 | ||
|
|
eae4e0f405 | ||
|
|
b2ac2794bb | ||
|
|
b565a32c7e | ||
|
|
a1835164d9 | ||
|
|
06e931d749 | ||
|
|
b9aa49853a | ||
|
|
03eb6302d5 | ||
|
|
5f8f798cf2 | ||
|
|
bbc0177a66 | ||
|
|
6ce9f9bd86 | ||
|
|
46254f79c4 | ||
|
|
ad659a5dc2 | ||
|
|
41f67b59e9 | ||
|
|
aa91a88be7 | ||
|
|
f299c9df3a | ||
|
|
b6c3231e30 | ||
|
|
496ad05247 | ||
|
|
93f9214aad | ||
|
|
22bbf9b177 | ||
|
|
7301323ed7 | ||
|
|
c6e4cf627c | ||
|
|
5c1c9852ae | ||
|
|
be2b2c3df7 | ||
|
|
1362a94448 | ||
|
|
189f66225c | ||
|
|
40d8b9c2f6 | ||
|
|
8af7028efc | ||
|
|
f1eff6700a | ||
|
|
082bb8ef45 | ||
|
|
7609450068 | ||
|
|
6570275176 | ||
|
|
4b579cddbe | ||
|
|
a84026d74d | ||
|
|
428b165198 | ||
|
|
56b2663e4d | ||
|
|
9dbb7ec53f | ||
|
|
7e9c7a52fd | ||
|
|
2e33fb9f81 | ||
|
|
208825807b | ||
|
|
381150a7b5 | ||
|
|
5fac8774f4 | ||
|
|
e9f20be15a | ||
|
|
9d06aae1f4 | ||
|
|
f574e39012 | ||
|
|
8495fae8a5 | ||
|
|
07a5dc09ac | ||
|
|
9e6fbe955a | ||
|
|
1217771fd0 | ||
|
|
3b86d13a96 | ||
|
|
c0f825c690 | ||
|
|
825999b151 | ||
|
|
cdf51fefbd | ||
|
|
665141f81d | ||
|
|
9cbd19d658 | ||
|
|
0e00fd24ab |
@@ -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)
|
||||
@@ -13,3 +13,7 @@ Makefile
|
||||
*_qml.cpp
|
||||
*_qmlcache.qrc
|
||||
sandbox/qmlcache_loader.cpp
|
||||
doc/html
|
||||
CMakeLists.txt.user
|
||||
.vscode
|
||||
build/
|
||||
|
||||
@@ -1,3 +1,43 @@
|
||||
<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)
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
project(StatusQ)
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 49 KiB |
@@ -22,6 +22,7 @@
|
||||
\li \l{StatusDescriptionListItem}
|
||||
\li \l{StatusLetterIdenticon}
|
||||
\li \l{StatusListItem}
|
||||
\li \l{StatusListPicker}
|
||||
\li \l{StatusListSectionHeadline}
|
||||
\li \l{StatusLoadingIndicator}
|
||||
\li \l{StatusMemberListItem}
|
||||
@@ -37,5 +38,6 @@
|
||||
\li \l{StatusMessageDetails}
|
||||
\li \l{StatusTagSelector}
|
||||
\li \l{StatusToastMessage}
|
||||
\li \l{StatusWizardStepper}
|
||||
\endlist
|
||||
*/
|
||||
@@ -30,8 +30,11 @@
|
||||
\li \l{StatusSlider}
|
||||
\li \l{StatusSelect}
|
||||
\li \l{StatusBaseInput}
|
||||
\li \l{StatusIdenticonRing}
|
||||
\li \l{StatusInput}
|
||||
\li \l{StatusItemPicker}
|
||||
\li \l{StatusPickerButton}
|
||||
\li \l{StatusPinInput}
|
||||
\li \l{StatusProgressBar}
|
||||
\li \l{StatusPasswordStrengthIndicator}
|
||||
\li \l{StatusSwitchTabButton}
|
||||
@@ -39,5 +42,8 @@
|
||||
\li \l{StatusSelectableText}
|
||||
\li \l{StatusWalletColorButton}
|
||||
\li \l{StatusWalletColorSelect}
|
||||
\li \l{StatusRegularExpressionValidator}
|
||||
\li \l{StatusIntValidator}
|
||||
\li \l{StatusSeedPhraseInput}
|
||||
\endlist
|
||||
*/
|
||||
@@ -15,6 +15,7 @@
|
||||
\li \l{StatusIcon}
|
||||
\li \l{StatusIconBackgroundSettings}
|
||||
\li \l{StatusIconSettings}
|
||||
\li \l{StatusIdenticonRingSettings}
|
||||
\li \l{StatusImageSettings}
|
||||
\li \l{StatusModalHeaderSettings}
|
||||
\li \l{StatusTooltipSettings}
|
||||
@@ -5,16 +5,16 @@ 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
|
||||
-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 \
|
||||
$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"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- StatusBaseText.qml -->
|
||||
<title>List of All Members for StatusBaseText | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">List of All Members for StatusBaseText</h1>
|
||||
<p>This is the complete list of members for <a href="qml-statusq-core-statusbasetext.html">StatusBaseText</a>, including inherited members.</p>
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,41 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- StatusBaseText.qml -->
|
||||
<title>StatusBaseText QML Type | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<div class="sidebar">
|
||||
<div class="toc">
|
||||
<h3><a name="toc">Contents</a></h3>
|
||||
<ul>
|
||||
<li class="level1"><a href="#details">Detailed Description</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusBaseText QML Type</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusBaseText-brief -->
|
||||
<p>Displays multiple lines of text. Inherits <a href="https://doc.qt.io/qt-5/qml-qtquick-text.html">Text</a>. <a href="#details">More...</a></p>
|
||||
<!-- @@@StatusBaseText -->
|
||||
<div class="table"><table class="alignedsummary">
|
||||
<tr><td class="memItemLeft rightAlign topAlign"> Import Statement:</td><td class="memItemRight bottomAlign"> import StatusQ.Core 0.1</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Since:</td><td class="memItemRight bottomAlign"> StatusQ.Core 0.1</td></tr></table></div><ul>
|
||||
<li><a href="qml-statusq-core-statusbasetext-members.html">List of all members, including inherited members</a></li>
|
||||
</ul>
|
||||
<!-- $$$StatusBaseText-description -->
|
||||
<a name="details"></a>
|
||||
<h2 id="details">Detailed Description</h2>
|
||||
<p>The <code>StatusBaseText</code> item displays text. For example:</p>
|
||||
<pre class="qml"><span class="type"><a href="qml-statusq-core-statusbasetext.html">StatusBaseText</a></span> {
|
||||
<span class="name">width</span>: <span class="number">240</span>
|
||||
<span class="name">text</span>: <span class="string">"Hello World!"</span>
|
||||
<span class="name">font</span>.pixelSize: <span class="number">24</span>
|
||||
<span class="name">color</span>: <span class="name">Theme</span>.<span class="name">pallete</span>.<span class="name">directColor1</span>
|
||||
}</pre>
|
||||
<p class="centerAlign"><img src="images/status_base_text.png" alt="" /></p><p>For a list of components available see <a href="statusq-index.html">StatusQ</a>.</p>
|
||||
<!-- @@@StatusBaseText -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,53 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusqcomponents.qdoc -->
|
||||
<title>StatusQ Components | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<li>StatusQ Components</li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ Components</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusQ.Components-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p>This is a listing of all Components components.</p>
|
||||
<p>This module is part of the <a href="statusq-index.html">StatusQ</a> project.</p>
|
||||
<ul>
|
||||
<li>StatusAddress</li>
|
||||
<li>StatusBadge</li>
|
||||
<li>StatusChatInfoToolBar</li>
|
||||
<li>StatusChatList</li>
|
||||
<li>StatusChatListItem</li>
|
||||
<li>StatusImageSettings</li>
|
||||
<li>StatusChatListCategory</li>
|
||||
<li>StatusChatListCategoryItem</li>
|
||||
<li>StatusChatListAndCategories</li>
|
||||
<li>StatusChatToolBar</li>
|
||||
<li>StatusContactRequestsIndicatorListItem</li>
|
||||
<li>StatusDescriptionListItem</li>
|
||||
<li>StatusLetterIdenticon</li>
|
||||
<li>StatusListItem</li>
|
||||
<li>StatusListSectionHeadline</li>
|
||||
<li>StatusLoadingIndicator</li>
|
||||
<li>StatusMemberListItem</li>
|
||||
<li>StatusNavigationListItem</li>
|
||||
<li>StatusNavigationPanelHeadline</li>
|
||||
<li>StatusRoundIcon</li>
|
||||
<li>StatusRoundedImage</li>
|
||||
<li>StatusMacWindowButtons</li>
|
||||
<li>StatusListItemBadge</li>
|
||||
<li>StatusExpandableItem</li>
|
||||
<li>StatusSmartIdenticon</li>
|
||||
<li>StatusMessage</li>
|
||||
<li>StatusMessageDetails</li>
|
||||
<li>StatusTagSelector</li>
|
||||
<li>StatusToastMessage</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@StatusQ.Components -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,55 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusqcontrols.qdoc -->
|
||||
<title>StatusQ Controls | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<li>StatusQ Controls</li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ Controls</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusQ.Controls-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p>This is a listing of all Controls components.</p>
|
||||
<p>This module is part of the <a href="statusq-index.html">StatusQ</a> project.</p>
|
||||
<ul>
|
||||
<li>StatusAccountSelector</li>
|
||||
<li>StatusAssetSelector</li>
|
||||
<li>StatusBanner</li>
|
||||
<li>StatusChatCommandButton</li>
|
||||
<li>StatusChatInfoButton</li>
|
||||
<li>StatusChatListCategoryItemButton</li>
|
||||
<li>StatusColorSelector</li>
|
||||
<li>StatusIconTabButton</li>
|
||||
<li>StatusNavBarTabButton</li>
|
||||
<li>StatusTabBarIconButton</li>
|
||||
<li>StatusToolTip</li>
|
||||
<li>StatusBaseButton</li>
|
||||
<li>StatusButton</li>
|
||||
<li>StatusFlatButton</li>
|
||||
<li>StatusRoundButton</li>
|
||||
<li>StatusFlatRoundButton</li>
|
||||
<li>StatusSwitch</li>
|
||||
<li>StatusRadioButton</li>
|
||||
<li>StatusCheckBox</li>
|
||||
<li>StatusSlider</li>
|
||||
<li>StatusSelect</li>
|
||||
<li>StatusBaseInput</li>
|
||||
<li>StatusInput</li>
|
||||
<li>StatusPickerButton</li>
|
||||
<li>StatusProgressBar</li>
|
||||
<li>StatusPasswordStrengthIndicator</li>
|
||||
<li>StatusSwitchTabButton</li>
|
||||
<li>StatusSwitchTabBar</li>
|
||||
<li>StatusSelectableText</li>
|
||||
<li>StatusWalletColorButton</li>
|
||||
<li>StatusWalletColorSelect</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@StatusQ.Controls -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusqcore.qdoc -->
|
||||
<title>StatusQ Core | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<li>StatusQ Core</li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ Core</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusQ.Core-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p>This is a listing of all Core components. These files are available for general import and they are based off the <a href="https://doc.qt.io/qt-5/qtquick-qmlmodule.html">Qt Quick Primitives</a> and <a href="https://doc.qt.io/archives/qt-5.11/qtquick-controls2-qmlmodule.html">Qt Quick Controls 2</a>.</p>
|
||||
<p>This module is part of the <a href="statusq-index.html">StatusQ</a> project.</p>
|
||||
<ul>
|
||||
<li>StatusAppNavBarFilterModel</li>
|
||||
<li><a href="qml-statusq-core-statusbasetext.html">StatusBaseText</a></li>
|
||||
<li>StatusIcon</li>
|
||||
<li>StatusIconBackgroundSettings</li>
|
||||
<li>StatusIconSettings</li>
|
||||
<li>StatusImageSettings</li>
|
||||
<li>StatusModalHeaderSettings</li>
|
||||
<li>StatusTooltipSettings</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@StatusQ.Core -->
|
||||
<div class="table"><table class="annotated">
|
||||
<tr class="odd topAlign"><td class="tblName"><p><a href="qml-statusq-core-statusbasetext.html">StatusBaseText</a></p></td><td class="tblDescr"><p>Displays multiple lines of text. Inherits Text</p></td></tr>
|
||||
</table></div>
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusq-overview.qdoc -->
|
||||
<title>StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$statusq-index.html-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p><a href="statusq-index.html">StatusQ</a> provides a collection of components....</p>
|
||||
<p><a href="statusq-index.html">StatusQ</a> - Components and Interfaces</p>
|
||||
<ul>
|
||||
<li><a href="statusq-components-qmlmodule.html">Components</a></li>
|
||||
<li><a href="statusq-controls-qmlmodule.html">Controls</a></li>
|
||||
<li><a href="statusq-core-qmlmodule.html">Core</a></li>
|
||||
<li><a href="statusq-layout-qmlmodule.html">Layout</a></li>
|
||||
<li><a href="statusq-platform-qmlmodule.html">Platform</a></li>
|
||||
<li><a href="statusq-popups-qmlmodule.html">Popups</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@statusq-index.html -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusqlayout.qdoc -->
|
||||
<title>StatusQ Layout | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<li>StatusQ Layout</li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ Layout</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusQ.Layout-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p>This is a listing of all Layout components.</p>
|
||||
<p>This module is part of the <a href="statusq-index.html">StatusQ</a> project.</p>
|
||||
<ul>
|
||||
<li>StatusAppLayout</li>
|
||||
<li>StatusAppNavBar</li>
|
||||
<li>StatusAppTwoPanelLayout</li>
|
||||
<li>StatusAppThreePanelLayout</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@StatusQ.Layout -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,27 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusqplatform.qdoc -->
|
||||
<title>StatusQ Platform | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<li>StatusQ Platform</li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ Platform</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusQ.Platform-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p>This is a listing of all Platform components.</p>
|
||||
<p>This module is part of the <a href="statusq-index.html">StatusQ</a> project.</p>
|
||||
<ul>
|
||||
<li>StatusMacTrafficLights</li>
|
||||
<li>StatusMacNotification</li>
|
||||
<li>StatusWindowsTitleBar</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@StatusQ.Platform -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- statusqpopups.qdoc -->
|
||||
<title>StatusQ Popups | StatusQ 0.1</title>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p class="header"><small>StatusQ - A Components selection for Status dekstop client. </p></small></p><hr/><li><a href="statusq-index.html">StatusQ</a></li>
|
||||
<li>StatusQ Popups</li>
|
||||
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
|
||||
<h1 class="title">StatusQ Popups</h1>
|
||||
<span class="subtitle"></span>
|
||||
<!-- $$$StatusQ.Popups-description -->
|
||||
<div class="descr"> <a name="details"></a>
|
||||
<p>This is a listing of all Popups components.</p>
|
||||
<p>This module is part of the <a href="statusq-index.html">StatusQ</a> project.</p>
|
||||
<ul>
|
||||
<li>StatusMenuSeparator</li>
|
||||
<li>StatusPopupMenu</li>
|
||||
<li>StatusMenuItem</li>
|
||||
<li>StatusMenuItemDelegate</li>
|
||||
<li>StatusModal</li>
|
||||
<li>StatusSearchPopup</li>
|
||||
<li>StatusModalDivider</li>
|
||||
<li>StatusSearchPopupMenuItem</li>
|
||||
<li>StatusSearchLocationMenu</li>
|
||||
<li>StatusSpellcheckingMenuItems</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- @@@StatusQ.Popups -->
|
||||
<hr/><div class="footer"><p><acronym title="Copyright">©</acronym> 2022 Status. All rights reserved. <a href="https://status.im" target="_blank"><small>status.im</a></small></p></div></body>
|
||||
</html>
|
||||
@@ -7,6 +7,8 @@ Item {
|
||||
id: themeSwitchWrapper
|
||||
signal checkedChanged()
|
||||
|
||||
property alias lightThemeEnabled: switchControl.checked
|
||||
|
||||
width: themeSwitch.width
|
||||
height: themeSwitch.height
|
||||
|
||||
@@ -26,6 +28,7 @@ Item {
|
||||
}
|
||||
|
||||
StatusSwitch {
|
||||
id: switchControl
|
||||
onCheckedChanged: themeSwitchWrapper.checkedChanged()
|
||||
|
||||
StatusToolTip {
|
||||
|
||||
@@ -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
|
||||
@@ -25,7 +26,7 @@ GridLayout {
|
||||
badge.value: 1
|
||||
}
|
||||
StatusNavigationListItem {
|
||||
title: "Menu Item (selected)"
|
||||
title: "Menu Item (selected) with very long text"
|
||||
selected: true
|
||||
icon.name: "info"
|
||||
badge.value: 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"
|
||||
@@ -322,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"
|
||||
@@ -351,24 +395,41 @@ 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 {
|
||||
nickName: "very-long-annoying-nickname.eth"
|
||||
isOnline: false
|
||||
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
|
||||
}
|
||||
|
||||
StatusMemberListItem {
|
||||
nickName: "This girl I know from work"
|
||||
userName: "annabelle"
|
||||
isOnline: true
|
||||
isOnline: true
|
||||
}
|
||||
|
||||
StatusMemberListItem {
|
||||
|
||||
@@ -4,38 +4,58 @@ import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
GridLayout {
|
||||
columns: 6
|
||||
columnSpacing: 5
|
||||
rowSpacing: 5
|
||||
ColumnLayout {
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
StatusLoadingIndicator {
|
||||
color: Theme.palette.directColor4
|
||||
columns: 6
|
||||
columnSpacing: 5
|
||||
rowSpacing: 5
|
||||
|
||||
StatusLoadingIndicator {
|
||||
color: Theme.palette.directColor4
|
||||
}
|
||||
|
||||
StatusLetterIdenticon {
|
||||
name: "#status"
|
||||
}
|
||||
|
||||
StatusRoundedImage {
|
||||
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
|
||||
}
|
||||
|
||||
StatusBadge {}
|
||||
|
||||
StatusBadge {
|
||||
value: 1
|
||||
}
|
||||
|
||||
StatusBadge {
|
||||
value: 10
|
||||
}
|
||||
|
||||
StatusBadge {
|
||||
value: 100
|
||||
}
|
||||
|
||||
StatusRoundIcon {
|
||||
icon.name: "info"
|
||||
}
|
||||
}
|
||||
|
||||
StatusLetterIdenticon {
|
||||
name: "#status"
|
||||
}
|
||||
Flow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 4
|
||||
|
||||
StatusRoundedImage {
|
||||
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
|
||||
}
|
||||
|
||||
StatusBadge {}
|
||||
|
||||
StatusBadge {
|
||||
value: 1
|
||||
}
|
||||
|
||||
StatusBadge {
|
||||
value: 10
|
||||
}
|
||||
|
||||
StatusBadge {
|
||||
value: 100
|
||||
}
|
||||
|
||||
StatusRoundIcon {
|
||||
icon.name: "info"
|
||||
Repeater {
|
||||
model: 12
|
||||
StatusLetterIdenticon {
|
||||
name: "A"
|
||||
color: Theme.palette.userCustomizationColors[index]
|
||||
letterSize: 16
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -41,7 +41,8 @@ ListView {
|
||||
}
|
||||
messageText: model.message
|
||||
hasMention: model.hasMention
|
||||
contactType: model.contactType
|
||||
isMutualContact: model.isMutualContact
|
||||
trustIndicator: model.trustIndicator
|
||||
isPinned: model.isPinned
|
||||
pinnedBy: model.pinnedBy
|
||||
hasExpired: model.hasExpired
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQml.Models 2.2
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
@@ -28,33 +26,50 @@ Page {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.leftMargin: 17
|
||||
implicitHeight: 44
|
||||
maxHeight: root.height
|
||||
toLabelText: qsTr("To: ")
|
||||
warningText: qsTr("5 USER LIMIT REACHED")
|
||||
//simulate model filtering, TODO this
|
||||
//makes more sense to be provided by the backend
|
||||
//figure how real implementation should look like
|
||||
property ListModel sortedList: ListModel { }
|
||||
onTextChanged: {
|
||||
sortedList.clear();
|
||||
if (text !== "") {
|
||||
for (var i = 0; i < contactsModel.count; i++ ) {
|
||||
var entry = contactsModel.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;
|
||||
warningText: qsTr("USER LIMIT REACHED")
|
||||
listLabel: qsTr("Contacts")
|
||||
ringSpecModelGetter: function(pubKey) {
|
||||
//for simulation purposes only, in real app
|
||||
//this would be Utils.getColorHashAsJson(pubKey)
|
||||
var index = -1;
|
||||
if (!!contactsModel) {
|
||||
for (var i = 0; i < contactsModel.count; i++) {
|
||||
if (contactsModel.get(i).publicId === pubKey) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return contactsModel.get(index).ringSpecModel;
|
||||
} else {
|
||||
userListView.model = contactsModel;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
compressedKeyGetter: function(pubKey) {
|
||||
//for simulation purposes only, in real app
|
||||
//this would be Utils.getCompressedPk(pubKey);
|
||||
var possibleCharacters = pubKey.split('');
|
||||
var randomStringLength = 12; // assuming you want random strings of 12 characters
|
||||
var randomString = [];
|
||||
for (var i=0; i<randomStringLength; ++i) {
|
||||
var index = (Math.random() * possibleCharacters.length).toFixed(0);
|
||||
var nextChar = possibleCharacters[index];
|
||||
randomString.push(nextChar);
|
||||
}
|
||||
return randomString.join().toString().replace(/,/g, '');
|
||||
}
|
||||
onTextChanged: {
|
||||
sortModel(root.contactsModel);
|
||||
}
|
||||
Component.onCompleted: {
|
||||
textEdit.forceActiveFocus();
|
||||
sortModel(root.contactsModel);
|
||||
}
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
implicitHeight: 44
|
||||
Layout.alignment: Qt.AlignTop
|
||||
enabled: (tagSelector.namesModel.count > 0)
|
||||
text: "Confirm"
|
||||
}
|
||||
@@ -62,155 +77,7 @@ Page {
|
||||
|
||||
contentItem: Item {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: headerRow.height + 16
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
visible: (contactsModel.count > 0)
|
||||
|
||||
StatusBaseText {
|
||||
id: contactsLabel
|
||||
font.pixelSize: 15
|
||||
color: Theme.palette.baseColor1
|
||||
text: "Contacts"
|
||||
}
|
||||
Control {
|
||||
width: 360
|
||||
anchors {
|
||||
top: contactsLabel.bottom
|
||||
topMargin: 8//Style.current.padding
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 20//Style.current.bigPadding
|
||||
}
|
||||
background: Rectangle {
|
||||
id: statusPopupMenuBackgroundContent
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: (userListView.height + 8)
|
||||
visible: (tagSelector.sortedList.count > 0)
|
||||
color: Theme.palette.statusPopupMenu.backgroundColor
|
||||
radius: 8
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
width: statusPopupMenuBackgroundContent.width
|
||||
height: statusPopupMenuBackgroundContent.height
|
||||
x: statusPopupMenuBackgroundContent.x
|
||||
visible: statusPopupMenuBackgroundContent.visible
|
||||
source: statusPopupMenuBackgroundContent
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 4
|
||||
radius: 12
|
||||
samples: 25
|
||||
spread: 0.2
|
||||
color: Theme.palette.dropShadow
|
||||
}
|
||||
}
|
||||
contentItem: ListView {
|
||||
id: userListView
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: (count * 64) > parent.height ? parent.height : (count * 64)
|
||||
clip: true
|
||||
model: contactsModel
|
||||
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.topMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
anchors.leftMargin: 8
|
||||
radius: 8
|
||||
visible: (tagSelector.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: 28
|
||||
height: 28
|
||||
letterSize: 15
|
||||
}
|
||||
image: StatusImageSettings {
|
||||
width: 28
|
||||
height: 28
|
||||
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
|
||||
}
|
||||
|
||||
StatusBadge {
|
||||
id: statusBadge
|
||||
width: 15
|
||||
height: 15
|
||||
anchors.left: contactImage.right
|
||||
anchors.leftMargin: -8
|
||||
anchors.bottom: contactImage.bottom
|
||||
border.width: 3
|
||||
border.color: Theme.palette.statusAppNavBar.backgroundColor
|
||||
color: {
|
||||
if (model.onlineStatus === 1)
|
||||
return Theme.palette.successColor1;
|
||||
else if (model.onlineStatus === 2)
|
||||
return Theme.palette.pinColor1;
|
||||
else if (model.onlineStatus === 3)
|
||||
return Theme.palette.dangerColor1;
|
||||
|
||||
return "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
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: {
|
||||
tagSelector.insertTag(model.name, model.publicId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
if (visible) {
|
||||
tagSelector.textEdit.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
anchors.topMargin: 68
|
||||
|
||||
StatusBaseText {
|
||||
visible: (contactsModel.count === 0)
|
||||
|
||||
@@ -27,21 +27,19 @@ StatusAppThreePanelLayout {
|
||||
|
||||
RowLayout {
|
||||
id: searchInputWrapper
|
||||
width: parent.width
|
||||
width: 288
|
||||
height: searchInput.height
|
||||
anchors.top: headline.bottom
|
||||
anchors.topMargin: 16
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StatusBaseInput {
|
||||
id: searchInput
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.leftMargin: 17
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
implicitHeight: 36
|
||||
topPadding: 8
|
||||
bottomPadding: 0
|
||||
bottomPadding: 8
|
||||
placeholderText: "Search"
|
||||
icon.name: "search"
|
||||
}
|
||||
@@ -61,7 +59,7 @@ StatusAppThreePanelLayout {
|
||||
Column {
|
||||
anchors.top: searchInputWrapper.bottom
|
||||
anchors.topMargin: 16
|
||||
width: parent.width
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 8
|
||||
|
||||
StatusContactRequestsIndicatorListItem {
|
||||
@@ -72,8 +70,8 @@ StatusAppThreePanelLayout {
|
||||
}
|
||||
|
||||
StatusChatList {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
model: Models.demoChatListItems
|
||||
highlightItem: !root.createChat
|
||||
onChatItemUnmuted: {
|
||||
for (var i = 0; i < Models.demoChatListItems.count; i++) {
|
||||
let item = Models.demoChatListItems.get(i);
|
||||
@@ -128,19 +126,18 @@ StatusAppThreePanelLayout {
|
||||
centerPanel: Loader {
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.createChat ? createChatView : chatChannelView
|
||||
}
|
||||
|
||||
Component {
|
||||
id: createChatView
|
||||
CreateChatView {
|
||||
contactsModel: Models.dummyContactsModel
|
||||
Component {
|
||||
id: createChatView
|
||||
CreateChatView {
|
||||
contactsModel: Models.membersListModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: chatChannelView
|
||||
ChatChannelView {
|
||||
model: Models.chatMessagesModel
|
||||
Component {
|
||||
id: chatChannelView
|
||||
ChatChannelView {
|
||||
model: Models.chatMessagesModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -259,13 +259,14 @@ StatusAppThreePanelLayout {
|
||||
delegate: StatusMemberListItem {
|
||||
implicitWidth: parent.width
|
||||
nickName: model.nickName
|
||||
userName: model.userName
|
||||
chatKey: model.chatKey
|
||||
userName: model.name
|
||||
chatKey: model.publicId
|
||||
trustIndicator: model.trustIndicator
|
||||
isMutualContact: model.isMutualContact
|
||||
image.source: model.source
|
||||
image.source: model.icon
|
||||
image.isIdenticon: model.isIdenticon
|
||||
isOnline: model.isOnline
|
||||
isOnline: model.onlineStatus
|
||||
ringSettings.ringSpecModel: model.ringSpecModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,65 +4,15 @@ import StatusQ.Components 0.1
|
||||
|
||||
QtObject {
|
||||
|
||||
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 {
|
||||
itemId: "x012340000"
|
||||
name: "#status"
|
||||
icon: ""
|
||||
emoji: ""
|
||||
isIdenticon: false
|
||||
colorHash: []
|
||||
color: "blue"
|
||||
description: ""
|
||||
type: StatusChatListItem.Type.PublicChat
|
||||
@@ -78,7 +28,9 @@ QtObject {
|
||||
itemId: "x012340001"
|
||||
name: "status-desktop"
|
||||
icon: ""
|
||||
emoji: ""
|
||||
isIdenticon: false
|
||||
colorHash: []
|
||||
color: "red"
|
||||
description: ""
|
||||
type: StatusChatListItem.Type.PublicChat
|
||||
@@ -95,7 +47,9 @@ QtObject {
|
||||
name: "Amazing Funny Squirrel"
|
||||
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
|
||||
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
|
||||
emoji: ""
|
||||
isIdenticon: true
|
||||
colorHash: []
|
||||
color: "green"
|
||||
description: ""
|
||||
type: StatusChatListItem.Type.OneToOneChat
|
||||
@@ -111,7 +65,9 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
itemId: "x012340003"
|
||||
name: "Black Ops"
|
||||
icon: ""
|
||||
emoji: ""
|
||||
isIdenticon: false
|
||||
colorHash: []
|
||||
color: "purple"
|
||||
description: ""
|
||||
type: StatusChatListItem.Type.OneToOneChat
|
||||
@@ -127,7 +83,9 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
itemId: "x012340004"
|
||||
name: "Spectacular Growing Otter"
|
||||
icon: ""
|
||||
emoji: ""
|
||||
isIdenticon: false
|
||||
colorHash: []
|
||||
color: "orange"
|
||||
description: ""
|
||||
type: StatusChatListItem.Type.OneToOneChat
|
||||
@@ -143,7 +101,9 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
itemId: "x012340005"
|
||||
name: "channel-with-a-super-duper-long-name"
|
||||
icon: ""
|
||||
emoji: ""
|
||||
isIdenticon: false
|
||||
colorHash: []
|
||||
color: "green"
|
||||
description: ""
|
||||
type: StatusChatListItem.Type.PublicChat
|
||||
@@ -397,7 +357,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: ""
|
||||
iconName: "chat"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
subItems: [
|
||||
ListElement {
|
||||
value: "sub_item_1_1"
|
||||
@@ -405,7 +364,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
|
||||
iconName: ""
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
},
|
||||
ListElement {
|
||||
value: "sub_item_1_2"
|
||||
@@ -413,7 +371,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
|
||||
iconName: ""
|
||||
iconColor: ""
|
||||
isIdenticon: true
|
||||
}]}
|
||||
ListElement {
|
||||
value: "item_2"
|
||||
@@ -421,7 +378,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
|
||||
iconName: ""
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
subItems: [
|
||||
ListElement {
|
||||
value: "sub_item_2_1"
|
||||
@@ -429,7 +385,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: ""
|
||||
iconName: "channel"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
},
|
||||
ListElement {
|
||||
value: "sub_item_2_2"
|
||||
@@ -437,7 +392,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: ""
|
||||
iconName: "channel"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
},
|
||||
ListElement {
|
||||
value: "sub_item_2_3"
|
||||
@@ -445,7 +399,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: ""
|
||||
iconName: "channel"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
}]}
|
||||
ListElement {
|
||||
value: "item_3"
|
||||
@@ -453,7 +406,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: "";
|
||||
iconName: "info"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
subItems: [
|
||||
ListElement {
|
||||
value: "sub_item_3_1"
|
||||
@@ -461,7 +413,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: ""
|
||||
iconName: "channel"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
}]}
|
||||
ListElement {
|
||||
value: "item_4"
|
||||
@@ -469,7 +420,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: "";
|
||||
iconName: ""
|
||||
iconColor: "red"
|
||||
isIdenticon: false
|
||||
subItems: [
|
||||
ListElement {
|
||||
value: "sub_item_4_1"
|
||||
@@ -477,7 +427,6 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
imageSource: ""
|
||||
iconName: "channel"
|
||||
iconColor: ""
|
||||
isIdenticon: false
|
||||
}]}
|
||||
}
|
||||
|
||||
@@ -497,7 +446,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
|
||||
@@ -525,7 +475,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
|
||||
@@ -552,7 +503,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
|
||||
@@ -579,7 +531,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
|
||||
@@ -607,7 +560,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
|
||||
@@ -635,7 +589,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
|
||||
@@ -663,7 +618,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
|
||||
@@ -692,7 +648,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
|
||||
@@ -721,7 +678,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
|
||||
@@ -750,7 +708,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
|
||||
@@ -779,7 +738,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
|
||||
@@ -807,7 +767,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
|
||||
@@ -834,7 +795,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
|
||||
@@ -861,7 +823,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
|
||||
@@ -881,46 +844,68 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
id: membersList
|
||||
ListElement {
|
||||
nickName: "This is an example"
|
||||
userName: "annabelle"
|
||||
chatKey: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
|
||||
trustIndicator: StatusMemberListItem.TrustedType.Verified
|
||||
name: "Maria"
|
||||
publicId: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
|
||||
trustIndicator: StatusContactVerificationIcons.TrustedType.Verified
|
||||
isMutualContact: true
|
||||
isOnline: true
|
||||
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
|
||||
onlineStatus: true
|
||||
icon: "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"
|
||||
userName: ""
|
||||
chatKey: ""
|
||||
trustIndicator: StatusMemberListItem.TrustedType.Untrustworthy
|
||||
nickName: ""
|
||||
name: "carmen.eth"
|
||||
publicId: "0x043a7ed78362567894688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
|
||||
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
|
||||
isMutualContact: false
|
||||
isOnline: false
|
||||
source: ""
|
||||
isIdenticon: false
|
||||
onlineStatus: false
|
||||
icon: ""
|
||||
isIdenticon: false
|
||||
}
|
||||
ListElement {
|
||||
nickName: "This girl I know from work"
|
||||
userName: "annabelle"
|
||||
chatKey: ""
|
||||
trustIndicator: StatusMemberListItem.TrustedType.None
|
||||
name: "annabelle"
|
||||
publicId: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486dsfkjghyu2cf04"
|
||||
trustIndicator: StatusContactVerificationIcons.TrustedType.None
|
||||
isMutualContact: false
|
||||
isOnline: true
|
||||
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDK
|
||||
onlineStatus: true
|
||||
icon: "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
|
||||
name: "mark.eth"
|
||||
publicId: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc79872cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
|
||||
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
|
||||
isMutualContact: true
|
||||
isOnline: false
|
||||
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
|
||||
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
|
||||
isIdenticon: true
|
||||
onlineStatus: false
|
||||
icon: ""
|
||||
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}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1016,4 +1001,309 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
|
||||
notificationsCount: 0
|
||||
}
|
||||
}
|
||||
|
||||
property ListModel currencyPickerModel: ListModel {
|
||||
ListElement {
|
||||
key: 0
|
||||
name: "United States Dollar"
|
||||
shortName: "USD"
|
||||
symbol: "$"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 1
|
||||
name: "British Pound"
|
||||
shortName: "GBP"
|
||||
symbol: "£"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b5.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 2
|
||||
name: "Euro"
|
||||
shortName: "EUR"
|
||||
symbol: "€"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b6.png"
|
||||
category: ""
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 3
|
||||
name: "Shout Korean Won"
|
||||
shortName: "KRW"
|
||||
symbol: "₩"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b8.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 4
|
||||
name: "Ethereum"
|
||||
shortName: "ETH"
|
||||
symbol: "Ξ"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b7.png"
|
||||
category: "Tokens"
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 5
|
||||
name: "Bitcoin"
|
||||
shortName: "BTC"
|
||||
symbol: "฿"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "Tokens"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 6
|
||||
name: "Status Network Token"
|
||||
shortName: "SNT"
|
||||
symbol: ""
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b8.png"
|
||||
category: "Tokens"
|
||||
selected: false
|
||||
}
|
||||
|
||||
ListElement {
|
||||
key: 7
|
||||
name: "Emirati Dirham"
|
||||
shortName: "AED"
|
||||
symbol: "د.إ"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "Other Fiat"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 8
|
||||
name: "Afghani"
|
||||
shortName: "AFN"
|
||||
symbol: "؋"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b7.png"
|
||||
category: "Other Fiat"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 9
|
||||
name: "Argentine Peso"
|
||||
shortName: "AFN"
|
||||
symbol: "$"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "Other Fiat"
|
||||
selected: false
|
||||
}
|
||||
}
|
||||
|
||||
property ListModel currencyPickerModel2: ListModel {
|
||||
ListElement {
|
||||
key: 0
|
||||
name: "United States Dollar"
|
||||
shortName: "USD"
|
||||
symbol: "$"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 1
|
||||
name: "British Pound"
|
||||
shortName: "GBP"
|
||||
symbol: "£"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b5.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 2
|
||||
name: "Euro"
|
||||
shortName: "EUR"
|
||||
symbol: "€"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b6.png"
|
||||
category: ""
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 3
|
||||
name: "Shout Korean Won"
|
||||
shortName: "KRW"
|
||||
symbol: "₩"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b8.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 4
|
||||
name: "Ethereum"
|
||||
shortName: "ETH"
|
||||
symbol: "Ξ"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b7.png"
|
||||
category: "Tokens"
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 5
|
||||
name: "Bitcoin"
|
||||
shortName: "BTC"
|
||||
symbol: "฿"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "Tokens"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 6
|
||||
name: "Status Network Token"
|
||||
shortName: "SNT"
|
||||
symbol: ""
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b8.png"
|
||||
category: "Tokens"
|
||||
selected: false
|
||||
}
|
||||
|
||||
ListElement {
|
||||
key: 7
|
||||
name: "Emirati Dirham"
|
||||
shortName: "AED"
|
||||
symbol: "د.إ"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "Other Fiat"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 8
|
||||
name: "Afghani"
|
||||
shortName: "AFN"
|
||||
symbol: "؋"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b7.png"
|
||||
category: "Other Fiat"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 9
|
||||
name: "Argentine Peso"
|
||||
shortName: "AFN"
|
||||
symbol: "$"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "Other Fiat"
|
||||
selected: false
|
||||
}
|
||||
}
|
||||
|
||||
property ListModel languagePickerModel: ListModel {
|
||||
ListElement {
|
||||
key: 0
|
||||
name: "English"
|
||||
shortName: "English"
|
||||
imageSource: "../../assets/twemoji/26x26/1f1ec-1f1e7.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 1
|
||||
name: "Korean"
|
||||
shortName: "한국어"
|
||||
imageSource: "../../assets/twemoji/26x26/1f1f0-1f1f7.png"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 2
|
||||
name: "Portuguese (Brazilian)"
|
||||
shortName: "Português"
|
||||
imageSource: "../../assets/twemoji/26x26/1f1e7-1f1f7.png"
|
||||
category: ""
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 3
|
||||
name: "Dutch"
|
||||
shortName: "Nederlands"
|
||||
imageSource: "../../assets/twemoji/26x26/1f1f3-1f1f1.png"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 4
|
||||
name: "Indonesian"
|
||||
shortName: "Bahasa Indonesia"
|
||||
imageSource: "../../assets/twemoji/26x26/1f1ee-1f1e9.png"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 5
|
||||
name: "Spanish"
|
||||
shortName: "Español"
|
||||
imageSource: "../../assets/twemoji/26x26/1f1ea-1f1e6.png"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
}
|
||||
|
||||
property ListModel languageNoImagePickerModel: ListModel {
|
||||
ListElement {
|
||||
key: 0
|
||||
name: "Chinese (Mainland China)"
|
||||
shortName: "普通话"
|
||||
category: ""
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 1
|
||||
name: "Russian"
|
||||
shortName: "Русский Язык"
|
||||
category: ""
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 2
|
||||
name: "Arabic"
|
||||
shortName: "اَلْعَرَبِيَّةُ"
|
||||
category: "Beta Languages"
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 3
|
||||
name: "Chinese (Taiwan)"
|
||||
shortName: "臺灣華語"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 4
|
||||
name: "Filipino"
|
||||
shortName: "Wikang Filipino"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 5
|
||||
name: "French"
|
||||
shortName: "Français"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 6
|
||||
name: "Italian"
|
||||
shortName: "Italiano"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 7
|
||||
name: "Turkish"
|
||||
shortName: "Türkçe"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
ListElement {
|
||||
key: 8
|
||||
name: "Urdu"
|
||||
shortName: "اُردُو"
|
||||
category: "Beta Languages"
|
||||
selected: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 18 KiB |
@@ -1,41 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -11,6 +11,11 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
SandboxApp app(argc, argv);
|
||||
|
||||
app.setOrganizationName("Status");
|
||||
app.setOrganizationDomain("status.im");
|
||||
app.setApplicationName("Sandbox");
|
||||
|
||||
app.startEngine();
|
||||
|
||||
return app.exec();
|
||||
|
||||
@@ -2,6 +2,8 @@ import QtQuick 2.14
|
||||
import QtQuick.Window 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
import QtGraphicalEffects 1.13
|
||||
import QtQuick.Layouts 1.14
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import Sandbox 0.1
|
||||
|
||||
@@ -31,10 +33,7 @@ StatusWindow {
|
||||
|
||||
property real factor: 1.0
|
||||
|
||||
Component.onCompleted: {
|
||||
Theme.palette = lightTheme
|
||||
rootWindow.updatePosition();
|
||||
}
|
||||
Component.onCompleted: rootWindow.updatePosition()
|
||||
|
||||
QtObject {
|
||||
id: appSectionType
|
||||
@@ -110,12 +109,10 @@ StatusWindow {
|
||||
anchors.topMargin: 32
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 32
|
||||
onCheckedChanged: {
|
||||
if (Theme.palette === rootWindow.lightTheme) {
|
||||
Theme.palette = rootWindow.darkTheme
|
||||
} else {
|
||||
Theme.palette = rootWindow.lightTheme
|
||||
}
|
||||
lightThemeEnabled: storeSettings.lightTheme
|
||||
onLightThemeEnabledChanged: {
|
||||
Theme.palette = lightThemeEnabled ? rootWindow.darkTheme : rootWindow.lightTheme
|
||||
storeSettings.lightTheme = lightThemeEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,11 +123,13 @@ StatusWindow {
|
||||
StatusAppTwoPanelLayout {
|
||||
id: mainPageView
|
||||
|
||||
function page(name) {
|
||||
function page(name, fillPage) {
|
||||
storeSettings.fillPage = fillPage ? true : false
|
||||
viewLoader.source = Qt.resolvedUrl("./pages/" + name + "Page.qml");
|
||||
}
|
||||
function control(name) {
|
||||
viewLoader.source = Qt.resolvedUrl("./controls/" + name + ".qml");
|
||||
storeSettings.fillPage = false
|
||||
}
|
||||
|
||||
leftPanel: Item {
|
||||
@@ -184,6 +183,11 @@ StatusWindow {
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.control(title);
|
||||
}
|
||||
StatusNavigationListItem {
|
||||
title: "StatusTabBarButton"
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.page(title);
|
||||
}
|
||||
StatusNavigationListItem {
|
||||
title: "StatusTabBarIconButton"
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
@@ -229,6 +233,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"
|
||||
@@ -270,6 +279,11 @@ StatusWindow {
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.page(title);
|
||||
}
|
||||
StatusNavigationListItem {
|
||||
title: "StatusListPicker"
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.page(title);
|
||||
}
|
||||
StatusListSectionHeadline { text: "StatusQ.Popup" }
|
||||
StatusNavigationListItem {
|
||||
title: "StatusPopupMenu"
|
||||
@@ -288,6 +302,16 @@ StatusWindow {
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.page(title);
|
||||
}
|
||||
StatusNavigationListItem {
|
||||
title: "StatusColorSelectorGrid"
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.page(title);
|
||||
}
|
||||
StatusNavigationListItem {
|
||||
title: "StatusImageCropPanel"
|
||||
selected: viewLoader.source.toString().includes(title)
|
||||
onClicked: mainPageView.page(title, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,8 +319,11 @@ StatusWindow {
|
||||
rightPanel: Item {
|
||||
id: rightPanel
|
||||
anchors.fill: parent
|
||||
|
||||
ScrollView {
|
||||
visible: !storeSettings.fillPage
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 64
|
||||
contentHeight: (pageWrapper.height + pageWrapper.anchors.topMargin) * rootWindow.factor
|
||||
contentWidth: (pageWrapper.width * rootWindow.factor)
|
||||
clip: true
|
||||
@@ -305,14 +332,16 @@ StatusWindow {
|
||||
id: pageWrapper
|
||||
width: rightPanel.width
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 64
|
||||
height: Math.max(rootWindow.height, viewLoader.height + 128)
|
||||
scale: rootWindow.factor
|
||||
|
||||
Loader {
|
||||
id: viewLoader
|
||||
active: !storeSettings.fillPage
|
||||
anchors.centerIn: parent
|
||||
source: mainPageView.control("Icons")
|
||||
source: storeSettings.selected.length === 0 ? mainPageView.control("Icons") : storeSettings.selected
|
||||
onSourceChanged: {
|
||||
storeSettings.selected = viewLoader.source
|
||||
if (source.toString().includes("Icons")) {
|
||||
item.iconColor = Theme.palette.primaryColor1;
|
||||
}
|
||||
@@ -320,6 +349,15 @@ StatusWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
active: storeSettings.fillPage
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 64
|
||||
visible: storeSettings.fillPage
|
||||
clip: true
|
||||
|
||||
source: viewLoader.source
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,4 +475,11 @@ StatusWindow {
|
||||
rootWindow.toggleFullScreen()
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
id: storeSettings
|
||||
property string selected: ""
|
||||
property bool lightTheme: true
|
||||
property bool fillPage: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import QtQuick 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
import QtGraphicalEffects 1.14
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
implicitWidth: mainLayout.implicitWidth
|
||||
implicitHeight: mainLayout.implicitHeight
|
||||
|
||||
property var testControls: [ctrl1, ctrl2, ctrl3]
|
||||
|
||||
property bool globalStylePreferRound: true
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
ColumnLayout {
|
||||
Text {
|
||||
text: `AR: ${ctrl1.aspectRatio.toFixed(2)}`
|
||||
}
|
||||
|
||||
StatusImageCropPanel {
|
||||
id: ctrl1
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
|
||||
}
|
||||
Text {
|
||||
text: `AR: ${ctrl2.aspectRatio.toFixed(2)}`
|
||||
}
|
||||
StatusImageCropPanel {
|
||||
id: ctrl2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rectangular : StatusImageCrop.WindowStyle.Rounded
|
||||
aspectRatio: 16/9
|
||||
enableCheckers: true
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Text {
|
||||
text: `AR: ${ctrl3.aspectRatio.toFixed(2)}`
|
||||
}
|
||||
StatusImageCropPanel {
|
||||
id: ctrl3
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
|
||||
aspectRatio: 0.8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.ZoomIn
|
||||
onActivated: {
|
||||
for(let i in testControls) {
|
||||
const c = testControls[i]
|
||||
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, -0.05))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.ZoomOut
|
||||
onActivated: {
|
||||
for(let i in testControls) {
|
||||
const c = testControls[i]
|
||||
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, 0.05))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequences: ["Ctrl+W"]
|
||||
onActivated: globalStylePreferRound = !globalStylePreferRound
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,11 +57,38 @@ Column {
|
||||
input.clearable: true
|
||||
}
|
||||
|
||||
Item {
|
||||
implicitWidth: 480
|
||||
implicitHeight: 82
|
||||
z: 100000
|
||||
StatusSeedPhraseInput {
|
||||
id: statusSeedInput
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.height
|
||||
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
|
||||
errorMessage: "Error message"
|
||||
|
||||
input.clearable: true
|
||||
input.valid: false
|
||||
input.placeholderText: "Placeholder"
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core 0.1
|
||||
|
||||
import "../demoapp/data" 1.0
|
||||
|
||||
GridLayout {
|
||||
id: root
|
||||
columns: 1
|
||||
rowSpacing: 150
|
||||
|
||||
GridLayout {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
rows: 4
|
||||
columns: 2
|
||||
rowSpacing: 170
|
||||
columnSpacing: 150
|
||||
z: 100
|
||||
StatusListPicker {
|
||||
id: languagePicker
|
||||
z: 100
|
||||
inputList: Models.languagePickerModel
|
||||
placeholderSearchText: qsTr("Search Languages")
|
||||
menuAlignment: StatusListPicker.MenuAlignment.Left
|
||||
}
|
||||
|
||||
StatusListPicker {
|
||||
id: languagePicker2
|
||||
z: 100
|
||||
inputList: Models.languageNoImagePickerModel
|
||||
placeholderSearchText: qsTr("Search Languages")
|
||||
menuAlignment: StatusListPicker.MenuAlignment.Center
|
||||
}
|
||||
|
||||
StatusListPicker {
|
||||
id: currencyPicker
|
||||
inputList: Models.currencyPickerModel
|
||||
placeholderSearchText: qsTr("Search Currencies")
|
||||
multiSelection: true
|
||||
}
|
||||
|
||||
StatusListPicker {
|
||||
id: currencyPicker2
|
||||
inputList: Models.currencyPickerModel2
|
||||
placeholderSearchText: qsTr("Search Currencies")
|
||||
multiSelection: true
|
||||
printSymbol: true
|
||||
enableSelectableItem: false
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: pageDesc
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
height: 100
|
||||
width: 500
|
||||
text: "4 different configurations for the `StatusListPicker` component:\n
|
||||
* Single selection. \n
|
||||
* Single selection but dynamically changed to multiple selection (model provides multiple selected items).\n
|
||||
* Multiple selection.\n
|
||||
* Multiple selection and displayed name is the symbol + shortName\n"
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
// Outsite area
|
||||
MouseArea {
|
||||
height: root.height
|
||||
width: root.width
|
||||
onClicked: {
|
||||
languagePicker.close()
|
||||
languagePicker2.close()
|
||||
currencyPicker.close()
|
||||
currencyPicker2.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import QtQuick 2.14
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import Sandbox 0.1
|
||||
|
||||
Column {
|
||||
spacing: 8
|
||||
|
||||
StatusTabBar {
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: "Button 1"
|
||||
}
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: "Button 2"
|
||||
}
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: "Button 3"
|
||||
badge.value: 42
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,6 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
namesModel: root.asortedContacts
|
||||
toLabelText: qsTr("To: ")
|
||||
warningText: qsTr("5 USER LIMIT REACHED")
|
||||
warningText: qsTr("USER LIMIT REACHED")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,11 @@ Item {
|
||||
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":""}
|
||||
{"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":"", "duration":0},
|
||||
{"title":"Verification Request Sent", "subTitle":"", "icon":"checkmark-circle", "loading":false, "type":1,"url":"", "duration":4000},
|
||||
{"title":"Collectible is being minted...", "subTitle":"View on Etherscan", "icon":"", "loading":true, "type":0,"url":"http://google.com", "duration":0},
|
||||
{"title":"Contact request sent", "subTitle":"", "icon":"checkmark-circle", "loading":false, "type":1,"url":"", "duration":4000},
|
||||
{"title":"Test User", "subTitle":"Hello message...", "icon":"", "loading":false, "type":0,"url":"", "duration":4000}
|
||||
]
|
||||
delegate: StatusToastMessage {
|
||||
primaryText: modelData.title
|
||||
@@ -27,12 +28,12 @@ Item {
|
||||
loading: modelData.loading
|
||||
type: modelData.type
|
||||
linkUrl: modelData.url
|
||||
duration: modelData.duration
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link);
|
||||
}
|
||||
//simulate open
|
||||
Component.onCompleted: {
|
||||
open = true;
|
||||
onClose: {
|
||||
console.warn("toast closed: ", modelData.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ Column {
|
||||
spacing: 8
|
||||
|
||||
StatusWalletColorSelect {
|
||||
model: Theme.palette.accountColors
|
||||
model: Theme.palette.userCustomizationColors
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<file>pages/StatusTabSwitchPage.qml</file>
|
||||
<file>pages/StatusWalletColorButtonPage.qml</file>
|
||||
<file>pages/StatusWalletColorSelectPage.qml</file>
|
||||
<file>pages/StatusPasswordStrengthIndicatorPage.qml</file>
|
||||
<file>pages/StatusPasswordStrengthIndicatorPage.qml</file>
|
||||
<file>controls/Buttons.qml</file>
|
||||
<file>controls/Controls.qml</file>
|
||||
<file>controls/Icons.qml</file>
|
||||
@@ -24,6 +24,8 @@
|
||||
<file>controls/ListItems.qml</file>
|
||||
<file>controls/Others.qml</file>
|
||||
<file>controls/Popups.qml</file>
|
||||
<file>demoapp/ChatChannelView.qml</file>
|
||||
<file>demoapp/CreateChatView.qml</file>
|
||||
<file>demoapp/DemoCommunityDetailModal.qml</file>
|
||||
<file>demoapp/DemoContactRequestsModal.qml</file>
|
||||
<file>demoapp/StatusAppChatView.qml</file>
|
||||
@@ -31,5 +33,15 @@
|
||||
<file>demoapp/StatusAppProfileSettingsView.qml</file>
|
||||
<file>demoapp/data/Models.qml</file>
|
||||
<file>demoapp/data/qmldir</file>
|
||||
<file>demoapp/data/logo-test-image.png</file>
|
||||
<file>DemoApp.qml</file>
|
||||
<file>ThemeSwitch.qml</file>
|
||||
<file>pages/StatusColorSelectorGridPage.qml</file>
|
||||
<file>pages/StatusListPickerPage.qml</file>
|
||||
<file>pages/StatusPinInputPage.qml</file>
|
||||
<file>pages/StatusTagSelectorPage.qml</file>
|
||||
<file>pages/StatusToastMessagePage.qml</file>
|
||||
<file>pages/StatusWizardStepperPage.qml</file>
|
||||
<file>pages/StatusTabBarButtonPage.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
</RCC>
|
||||
|
||||
@@ -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
|
||||
@@ -32,7 +32,7 @@ Rectangle {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
if (statusBadge.value > 99) {
|
||||
return "99+";
|
||||
return qsTr("99+");
|
||||
}
|
||||
return statusBadge.value;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ Item {
|
||||
id: statusChatInfoButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
anchors.right: (implicitWidth > parent.width - 50) ? statusMenuButton.left : undefined
|
||||
anchors.rightMargin: 5
|
||||
type: StatusChatInfoButton.Type.OneToOneChat
|
||||
@@ -37,7 +36,6 @@ Item {
|
||||
StatusRoundButton {
|
||||
id: statusMenuButton
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
visible: popupMenuSlot.active
|
||||
@@ -104,5 +102,4 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,9 @@ Column {
|
||||
width: 288
|
||||
|
||||
property string categoryId: ""
|
||||
property var model: []
|
||||
property var model: null
|
||||
property bool draggableItems: false
|
||||
property bool highlightItem: true
|
||||
|
||||
property alias statusChatListItems: statusChatListItems
|
||||
|
||||
@@ -90,8 +91,8 @@ Column {
|
||||
}
|
||||
|
||||
StatusChatListItem {
|
||||
|
||||
id: statusChatListItem
|
||||
|
||||
opacity: dragSensor.active ? 0.0 : 1.0
|
||||
originalOrder: model.position
|
||||
chatId: model.itemId
|
||||
@@ -101,13 +102,19 @@ Column {
|
||||
muted: model.muted
|
||||
hasUnreadMessages: model.hasUnreadMessages
|
||||
notificationsCount: model.notificationsCount
|
||||
selected: model.active
|
||||
icon.color: model.color
|
||||
image.isIdenticon: model.isIdenticon
|
||||
highlightWhenCreated: !!model.highlight
|
||||
selected: (model.active && statusChatList.highlightItem)
|
||||
|
||||
icon.emoji: model.emoji
|
||||
icon.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
|
||||
image.isIdenticon: false
|
||||
image.source: model.icon
|
||||
ringSettings.ringSpecModel: model.colorHash
|
||||
|
||||
sensor.cursorShape: dragSensor.cursorShape
|
||||
onClicked: {
|
||||
highlightWhenCreated = false
|
||||
|
||||
if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
|
||||
statusChatListItem.highlighted = true
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ Item {
|
||||
implicitWidth: chatListsAndCategories.width
|
||||
|
||||
property StatusTooltipSettings categoryAddButtonToolTip: StatusTooltipSettings {
|
||||
text: "Add channel inside category"
|
||||
text: qsTr("Add channel inside category")
|
||||
}
|
||||
property StatusTooltipSettings categoryMenuButtonToolTip: StatusTooltipSettings {
|
||||
text: "More"
|
||||
text: qsTr("More")
|
||||
}
|
||||
|
||||
property var model: []
|
||||
@@ -68,7 +68,6 @@ Item {
|
||||
|
||||
StatusChatList {
|
||||
id: statusChatList
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: statusChatList.model.count > 0
|
||||
onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
|
||||
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
|
||||
|
||||
@@ -48,7 +48,6 @@ Column {
|
||||
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6);
|
||||
return
|
||||
}
|
||||
statusChatListCategory.opened = !opened;
|
||||
}
|
||||
}
|
||||
onTitleClicked: statusChatListCategory.opened = !opened
|
||||
|
||||
@@ -39,21 +39,21 @@ StatusListItem {
|
||||
id: addButton
|
||||
icon.name: "add"
|
||||
icon.width: 20
|
||||
visible: statusChatListCategoryItem.showAddButton &&
|
||||
visible: statusChatListCategoryItem.showAddButton &&
|
||||
(statusChatListCategoryItem.highlighted ||
|
||||
statusChatListCategoryItem.sensor.containsMouse)
|
||||
onClicked: statusChatListCategoryItem.addButtonClicked(mouse)
|
||||
tooltip.text: "Add channel inside category"
|
||||
tooltip.text: qsTr("Add channel inside category")
|
||||
},
|
||||
StatusChatListCategoryItemButton {
|
||||
id: menuButton
|
||||
icon.name: "more"
|
||||
icon.width: 21
|
||||
visible: statusChatListCategoryItem.showMenuButton &&
|
||||
visible: statusChatListCategoryItem.showMenuButton &&
|
||||
(statusChatListCategoryItem.highlighted ||
|
||||
statusChatListCategoryItem.sensor.containsMouse)
|
||||
onClicked: statusChatListCategoryItem.menuButtonClicked(mouse)
|
||||
tooltip.text: "More"
|
||||
tooltip.text: qsTr("More")
|
||||
},
|
||||
StatusChatListCategoryItemButton {
|
||||
id: toggleButton
|
||||
|
||||
@@ -5,11 +5,12 @@ 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
|
||||
|
||||
Rectangle {
|
||||
id: statusChatListItem
|
||||
id: root
|
||||
|
||||
objectName: "chatItem"
|
||||
property int originalOrder: -1
|
||||
@@ -28,10 +29,13 @@ Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
color: Theme.palette.miscColor5
|
||||
letterSize: 15
|
||||
emoji: ""
|
||||
charactersLen: root.type === StatusChatListItem.Type.OneToOneChat ? 2 : 1
|
||||
}
|
||||
property alias ringSettings: identicon.ringSettings
|
||||
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
|
||||
@@ -74,16 +78,16 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onClicked: statusChatListItem.clicked(mouse)
|
||||
onClicked: root.clicked(mouse)
|
||||
|
||||
StatusSmartIdenticon {
|
||||
id: identicon
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
image: statusChatListItem.image
|
||||
icon: statusChatListItem.icon
|
||||
name: statusChatListItem.name
|
||||
image: root.image
|
||||
icon: root.icon
|
||||
name: root.name
|
||||
}
|
||||
|
||||
StatusIcon {
|
||||
@@ -93,21 +97,21 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
width: 14
|
||||
visible: statusChatListItem.type !== StatusChatListItem.Type.OneToOneChat
|
||||
visible: root.type !== StatusChatListItem.Type.OneToOneChat
|
||||
opacity: {
|
||||
if (statusChatListItem.muted && !hoverHander.hovered && !statusChatListItem.highlighted) {
|
||||
if (root.muted && !hoverHander.hovered && !root.highlighted) {
|
||||
return 0.4
|
||||
}
|
||||
return statusChatListItem.hasUnreadMessages ||
|
||||
statusChatListItem.notificationsCount > 0 ||
|
||||
statusChatListItem.selected ||
|
||||
statusChatListItem.highlighted ||
|
||||
return root.hasUnreadMessages ||
|
||||
root.notificationsCount > 0 ||
|
||||
root.selected ||
|
||||
root.highlighted ||
|
||||
statusBadge.visible ||
|
||||
hoverHander.hovered ? 1.0 : 0.7
|
||||
}
|
||||
|
||||
icon: {
|
||||
switch (statusChatListItem.type) {
|
||||
switch (root.type) {
|
||||
case StatusChatListItem.Type.PublicCat:
|
||||
return Theme.palette.name == "light" ? "tiny/public-chat" : "tiny/public-chat-white"
|
||||
break;
|
||||
@@ -132,25 +136,27 @@ Rectangle {
|
||||
anchors.rightMargin: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
text: (statusChatListItem.type === StatusChatListItem.Type.PublicChat &&
|
||||
!statusChatListItem.name.startsWith("#") ?
|
||||
"#" + statusChatListItem.name :
|
||||
statusChatListItem.name)
|
||||
text: (root.type === StatusChatListItem.Type.PublicChat &&
|
||||
!root.name.startsWith("#") ?
|
||||
"#" + root.name :
|
||||
root.name)
|
||||
elide: Text.ElideRight
|
||||
color: {
|
||||
if (statusChatListItem.muted && !hoverHander.hovered && !statusChatListItem.highlighted) {
|
||||
if (root.muted && !hoverHander.hovered && !root.highlighted) {
|
||||
return Theme.palette.directColor5
|
||||
}
|
||||
return statusChatListItem.hasUnreadMessages ||
|
||||
statusChatListItem.notificationsCount > 0 ||
|
||||
statusChatListItem.selected ||
|
||||
statusChatListItem.highlighted ||
|
||||
return root.hasUnreadMessages ||
|
||||
root.notificationsCount > 0 ||
|
||||
root.selected ||
|
||||
root.highlighted ||
|
||||
root.highlightWhenCreated ||
|
||||
hoverHander.hovered ||
|
||||
statusBadge.visible ? Theme.palette.directColor1 : Theme.palette.directColor4
|
||||
}
|
||||
font.weight: !statusChatListItem.muted &&
|
||||
(statusChatListItem.hasUnreadMessages ||
|
||||
statusChatListItem.notificationsCount > 0 ||
|
||||
font.weight: !root.muted &&
|
||||
(root.hasUnreadMessages ||
|
||||
root.notificationsCount > 0 ||
|
||||
root.highlightWhenCreated ||
|
||||
statusBadge.visible) ? Font.Bold : Font.Medium
|
||||
font.pixelSize: 15
|
||||
}
|
||||
@@ -163,18 +169,18 @@ Rectangle {
|
||||
width: 14
|
||||
opacity: mutedIconSensor.containsMouse ? 1.0 : 0.2
|
||||
icon: Theme.palette.name === "light" ? "tiny/muted" : "tiny/muted-white"
|
||||
visible: statusChatListItem.muted
|
||||
visible: root.muted
|
||||
|
||||
MouseArea {
|
||||
id: mutedIconSensor
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: statusChatListItem.unmute()
|
||||
onClicked: root.unmute()
|
||||
}
|
||||
|
||||
StatusToolTip {
|
||||
text: "Unmute"
|
||||
text: qsTr("Unmute")
|
||||
visible: mutedIconSensor.containsMouse
|
||||
}
|
||||
}
|
||||
@@ -186,11 +192,11 @@ Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
|
||||
color: statusChatListItem.muted ? Theme.palette.primaryColor2 : Theme.palette.primaryColor1
|
||||
color: root.muted ? Theme.palette.primaryColor2 : Theme.palette.primaryColor1
|
||||
border.width: 4
|
||||
border.color: color
|
||||
value: statusChatListItem.notificationsCount
|
||||
visible: statusChatListItem.notificationsCount > 0
|
||||
value: root.notificationsCount
|
||||
visible: root.notificationsCount > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ Rectangle {
|
||||
onClicked: statusChatToolBar.searchButtonClicked()
|
||||
|
||||
// initializing the tooltip
|
||||
tooltip.text: "Search"
|
||||
tooltip.text: qsTr("Search")
|
||||
tooltip.orientation: StatusToolTip.Orientation.Bottom
|
||||
tooltip.y: parent.height + 12
|
||||
}
|
||||
@@ -72,7 +72,7 @@ Rectangle {
|
||||
onClicked: statusChatToolBar.membersButtonClicked()
|
||||
|
||||
// initializing the tooltip
|
||||
tooltip.text: "Members"
|
||||
tooltip.text: qsTr("Members")
|
||||
tooltip.orientation: StatusToolTip.Orientation.Bottom
|
||||
tooltip.y: parent.height + 12
|
||||
}
|
||||
@@ -87,7 +87,7 @@ Rectangle {
|
||||
|
||||
// initializing the tooltip
|
||||
tooltip.visible: !!tooltip.text && menuButton.hovered && !popupMenuSlot.item.opened
|
||||
tooltip.text: "More"
|
||||
tooltip.text: qsTr("More")
|
||||
tooltip.orientation: StatusToolTip.Orientation.Bottom
|
||||
tooltip.y: parent.height + 12
|
||||
|
||||
@@ -141,7 +141,7 @@ Rectangle {
|
||||
type: StatusFlatRoundButton.Type.Secondary
|
||||
|
||||
// initializing the tooltip
|
||||
tooltip.text: "Activity"
|
||||
tooltip.text: qsTr("Activity")
|
||||
tooltip.orientation: StatusToolTip.Orientation.Bottom
|
||||
tooltip.y: parent.height + 12
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import QtQuick 2.13
|
||||
import StatusQ.Core 0.1
|
||||
|
||||
|
||||
Image {
|
||||
id: root
|
||||
|
||||
property string emojiId: ""
|
||||
|
||||
width: 14
|
||||
height: 14
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
mipmap: true
|
||||
antialiasing: true
|
||||
source: emojiId ? `../../assets/twemoji/svg/${emojiId}.svg` : ""
|
||||
}
|
||||
@@ -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}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
import QtQuick 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusImageCropPanel
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Draw a crop-window onto an image and allows manipulating the position of the crop-window. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}.
|
||||
|
||||
Adds mouse pan and zoom functionality on top of StatusImageCrop functionality. Also adds small
|
||||
practical features and optimizes drawing by minimizing StatusImageCrop area
|
||||
|
||||
\sa StatusImageCrop for more details
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusImageCropPanel {
|
||||
width: 400
|
||||
height: 200
|
||||
source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
windowStyle: StatusImageCrop.WindowStyle.Rectangular
|
||||
Component.onCompleted: setCropRect(Qt.rect(10, 0, sourceSize.width - 20, sourceSize.height))
|
||||
}
|
||||
\endqml
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
Item {
|
||||
id: root
|
||||
|
||||
implicitWidth: mainLayout.implicitWidth
|
||||
implicitHeight: mainLayout.implicitHeight
|
||||
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::aspectRatio
|
||||
Initial aspect-ratio of the crop-window
|
||||
*/
|
||||
property real aspectRatio: 1
|
||||
/*!
|
||||
\qmlproperty bool StatusImageCrop::interactive
|
||||
If true allows user to interact with the image. Set to false for previewing existing crop-data
|
||||
*/
|
||||
property bool interactive: true
|
||||
/*!
|
||||
\qmlproperty bool StatusImageCrop::margins
|
||||
Space to keep around the control borders and crop area
|
||||
*/
|
||||
property int margins: 10
|
||||
|
||||
/*!
|
||||
\qmlproperty url StatusImageCropPanel::source
|
||||
\sa StatusImageCrop::source
|
||||
*/
|
||||
/*required*/ property alias source: cropEditor.source
|
||||
|
||||
/*!
|
||||
\qmlproperty WindowStyle StatusImageCropPanel::windowStyle
|
||||
\sa StatusImageCrop::windowStyle
|
||||
*/
|
||||
property alias windowStyle: cropEditor.windowStyle
|
||||
/*!
|
||||
\qmlproperty int StatusImageCropPanel::radius
|
||||
\sa StatusImageCrop::radius
|
||||
*/
|
||||
property alias radius: cropEditor.radius
|
||||
/*!
|
||||
\qmlproperty color StatusImageCropPanel::wallColor
|
||||
\sa StatusImageCrop::wallColor
|
||||
*/
|
||||
property alias wallColor: cropEditor.wallColor
|
||||
/*!
|
||||
\qmlproperty real StatusImageCropPanel::wallTransparency
|
||||
\sa StatusImageCrop::wallTransparency
|
||||
*/
|
||||
property alias wallTransparency: cropEditor.wallTransparency
|
||||
/*!
|
||||
\qmlproperty rect StatusImageCropPanel::cropRect
|
||||
\sa StatusImageCrop::cropRect
|
||||
*/
|
||||
property alias cropRect: cropEditor.cropRect
|
||||
/*!
|
||||
\qmlproperty rect StatusImageCropPanel::cropRect
|
||||
\sa StatusImageCrop::cropRect
|
||||
*/
|
||||
readonly property alias cropWindow: cropEditor.cropWindow
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::scrollZoomFactor
|
||||
How fast is image scaled (zoomed) when using mouse scroll
|
||||
*/
|
||||
property real scrollZoomFactor: 0.5
|
||||
/*!
|
||||
\qmlproperty bool StatusImageCropPanel::enableCheckers
|
||||
Shows helper guiding checkers pattern where image is not covering
|
||||
*/
|
||||
property bool enableCheckers: root.interactive
|
||||
/*!
|
||||
\qmlproperty size StatusImageCropPanel::sourceSize
|
||||
\sa StatusImageCrop::sourceSize
|
||||
*/
|
||||
property alias sourceSize: cropEditor.sourceSize
|
||||
|
||||
/*
|
||||
\qmlmethod StatusImageCropPanel::setCropRect(rect)
|
||||
\sa StatusImageCrop::cropRect
|
||||
*/
|
||||
function setCropRect(newRect) {
|
||||
cropEditor.setCropRect(newRect)
|
||||
aspectRatio = cropEditor.aspectRatio
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
function updateAspectRatio(newAR) {
|
||||
// Keep width and adjust height
|
||||
const eW = cropEditor.cropRect.width
|
||||
const w = (eW <= 0) ? cropEditor.sourceSize.width : eW
|
||||
const h = w/newAR
|
||||
const c = (eW <= 0)
|
||||
? Qt.point(cropEditor.sourceSize.width/2, cropEditor.sourceSize.height/2)
|
||||
: Qt.point(cropEditor.cropRect.x + w/2, cropEditor.cropRect.y + cropEditor.cropRect.height/2)
|
||||
const nR = Qt.rect(c.x - w/2, c.y-h/2, w, h)
|
||||
cropEditor.setCropRect(nR)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: d.updateAspectRatio(root.aspectRatio)
|
||||
onAspectRatioChanged: d.updateAspectRatio(root.aspectRatio)
|
||||
onSourceSizeChanged: d.updateAspectRatio(root.aspectRatio)
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
id: cropSpaceItem
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
clip: true
|
||||
|
||||
Rectangle {
|
||||
id: leftOverlay
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: cropEditor.left
|
||||
anchors.bottom: parent.bottom
|
||||
color: wallColor
|
||||
opacity: wallTransparency
|
||||
z: cropEditor.z + 1
|
||||
}
|
||||
Rectangle {
|
||||
id: topOverlay
|
||||
anchors.left: leftOverlay.right
|
||||
anchors.top: parent.top
|
||||
anchors.right: rightOverlay.left
|
||||
anchors.bottom: cropEditor.top
|
||||
color: wallColor
|
||||
opacity: wallTransparency
|
||||
z: cropEditor.z + 1
|
||||
}
|
||||
|
||||
StatusImageCrop {
|
||||
id: cropEditor
|
||||
anchors.centerIn: parent
|
||||
width: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height * aspectRatio : cropSpaceItem.width - root.margins * 2
|
||||
height: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height - root.margins * 2 : cropSpaceItem.width / aspectRatio
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rightOverlay
|
||||
anchors.left: cropEditor.right
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: wallColor
|
||||
opacity: wallTransparency
|
||||
z: cropEditor.z + 1
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: bottomOverlay
|
||||
anchors.left: leftOverlay.right
|
||||
anchors.top: cropEditor.bottom
|
||||
anchors.right: rightOverlay.left
|
||||
anchors.bottom: parent.bottom
|
||||
color: wallColor
|
||||
opacity: wallTransparency
|
||||
z: cropEditor.z + 1
|
||||
}
|
||||
|
||||
// Checkers
|
||||
Canvas {
|
||||
visible: root.enableCheckers
|
||||
anchors.fill: parent
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
for(let xI = 0; xI < Math.ceil(width/10); xI++) {
|
||||
for(let yI = 0; yI < Math.ceil(height/10); yI++) {
|
||||
ctx.fillStyle = (xI % 2) === (yI % 2) ? "#FFFFFE" : "#DBDBDB"
|
||||
ctx.fillRect(xI * 10, yI * 10, 10, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
z: cropEditor.z - 1
|
||||
}
|
||||
|
||||
// Drag and zoom
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
enabled: root.interactive
|
||||
|
||||
property var lastDragPoint: null
|
||||
onReleased: lastDragPoint = null
|
||||
|
||||
onMouseXChanged: updateDrag(Qt.point(mouse.x, mouse.y))
|
||||
onMouseYChanged: updateDrag(Qt.point(mouse.x, mouse.y))
|
||||
|
||||
onWheel: {
|
||||
const delta = wheel.angleDelta.y / 120
|
||||
cropEditor.setCropRect(cropEditor.getZoomRect(cropEditor.zoomScale + delta * root.scrollZoomFactor))
|
||||
}
|
||||
|
||||
function moveRect(r /*rect*/, delta /*real*/) {
|
||||
return Qt.rect(r.x + delta.x, r.y + delta.y, r.width, r.height)
|
||||
}
|
||||
|
||||
function scaleSize(sz /*size*/, s /*size*/) {
|
||||
return Qt.point(sz.width * s, sz.height * s)
|
||||
}
|
||||
|
||||
function updateDrag(p) {
|
||||
let delta = (lastDragPoint ? Qt.size(lastDragPoint.x - p.x, lastDragPoint.y - p.y) : Qt.size(0, 0))
|
||||
delta = scaleSize(delta, 1/cropEditor.scrToImgScale)
|
||||
cropEditor.setCropRect(moveRect(cropEditor.cropRect, delta))
|
||||
lastDragPoint = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: root.interactive
|
||||
|
||||
StatusIcon {
|
||||
icon: "remove-circle"
|
||||
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
}
|
||||
StatusSlider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 25
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
enabled: root.interactive
|
||||
|
||||
from: cropEditor.minZoomScale
|
||||
to: cropEditor.maxZoomScale
|
||||
value: cropEditor.zoomScale
|
||||
live: false
|
||||
onMoved: cropEditor.setCropRect(cropEditor.getZoomRect(valueAt(visualPosition)))
|
||||
}
|
||||
StatusIcon {
|
||||
icon: "add-circle"
|
||||
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,60 @@
|
||||
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: Emoji.size.small
|
||||
property int letterSize: 21
|
||||
property int charactersLen: 1
|
||||
|
||||
color: Theme.palette.miscColor5
|
||||
width: 40
|
||||
height: 40
|
||||
radius: width / 2
|
||||
|
||||
StatusEmoji {
|
||||
visible: root.emoji
|
||||
anchors.centerIn: parent
|
||||
width: Math.round(parent.width / 2)
|
||||
height: Math.round(parent.height / 2)
|
||||
emojiId: Emoji.iconId(root.emoji, root.emojiSize) || ""
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: identiconText
|
||||
text: ((statusLetterIdenticon.name.charAt(0) === "#")
|
||||
|| (statusLetterIdenticon.name.charAt(0) === "@") ?
|
||||
statusLetterIdenticon.name.charAt(1) : statusLetterIdenticon.name.charAt(0)).toUpperCase()
|
||||
|
||||
visible: !root.emoji
|
||||
anchors.alignWhenCentered: false
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: statusLetterIdenticon.letterSize
|
||||
color: Qt.rgba(255, 255, 255, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: root.letterSize
|
||||
color: d.luminance(root.color) > 0.5 ? Qt.rgba(0, 0, 0, 0.5) : Qt.rgba(255, 255, 255, 0.7)
|
||||
|
||||
text: {
|
||||
const shift = (root.name.charAt(0) === "#") ||
|
||||
(root.name.charAt(0) === "@")
|
||||
return root.name.substring(shift, shift + charactersLen).toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
function luminance(color) {
|
||||
let r = Math.pow(color.r, 2.2) * 0.2126
|
||||
let g = Math.pow(color.g, 2.2) * 0.7151
|
||||
let b = Math.pow(color.b, 2.2) * 0.0721
|
||||
return r + g + b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,17 +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 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
|
||||
@@ -31,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 {
|
||||
@@ -52,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
|
||||
@@ -84,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)
|
||||
@@ -99,7 +85,12 @@ 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 || statusListItem.highlighted) {
|
||||
switch(type) {
|
||||
@@ -148,18 +139,29 @@ Rectangle {
|
||||
name: statusListItem.title
|
||||
active: statusListItem.icon.isLetterIdenticon ||
|
||||
!!statusListItem.icon.name ||
|
||||
!!statusListItem.image.source.toString()
|
||||
!!statusListItem.image.source.toString() ||
|
||||
!!statusListItem.icon.emoji
|
||||
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 {
|
||||
@@ -167,29 +169,39 @@ Rectangle {
|
||||
text: statusListItem.title
|
||||
font.pixelSize: 15
|
||||
height: visible ? contentHeight : 0
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
elide: Text.ElideRight
|
||||
anchors.left: parent.left
|
||||
anchors.right: !statusListItem.titleAsideText && !statusListItem.titleIcon1Visible && !statusListItem.titleIcon2Visible
|
||||
? parent.right : undefined
|
||||
anchors.top: bottomModel.length === 0 ? undefined: parent.top
|
||||
anchors.topMargin: bottomModel.length === 0 ? undefined : 20
|
||||
width: Math.min(implicitWidth, parent.width)
|
||||
color: {
|
||||
if (!statusListItem.enabled) {
|
||||
return Theme.palette.baseColor1
|
||||
}
|
||||
switch (statusListItem.type) {
|
||||
case StatusListItem.Type.Primary:
|
||||
return Theme.palette.directColor1
|
||||
case StatusListItem.Type.Secondary:
|
||||
return Theme.palette.primaryColor1
|
||||
case StatusListItem.Type.Danger:
|
||||
return Theme.palette.dangerColor1
|
||||
}
|
||||
if (!statusListItem.enabled) {
|
||||
return Theme.palette.baseColor1
|
||||
}
|
||||
switch (statusListItem.type) {
|
||||
case StatusListItem.Type.Primary:
|
||||
return Theme.palette.directColor1
|
||||
case StatusListItem.Type.Secondary:
|
||||
return Theme.palette.primaryColor1
|
||||
case StatusListItem.Type.Danger:
|
||||
return Theme.palette.dangerColor1
|
||||
}
|
||||
}
|
||||
|
||||
StatusToolTip {
|
||||
id: statusListItemTitleTooltip
|
||||
text: statusListItemTitle.text
|
||||
delay: 0
|
||||
visible: statusListItemTitle.truncated && statusListItemTitleMouseArea.containsMouse
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: statusListItemTitleMouseArea
|
||||
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
|
||||
@@ -202,43 +214,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
|
||||
@@ -270,11 +259,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
|
||||
|
||||
@@ -284,12 +304,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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtGraphicalEffects 1.13
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusListPicker
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief It is a combination of StatusPickerButton and a drop-down list component that provides a way of presenting a list of selectable options to the user. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}.
|
||||
|
||||
The \c StatusListPicker is populated with a data model. The data model is commonly a JavaScript array or a ListModel object.
|
||||
|
||||
StatusListPicker can be made as a single or multiple options picker by setting its StatusListPicker::multiSelection property properly or will be auto-set if the model contains / provides more than one selected items.
|
||||
The StatusPickerButton text holds the text of the current item selected in the list picker. If there is more than one item selected, a string composed will be displayed.
|
||||
The drop-down list incorporates a searcher by the following model roles: `name` or / and `shortName`.
|
||||
|
||||
NOTE: Make sure to set the appropriate z-index when instantiating the component in order to place it on top of your view in order to display the drop-down data properly.
|
||||
Make sure to position the component inside its parent also when it is spanned in order to achieve a better user experience.
|
||||
|
||||
Example of how the component looks like:
|
||||
\image status_list_picker.png
|
||||
Example of how to use it:
|
||||
\qml
|
||||
StatusListPicker {
|
||||
id: currencyPicker
|
||||
inputList: Models.currencyPickerModel
|
||||
searchText: qsTr("Search Language")
|
||||
multiSelection: true
|
||||
printSymbol: true
|
||||
}
|
||||
\endqml
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
Item {
|
||||
id: root
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::inputList
|
||||
This property holds the data that will be populated in the list picker.
|
||||
|
||||
NOTE: This model property should not change so it is an in / out property where the selected role will be dynamically changed according to user actions.
|
||||
|
||||
Here an example of the model roles expected:
|
||||
\qml
|
||||
inputList: ListModel {
|
||||
ListElement {
|
||||
key: 0
|
||||
name: "United States Dollar"
|
||||
shortName: "USD"
|
||||
symbol: "$"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b4.png"
|
||||
category: "fiat"
|
||||
selected: true
|
||||
}
|
||||
ListElement {
|
||||
key: 1
|
||||
name: "British Pound"
|
||||
shortName: "GBP"
|
||||
symbol: "£"
|
||||
imageSource: "../../assets/twemoji/26x26/1f4b5.png"
|
||||
category: "fiat"
|
||||
selected: false
|
||||
}
|
||||
}
|
||||
\endqml
|
||||
*/
|
||||
property ListModel inputList: ListModel { }
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::searchText
|
||||
This property holds the search text the searcher input displays by default.
|
||||
*/
|
||||
property string searchText: ""
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::placeholderSearchText
|
||||
This property holds the placeholder text the searcher input displays by default.
|
||||
*/
|
||||
property string placeholderSearchText: qsTr("Search")
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::multiSelection
|
||||
This property holds whether the list picker is a single or a multiple picker option by displaying a StatusRadioButton or StatusCheckBox instead.
|
||||
*/
|
||||
property bool multiSelection: false
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::printSymbol
|
||||
This property holds whether the selected items will display a composition of the role `symbol` in the StatusPickerButton text or just only the role `shortName`.
|
||||
*/
|
||||
property bool printSymbol: false
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::maxPickerHeight
|
||||
This property holds the maximum drop-down list height allowed. The drop-down list height will be set as the minimum value between the list content height and the maxPickerHeight property.
|
||||
*/
|
||||
property int maxPickerHeight: 718
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::enableSelectableItem
|
||||
This property holds if the item in the list will be highlighted when hovering and clickable in its complete area or just not highlighted and able to be selected by clicking only the checbox or radiobutton area.
|
||||
*/
|
||||
property bool enableSelectableItem: true
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusListPicker::menuAlignment
|
||||
This property holds the allignment of the menu in terms of the button
|
||||
*/
|
||||
property int menuAlignment: StatusListPicker.MenuAlignment.Right
|
||||
|
||||
/*!
|
||||
\qmlproperty enum StatusListPicker::MenuAlignment
|
||||
This property holds the allignment of the menu in terms of the button
|
||||
values can be Left, Right or Center
|
||||
*/
|
||||
enum MenuAlignment {
|
||||
Left,
|
||||
Right,
|
||||
Center
|
||||
}
|
||||
|
||||
/*
|
||||
\qmlmethod StatusListPicker::close()
|
||||
It can be used to force to close the drop-down picker list whenever the consumer needs it. For example by adding an outside MouseArea to close the picker when user clicks outsite the component:
|
||||
\qml
|
||||
// Outsite area
|
||||
MouseArea {
|
||||
height: root.height
|
||||
width: root.width
|
||||
onClicked: { currencyPicker.close() }
|
||||
}
|
||||
\endqml
|
||||
*/
|
||||
function close() {
|
||||
picker.visible = false
|
||||
|
||||
// Reset searcher:
|
||||
root.searchText = ""
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlsignal StatusListPicker::itemPickerChanged(string key, bool selected)
|
||||
This signal is emitted when an item changes its selected value.
|
||||
*/
|
||||
signal itemPickerChanged(string key, bool selected)
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var filteredModel: ListModel { }
|
||||
|
||||
// Used to set up component and the needed private properties
|
||||
function initialize() {
|
||||
if(filteredModel.count === 0) {
|
||||
// It is necessary to load the model, not loaded yet!
|
||||
var selected = 0
|
||||
var selectionText = ""
|
||||
for(var i = 0; i < root.inputList.count; i++) {
|
||||
var item = root.inputList.get(i)
|
||||
d.filteredModel.append(item)
|
||||
if(item.selected) selected++;
|
||||
}
|
||||
|
||||
// If the given model has more than one selected elements, the behaviour of the list picker will be as a multiple selector with checkboxes although it is
|
||||
// set in the radiobutton mode. Radiobutton mode is only for mutial-exclusion.
|
||||
if(selected > 1)
|
||||
multiSelection = true
|
||||
|
||||
// Update selected items text:
|
||||
d.getSelectedItemsText()
|
||||
}
|
||||
}
|
||||
|
||||
// Used to update model elements given a specific text by filtering them for its `name` and / or `shortName`.
|
||||
function applyFilter(text) {
|
||||
const input = text.toLowerCase()
|
||||
filteredModel.clear()
|
||||
for(var i = 0; i < root.inputList.count; i++) {
|
||||
let item = root.inputList.get(i)
|
||||
if(item.name.toLowerCase().includes(input) || item.shortName.toLowerCase().includes(input))
|
||||
filteredModel.append(item)
|
||||
}
|
||||
}
|
||||
|
||||
function formatSymbolShortNameText(symbol, shortName) {
|
||||
var formattedText = ""
|
||||
if(root.printSymbol && symbol)
|
||||
formattedText = symbol + shortName
|
||||
else
|
||||
formattedText = shortName
|
||||
return formattedText
|
||||
}
|
||||
|
||||
function getSelectedItemsText() {
|
||||
var res = ""
|
||||
for(var i = 0; i < root.inputList.count; i++) {
|
||||
var item = root.inputList.get(i)
|
||||
if(item.selected) {
|
||||
if(res != "")
|
||||
res += ", "
|
||||
res += d.formatSymbolShortNameText(item.symbol, item.shortName)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Used to update the base input list model with the new selected property
|
||||
function updateInputListModel(key, selected, isSingleSelection) {
|
||||
// If it is a single selection we must ensure that when a new key is selected others are cleared.
|
||||
// It must be done manually because as there is the option of filterning, the model visualized changes
|
||||
// and it could be possible to have a filtered list without an element selected (but in the base model
|
||||
// it is) so, the binding to not selected will not be executed, as in the current filtered model
|
||||
// there are no changes to update, just only the selected one.
|
||||
for(var i = 0; i < root.inputList.count; i++) {
|
||||
if(root.inputList.get(i).key === key) {
|
||||
root.inputList.get(i).selected = selected
|
||||
}
|
||||
else if(isSingleSelection && selected) {
|
||||
// Clear all the list
|
||||
root.inputList.get(i).selected = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
width: 110
|
||||
height: 38
|
||||
|
||||
Component.onCompleted: d.initialize()
|
||||
|
||||
StatusPickerButton {
|
||||
id: btn
|
||||
anchors.fill: parent
|
||||
bgColor: Theme.palette.primaryColor3
|
||||
contentColor: Theme.palette.primaryColor1
|
||||
text: picker.selectedItemsText
|
||||
textPixelSize: 13
|
||||
type: StatusPickerButton.Type.Down
|
||||
|
||||
onClicked: {
|
||||
picker.visible = !picker.visible
|
||||
|
||||
// Restart list position:
|
||||
content.positionViewAtBeginning()
|
||||
content.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: picker
|
||||
|
||||
property string selectedItemsText: ""
|
||||
|
||||
width: content.itemWidth
|
||||
height: Math.min(content.contentHeight + content.anchors.topMargin + content.anchors.bottomMargin, root.maxPickerHeight)
|
||||
anchors.left: root.menuAlignment === StatusListPicker.MenuAlignment.Left ? btn.left : undefined
|
||||
anchors.right: root.menuAlignment === StatusListPicker.MenuAlignment.Right ? btn.right : undefined
|
||||
anchors.horizontalCenter: root.menuAlignment === StatusListPicker.MenuAlignment.Center ? btn.horizontalCenter : undefined
|
||||
anchors.top: btn.bottom
|
||||
anchors.topMargin: 4
|
||||
visible: false
|
||||
color: Theme.palette.statusPopupMenu.backgroundColor
|
||||
radius: 8
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
source: picker
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 4
|
||||
radius: 12
|
||||
samples: 25
|
||||
spread: 0.2
|
||||
color: Theme.palette.dropShadow
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: content
|
||||
|
||||
property int itemHeight: 40
|
||||
property int itemWidth: 360
|
||||
|
||||
model: d.filteredModel
|
||||
width: itemWidth
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
currentIndex: -1
|
||||
clip: true
|
||||
headerPositioning: ListView.OverlayHeader
|
||||
header: Rectangle {
|
||||
id: header
|
||||
width: content.itemWidth
|
||||
height: searchInput.height + 24
|
||||
color: Theme.palette.statusPopupMenu.backgroundColor
|
||||
z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
|
||||
|
||||
StatusBaseInput {
|
||||
id: searchInput
|
||||
implicitHeight: 36
|
||||
width: content.itemWidth - 2 * 18
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
placeholderText: root.placeholderSearchText
|
||||
text: root.searchText
|
||||
icon.name: "search"
|
||||
|
||||
onTextChanged: {
|
||||
d.applyFilter(text)
|
||||
root.searchText = text
|
||||
}
|
||||
}
|
||||
}// End of search input item
|
||||
delegate: StatusItemPicker {
|
||||
width: content.itemWidth
|
||||
height: content.itemHeight
|
||||
color: mouseArea.containsMouse ? Theme.palette.baseColor4 : "transparent"
|
||||
image: StatusImageSettings {
|
||||
source: model.imageSource ? model.imageSource : ""
|
||||
width: 15
|
||||
height: 15
|
||||
isIdenticon: false
|
||||
}
|
||||
name: model.name
|
||||
shortName: model.shortName
|
||||
selectorType: root.multiSelection ? StatusItemPicker.SelectorType.CheckBox : StatusItemPicker.SelectorType.RadioButton
|
||||
selected: model.selected
|
||||
radioGroup: radioBtnGroup
|
||||
|
||||
onCheckedChanged: {
|
||||
d.updateInputListModel(model.key, checked, selectorType === StatusItemPicker.SelectorType.RadioButton)
|
||||
if(selectorType === StatusItemPicker.SelectorType.RadioButton && checked) {
|
||||
// Update selected item text
|
||||
picker.selectedItemsText = d.formatSymbolShortNameText(model.symbol, model.shortName)
|
||||
}
|
||||
else {
|
||||
// Update selected items text (multiple selection, text chain).
|
||||
picker.selectedItemsText = d.getSelectedItemsText()
|
||||
}
|
||||
|
||||
// Used to notify selected property changes in the specific item picker.
|
||||
itemPickerChanged(model.key, checked)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
enabled: root.enableSelectableItem
|
||||
anchors.fill: parent
|
||||
cursorShape: root.enableSelectableItem ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if(selectorType === StatusItemPicker.SelectorType.RadioButton) {
|
||||
// Just only allow to select, not unselect in case of single selection (radiobutton)
|
||||
if(!selected) selected = !selected
|
||||
}
|
||||
else
|
||||
// In case of multiple selections you can both select and unselect.
|
||||
selected = !selected
|
||||
}
|
||||
}
|
||||
}
|
||||
section.property: "category"
|
||||
section.criteria: ViewSection.FullString
|
||||
section.delegate: Item {
|
||||
width: content.itemWidth
|
||||
height: content.itemHeight
|
||||
|
||||
StatusBaseText {
|
||||
anchors.leftMargin: 18
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: section
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: 15
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}// End of Category item
|
||||
|
||||
onActiveFocusChanged: { if(!activeFocus) root.close() }
|
||||
|
||||
// Not visual element to control mutual-exclusion of radiobuttons that are not sharing the same parent (inside list view)
|
||||
ButtonGroup {
|
||||
id: radioBtnGroup
|
||||
}
|
||||
}// End of Content
|
||||
}// End of Rectangle picker
|
||||
}
|
||||
@@ -2,56 +2,116 @@ import QtQuick 2.0
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusMemberListItem
|
||||
\inherits StatusListItem
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief It is a list item with a specific format to display members of a community or chat. Inherits from \c StatusListItem.
|
||||
|
||||
The \c StatusMemberListItem is a clickable / hovering list item with a specific format to display members of a community or chat.
|
||||
|
||||
It displays the member avatar, trust and mutual contact indicators, nick name, user name, chat key and information about the member connectivity.
|
||||
|
||||
Example of how the control looks like:
|
||||
\image status_member_list_item.png
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusMemberListItem {
|
||||
nickName: "carmen.eth"
|
||||
isOnline: false
|
||||
trustIndicator: StatusContactVerificationIcons.TrustedType.Untrustworthy
|
||||
}
|
||||
|
||||
StatusMemberListItem {
|
||||
nickName: "This girl I know from work"
|
||||
userName: "annabelle"
|
||||
isOnline: true
|
||||
}
|
||||
\endqml
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
StatusListItem {
|
||||
id: root
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusMemberListItem::nickName
|
||||
This property holds the nick name of the member represented.
|
||||
*/
|
||||
property string nickName: ""
|
||||
/*!
|
||||
\qmlproperty string StatusMemberListItem::userName
|
||||
This property holds the user name of the member represented.
|
||||
*/
|
||||
property string userName: ""
|
||||
/*!
|
||||
\qmlproperty string StatusMemberListItem::chatKey
|
||||
This property holds the chat key of the member represented.
|
||||
*/
|
||||
property string chatKey: ""
|
||||
/*!
|
||||
\qmlproperty string StatusMemberListItem::isMutualContact
|
||||
This property holds if the member represented is a mutual contact.
|
||||
*/
|
||||
property bool isMutualContact: false
|
||||
property var trustIndicator: StatusMemberListItem.TrustedType.None
|
||||
/*!
|
||||
\qmlproperty string StatusMemberListItem::trustIndicator
|
||||
This property holds the trust indicator of the member represented. Possible values are:
|
||||
\list
|
||||
\li StatusContactVerificationIcons.TrustedType.None
|
||||
\li StatusContactVerificationIcons.TrustedType.Verified
|
||||
\li StatusContactVerificationIcons.TrustedType.Untrustworthy
|
||||
\endlist
|
||||
*/
|
||||
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
|
||||
/*!
|
||||
\qmlproperty string StatusMemberListItem::isOnline
|
||||
This property holds the connectivity status of the member represented.
|
||||
*/
|
||||
property bool isOnline: false
|
||||
|
||||
enum TrustedType {
|
||||
None, //0
|
||||
Verified, //1
|
||||
Untrustworthy //2
|
||||
}
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
// Subtitle composition:
|
||||
function composeSubtitile() {
|
||||
var compose = ""
|
||||
if(root.userName !== "")
|
||||
compose = "(" + root.userName + ")"
|
||||
// Subtitle composition:
|
||||
function composeSubtitile() {
|
||||
var compose = ""
|
||||
if(root.userName !== "" && root.nickName !== "")
|
||||
compose = "(" + root.userName + ")"
|
||||
|
||||
if(compose !== "" && root.chatKey !== "")
|
||||
// Composition
|
||||
compose += " • " + composeShortKeyChat(root.chatKey)
|
||||
if(compose !== "" && root.chatKey !== "")
|
||||
// Composition
|
||||
compose += " • " + composeShortKeyChat(root.chatKey)
|
||||
|
||||
else if(root.chatKey !== "")
|
||||
compose = composeShortKeyChat(root.chatKey)
|
||||
else if(root.chatKey !== "")
|
||||
compose = composeShortKeyChat(root.chatKey)
|
||||
|
||||
return compose
|
||||
}
|
||||
return compose
|
||||
}
|
||||
|
||||
// Short keychat composition:
|
||||
function composeShortKeyChat(chatKey) {
|
||||
return chatKey.substring(0, 5) + "..." + chatKey.substring(chatKey.length - 3)
|
||||
// Short keychat composition:
|
||||
function composeShortKeyChat(chatKey) {
|
||||
return chatKey.substring(0, 5) + "..." + chatKey.substring(chatKey.length - 3)
|
||||
}
|
||||
}
|
||||
|
||||
// root object settings:
|
||||
title: root.nickName
|
||||
titleIcon1Visible: root.isMutualContact
|
||||
titleIcon2Visible: root.trustIndicator !== StatusMemberListItem.TrustedType.None
|
||||
subTitle: composeSubtitile()
|
||||
title: (root.nickName === "") ? root.userName : root.nickName
|
||||
statusListItemTitleIcons.sourceComponent: StatusContactVerificationIcons {
|
||||
isMutualContact: root.isMutualContact
|
||||
trustIndicator: root.trustIndicator
|
||||
}
|
||||
subTitle: d.composeSubtitile()
|
||||
statusListItemSubTitle.font.pixelSize: 10
|
||||
icon.isLetterIdenticon: !root.image.source.toString()
|
||||
statusListItemIcon.badge.visible: true
|
||||
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 +124,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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -20,6 +22,12 @@ Loader {
|
||||
height: 40
|
||||
}
|
||||
|
||||
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
|
||||
initalAngleRad: 0
|
||||
ringPxSize: Math.max(1.5, statusSmartIdenticon.image.width / 24.0)
|
||||
distinctiveColors: Theme.palette.identiconRingColors
|
||||
}
|
||||
|
||||
sourceComponent: statusSmartIdenticon.icon.isLetterIdenticon ? letterIdenticon :
|
||||
!!statusSmartIdenticon.image.source.toString() ? roundedImage :
|
||||
!!statusSmartIdenticon.icon.name.toString() ? roundedIcon : letterIdenticon
|
||||
@@ -75,10 +83,20 @@ Loader {
|
||||
height: statusSmartIdenticon.icon.height
|
||||
color: statusSmartIdenticon.icon.color
|
||||
name: statusSmartIdenticon.name
|
||||
emoji: statusSmartIdenticon.icon.emoji
|
||||
emojiSize: statusSmartIdenticon.icon.emojiSize
|
||||
letterSize: statusSmartIdenticon.icon.letterSize
|
||||
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 +106,6 @@ Loader {
|
||||
border.width: 3
|
||||
implicitHeight: 15
|
||||
implicitWidth: 15
|
||||
z: 100
|
||||
z: statusSmartIdenticon.dZ
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,192 @@
|
||||
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
|
||||
|
||||
/*!
|
||||
\qmltype StatusTagSelector
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Displays a tag selector component together with a list of where to select and add the tags from.
|
||||
Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}.
|
||||
|
||||
The \c StatusTagSelector displays a list of asorted elements together with a text input where tags are added. As the user
|
||||
types some text, the list elements are filtered and if the user selects any of those a new tag is created.
|
||||
For example:
|
||||
|
||||
\qml
|
||||
StatusTagSelector {
|
||||
width: 650
|
||||
height: 44
|
||||
anchors.centerIn: parent
|
||||
namesModel: 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
|
||||
}
|
||||
}
|
||||
toLabelText: qsTr("To: ")
|
||||
warningText: qsTr("USER LIMIT REACHED")
|
||||
}
|
||||
\endqml
|
||||
|
||||
\image status_tag_selector.png
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
implicitWidth: 448
|
||||
implicitHeight: 44
|
||||
implicitHeight: (104 + contactsLabel.height + contactsLabel.anchors.topMargin + (userListView.model.count * 64)) > root.maxHeight ? root.maxHeight :
|
||||
(104 + contactsLabel.height + contactsLabel.anchors.topMargin + (userListView.model.count * 64))
|
||||
|
||||
/*!
|
||||
\qmlproperty real StatusTagSelector::maxHeight
|
||||
This property holds the maximum height of the component.
|
||||
*/
|
||||
property real maxHeight: (488 + contactsLabel.height + contactsLabel.anchors.topMargin) //default min
|
||||
/*!
|
||||
\qmlproperty alias StatusTagSelector::textEdit
|
||||
This property holds a reference to the TextEdit component.
|
||||
*/
|
||||
property alias textEdit: edit
|
||||
/*!
|
||||
\qmlproperty alias StatusTagSelector::text
|
||||
This property holds a reference to the TextEdit's text property.
|
||||
*/
|
||||
property alias text: edit.text
|
||||
/*!
|
||||
\qmlproperty string StatusTagSelector::warningText
|
||||
This property sets the warning text.
|
||||
*/
|
||||
property string warningText: ""
|
||||
/*!
|
||||
\qmlproperty string StatusTagSelector::toLabelText
|
||||
This property sets the 'to' label text.
|
||||
*/
|
||||
property string toLabelText: ""
|
||||
/*!
|
||||
\qmlproperty string StatusTagSelector::listLabel
|
||||
This property sets the elements list label text.
|
||||
*/
|
||||
property string listLabel: ""
|
||||
/*!
|
||||
\qmlproperty int StatusTagSelector::nameCountLimit
|
||||
This property sets the tags count limit.
|
||||
*/
|
||||
property int nameCountLimit: 5
|
||||
|
||||
/*!
|
||||
\qmlproperty var StatusTagSelector::ringSpecModel
|
||||
This property holds the function to calculate the ring spec model
|
||||
based on the public key.
|
||||
*/
|
||||
property var ringSpecModelGetter: (pubKey) => { /*return ringSpecModel*/ }
|
||||
|
||||
/*!
|
||||
\qmlproperty var StatusTagSelector::compressKey
|
||||
This property holds the function to calculate the compressed
|
||||
key based on the public key.
|
||||
*/
|
||||
property var compressedKeyGetter: (pubKey) => { /*return compressed key;*/ }
|
||||
|
||||
/*!
|
||||
\qmlproperty ListModel StatusTagSelector::sortedList
|
||||
This property holds the sorted list model.
|
||||
*/
|
||||
property ListModel sortedList: ListModel { }
|
||||
/*!
|
||||
\qmlproperty ListModel StatusTagSelector::namesModel
|
||||
This property holds the asorted names model.
|
||||
*/
|
||||
property ListModel namesModel: ListModel { }
|
||||
|
||||
/*!
|
||||
\qmlmethod
|
||||
This function is used to find an entry in a model.
|
||||
*/
|
||||
function find(model, criteria) {
|
||||
for (var i = 0; i < model.count; ++i) if (criteria(model.get(i))) return model.get(i);
|
||||
return null;
|
||||
for (var i = 0; i < model.count; ++i) if (criteria(model.get(i))) return model.get(i);
|
||||
return null;
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod
|
||||
This function is used to insert a new tag.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod
|
||||
This function is used to sort the source model.
|
||||
*/
|
||||
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()) &&
|
||||
!find(namesModel, function(item) { return item.name === entry.name })) {
|
||||
sortedList.append({"publicId": entry.publicId, "name": entry.name,
|
||||
"nickName": entry.nickName, "trustIndicator": entry.trustIndicator,
|
||||
"isMutualContact": entry.isMutualContact, "ringSpecModel": entry.ringSpecModel,
|
||||
"icon": entry.icon, "isIdenticon": entry.isIdenticon,
|
||||
"onlineStatus": entry.onlineStatus});
|
||||
userListView.model = sortedList;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
userListView.model = inputModel;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when a new tag is created.
|
||||
*/
|
||||
signal addMember(string memberId)
|
||||
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when a tag is removed.
|
||||
*/
|
||||
signal removeMember(string memberId)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
id: tagSelectorRect
|
||||
width: parent.width
|
||||
height: 44
|
||||
radius: 8
|
||||
color: Theme.palette.baseColor2
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
@@ -47,79 +199,188 @@ Item {
|
||||
text: root.toLabelText
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: namesList
|
||||
Layout.preferredWidth: (count >= 5) ? (parent.width - warningTextLabel.width - 30) : childrenRect.width
|
||||
ScrollView {
|
||||
Layout.preferredWidth: (namesList.contentWidth > (parent.width - 177)) ?
|
||||
(parent.width - 177) : namesList.contentWidth
|
||||
implicitHeight: 30
|
||||
visible: (count > 0)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
model: namesModel
|
||||
orientation: ListView.Horizontal
|
||||
spacing: 8
|
||||
visible: (namesList.count > 0)
|
||||
contentWidth: namesList.contentWidth
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
clip: true
|
||||
onWidthChanged: {
|
||||
positionViewAtEnd();
|
||||
}
|
||||
|
||||
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
|
||||
ListView {
|
||||
id: namesList
|
||||
anchors.fill: parent
|
||||
model: namesModel
|
||||
orientation: ListView.Horizontal
|
||||
spacing: 8
|
||||
function scrollToEnd() {
|
||||
if (contentWidth > width) {
|
||||
contentX = contentWidth;
|
||||
}
|
||||
}
|
||||
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: {
|
||||
namesModel.remove(index, 1);
|
||||
onWidthChanged: { scrollToEnd(); }
|
||||
onCountChanged: { scrollToEnd(); }
|
||||
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 {
|
||||
TextInput {
|
||||
id: edit
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
focus: true
|
||||
color: Theme.palette.directColor1
|
||||
clip: true
|
||||
font.pixelSize: 15
|
||||
wrapMode: TextEdit.NoWrap
|
||||
font.family: Theme.palette.baseFont.name
|
||||
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)) === "") {
|
||||
&& getText(cursorPosition, (cursorPosition-1)) === ""
|
||||
&& (namesList.count-1) >= 0) {
|
||||
removeMember(namesModel.get(namesList.count-1).publicId);
|
||||
namesModel.remove((namesList.count-1), 1);
|
||||
}
|
||||
if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (sortedList.count > 0)) {
|
||||
root.insertTag(sortedList.get(userListView.currentIndex).name, sortedList.get(userListView.currentIndex).publicId);
|
||||
}
|
||||
}
|
||||
Keys.onUpPressed: { userListView.decrementCurrentIndex(); }
|
||||
Keys.onDownPressed: { userListView.incrementCurrentIndex(); }
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: warningTextLabel
|
||||
visible: (namesModel.count === 5)
|
||||
Layout.preferredWidth: 120
|
||||
visible: (namesModel.count === root.nameCountLimit)
|
||||
Layout.preferredWidth: visible ? 120 : 0
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
font.pixelSize: 10
|
||||
color: Theme.palette.dangerColor1
|
||||
text: root.warningText
|
||||
text: root.nameCountLimit + " " + root.warningText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: contactsLabel
|
||||
font.pixelSize: 15
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.top: tagSelectorRect.bottom
|
||||
anchors.topMargin: visible ? 32 : 0
|
||||
height: visible ? contentHeight : 0
|
||||
visible: (root.sortedList.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.halfPadding
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 16//Style.current.padding
|
||||
}
|
||||
clip: true
|
||||
visible: ((edit.text === "") || (root.sortedList.count > 0))
|
||||
x: ((root.namesModel.count > 0) && (root.sortedList.count > 0) && ((edit.x + 8) <= (root.width - suggestionsContainer.width)))
|
||||
? (edit.x + 8) : 0
|
||||
background: Rectangle {
|
||||
id: bgRect
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
visible: (root.sortedList.count > 0)
|
||||
color: Theme.palette.statusPopupMenu.backgroundColor
|
||||
radius: 8
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
source: bgRect
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 4
|
||||
radius: 12
|
||||
samples: 25
|
||||
spread: 0.2
|
||||
color: Theme.palette.dropShadow
|
||||
}
|
||||
}
|
||||
contentItem: ListView {
|
||||
id: userListView
|
||||
anchors {
|
||||
fill: parent
|
||||
topMargin: 16
|
||||
leftMargin: 8
|
||||
rightMargin: 8
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
onCountChanged: {
|
||||
userListView.currentIndex = 0;
|
||||
}
|
||||
delegate: StatusMemberListItem {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: bgRect.visible ? 8 : 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: bgRect.visible ? 8 : 0
|
||||
height: visible ? 64 : 0
|
||||
visible: {
|
||||
for (let i = 0; i < namesModel.count; i++) {
|
||||
if (namesModel.get(i).publicId === model.publicId) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
nickName: model.nickName
|
||||
userName: model.name
|
||||
chatKey: root.compressedKeyGetter(model.publicId)
|
||||
trustIndicator: model.trustIndicator
|
||||
isMutualContact: model.isMutualContact
|
||||
image.source: model.icon
|
||||
image.isIdenticon: model.isIdenticon
|
||||
isOnline: model.onlineStatus
|
||||
statusListItemIcon.badge.border.color: sensor.containsMouse ? Theme.palette.baseColor2 : Theme.palette.baseColor4
|
||||
ringSettings.ringSpecModel: root.ringSpecModelGetter(publicId)
|
||||
color: (sensor.containsMouse || highlighted) ? Theme.palette.baseColor2 : "transparent"
|
||||
onClicked: {
|
||||
root.insertTag(model.name, model.publicId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,30 +7,114 @@ import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusToastMessage
|
||||
\inherits Control
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Displays a toast message in the UI. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-controls2-control.html}{Control}.
|
||||
|
||||
The \c StatusToastMessage displays a toast message in the UI either standalone or as part
|
||||
of a stack of toast messages.
|
||||
For example:
|
||||
|
||||
\qml
|
||||
StatusToastMessage {
|
||||
primaryText: qsTr("Collectible is being minted...")
|
||||
secondaryText: qsTr("View on Etherscan")
|
||||
loading: true
|
||||
type: 0
|
||||
linkUrl: "http://google.com"
|
||||
duration: 5000
|
||||
}
|
||||
\endqml
|
||||
|
||||
\image status_toast_message.png
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
|
||||
|
||||
Control {
|
||||
id: root
|
||||
width: 343
|
||||
height: !!secondaryText ? 68 : 48
|
||||
anchors.right: parent.right
|
||||
|
||||
property bool open: false
|
||||
/*!
|
||||
\qmlproperty bool StatusToastMessage::open
|
||||
This property represents all steps and their descriptions as provided by the user.
|
||||
*/
|
||||
property bool open: true
|
||||
/*!
|
||||
\qmlproperty string StatusToastMessage::primaryText
|
||||
This property represents the title text of the ToastMessage.
|
||||
*/
|
||||
property string primaryText: ""
|
||||
/*!
|
||||
\qmlproperty string StatusToastMessage::secondaryText
|
||||
This property represents the subtitle text of the ToastMessage.
|
||||
*/
|
||||
property string secondaryText: ""
|
||||
/*!
|
||||
\qmlproperty bool StatusToastMessage::loading
|
||||
This property represents activates/deactivates the loading indicator of the ToastMessage.
|
||||
*/
|
||||
property bool loading: false
|
||||
property string iconName: ""
|
||||
/*!
|
||||
\qmlproperty string StatusToastMessage::linkUrl
|
||||
This property represents all steps and their descriptions as provided by the user.
|
||||
*/
|
||||
property string linkUrl: ""
|
||||
|
||||
/*!
|
||||
\qmlproperty int StatusToastMessage::duration
|
||||
This property represents duration in milliseconds, for how long a toast will be visible. If 0 is set for
|
||||
duration, that means a toast won't dissapear without user's interaction (click on close).
|
||||
*/
|
||||
property int duration: 0
|
||||
|
||||
/*!
|
||||
\qmlproperty StatusIconSettings StatusToastMessage::icon
|
||||
This property holds a set of settings for the icon of the ToastMessage.
|
||||
*/
|
||||
property StatusIconSettings icon: StatusIconSettings {
|
||||
width: 23
|
||||
height: 23
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlproperty int StatusToastMessage::type
|
||||
This property holds the type of the ToastMessage. Values are:
|
||||
\list
|
||||
\li Default
|
||||
\li Success
|
||||
\endlist
|
||||
|
||||
*/
|
||||
property int type: StatusToastMessage.Type.Default
|
||||
enum Type {
|
||||
Default,
|
||||
Success
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod
|
||||
This function is used to open the ToastMessage setting all its properties.
|
||||
Examples of usage:
|
||||
\qml
|
||||
StatusToastMessage {
|
||||
id: toastMessage
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
toastMessage.open(qsTr("Verification Request Sent"), "", "checkmark-circle", 1, false,"");
|
||||
}
|
||||
}
|
||||
\endqml
|
||||
|
||||
*/
|
||||
function open(title, subTitle, iconName, type, loading, url) {
|
||||
root.primaryText = title;
|
||||
root.secondaryText = subTitle;
|
||||
@@ -41,12 +125,36 @@ Control {
|
||||
root.open = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when the ToastMessage is closed (after animation).
|
||||
*/
|
||||
signal close()
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when the ToastMessage contains a url and this url
|
||||
is clicked by the user.
|
||||
*/
|
||||
signal linkActivated(var link)
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property string openedState: "opened"
|
||||
readonly property string closedState: "closed"
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: root.duration
|
||||
running: root.duration > 0
|
||||
onTriggered: {
|
||||
root.open = false;
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "opened"
|
||||
name: d.openedState
|
||||
when: root.open
|
||||
PropertyChanges {
|
||||
target: root
|
||||
@@ -55,16 +163,13 @@ Control {
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "closed"
|
||||
name: d.closedState
|
||||
when: !root.open
|
||||
PropertyChanges {
|
||||
target: root
|
||||
anchors.rightMargin: -width
|
||||
opacity: 0.0
|
||||
}
|
||||
StateChangeScript {
|
||||
script: { root.close(); }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -72,6 +177,12 @@ Control {
|
||||
Transition {
|
||||
to: "*"
|
||||
NumberAnimation { properties: "anchors.rightMargin,opacity"; duration: 400 }
|
||||
|
||||
onRunningChanged: {
|
||||
if(!running && state == d.closedState) {
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -114,9 +225,14 @@ Control {
|
||||
radius: (root.width/2)
|
||||
color: (root.type === StatusToastMessage.Type.Success) ?
|
||||
Theme.palette.successColor2 : Theme.palette.primaryColor3
|
||||
visible: loader.sourceComponent != undefined
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.loading ? loadingInd : statusIcon
|
||||
sourceComponent: root.loading ? loadingInd :
|
||||
root.icon.name != ""? statusIcon :
|
||||
undefined
|
||||
|
||||
Component {
|
||||
id: loadingInd
|
||||
StatusLoadingIndicator {
|
||||
|
||||
@@ -6,10 +6,42 @@ import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusWizardStepper
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Displays a step sequence provided by the stepsModel. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}.
|
||||
|
||||
The \c StatusWizardStepper steps and their descriptions as provided by the stepsModel.
|
||||
For example:
|
||||
|
||||
\qml
|
||||
StatusWizardStepper {
|
||||
id: wizardStepper
|
||||
stepsModel: ListModel {
|
||||
ListElement {description: qsTr("Send Request"); loadingTime: 0; stepCompleted: false}
|
||||
ListElement {description: qsTr("Receive Response"); loadingTime: 0; stepCompleted: false}
|
||||
ListElement {description: qsTr("Confirm Identity"); loadingTime: 0; stepCompleted: false}
|
||||
}
|
||||
}
|
||||
\endqml
|
||||
|
||||
\image status_wizard_stepper.png
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
|
||||
Item {
|
||||
property int maxDuration: 2000
|
||||
|
||||
id: wizardWrapper
|
||||
width: parent.width
|
||||
height: 56
|
||||
/*!
|
||||
\qmlproperty ListModel StatusWizardStepper::stepsModel
|
||||
This property represents all steps and their descriptions as provided by the user.
|
||||
*/
|
||||
property ListModel stepsModel: ListModel { }
|
||||
|
||||
ListView {
|
||||
@@ -35,8 +67,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: -12
|
||||
from: 0
|
||||
//TODO what is to: here?
|
||||
to: 2000
|
||||
to: wizardWrapper.maxDuration
|
||||
value: loadingTime
|
||||
backgroundColor: "transparent"
|
||||
backgroundBorderColor: Theme.palette.primaryColor1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,6 +10,8 @@ StatusChatListCategoryItem 0.1 StatusChatListCategoryItem.qml
|
||||
StatusChatListAndCategories 0.1 StatusChatListAndCategories.qml
|
||||
StatusChatToolBar 0.1 StatusChatToolBar.qml
|
||||
StatusContactRequestsIndicatorListItem 0.1 StatusContactRequestsIndicatorListItem.qml
|
||||
StatusEmoji 0.1 StatusEmoji.qml
|
||||
StatusContactVerificationIcons 0.1 StatusContactVerificationIcons.qml
|
||||
StatusDescriptionListItem 0.1 StatusDescriptionListItem.qml
|
||||
StatusLetterIdenticon 0.1 StatusLetterIdenticon.qml
|
||||
StatusListItem 0.1 StatusListItem.qml
|
||||
@@ -22,6 +24,8 @@ 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
|
||||
StatusListPicker 0.1 StatusListPicker.qml
|
||||
StatusExpandableItem 0.1 StatusExpandableItem.qml
|
||||
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
|
||||
StatusMessage 0.1 StatusMessage.qml
|
||||
@@ -29,3 +33,4 @@ StatusMessageDetails 0.1 StatusMessageDetails.qml
|
||||
StatusTagSelector 0.1 StatusTagSelector.qml
|
||||
StatusToastMessage 0.1 StatusToastMessage.qml
|
||||
StatusWizardStepper 0.1 StatusWizardStepper.qml
|
||||
StatusImageCropPanel 0.1 StatusImageCropPanel.qml
|
||||
|
||||
@@ -55,7 +55,7 @@ Item {
|
||||
return
|
||||
}
|
||||
if (selectedAccount.color) {
|
||||
selectedIconImg.color = Utils.getThemeAccountColor(selectedAccount.color, Theme.palette.accountColors) || Theme.palette.accountColors[0]
|
||||
selectedIconImg.color = Utils.getThemeAccountColor(selectedAccount.color, Theme.palette.userCustomizationColors) || Theme.palette.userCustomizationColors[0]
|
||||
}
|
||||
if (selectedAccount.name) {
|
||||
selectedTextField.text = selectedAccount.name
|
||||
@@ -208,7 +208,7 @@ Item {
|
||||
width: 20
|
||||
height: 20
|
||||
icon: "filled-account"
|
||||
color: Utils.getThemeAccountColor(model.color, Theme.palette.accountColors) || Theme.palette.accountColors[0]
|
||||
color: Utils.getThemeAccountColor(model.color, Theme.palette.userCustomizationColors) || Theme.palette.userCustomizationColors[0]
|
||||
}
|
||||
|
||||
Column {
|
||||
|
||||
@@ -3,13 +3,61 @@ import QtQuick 2.14
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusBanner
|
||||
\inherits Column
|
||||
\inqmlmodule StatusQ.Controls
|
||||
\since StatusQ.Controls 0.1
|
||||
\brief It displays a banner with a custom text, size and type. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-column.html}{Column}.
|
||||
|
||||
The \c StatusBanner displays a banner with a custom text, size and type (Info, Danger, Success or Warning).
|
||||
|
||||
Example of how the control looks like:
|
||||
\image status_banner.png
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusBanner {
|
||||
width: parent.width
|
||||
visible: popup.userIsBlocked
|
||||
type: StatusBanner.Type.Danger
|
||||
statusText: qsTr("Blocked")
|
||||
}
|
||||
\endqml
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
Column {
|
||||
id: statusBanner
|
||||
width: parent.width
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusBanner::statusText
|
||||
This property holds the text the banner will display.
|
||||
*/
|
||||
property string statusText
|
||||
/*!
|
||||
\qmlproperty string StatusBanner::type
|
||||
This property holds type of banner. Possible values are:
|
||||
\qml
|
||||
enum Type {
|
||||
Info, // 0
|
||||
Danger, // 1
|
||||
Success, // 2
|
||||
Warning // 3
|
||||
}
|
||||
\endqml
|
||||
*/
|
||||
property int type: StatusBanner.Type.Info
|
||||
/*!
|
||||
\qmlproperty string StatusBanner::textPixels
|
||||
This property holds the pixels size of the text inside the banner.
|
||||
*/
|
||||
property int textPixels: 15
|
||||
/*!
|
||||
\qmlproperty string StatusBanner::statusBannerHeight
|
||||
This property holds the height of the banner rectangle.
|
||||
*/
|
||||
property int statusBannerHeight: 38
|
||||
|
||||
// "private" properties
|
||||
@@ -27,6 +75,8 @@ Column {
|
||||
Warning // 3
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
|
||||
// Component definition
|
||||
Rectangle {
|
||||
id: topDiv
|
||||
|
||||
@@ -40,11 +40,9 @@ Rectangle {
|
||||
return 5
|
||||
case StatusBaseButton.Size.Small:
|
||||
return 10
|
||||
break;
|
||||
case StatusBaseButton.Size.Large:
|
||||
default:
|
||||
return 11
|
||||
break;
|
||||
}
|
||||
}
|
||||
property real defaultBottomPadding: {
|
||||
@@ -53,11 +51,9 @@ Rectangle {
|
||||
return 5
|
||||
case StatusBaseButton.Size.Small:
|
||||
return 10
|
||||
break;
|
||||
case StatusBaseButton.Size.Large:
|
||||
default:
|
||||
return 11
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +105,17 @@ Rectangle {
|
||||
hoverEnabled: !loading
|
||||
enabled: !loading
|
||||
|
||||
|
||||
Loader {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
active: loading
|
||||
sourceComponent: StatusLoadingIndicator {
|
||||
color: statusBaseButton.enabled ? textColor
|
||||
: disabledTextColor
|
||||
} // Indicator
|
||||
} // Loader
|
||||
|
||||
Row {
|
||||
id: layout
|
||||
anchors.left: parent.left
|
||||
@@ -121,28 +128,20 @@ Rectangle {
|
||||
height: statusBaseButton.icon.height
|
||||
icon: statusBaseButton.icon.name
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !loading && statusBaseButton.icon.name !== ""
|
||||
opacity: !loading && statusBaseButton.icon.name !== ""
|
||||
visible: statusBaseButton.icon.name !== ""
|
||||
color: statusBaseButton.enabled ? textColor
|
||||
: disabledTextColor
|
||||
} // Icon
|
||||
StatusBaseText {
|
||||
id: label
|
||||
visible: !loading
|
||||
opacity: !loading
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: size === StatusBaseButton.Size.Large ? 15 : 13 // by design
|
||||
|
||||
color: statusBaseButton.enabled ? textColor
|
||||
: disabledTextColor
|
||||
} // Text
|
||||
|
||||
Loader {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
active: loading
|
||||
sourceComponent: StatusLoadingIndicator {
|
||||
color: statusBaseButton.enabled ? textColor
|
||||
: disabledTextColor
|
||||
} // Indicator
|
||||
} // Loader
|
||||
} // Ro
|
||||
|
||||
|
||||
|
||||
@@ -1,252 +1,470 @@
|
||||
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
|
||||
|
||||
/*!
|
||||
\qmltype StatusBaseInput
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Controls
|
||||
\since StatusQ.Controls 0.1
|
||||
\brief Displays a customized TextInput component.
|
||||
Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}.
|
||||
|
||||
The \c StatusBaseInput displays an enhanced TextInput for users to type text.
|
||||
For example:
|
||||
|
||||
\qml
|
||||
StatusBaseInput {
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
clearable: true
|
||||
placeholderText: qsTr("Search")
|
||||
icon.name: "search"
|
||||
}
|
||||
\endqml
|
||||
|
||||
\image status_base_input.png
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: statusBaseInput
|
||||
id: root
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::multiline
|
||||
This property indicates whether the StatusBaseInput allows multiline text. Default value is false.
|
||||
*/
|
||||
property bool multiline: false
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::acceptReturn
|
||||
This property indicates whether the StatusBaseInput allows pressing Enter or Return.
|
||||
This is used in case multiline is false and we still want to interact using Enter or Return. Default value is false.
|
||||
*/
|
||||
property bool acceptReturn: false
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::clearable
|
||||
This property indicates whether the StatusBaseInput allows clearing all text. Default value is false.
|
||||
*/
|
||||
property bool clearable: false
|
||||
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::inputMethodHints
|
||||
This property holds a reference to the TextEdit component's inputMethodHints property.
|
||||
*/
|
||||
property alias inputMethodHints: edit.inputMethodHints
|
||||
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::selectedText
|
||||
This property holds a reference to the TextEdit component's selectedText property.
|
||||
*/
|
||||
property alias selectedText: edit.selectedText
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::selectedTextColor
|
||||
This property holds a reference to the TextEdit component's selectedTextColor property.
|
||||
*/
|
||||
property alias selectedTextColor: edit.selectedTextColor
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::selectionStart
|
||||
This property holds a reference to the TextEdit component's selectionStart property.
|
||||
*/
|
||||
property alias selectionStart: edit.selectionStart
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::selectionEnd
|
||||
This property holds a reference to the TextEdit component's selectionEnd property.
|
||||
*/
|
||||
property alias selectionEnd: edit.selectionEnd
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::cursorPosition
|
||||
This property holds a reference to the TextEdit component's cursorPosition property.
|
||||
*/
|
||||
property alias cursorPosition: edit.cursorPosition
|
||||
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::edit
|
||||
This property holds a reference to the TextEdit component.
|
||||
*/
|
||||
property alias edit: edit
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::text
|
||||
This property holds a reference to the TextEdit component's text property.
|
||||
*/
|
||||
property alias text: edit.text
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::background
|
||||
This property holds a reference to the background component.
|
||||
*/
|
||||
property alias background: background
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::color
|
||||
This property holds a reference to the TextEdit component's color property.
|
||||
*/
|
||||
|
||||
property alias color: edit.color
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::font
|
||||
This property holds a reference to the TextEdit component's font property.
|
||||
*/
|
||||
property alias font: edit.font
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::focussed
|
||||
This property holds a reference to the TextEdit component's activeFocus property.
|
||||
*/
|
||||
property alias focussed: edit.activeFocus
|
||||
property alias verticalAlignmet: edit.verticalAlignment
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::verticalAlignment
|
||||
This property holds a reference to the TextEdit component's verticalAlignment property.
|
||||
*/
|
||||
property alias verticalAlignment: edit.verticalAlignment
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::horizontalAlignment
|
||||
This property holds a reference to the TextEdit component's horizontalAlignment property.
|
||||
*/
|
||||
property alias horizontalAlignment: edit.horizontalAlignment
|
||||
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::placeholderText
|
||||
This property holds a reference to the placeholder component's placeholderText property.
|
||||
*/
|
||||
property alias placeholderText: placeholder.text
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::placeholderTextColor
|
||||
This property holds a reference to the placeholder component's placeholderTextColor property.
|
||||
*/
|
||||
property alias placeholderTextColor: placeholder.color
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::placeholderFont
|
||||
This property holds a reference to the placeholder component's font property.
|
||||
*/
|
||||
property alias placeholderFont: placeholder.font
|
||||
|
||||
property real leftPadding: 16
|
||||
/*!
|
||||
\qmlproperty real StatusBaseInput::leftPadding
|
||||
This property sets the leftComponentLoader's left padding.
|
||||
*/
|
||||
property real leftPadding: leftComponentLoader.item ? 8 : 16
|
||||
/*!
|
||||
\qmlproperty real StatusBaseInput::rightPadding
|
||||
This property sets the right padding.
|
||||
*/
|
||||
property real rightPadding: 16
|
||||
/*!
|
||||
\qmlproperty real StatusBaseInput::topPadding
|
||||
This property sets the top padding.
|
||||
*/
|
||||
property real topPadding: 12
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::bottomPadding
|
||||
This property sets the bottom padding.
|
||||
*/
|
||||
property real bottomPadding: 12
|
||||
/*!
|
||||
\qmlproperty var StatusBaseInput::tabNavItem
|
||||
This property sets the tab key navigation item.
|
||||
*/
|
||||
property var tabNavItem: null
|
||||
|
||||
/*!
|
||||
\qmlproperty real StatusBaseInput::minimumHeight
|
||||
This property sets the minimum height.
|
||||
*/
|
||||
property real minimumHeight: 0
|
||||
/*!
|
||||
\qmlproperty alias StatusBaseInput::maximumHeight
|
||||
This property sets the maximum height.
|
||||
*/
|
||||
property real maximumHeight: 0
|
||||
/*!
|
||||
\qmlproperty int StatusBaseInput::maximumLength
|
||||
This property sets the text's maximum length.
|
||||
*/
|
||||
property int maximumLength: 0
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::valid
|
||||
This property sets the valid state. Default value is true.
|
||||
*/
|
||||
property bool valid: true
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::pristine
|
||||
This property sets the pristine. Default value is true.
|
||||
*/
|
||||
property bool pristine: true
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::dirty
|
||||
This property sets the dirty property. Default value is false.
|
||||
*/
|
||||
property bool dirty: false
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::pending
|
||||
This property holds the maximum height of the component. Default value is false.
|
||||
*/
|
||||
property bool pending: false
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::leftIcon
|
||||
This property sets the visibility of the left icon. Default value is true.
|
||||
*/
|
||||
property bool leftIcon: true
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::isIconSelectable
|
||||
This property indicates whether icon is selectable. Default value is false.
|
||||
*/
|
||||
property bool isIconSelectable: false
|
||||
/*!
|
||||
\qmlproperty bool StatusBaseInput::showBackground
|
||||
This property sets the visibility of the background. Default value is true.
|
||||
*/
|
||||
property bool showBackground: true
|
||||
|
||||
/*!
|
||||
\qmlproperty StatusIconSettings StatusBaseInput::icon
|
||||
This property holds a set of settings for the icon of the StatusBaseInput.
|
||||
*/
|
||||
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
|
||||
}
|
||||
}
|
||||
/*!
|
||||
\qmlproperty string StatusBaseInput::letterIconName
|
||||
This property holds the letter that should be displayed in the letter identicon component.
|
||||
*/
|
||||
property string letterIconName: ""
|
||||
/*!
|
||||
\qmlproperty Component StatusBaseInput::leftComponent
|
||||
This property sets the left component to be displayed inside the input.
|
||||
*/
|
||||
property Component leftComponent
|
||||
/*!
|
||||
\qmlproperty Component StatusBaseInput::selectedText
|
||||
This property sets the right component to be displayed inside the input.
|
||||
*/
|
||||
property Component rightComponent
|
||||
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when the icon is clicked.
|
||||
*/
|
||||
signal iconClicked
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when a hard key is pressed passing as parameter the keyboard event.
|
||||
*/
|
||||
signal keyPressed(var event)
|
||||
/*!
|
||||
\qmlsignal
|
||||
This signal is emitted when the text edit is clicked.
|
||||
*/
|
||||
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
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: {
|
||||
if (edit.activeFocus)
|
||||
return;
|
||||
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 {
|
||||
spacing: 10
|
||||
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 || root.icon.isLetterIdenticon) 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: TextEdit.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 && !acceptReturn
|
||||
Keys.onEnterPressed: event.accepted = !multiline && !acceptReturn
|
||||
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: {
|
||||
if (previousText === text) {
|
||||
// Not sure why, but the textChanged event was triggered even if it didn't really
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
cursorDelegate: Rectangle {
|
||||
color: Theme.palette.primaryColor1
|
||||
implicitWidth: 2
|
||||
implicitHeight: 22
|
||||
radius: 1
|
||||
visible: edit.cursorVisible
|
||||
|
||||
SequentialAnimation on visible {
|
||||
loops: Animation.Infinite
|
||||
running: edit.cursorVisible
|
||||
PropertyAnimation { to: false; duration: 600; }
|
||||
PropertyAnimation { to: true; duration: 600; }
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: placeholder
|
||||
visible: (edit.text.length === 0)
|
||||
anchors.fill: parent
|
||||
verticalAlignment: parent.verticalAlignment
|
||||
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 +478,43 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: identiconComponent
|
||||
|
||||
StatusSmartIdenticon {
|
||||
id: identicon
|
||||
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
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 : ""
|
||||
icon.isLetterIdenticon: root.icon.isLetterIdenticon
|
||||
name: root.letterIconName
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,10 @@ Rectangle {
|
||||
property StatusIconSettings icon: StatusIconSettings {
|
||||
width: 36
|
||||
height: 36
|
||||
letterSize: 20
|
||||
charactersLen: 2
|
||||
}
|
||||
property alias ringSettings: identicon.ringSettings
|
||||
|
||||
property int type: StatusChatInfoButton.Type.PublicChat
|
||||
property alias tooltip: statusToolTip
|
||||
property alias sensor: sensor
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ TabButton {
|
||||
property string name: ""
|
||||
property bool highlighted: false
|
||||
|
||||
property alias identicon: identicon
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
@@ -32,7 +34,6 @@ TabButton {
|
||||
icon.name: statusIconTabButton.icon.name
|
||||
icon.color: (statusIconTabButton.hovered || highlighted || statusIconTabButton.checked) ? Theme.palette.primaryColor1 : statusIconTabButton.icon.color
|
||||
icon.isLetterIdenticon: statusIconTabButton.name !== "" && !statusIconTabButton.icon.source.toString()
|
||||
icon.letterSize: 15
|
||||
name: statusIconTabButton.name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
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.rowCount !== "undefined") {
|
||||
return settings.ringSpecModel.rowCount()
|
||||
}
|
||||
if (typeof settings.ringSpecModel.count !== "undefined") {
|
||||
return settings.ringSpecModel.count
|
||||
}
|
||||
return settings.ringSpecModel.length
|
||||
}
|
||||
|
||||
function getSegment(i) {
|
||||
if (typeof settings.ringSpecModel.rowCount !== "undefined") {
|
||||
return abstactItemModelWrapper.itemAt(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)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: abstactItemModelWrapper
|
||||
model: typeof settings.ringSpecModel.rowCount !== "undefined" ? settings.ringSpecModel : null
|
||||
delegate: Item {
|
||||
readonly property int segmentLength: model.segmentLength
|
||||
readonly property int colorId: model.colorId
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.settings
|
||||
onRingSpecModelChanged: requestPaint()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
import QtQuick 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import QtGraphicalEffects 1.1
|
||||
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusImageCrop
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Controls
|
||||
\since StatusQ.Controls 0.1
|
||||
\brief Draw a crop-window onto an image. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}.
|
||||
|
||||
Sizing
|
||||
|
||||
User resizes the control as needed. Control adapts and centers the crop
|
||||
window inside the available space
|
||||
|
||||
Performance
|
||||
|
||||
The \c StatusImageCrop uses Canvas to draw the overlay in multiple steps.
|
||||
Drawing with canvas is inefficient therefore keep the usage to a minimum,
|
||||
as in the required space
|
||||
|
||||
API
|
||||
|
||||
The setCropRect is the only way to set the content shown in the crop window.
|
||||
|
||||
/note "Fit window" used here reffer to optimum zoom to fit all the content
|
||||
in the view window; produces window borders if AR of the image is different
|
||||
than the window. This ia opposite to "Fill window" reffers to optimum zoom
|
||||
to fill all the view; parts of the content won't be visible if AR of the
|
||||
image is different than the AR of window
|
||||
/note The math is based on pixels so no subpixel accuracy. Didn't find it necessary for the current needs
|
||||
/note windowRect aspect ratio and cropRect aspect ratio are keept in sync
|
||||
|
||||
Example of two controls; top WindowStyle.Rounded, bottom WindowStyle.Rectangular
|
||||
\image eg-StatusImageCrop.png
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusImageCrop {
|
||||
anchors.fill: parent
|
||||
|
||||
width: 100
|
||||
height: 100 * aspectRatio
|
||||
source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
windowStyle: StatusImageCrop.WindowStyle.Rounded
|
||||
}
|
||||
\endqml
|
||||
|
||||
For a list of components available see StatusQ.
|
||||
*/
|
||||
Item {
|
||||
id: root
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: 400 / aspectRatio
|
||||
|
||||
/*!
|
||||
\qmlproperty url StatusImageCrop::source
|
||||
Path to the image to be cropped
|
||||
*/
|
||||
/*required*/ property alias source: mainImage.source
|
||||
|
||||
enum WindowStyle {
|
||||
Rounded,
|
||||
Rectangular
|
||||
}
|
||||
/*!
|
||||
\qmlproperty WindowStyle StatusImageCrop::windowStyle
|
||||
Crop window styles
|
||||
\value Rounded ellipses bounded by cropRect rectangle
|
||||
\value Rectangular with rounded corners specified by radius
|
||||
*/
|
||||
property int windowStyle: StatusImageCrop.WindowStyle.Rectangular
|
||||
/*!
|
||||
\qmlproperty int StatusImageCrop::radius
|
||||
Valid only when windowStyle is Rounded
|
||||
*/
|
||||
property int radius: 8
|
||||
/*!
|
||||
\qmlproperty color StatusImageCrop::wallColor
|
||||
Color used outside the crop-rect. Tells user which part won't be available after cropping
|
||||
*/
|
||||
property color wallColor: Theme.palette.black
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::wallTransparency
|
||||
Transparency outside the crop-rect 0.0 - 1.0 (inclusive). Tells user which part won't
|
||||
be available after cropping
|
||||
*/
|
||||
property real wallTransparency: 0.7
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusImageCrop::allowZoomToFitAllContent
|
||||
|
||||
\c true to limit the content to fit at minimum zoom; that's it, the user will see the entire image
|
||||
in the crop window, in case of aspect-ratio mismatch, allowing transparent/no-content borders in the crop window.
|
||||
\c false to limit the content to fill at minimum zoom; that's it, the user will see only part of the image
|
||||
in the crop window in case of aspect-ratio mismatch. This way, we don't allow transparent/no-content space
|
||||
*/
|
||||
property bool allowZoomToFitAllContent: false
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::minZoomScale
|
||||
Minimum allowed zoom. This is 1 if \c allowZoomToFitAllContent is true else depends on the
|
||||
source aspect ratio.
|
||||
*/
|
||||
readonly property real minZoomScale: allowZoomToFitAllContent ? 1 : d.zoomToFill
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::maxZoomScale
|
||||
Don't allow to zoom in more than maxZoomScale factor
|
||||
*/
|
||||
property real maxZoomScale: 10
|
||||
|
||||
/*!
|
||||
\qmlproperty rect StatusImageCrop::cropRect
|
||||
The content shown in the crop window. Values are expected to be in image coordinates.
|
||||
The crop-window aspect-ratio is adjusted to match the cropRect value.
|
||||
The default value shows an 1.0 AR to Fit Window
|
||||
e.g. to set the crop window to show and match image's AR use Qt.rect(0, 0, sourceSize.width, sourceSize.height)
|
||||
*/
|
||||
readonly property rect cropRect: d.cropRect
|
||||
/*!
|
||||
\qmlproperty rect StatusImageCrop::cropRect
|
||||
|
||||
The position and zis of the crop rectangle in item's space; without extra spacing
|
||||
*/
|
||||
readonly property alias cropWindow: d.cropWindow
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::aspectRatio
|
||||
*/
|
||||
readonly property real aspectRatio: d.cropRect.height !== 0 ? d.cropRect.width/d.cropRect.height : 0
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::zoomScale
|
||||
*/
|
||||
readonly property real zoomScale: d.currentZoom(sourceSize, Qt.size(d.cropRect.width, d.cropRect.height))
|
||||
|
||||
/*!
|
||||
\qmlproperty size StatusImageCrop::sourceSize
|
||||
|
||||
Image size if one is set. StatusImageCrop::cropRect is relative to the rect with top-corner
|
||||
(0,0) and StatusImageCrop::sourceSize
|
||||
|
||||
\sa StatusImageCrop::source
|
||||
*/
|
||||
readonly property size sourceSize: mainImage.sourceSize
|
||||
/*!
|
||||
\qmlproperty real StatusImageCrop::scrToImgScale
|
||||
|
||||
Screen crop window to \a cropRect ratio. Can be used to translate from
|
||||
screen coordinates into image coordinates e.g. to adjust \a cropRect accordingly
|
||||
|
||||
\note windowRect aspect-ratio and d.cropRect aspect-ratio are the same
|
||||
\sa StatusImageCrop::cropRect
|
||||
*/
|
||||
readonly property real scrToImgScale: windowRect.wW/d.cropRect.width
|
||||
|
||||
/*!
|
||||
\qmlmethod StatusImageCrop::setCropRect(rect)
|
||||
|
||||
The only way to set StatusImageCrop::cropRect from outside
|
||||
|
||||
The new rect will be adjusted to account for the zoom [1, StatusImageCrop::maxZoomScale]
|
||||
|
||||
\note the source image must be set and \c sourceSize valid otherwise, an error is logged to \c console
|
||||
\note If the new rect has a diferent area the crop window will adjust to the new AR
|
||||
*/
|
||||
function setCropRect(newRect /*rect*/) {
|
||||
if(newRect.width === 0 || newRect.height === 0)
|
||||
return
|
||||
if(root.sourceSize.width === 0 || root.sourceSize.height === 0)
|
||||
console.error("Wrong source size. Ensure source is set")
|
||||
|
||||
let n = newRect
|
||||
const s = root.sourceSize
|
||||
let nZoom = d.currentZoom(s, Qt.size(n.width, n.height))
|
||||
if(nZoom > root.maxZoomScale) {
|
||||
nZoom = root.maxZoomScale
|
||||
n = root.getZoomRect(nZoom)
|
||||
}
|
||||
else if(nZoom < root.minZoomScale) {
|
||||
nZoom = root.minZoomScale
|
||||
n = root.getZoomRect(nZoom)
|
||||
}
|
||||
|
||||
// Limit panning
|
||||
if((n.width/n.height) < (s.width/s.height)) {
|
||||
// Crop window narrower than source
|
||||
if(n.x < 0)
|
||||
n.x = 0
|
||||
const upBoundY = n.height > s.height ? s.height - n.height : 0
|
||||
if(n.y < upBoundY)
|
||||
n.y = upBoundY
|
||||
if((n.x + n.width) > s.width)
|
||||
n.x = s.width - n.width
|
||||
const loBoundY = n.height > s.height ? 0 : s.height - n.height
|
||||
if(n.y > loBoundY)
|
||||
n.y = loBoundY
|
||||
}
|
||||
else {
|
||||
// Crop window wider than source
|
||||
const leftBoundX = n.width > s.width ? s.width - n.width : 0
|
||||
if(n.x < leftBoundX)
|
||||
n.x = leftBoundX
|
||||
if(n.y < 0)
|
||||
n.y = 0
|
||||
const rightBoundY = n.width > s.width ? 0 : s.width - n.width
|
||||
if(n.x > rightBoundY)
|
||||
n.x = rightBoundY
|
||||
if((n.y + n.height) > s.height)
|
||||
n.y = s.height - n.height
|
||||
}
|
||||
d.cropRect = n
|
||||
}
|
||||
|
||||
function getZoomRect(scale /*real*/) {
|
||||
const oldCenter = root.rectCenter(root.cropRect)
|
||||
const inflatedRect = root.inflateRectBy(root.minimumCropRect(), 1/scale)
|
||||
return root.recenterRect(inflatedRect, oldCenter);
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod StatusImageCrop::inflateRectBy(rect target, real scale)
|
||||
Inflates the curren \a target rectangle with the \a scale while keeping the center fixed
|
||||
*/
|
||||
function inflateRectBy(target /*rect*/, scale /*real*/) {
|
||||
const inflatedWidth = target.width * scale
|
||||
const inflatedHeight = target.height * scale
|
||||
return Qt.rect(target.x - (inflatedWidth - target.width)/2, target.y - (inflatedHeight - target.height)/2, inflatedWidth, inflatedHeight)
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod StatusImageCrop::rectCenter(rect target)
|
||||
Returns the center point of the \a target rectangle as a Qt.point
|
||||
*/
|
||||
function rectCenter(target /*rect*/) /*Qt.point*/ {
|
||||
return Qt.point(target.x + target.width/2, target.y + target.height/2)
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod StatusImageCrop::recenterRect(rect target)
|
||||
Move the \a target rectangle's center to a /a newCenter
|
||||
*/
|
||||
function recenterRect(target /*rect*/, newCenter/*point*/) {
|
||||
return Qt.rect(newCenter.x - target.width/2 , newCenter.y - target.height/2, target.width, target.height)
|
||||
}
|
||||
|
||||
//> cropRect for minimum zoom: 1.0
|
||||
function minimumCropRect() {
|
||||
const sourceAR = root.sourceSize.width/root.sourceSize.height
|
||||
const widthBound = sourceAR > root.aspectRatio
|
||||
const minCropSize = widthBound ? Qt.size(root.sourceSize.width, root.sourceSize.width/root.aspectRatio)
|
||||
: Qt.size(root.sourceSize.height * root.aspectRatio, root.sourceSize.height)
|
||||
let res = Qt.rect(widthBound ? 0 : -(root.sourceSize.width - minCropSize.width)/2, // x
|
||||
widthBound ? -(root.sourceSize.height - minCropSize.height)/2 : 0, // y
|
||||
minCropSize.width, minCropSize.height)
|
||||
return res
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
property rect cropRect: fillContentInSquaredWindow(root.sourceSize)
|
||||
onCropRectChanged: windowRect.requestPaint()
|
||||
|
||||
readonly property real zoomToFill: {
|
||||
const rectangle = fillContentInSquaredWindow(root.sourceSize)
|
||||
return d.currentZoom(root.sourceSize, Qt.size(rectangle.width, rectangle.height))
|
||||
}
|
||||
|
||||
property rect cropWindow
|
||||
// Probably called from render thread, run async
|
||||
signal updateCropWindow(rect newRect)
|
||||
onUpdateCropWindow: cropWindow = newRect
|
||||
|
||||
function fillContentInSquaredWindow(c /*size*/) {
|
||||
if(c.width > c.height) {
|
||||
const border = (c.width - c.height)/2
|
||||
return Qt.rect(border, 0, c.height, c.height)
|
||||
}
|
||||
else {
|
||||
const border = (c.height - c.width)/2
|
||||
return Qt.rect(0, border, c.width, c.width)
|
||||
}
|
||||
}
|
||||
|
||||
//> 1.0 is the content represented by w fully inscribed in c
|
||||
function currentZoom(c /*size*/, w /*size*/) {
|
||||
const wScale = c.width/w.width
|
||||
const hScale = c.height/w.height
|
||||
return Math.max(wScale, hScale)
|
||||
}
|
||||
}
|
||||
|
||||
onWindowStyleChanged: windowRect.requestPaint()
|
||||
onSourceSizeChanged: d.cropRect = d.fillContentInSquaredWindow(sourceSize)
|
||||
|
||||
Canvas {
|
||||
id: windowRect
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
layer.enabled: true
|
||||
|
||||
property bool widthFit: (root.width / root.aspectRatio) <= root.height
|
||||
// Window width
|
||||
property real wW: widthFit ? root.width : root.height * root.aspectRatio
|
||||
// Window height
|
||||
property real wH: widthFit ? root.width / root.aspectRatio : root.height
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
ctx.save()
|
||||
// TODO: observed drawing artefacts at the edge. Draw one pixel more for now until root cause is found
|
||||
ctx.clearRect(0, 0, width + 1, height + 1)
|
||||
// Fill all with wallColor in order to clip the window from it
|
||||
ctx.fillStyle = Qt.rgba(root.wallColor.r, root.wallColor.g, root.wallColor.b, root.wallTransparency)
|
||||
ctx.fillRect(0, 0, width + 1, height + 1)
|
||||
// Cut opaque new pixels from background
|
||||
ctx.globalCompositeOperation = "source-out"
|
||||
// Draw the window
|
||||
ctx.beginPath()
|
||||
const cW = Qt.rect((width - wW)/2, (height - wH)/2, wW, wH)
|
||||
if(root.windowStyle === StatusImageCrop.WindowStyle.Rounded)
|
||||
ctx.ellipse(cW.x, cW.y, cW.width, cW.height)
|
||||
else if(root.windowStyle === StatusImageCrop.WindowStyle.Rectangular)
|
||||
ctx.roundedRect(cW.x, cW.y, cW.width, cW.height, root.radius, root.radius)
|
||||
ctx.fill()
|
||||
ctx.restore()
|
||||
d.updateCropWindow(cW)
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: mainImage
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
z: windowRect.z - 1
|
||||
|
||||
// Transform to keep the center of the image window in x and y coordinates
|
||||
transform: [
|
||||
Translate {
|
||||
readonly property real s: mainImage.scale
|
||||
x: -(d.cropRect.x + d.cropRect.width/2)
|
||||
y: -(d.cropRect.y + d.cropRect.height/2)
|
||||
},
|
||||
Scale {
|
||||
xScale: root.scrToImgScale
|
||||
yScale: root.scrToImgScale
|
||||
}
|
||||
]
|
||||
// Align window center to window rect
|
||||
x: windowRect.x + windowRect.width/2
|
||||
y: windowRect.y + windowRect.height/2
|
||||
}
|
||||
}
|
||||