Compare commits

..
Author SHA1 Message Date
Alexandra Betouni d924768892 fix(Components/StatusTagSelector): Updates and fixes in the component
Moved `remove` function below remove contact signal
also removed online status badge from CreateChatView

Fixed as well name tags to be adapting on parent's
width and scrolling the list to the end when this is
bigger than the available width. Switcehd to use
nameCountLimit property where needed
2022-02-21 23:37:46 +02:00
10147 changed files with 442 additions and 23045 deletions
-17
View File
@@ -1,17 +0,0 @@
### 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)
+1 -4
View File
@@ -13,7 +13,4 @@ Makefile
*_qml.cpp
*_qmlcache.qrc
sandbox/qmlcache_loader.cpp
doc/html
CMakeLists.txt.user
.vscode
build/
doc/html
-29
View File
@@ -1,32 +1,3 @@
<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)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

+1 -44
View File
@@ -4,7 +4,6 @@ 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
@@ -65,12 +64,6 @@ 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"
@@ -329,43 +322,6 @@ 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"
@@ -412,6 +368,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
ListElement {colorId: 28; segmentLength: 3}
}
ringSettings.distinctiveColors: Theme.palette.identiconRingColors
ringSettings.totalRingUnits: 25
}
StatusMemberListItem {
-41
View File
@@ -78,11 +78,6 @@ Column {
onClicked: editTitleModal.open()
}
StatusButton {
text: "Modal with Advanced Header/Footer"
onClicked: advancedHeaderFooterModal.open()
}
StatusModal {
id: simpleModal
anchors.centerIn: parent
@@ -358,42 +353,6 @@ 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"}
+154 -7
View File
@@ -1,6 +1,8 @@
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
@@ -26,19 +28,33 @@ Page {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: 17
maxHeight: root.height
implicitHeight: 44
toLabelText: qsTr("To: ")
warningText: qsTr("USER LIMIT REACHED")
listLabel: qsTr("Contacts")
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: {
sortModel(root.contactsModel);
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;
}
}
} else {
userListView.model = contactsModel;
}
}
Component.onCompleted: { sortModel(root.contactsModel); }
}
StatusButton {
implicitHeight: 44
Layout.alignment: Qt.AlignTop
enabled: (tagSelector.namesModel.count > 0)
text: "Confirm"
}
@@ -46,7 +62,138 @@ Page {
contentItem: Item {
anchors.fill: parent
anchors.topMargin: 68
anchors.topMargin: headerRow.height + 16
Item {
anchors.fill: parent
visible: (contactsModel.count > 0)
StatusBaseText {
id: contactsLabel
font.pixelSize: 15
anchors.left: parent.left
anchors.leftMargin: 8
color: Theme.palette.baseColor1
text: qsTr("Contacts")
}
Control {
width: 360
anchors {
top: contactsLabel.bottom
topMargin: 8//Style.current.padding
bottom: !statusPopupMenuBackgroundContent.visible ? parent.bottom : undefined
bottomMargin: 20//Style.current.bigPadding
}
height: 16 + (!statusPopupMenuBackgroundContent.visible ? parent.height :
(((userListView.count * 64) > parent.height) ? parent.height : (userListView.count * 64)))
x: (statusPopupMenuBackgroundContent.visible && (tagSelector.namesModel.count > 0) &&
((tagSelector.textEdit.x + 24 + statusPopupMenuBackgroundContent.width) < parent.width))
? (tagSelector.textEdit.x + 24) : 0
background: Rectangle {
id: statusPopupMenuBackgroundContent
anchors.fill: parent
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.fill: parent
anchors.topMargin: 8
anchors.bottomMargin: 8
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.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
}
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();
}
}
}
StatusBaseText {
visible: (contactsModel.count === 0)
@@ -268,6 +268,7 @@ StatusAppThreePanelLayout {
isOnline: model.isOnline
ringSettings.ringSpecModel: model.ringSpecModel
ringSettings.distinctiveColors: Theme.palette.identiconRingColors
ringSettings.totalRingUnits: model.totalRingUnits
}
}
}
+3
View File
@@ -903,6 +903,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
isIdenticon: true
totalRingUnits: 25
ringSpecModel: [ ListElement {colorId: 13; segmentLength: 5},
ListElement {colorId: 31; segmentLength: 5},
ListElement {colorId: 10; segmentLength: 1},
@@ -931,6 +932,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzXUQpAQBRGYWQvLNAyLJDV8C5qpiGnv/M9al5Ot27X0IUwhMYQGkNoDKGJCRlLH67bftx9X+ap/+P9VcxEDK
ExhKZ4a9Uq3TZviZmIITSG0DRvlqcbqVbrlouZiCE0htD4h0hjCI0hNN5aNIbQGKKPxEzEEBpDaAyhMYTmDAAA//+gYCErzmCpCQAAAABJRU5ErkJggg=="
isIdenticon: true
totalRingUnits: 25
ringSpecModel: [ ListElement {colorId: 11; segmentLength: 1},
ListElement {colorId: 23; segmentLength: 5},
ListElement {colorId: 23; segmentLength: 5},
@@ -948,6 +950,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
isOnline: false
source: ""
isIdenticon: false
totalRingUnits: 25
ringSpecModel: [ ListElement {colorId: 0; segmentLength: 1},
ListElement {colorId: 28; segmentLength: 1},
ListElement {colorId: 31; segmentLength: 1},
-5
View File
@@ -293,11 +293,6 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusColorSelectorGrid"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
}
}
}
@@ -1,36 +0,0 @@
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
}
}
+1 -83
View File
@@ -57,33 +57,6 @@ Column {
input.clearable: true
}
Item {
implicitWidth: 480
implicitHeight: 102
z: 100000
StatusSeedPhraseInput {
id: statusSeedInput
anchors.left: parent.left
anchors.right: parent.right
textEdit.input.anchors.leftMargin: 16
textEdit.input.anchors.rightMargin: 16
textEdit.input.anchors.topMargin: 11
textEdit.label: "Input with drop down selection list"
leftComponentText: "1"
inputList: ListModel {
ListElement {
seedWord: "panda"
}
ListElement {
seedWord: "posible"
}
ListElement {
seedWord: "wing"
}
}
}
}
StatusInput {
label: "Label"
charLimit: 30
@@ -129,24 +102,10 @@ 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.rightComponent: StatusIcon {
input.component: StatusIcon {
icon: "cancel"
height: 16
color: Theme.palette.dangerColor1
@@ -171,45 +130,4 @@ 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
}
}
+1 -1
View File
@@ -51,6 +51,6 @@ Item {
anchors.centerIn: parent
namesModel: root.asortedContacts
toLabelText: qsTr("To: ")
warningText: qsTr("USER LIMIT REACHED")
warningText: qsTr("5 USER LIMIT REACHED")
}
}
+3 -9
View File
@@ -1,10 +1,4 @@
#!/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
qmake sandbox.pro -spec macx-clang CONFIG+=debug CONFIG+=x86_64 && /usr/bin/make qmake_all
make
+2 -3
View File
@@ -15,7 +15,7 @@ Column {
width: 288
property string categoryId: ""
property var model: null
property var model: []
property bool draggableItems: false
property alias statusChatListItems: statusChatListItems
@@ -97,12 +97,11 @@ Column {
chatId: model.itemId
categoryId: model.parentItemId? model.parentItemId : ""
name: model.name
icon.emoji: model.emoji
type: !!model.type ? model.type : StatusChatListItem.Type.CommunityChat
muted: model.muted
hasUnreadMessages: model.hasUnreadMessages
notificationsCount: model.notificationsCount
highlightWhenCreated: !!model.highlight
highlightWhenCreated: model.highlight
selected: model.active
icon.color: model.color
image.isIdenticon: model.isIdenticon
@@ -48,6 +48,7 @@ Column {
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6);
return
}
statusChatListCategory.opened = !opened;
}
}
onTitleClicked: statusChatListCategory.opened = !opened
@@ -5,7 +5,6 @@ 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
@@ -29,10 +28,7 @@ Rectangle {
width: 24
height: 24
color: Theme.palette.miscColor5
letterSize: emoji ? 11 : 15
emoji: ""
emojiSize: Emoji.size.verySmall
charactersLen: 1
letterSize: 15
}
property int type: StatusChatListItem.Type.PublicChat
property bool highlighted: false
@@ -14,7 +14,6 @@ StatusListItem {
components: [
StatusBadge {
visible: statusContactRequestsListItem.requestsCount > 0
value: statusContactRequestsListItem.requestsCount
anchors.verticalCenter: parent.verticalCenter
border.width: 4
@@ -12,7 +12,6 @@ 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
@@ -186,7 +185,7 @@ Rectangle {
anchors.leftMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Primary) ? 48 : 0
anchors.right: parent.right
anchors.rightMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Primary) ? 16 : 0
visible: false
active: false
}
onExpandedChanged: {
@@ -203,13 +202,13 @@ Rectangle {
name: "EXPANDED"
PropertyChanges {target: expandImage; icon: "chevron-up"}
PropertyChanges {target: statusExpandableItem; height: 82 + expandableRegion.height + 22}
PropertyChanges {target: expandableRegion; visible: true}
PropertyChanges {target: expandableRegion; active: true}
},
State {
name: "COLLAPSED"
PropertyChanges {target: expandImage; icon: "chevron-down"}
PropertyChanges {target: statusExpandableItem; height: 82}
PropertyChanges {target: expandableRegion; visible: false}
PropertyChanges {target: expandableRegion; active: false}
}
]
@@ -1,17 +1,13 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
Rectangle {
id: root
id: statusLetterIdenticon
property alias identiconText: identiconText
property string name
property string emoji
property string emojiSize
property int letterSize: 21
property int charactersLen: 1
color: Theme.palette.miscColor5
width: 40
@@ -20,30 +16,15 @@ Rectangle {
StatusBaseText {
id: identiconText
anchors.alignWhenCentered: false
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
height: parent.height
text: ((statusLetterIdenticon.name.charAt(0) === "#")
|| (statusLetterIdenticon.name.charAt(0) === "@") ?
statusLetterIdenticon.name.charAt(1) : statusLetterIdenticon.name.charAt(0)).toUpperCase()
font.weight: Font.Bold
font.pixelSize: root.letterSize
font.pixelSize: statusLetterIdenticon.letterSize
color: Qt.rgba(255, 255, 255, 0.7)
text: {
if (emoji) {
if(Utils.isHtml(emoji))
return emoji
else
return Emoji.parse(emoji, emojiSize || undefined)
}
const shift = (root.name.charAt(0) === "#") ||
(root.name.charAt(0) === "@")
return root.name.substring(shift, shift + charactersLen).toUpperCase()
}
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
+8 -60
View File
@@ -20,13 +20,8 @@ Rectangle {
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
@@ -34,7 +29,6 @@ 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 {
@@ -57,9 +51,9 @@ Rectangle {
isIdenticon: false
}
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
totalRingUnits: 1
initalAngleRad: 0
ringPxSize: 1.5
distinctiveColors: Theme.palette.identiconRingColors
}
property alias sensor: sensor
@@ -72,8 +66,6 @@ Rectangle {
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)
@@ -85,12 +77,7 @@ Rectangle {
}
implicitWidth: 448
implicitHeight: {
if (bottomModel.length === 0) {
return Math.max(64, statusListItemTitleArea.height + 16)
}
return Math.max(64, statusListItemTitleArea.height + 90)
}
implicitHeight: Math.max(64, statusListItemTitleArea.height + 16)
color: {
if (sensor.containsMouse || statusListItem.highlighted) {
switch(type) {
@@ -157,10 +144,9 @@ Rectangle {
anchors.left: iconOrImage.active ? iconOrImage.right : parent.left
anchors.right: statusListItemLabel.visible ? statusListItemLabel.left : statusListItemComponentsSlot.left
anchors.leftMargin: iconOrImage.active ? 16 : statusListItem.leftPadding
anchors.leftMargin: statusListItem.leftPadding
anchors.rightMargin: statusListItem.rightPadding
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.verticalCenter: parent.verticalCenter
height: childrenRect.height
StatusBaseText {
@@ -171,8 +157,6 @@ Rectangle {
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
anchors.left: parent.left
anchors.right: !statusListItem.titleAsideText && !titleIconsRow.sourceComponent ? parent.right : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 20
color: {
if (!statusListItem.enabled) {
return Theme.palette.baseColor1
@@ -189,10 +173,9 @@ Rectangle {
MouseArea {
anchors.fill: parent
enabled: statusListItem.enabled
cursorShape: sensor.enabled && containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
cursorShape: containsMouse? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
propagateComposedEvents: statusListItem.propagateTitleClicks
propagateComposedEvents: true
onClicked: {
statusListItem.titleClicked(statusListItem.titleId)
mouse.accepted = false
@@ -205,8 +188,6 @@ 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
@@ -250,42 +231,11 @@ 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: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 16
anchors.verticalCenter: parent.verticalCenter
anchors.right: statusListItemComponentsSlot.left
anchors.rightMargin: statusListItemComponentsSlot.width > 0 ? 10 : 0
@@ -299,9 +249,7 @@ Rectangle {
id: statusListItemComponentsSlot
anchors.right: parent.right
anchors.rightMargin: statusListItem.rightPadding
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 12
anchors.verticalCenter: parent.verticalCenter
spacing: 10
}
}
@@ -57,8 +57,6 @@ 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
@@ -1,81 +0,0 @@
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()
}
}
}
}
}
@@ -15,7 +15,6 @@ Loader {
property StatusIconSettings icon: StatusIconSettings {
width: 40
height: 40
charactersLen: 1
}
property StatusImageSettings image: StatusImageSettings {
@@ -24,9 +23,9 @@ Loader {
}
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
totalRingUnits: 1
initalAngleRad: 0
ringPxSize: 1.5
distinctiveColors: Theme.palette.identiconRingColors
}
sourceComponent: statusSmartIdenticon.icon.isLetterIdenticon ? letterIdenticon :
@@ -84,11 +83,7 @@ Loader {
height: statusSmartIdenticon.icon.height
color: statusSmartIdenticon.icon.color
name: statusSmartIdenticon.name
emoji: statusSmartIdenticon.icon.emoji
emojiSize: statusSmartIdenticon.icon.emojiSize
letterSize: statusSmartIdenticon.icon.letterSize
identiconText.color: statusSmartIdenticon.icon.textColor
charactersLen: statusSmartIdenticon.icon.charactersLen
}
}
+5 -153
View File
@@ -1,7 +1,6 @@
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
@@ -10,18 +9,13 @@ Item {
id: root
implicitWidth: 448
implicitHeight: 44 + ((userListView.count > 0) ? 44 + ((((userListView.count * 64) > root.maxHeight)
? root.maxHeight : (userListView.count * 64))) :0)
implicitHeight: 44
property real maxHeight
property alias textEdit: edit
property alias text: edit.text
property string warningText: ""
property string toLabelText: ""
property string listLabel: ""
property int nameCountLimit: 5
property ListModel sortedList: ListModel { }
property ListModel namesModel: ListModel { }
function find(model, criteria) {
@@ -37,30 +31,11 @@ Item {
}
}
function sortModel(inputModel) {
sortedList.clear();
if (text !== "") {
for (var i = 0; i < inputModel.count; i++ ) {
var entry = inputModel.get(i);
if (entry.name.toLowerCase().includes(text.toLowerCase())) {
sortedList.insert(sortedList.count, {"publicId": entry.publicId, "name": entry.name,
"icon": entry.icon, "isIdenticon": entry.isIdenticon,
"onlineStatus": entry.onlineStatus});
userListView.model = sortedList;
}
}
} else {
userListView.model = inputModel;
}
}
signal addMember(string memberId)
signal removeMember(string memberId)
Rectangle {
id: tagSelectorRect
width: parent.width
height: 44
anchors.fill: parent
radius: 8
color: Theme.palette.baseColor2
@@ -77,8 +52,7 @@ Item {
}
ScrollView {
Layout.preferredWidth: (namesList.contentWidth > (parent.width - 142)) ?
(parent.width - 142) : namesList.contentWidth
Layout.fillWidth: true
implicitHeight: 30
Layout.alignment: Qt.AlignVCenter
visible: (namesList.count > 0)
@@ -92,8 +66,8 @@ Item {
model: namesModel
orientation: ListView.Horizontal
spacing: 8
onCountChanged: {
contentX = contentWidth;
onContentWidthChanged: {
positionViewAtEnd();
}
delegate: Rectangle {
id: nameDelegate
@@ -160,126 +134,4 @@ Item {
}
}
}
StatusBaseText {
id: contactsLabel
font.pixelSize: 15
anchors.left: parent.left
anchors.leftMargin: 8
anchors.top: tagSelectorRect.bottom
anchors.topMargin: 32
visible: (namesModel.count === 0)
color: Theme.palette.baseColor1
text: root.listLabel
}
Control {
id: suggestionsContainer
width: 360
anchors {
top: (root.sortedList.count > 0) ? tagSelectorRect.bottom : contactsLabel.bottom
topMargin: 8//Style.current.padding
bottom: parent.bottom
bottomMargin: 20//Style.current.bigPadding
}
visible: ((root.namesModel.count === 0) || (root.sortedList.count > 0))
x: ((root.namesModel.count > 0) && ((edit.x + 8) <= (root.width - suggestionsContainer.width)))
? (edit.x + 8) : 0
background: Rectangle {
id: bgRect
anchors.fill: parent
visible: (root.sortedList.count > 0)
color: Theme.palette.statusPopupMenu.backgroundColor
radius: 8
layer.enabled: true
layer.effect: DropShadow {
width: bgRect.width
height: bgRect.height
x: bgRect.x
source: bgRect
horizontalOffset: 0
verticalOffset: 4
radius: 12
samples: 25
spread: 0.2
color: Theme.palette.dropShadow
}
}
contentItem: ListView {
id: userListView
anchors.fill: parent
anchors.topMargin: 8
anchors.bottomMargin: 8
clip: true
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
boundsBehavior: Flickable.StopAtBounds
delegate: Item {
id: wrapper
anchors.right: parent.right
anchors.left: parent.left
height: 64
property bool hovered: false
Rectangle {
id: rectangle
anchors.fill: parent
anchors.rightMargin: 8
anchors.leftMargin: 8
radius: 8
visible: (root.sortedList.count > 0)
color: (wrapper.hovered) ? Theme.palette.baseColor2 : "transparent"
}
StatusSmartIdenticon {
id: contactImage
anchors.left: parent.left
anchors.leftMargin: 16//Style.current.padding
anchors.verticalCenter: parent.verticalCenter
name: model.name
icon: StatusIconSettings {
width: 40
height: 40
letterSize: 15
}
image: StatusImageSettings {
width: 40
height: 40
source: model.icon
isIdenticon: model.isIdenticon
}
}
StatusBaseText {
id: contactInfo
text: model.name
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: contactImage.right
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
color: Theme.palette.directColor1
font.weight: Font.Medium
font.pixelSize: 15
}
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
onEntered: {
wrapper.hovered = true;
}
onExited: {
wrapper.hovered = false;
}
onClicked: {
root.insertTag(model.name, model.publicId);
}
}
}
}
}
}
-1
View File
@@ -23,7 +23,6 @@ StatusRoundIcon 0.1 StatusRoundIcon.qml
StatusRoundedImage 0.1 StatusRoundedImage.qml
StatusMacWindowButtons 0.1 StatusMacWindowButtons.qml
StatusListItemBadge 0.1 StatusListItemBadge.qml
StatusListItemTag 0.1 StatusListItemTag.qml
StatusExpandableItem 0.1 StatusExpandableItem.qml
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
StatusMessage 0.1 StatusMessage.qml
+150 -189
View File
@@ -1,15 +1,14 @@
import QtQuick 2.14
import QtQuick.Controls 2.14 as QC
import QtQuick.Layouts 1.14
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
id: statusBaseInput
property bool multiline: false
@@ -25,7 +24,6 @@ Item {
property alias edit: edit
property alias text: edit.text
property alias background: background
property alias color: edit.color
property alias font: edit.font
@@ -37,11 +35,10 @@ Item {
property alias placeholderTextColor: placeholder.color
property alias placeholderFont: placeholder.font
property real leftPadding: leftComponentLoader.item ? 8 : 16
property real leftPadding: 16
property real rightPadding: 16
property real topPadding: 12
property real bottomPadding: 12
property var tabNavItem: null
property real minimumHeight: 0
property real maximumHeight: 0
@@ -52,64 +49,56 @@ Item {
property bool dirty: false
property bool pending: false
property bool leftIcon: true
property bool isIconSelectable: false
property bool showBackground: true
property StatusIconSettings icon: StatusIconSettings {
width: 24
height: 24
name: ""
color: Theme.palette.baseColor1
emoji: ""
letterSize: emoji ? 11 : 14
background: StatusIconBackgroundSettings {
width: 30
height: 30
color: Theme.palette.indirectColor1
}
property Item component
onClearableChanged: {
if (clearable && !component) {
clearButtonLoader.active = true
clearButtonLoader.parent = statusBaseInputComponentSlot
} else {
clearButtonLoader.active = false
}
}
property Component leftComponent
property Component rightComponent
signal iconClicked
signal keyPressed(var event)
signal editClicked()
onComponentChanged: {
if (!!component) {
component.parent = statusBaseInputComponentSlot
}
}
implicitWidth: 448
implicitHeight: multiline ? Math.min(Math.max(
(edit.implicitHeight + topPadding + bottomPadding),
44, root.minimumHeight), root.maximumHeight) : 44
implicitHeight: multiline ? Math.max((edit.implicitHeight + topPadding + bottomPadding), 44) : 44
Rectangle {
id: background
width: parent.width
height: maximumHeight != 0 ? Math.min(
minimumHeight
!= 0 ? Math.max(
root.implicitHeight,
minimumHeight) : root.implicitHeight,
maximumHeight) : parent.height
color: root.showBackground ? Theme.palette.baseColor2
: "transparent"
minimumHeight != 0 ? Math.max(statusBaseInput.implicitHeight, minimumHeight)
: statusBaseInput.implicitHeight, maximumHeight) : parent.height
color: Theme.palette.baseColor2
radius: 8
clip: true
border.width: 1
border.color: {
if (!root.showBackground) {
return "transparent"
}
if (!root.valid && root.dirty) {
return Theme.palette.dangerColor1
if (!statusBaseInput.valid && statusBaseInput.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
@@ -118,138 +107,146 @@ Item {
cursorShape: Qt.IBeamCursor
onClicked: {
edit.forceActiveFocus()
root.editClicked()
}
RowLayout {
anchors {
fill: parent
leftMargin: root.leftPadding
rightMargin: root.rightPadding
}
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
}
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
Loader {
id: leftComponentLoader
sourceComponent: {
if (root.leftComponent) return root.leftComponent
if (!root.leftIcon) return undefined
if (root.icon.emoji) return identiconComponent
if (root.icon.name) return isIconSelectable ? identiconComponent : iconComponent
return undefined
}
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;
}
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
}
TextEdit {
id: edit
property string previousText: text
property var keyEvent
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
wrapMode: root.multiline ? Text.WrapAtWordBoundaryOrAnywhere : TextEdit.NoWrap
Keys.onReturnPressed: event.accepted = !multiline
Keys.onEnterPressed: event.accepted = !multiline
Keys.forwardTo: [root]
KeyNavigation.priority: !!root.tabNavItem ? KeyNavigation.BeforeItem : KeyNavigation.AfterItem
KeyNavigation.tab: root.tabNavItem
Keys.onPressed: {
edit.keyEvent = event.key
root.keyPressed(event);
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
}
}
onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
onActiveFocusChanged: if (root.pristine) root.pristine = false
onTextChanged: {
root.dirty = true
if (root.maximumLength > 0) {
if (text.length > root.maximumLength) {
var cursor = cursorPosition
text = previousText
if (cursor > text.length) {
cursorPosition = text.length
} else {
cursorPosition = cursor - 1
}
Keys.onReturnPressed: {
if (multiline) {
event.accepted = false
} else {
event.accepted = true
}
}
Keys.onEnterPressed: {
if (multiline) {
event.accepted = false
} else {
event.accepted = true
}
}
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: root.rightPadding
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name
color: root.enabled ? Theme.palette.baseColor1 : Theme.palette.directColor6
previousText = text
}
}
} // 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
StatusBaseText {
id: placeholder
visible: (edit.text.length === 0)
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: statusBaseInput.rightPadding
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name
color: statusBaseInput.enabled ? Theme.palette.baseColor1 :
Theme.palette.directColor6
}
}
} // Flickable
Item {
id: statusBaseInputComponentSlot
anchors.right: parent.right
anchors.rightMargin: 12
width: childrenRect.width
height: childrenRect.height
anchors.verticalCenter: parent.verticalCenter
}
}
} // Rectangle
Component {
id: clearButton
StatusFlatRoundButton {
visible: edit.text.length != 0 && root.clearable && !root.multiline
&& edit.activeFocus
Loader {
id: clearButtonLoader
sourceComponent: StatusFlatRoundButton {
id: clearButton
visible: edit.text.length != 0 &&
statusBaseInput.clearable &&
!statusBaseInput.multiline &&
edit.activeFocus
type: StatusFlatRoundButton.Type.Secondary
width: 24
height: 24
@@ -263,41 +260,5 @@ Item {
}
}
Component {
id: identiconComponent
StatusSmartIdenticon {
id: identicon
icon.width: !root.icon.emoji ? 20 : 30
icon.height: !root.icon.emoji ? 20 : 30
icon.background: root.icon.background
icon.color: root.icon.color
icon.letterSize: root.icon.letterSize
icon.emoji: root.icon.emoji
icon.name: !root.icon.emoji ? root.icon.name : ""
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
enabled: identicon.visible
onClicked: root.iconClicked()
}
}
}
Component {
id: iconComponent
StatusIcon {
id: statusIcon
icon: root.icon.name
width: root.icon.width
height: root.icon.height
color: root.icon.color
}
}
}
@@ -1,32 +0,0 @@
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
}
}
}
@@ -1,56 +0,0 @@
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]
}
}
}
}
}
}
+37 -61
View File
@@ -22,6 +22,7 @@ import StatusQ.Core 0.1
StatusIdenticonRing {
anchors.fill: parent
settings: StatusIdenticonRingSettings {
totalRingUnits: 25
initalAngleRad: 0
ringPxSize: 1.5
ringSpecModel: [ ListElement {colorId: 0; segmentLength: 1},
@@ -51,80 +52,55 @@ import StatusQ.Core 0.1
For a list of components available see StatusQ.
*/
Item {
id: root
id: identiconRing
/*!
\qmlproperty StatusIdenticonRingSettings StatusIdenticonRing::settings
This property holds a set of settings for building the ring.
*/
property StatusIdenticonRingSettings settings: StatusIdenticonRingSettings {
totalRingUnits: 1
initalAngleRad: 0
ringPxSize: 1.5
}
/*!
\qmlproperty real StatusIdenticonRing::segmentRadLen
This property holds the total ring line length in radians. It depends on totalRingUnits value of settings object.
*/
readonly property real segmentRadLen: 2 * Math.PI / settings.totalRingUnits
visible: settings.ringSpecModel !== undefined
Loader {
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()
}
anchors.fill: parent
active: root.visible
sourceComponent: Canvas {
function printArcSegment(context, xPos, yPos, radius, color, startAngle, arcAngleLen, lineWidth) {
context.beginPath()
context.arc(xPos, yPos, radius, startAngle, startAngle + arcAngleLen, false/*anticlockwise*/)
context.strokeStyle = color
context.lineWidth = lineWidth
context.stroke()
}
function getSegmentsCount() {
if (typeof settings.ringSpecModel.count !== "undefined") {
return settings.ringSpecModel.count
}
return settings.ringSpecModel.length
}
function getSegment(i) {
if (typeof settings.ringSpecModel.count !== "undefined") {
return settings.ringSpecModel.get(i)
}
return settings.ringSpecModel[i]
}
function totalRingUnits() {
var units = 0
for (let i=0; i < getSegmentsCount(); i++) {
const segment = getSegment(i)
units += segment.segmentLength
}
return Math.max(1, units)
}
onPaint: {
const context = getContext("2d")
const radius = (height - settings.ringPxSize) / 2
const xPos = width / 2
const yPos = height / 2
const unitRadLen = 2 * Math.PI / totalRingUnits()
const segmentsCount = getSegmentsCount()
let arcPos = settings.initalAngleRad
context.reset()
if(settings.ringSpecModel) {
for (let i=0; i < segmentsCount; i++) {
const segment = getSegment(i)
printArcSegment(context,
xPos,
yPos,
radius,
settings.distinctiveColors[segment.colorId],
arcPos,
segment.segmentLength * unitRadLen,
settings.ringPxSize)
arcPos += segment.segmentLength * unitRadLen
}
onPaint: {
const context = getContext("2d")
const radius = (height - settings.ringPxSize) / 2
const xPos = width / 2
const yPos = height / 2
let arcPos = settings.initalAngleRad
context.reset()
if(settings.ringSpecModel) {
for (let i=0; i<settings.ringSpecModel.count; i++) {
const segment = settings.ringSpecModel.get(i)
printArcSegment(context,
xPos,
yPos,
radius,
settings.distinctiveColors[segment.colorId],
arcPos,
segment.segmentLength * identiconRing.segmentRadLen,
settings.ringPxSize)
arcPos += segment.segmentLength * identiconRing.segmentRadLen
}
}
}
+15 -124
View File
@@ -6,71 +6,27 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
/*!
\qmltype StatusInput
\inherits Item
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief The StatusInput control provides a generic user text input
Example of how to use it:
\qml
StatusInput {
label: "Label"
charLimit: 30
errorMessage: "Input doesn't match validator"
input.clearable: true
input.placeholderText: "Placeholder text"
}
\endqml
For a list of components available see StatusQ.
*/
Item {
id: root
implicitWidth: 480
implicitHeight: (label.visible ?
label.anchors.topMargin +
label.height :
charLimitLabel.visible ?
charLimitLabel.anchors.topMargin +
charLimitLabel.height :
0) +
statusBaseInput.anchors.topMargin +
statusBaseInput.height +
(errorMessage.visible ?
errorMessage.anchors.topMargin +
errorMessage.height :
0) + 8
height: implicitHeight
width: implicitWidth
height: (label.visible ?
label.anchors.topMargin +
label.height :
charLimitLabel.visible ?
charLimitLabel.anchors.topMargin +
charLimitLabel.height :
0) +
statusBaseInput.anchors.topMargin +
statusBaseInput.height +
(errorMessage.visible ?
errorMessage.anchors.topMargin +
errorMessage.height :
0) + 8
property alias input: statusBaseInput
property alias valid: statusBaseInput.valid
property alias pending: statusBaseInput.pending
property alias text: statusBaseInput.text
/*!
\qmlproperty errorMessageCmp
This property represents the errorMessage shown on statusInput in cases one of the validators fails
This can be used to control the error message's look and position from the outside.
Examples of usage
\qml
StatusInput {
errorMessageCmp.font.pixelSize: 15
errorMessageCmp.font.weight: Font.Medium
}
\endqml
*/
property alias errorMessageCmp: errorMessage
property string label: ""
property string secondaryLabel: ""
property int charLimit: 0
@@ -79,73 +35,27 @@ Item {
property real rightPadding: 16
property list<StatusValidator> validators
property list<StatusAsyncValidator> asyncValidators
/*!
\qmlproperty int (enumeration ValidationMode)
This property describes the validation mode
Note that this property should be always strictly compared with one of ValidationMode's value
Default value: StatusInput.ValidationMode.OnlyWhenDirty
Examples of usage
> To ignore invalid input
\qml
StatusInput {
validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
validators: [
StatusMinLengthValidator {
minLength: 15
}
]
}
\endqml
*/
property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty
property string validatedValue
property var pendingValidators: []
signal iconClicked()
signal keyPressed(var event)
signal editClicked()
/*!
\qmltype ValidationMode
\brief Available validation modes supported by StatusInput
Values:
- OnlyWhenDirty validates input only after it has become dirty
- Always validates input even before it has become dirty
- IgnoreInvalidInput ignore the new content if it doesn't match validators
Has no effect without at least a validator
\note that it represents a QML enumeration and can't be used as a property type, we use int instead
\see validationMode for a usage example
\see validators
*/
enum ValidationMode {
OnlyWhenDirty, // validates input only after it has become dirty
Always, // validates input even before it has become dirty
IgnoreInvalidInput // ignore the new content if it doesn't match
Always // validates input even before it has become dirty
}
property var errors: ({})
property var asyncErrors: ({})
function reset() {
statusBaseInput.valid = true
statusBaseInput.valid = false
statusBaseInput.pristine = true
statusBaseInput.text = ""
root.errorMessage = ""
}
property string _previousText: text
function validate() {
if (!statusBaseInput.dirty && validationMode === StatusInput.ValidationMode.OnlyWhenDirty) {
return
}
@@ -175,23 +85,11 @@ Item {
if (errors){
let errs = Object.values(errors)
if (errs && errs[0]) {
if(validationMode === StatusInput.ValidationMode.IgnoreInvalidInput
&& text.length > _previousText.length) {
// Undo the last input
const cursor = statusBaseInput.cursorPosition;
statusBaseInput.text = _previousText;
if (statusBaseInput.cursor > statusBaseInput.text.length) {
statusBaseInput.cursorPosition = statusBaseInput.text.length;
} else {
statusBaseInput.cursorPosition = cursor-1;
}
}
errorMessage.text = errs[0].errorMessage || root.errorMessage;
} else {
errorMessage.text = ""
}
}
_previousText = text
}
if (asyncValidators.length && !Object.values(errors).length) {
@@ -291,13 +189,6 @@ Item {
onTextChanged: root.validate()
Keys.forwardTo: [root]
onIconClicked: root.iconClicked()
onKeyPressed: {
root.keyPressed(event);
}
onEditChanged: {
root.editClicked();
}
}
StatusBaseText {
@@ -15,23 +15,16 @@ StatusProgressBar {
property string labelGreat: "Great"
enum Strength {
None, // 0
VeryWeak, // 1
Weak, // 2
SoSo, // 3
Good, // 4
Great // 5
VeryWeak, // 0
Weak, // 1
SoSo, // 2
Good, // 3
Great // 4
}
onValueChanged: if(value === 0) control.strength = StatusPasswordStrengthIndicator.Strength.None
// Behavior:
states: [
// Strength states definition:
State {
when: control.strength === StatusPasswordStrengthIndicator.Strength.None
PropertyChanges { target: control; text: ""}
},
State {
when: control.strength === StatusPasswordStrengthIndicator.Strength.VeryWeak
PropertyChanges { target: control; fillColor : Theme.palette.dangerColor1}
@@ -1,141 +0,0 @@
import QtQuick 2.12
import QtGraphicalEffects 1.13
import QtQuick.Controls 2.12
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item {
id: root
width: 162
height: 44
property alias textEdit: seedWordInput
property alias text: seedWordInput.text
property string leftComponentText: ""
property ListModel inputList: ListModel { }
property ListModel filteredList: ListModel { }
signal doneInsertingWord(string word)
signal keyPressed(var event)
signal editClicked()
onActiveFocusChanged: {
if (root.activeFocus) {
seedWordInput.input.edit.forceActiveFocus();
}
}
StatusInput {
id: seedWordInput
implicitWidth: parent.width
implicitHeight: parent.height
input.anchors.topMargin: 0
input.anchors.leftMargin: 0
input.anchors.rightMargin: 0
input.leftComponent: StatusBaseText {
text: root.leftComponentText
color: seedWordInput.input.edit.activeFocus ?
Theme.palette.primaryColor1 : Theme.palette.baseColor1
font.pixelSize: 15
}
onTextChanged: {
filteredList.clear();
if (text !== "") {
for (var i = 0; i < inputList.count;i++) {
if (inputList.get(i).seedWord.startsWith(text)) {
filteredList.insert(filteredList.count, {"seedWord": inputList.get(i).seedWord});
}
}
seedSuggestionsList.model = filteredList;
if ((text.length === 3) && (filteredList.count === 1) &&
((input.edit.keyEvent !== Qt.Key_Backspace) && (input.edit.keyEvent !== Qt.Key_Delete))) {
seedWordInput.text = filteredList.get(0).seedWord;
seedWordInput.input.edit.cursorPosition = seedWordInput.text.length;
seedSuggestionsList.model = 0;
root.doneInsertingWord(seedWordInput.text);
}
} else {
seedSuggestionsList.model = 0;
}
}
onKeyPressed: {
root.keyPressed(event);
}
onEditClicked: {
root.editClicked();
}
}
Item {
id: suggListContainer
width: seedSuggestionsList.width
height: (((seedSuggestionsList.count <= 5) ? seedSuggestionsList.count : 5) *34) + 16
anchors.left: parent.left
anchors.leftMargin: 16
anchors.top: seedWordInput.bottom
anchors.topMargin: 4
visible: ((seedSuggestionsList.count > 0) && seedWordInput.input.edit.activeFocus)
Rectangle {
id: statusPopupMenuBackgroundContent
anchors.fill: parent
color: Theme.palette.statusPopupMenu.backgroundColor
radius: 8
layer.enabled: true
layer.effect: DropShadow {
anchors.fill: parent
source: statusPopupMenuBackgroundContent
horizontalOffset: 0
verticalOffset: 4
radius: 12
samples: 25
spread: 0.2
color: Theme.palette.dropShadow
}
}
ListView {
id: seedSuggestionsList
width: ((seedSuggestionsList.contentItem.childrenRect.width + 24) > root.width) ? root.width
: (seedSuggestionsList.contentItem.childrenRect.width + 24)
anchors.top: parent.top
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
clip: true
ScrollBar.vertical: ScrollBar { }
delegate: Item {
id: txtDelegate
width: suggWord.contentWidth
height: 34
Rectangle {
width: seedSuggestionsList.width
height: parent.height
color: mouseArea.containsMouse? Theme.palette.primaryColor1 : "transparent"
}
StatusBaseText {
id: suggWord
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: seedWord
color: mouseArea.containsMouse ? Theme.palette.indirectColor1 : Theme.palette.directColor1
font.pixelSize: 13
elide: Text.ElideRight
}
MouseArea {
id: mouseArea
width: seedSuggestionsList.width
height: parent.height
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
seedWordInput.text = seedWord;
seedWordInput.input.edit.cursorPosition = seedWordInput.text.length;
root.doneInsertingWord(seedWordInput.text);
seedSuggestionsList.model = 0;
}
}
}
}
}
}
@@ -1,170 +0,0 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusTokenInlineSelector
\inherits RowLayout
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief It presents selectable tokens in inline form.
The \c StatusTokenInlineSelector is a graphical component that is meant to be used as inline text input.
Example of how the component looks like:
\image status_token_inline_selector.png
*/
RowLayout {
id: root
/*!
\qmlproperty var StatusTokenInlineSelector::tokens
This is a REQUIRED property that contains an array of objects that describes each token.
\qml
tokens: [{amount: 0.1, token: "ETH"}, {amount: 10, token: "SNT"}]
\endqml
*/
property var tokens
/*!
\qmlproperty var StatusTokenInlineSelector::tokenImageSourceGetter
This is a property function used to acquire image source for given token.
*/
property var tokenImageSourceGetter: function (token) {
return "../../assets/img/icons/%1.png".arg(token)
}
signal triggered(real amount, string token)
StatusBaseText {
text: qsTr("Hold")
color: Theme.palette.directColor6
font.pixelSize: 15
}
Repeater {
model: Math.max(0, root.tokens.length - 1)
delegate: Loader {
sourceComponent: tokenComponent
onLoaded: d.assignItemProperties(item, index, root.tokens[index])
}
}
StatusBaseText {
text: qsTr("or")
color: Theme.palette.directColor6
font.pixelSize: 15
}
Loader {
active: root.tokens.length > 1
sourceComponent: tokenComponent
onLoaded: {
const index = root.tokens.length - 1
d.assignItemProperties(item, index, root.tokens[index])
}
}
StatusBaseText {
text: qsTr("to post")
color: Theme.palette.directColor6
font.pixelSize: 15
}
QtObject {
id: d
function assignItemProperties(item, index, modelData) {
item.tokenImageSource = root.tokenImageSourceGetter(modelData.token)
item.token = modelData.token
item.amount = modelData.amount
item.backgroundColor = Qt.binding(() => index % 2 ? Theme.palette.primaryColor3 : Theme.palette.dangerColor3)
item.hoverColor = Qt.binding(() => index % 2 ? Theme.palette.primaryColor2 : Theme.palette.dangerColor2)
item.textColor = Qt.binding(() => index % 2 ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1)
}
}
Component {
id: tokenComponent
Rectangle {
property string amount
property string token
property string tokenImageSource
property color backgroundColor
property color hoverColor
property color textColor
width: content.width + 4
height: content.height + 4
radius: height/2
color: mouseArea.containsMouse ? hoverColor : backgroundColor
Behavior on color {
ColorAnimation {
}
}
RowLayout {
id: content
anchors.centerIn: parent
StatusRoundedImage {
id: roundedImage
Layout.maximumHeight: text.height + 2
Layout.maximumWidth: text.height + 2
image.source: tokenImageSource
}
StatusBaseText {
id: text
text: amount + " " + token
color: textColor
font.pixelSize: 15
}
Item {
implicitWidth: 2
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
propagateComposedEvents: true
}
Rectangle {
id: pressIndicator
height: parent.height
radius: height / 2
color: textColor
opacity: 0.1
NumberAnimation on width {
from: 0
to: parent.width
duration: 800
running: mouseArea.containsPress
onStopped: {
if (pressIndicator.width == parent.width) {
root.triggered(amount, token)
}
pressIndicator.width = 0
}
}
}
}
}
}
@@ -1,57 +0,0 @@
import QtQuick 2.14
import StatusQ.Controls 0.1
/*!
\qmltype StatusFloatValidator
\inherits StatusValidator
\inqmlmodule StatusQ.Controls.Validators
\since StatusQ.Controls.Validators 0.1
\brief The StatusFloatValidator.qml type provides a validator for float values.
The \c StatusFloatValidator type provides a validator for float values.
Example of how to use it:
\qml
StatusFloatValidator {
bottom: 0
top: 1.25
errorMessage: qsTr("This is an invalid numeric value")
}
\endqml
For a list of components available see StatusQ.
*/
StatusValidator {
id: root
/*!
\qmlproperty string StatusFloatValidator::bottom
This property holds the validator's lowest acceptable value. By default, this property's value is derived from the lowest signed float available (typically -2147483647).
*/
property real bottom
/*!
\qmlproperty string StatusFloatValidator::locale
This property holds the name of the locale used to interpret the number.
*/
property string locale
/*!
\qmlproperty string StatusFloatValidator::top
This property holds the validator's highest acceptable value. By default, this property's value is derived from the highest float available (typically 2147483647).
*/
property real top
name: "floatValidator"
errorMessage: "Please enter a valid numeric value."
validate: function (t) {
return !isNaN(t) && t > bottom && t <= top ? true : {
bottom: bottom,
top: top,
actual: t
}
}
}
@@ -50,11 +50,11 @@ StatusValidator {
property var regularExpression
name: "regex"
errorMessage: `Must match regex(${validatorObj.regularExpression.toString()})`
errorMessage: "Please enter a valid regular expression."
validatorObj: RegularExpressionValidator { regularExpression: root.regularExpression }
validate: function (value) {
validate: function (t) {
// Basic validation management
return root.validatorObj.regularExpression.test(value)
return root.validatorObj.validate() === RegularExpressionValidator.Acceptable
}
}
-1
View File
@@ -10,4 +10,3 @@ StatusMaxLengthValidator 0.1 StatusMaxLengthValidator.qml
StatusRegularExpressionValidator 0.1 StatusRegularExpressionValidator.qml
StatusUrlValidator 0.1 StatusUrlValidator.qml
StatusValidator 0.1 StatusValidator.qml
StatusFloatValidator 0.1 StatusFloatValidator.qml
-3
View File
@@ -31,8 +31,5 @@ StatusPasswordStrengthIndicator 0.1 StatusPasswordStrengthIndicator.qml
StatusSwitchTabButton 0.1 StatusSwitchTabButton.qml
StatusSwitchTabBar 0.1 StatusSwitchTabBar.qml
StatusSelectableText 0.1 StatusSelectableText.qml
StatusTokenInlineSelector 0.1 StatusTokenInlineSelector.qml
StatusWalletColorButton 0.1 StatusWalletColorButton.qml
StatusWalletColorSelect 0.1 StatusWalletColorSelect.qml
StatusColorSelectorGrid 0.1 StatusColorSelectorGrid.qml
StatusSeedPhraseInput 0.1 StatusSeedPhraseInput.qml
-4
View File
@@ -8,14 +8,10 @@ QtObject {
property real width
property real height
property color color
property color textColor: Qt.rgba(255, 255, 255, 0.7)
property color disabledColor
property url source
property int rotation
property bool isLetterIdenticon
property int letterSize
property int charactersLen: 1
property string emoji
property string emojiSize
property StatusIconBackgroundSettings background: StatusIconBackgroundSettings {}
}
@@ -14,15 +14,29 @@ import StatusQ.Core 0.1
\qml
StatusIdenticonRingSettings {
totalRingUnits: 25
initalAngleRad: 0
ringPxSize: 1.5
ringSpecModel: [ {colorId: 0; segmentLength: 1},
{colorId: 5; segmentLength: 1},
{colorId: 1; segmentLength: 1},
{colorId: 1; segmentLength: 4},
{colorId: 2; segmentLength: 3} ]
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" ]
"#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
@@ -33,18 +47,10 @@ QtObject {
/*!
\qmlproperty ListModel StatusIdenticonRingSettings::ringSpecModel
This is a REQUIRED property that contains a ListModel or array of objects that describes each ring segment color and length.
Examples:
\qml
ringSpecModel: ListModel {ListElement{colorId: 0; segmentLength: 1} ListElement{colorId: 1; segmentLength: 2}}
\endqml
\qml
ringSpecModel: [{colorId: 0, segmentLength: 1}, {colorId: 1, segmentLength: 2}]
\endqml
This is a REQUIRED property that contains a ListModel object that describes each ring segment color and length.
Example of use: [ListElement {colorId: 0; segmentLength: 1}, ...]
*/
property var ringSpecModel
property ListModel ringSpecModel
/*!
\qmlproperty var StatusIdenticonRingSettings::distinctiveColors
@@ -52,6 +58,12 @@ QtObject {
*/
property var distinctiveColors
/*!
\qmlproperty real StatusIdenticonRingSettings::totalRingUnits
This property provides the total number of units the identicon ring is composed by.
*/
property real totalRingUnits
/*!
\qmlproperty real StatusIdenticonRingSettings::initalAngleRad
This property provides the initial angle, in radians, the identicon ring will start rendering the line.
-120
View File
@@ -1,120 +0,0 @@
pragma Singleton
import QtQuick 2.13
//import shared.status 1.0
import "../../../assets/twemoji/twemoji.js" as Twemoji
import "./emojiList.js" as EmojiJSON
QtObject {
readonly property var size: {
"veryBig": "86x86",
"big": "72x72",
"middle": "32x32",
"small": "18x18",
"verySmall": "16x16"
}
property string base: Qt.resolvedUrl("../../../assets/twemoji/")
function parse(text, renderSize = size.small) {
const renderSizes = renderSize.split("x");
if (!renderSize.includes("x") || renderSizes.length !== 2) {
throw new Error("Invalid value for 'renderSize' parameter: ", renderSize);
}
Twemoji.twemoji.base = base
Twemoji.twemoji.ext = ".svg"
Twemoji.twemoji.size = "svg"
return Twemoji.twemoji.parse(text, {
attributes: function() {
return {
width: renderSizes[0],
height: renderSizes[1],
style: "vertical-align: top"
}
}
})
}
function fromCodePoint(value) {
return Twemoji.twemoji.convert.fromCodePoint(value)
}
function deparse(value) {
// /StatusQ/src/assets/twemoji/
return value.replace(/<img src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" alt=\"(.+?)\" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g, "$1");
}
function deparseFromParse(value) {
return value.replace(/<img class=\"emoji\" draggable=\"false\" alt=\"(.+?)\" src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g, "$1");
}
function hasEmoji(value) {
let match = value.match(/<img src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" alt=\"(.+?)\" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g)
return match && match.length > 0
}
function nbEmojis(value) {
let match = value.match(/<img src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" alt=\"(.+?)\" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g)
return match ? match.length : 0
}
function getEmojis(value) {
return value.match(/<img class=\"emoji\" draggable=\"false\" alt=\"(.+?)\" src=\"qrc:\/StatusQ\/src\/assets\/twemoji\/.+?" width=\"[0-9]*\" height=\"[0-9]*\" style=\"(.+?)\" ?\/>/g, "$1");
}
function getEmojiUnicode(shortname) {
var _emoji;
EmojiJSON.emoji_json.forEach(function(emoji) {
if (emoji.shortname === shortname)
_emoji = emoji;
})
if (_emoji !== undefined)
return _emoji.unicode;
return undefined;
}
function getEmojiCodepoint(iconCodePoint) {
// Split the codepoint to get all the parts and then encode them from hex to utf8
const splitCodePoint = iconCodePoint.split('-')
let codePointParts = []
splitCodePoint.forEach(function (codePoint) {
codePointParts.push(`0x${codePoint}`)
})
return String.fromCodePoint(...codePointParts);
}
function getShortcodeFromId(emojiId) {
switch (emojiId) {
case 1: return ":heart:"
case 2: return ":thumbsup:"
case 3: return ":thumbsdown:"
case 4: return ":laughing:"
case 5: return ":cry:"
case 6: return ":angry:"
default: return undefined
}
}
function getEmojiFromId(emojiId) {
let shortcode = Emoji.getShortcodeFromId(emojiId)
let emojiUnicode = Emoji.getEmojiUnicode(shortcode)
if (emojiUnicode) {
return Emoji.fromCodePoint(emojiUnicode)
}
return undefined
}
function getRandomEmoji() {
var randomEmoji = EmojiJSON.emoji_json[Math.floor(Math.random() * EmojiJSON.emoji_json.length)]
const extenstionIndex = randomEmoji.unicode.lastIndexOf('.');
let iconCodePoint = randomEmoji.unicode
if (extenstionIndex > -1) {
iconCodePoint = iconCodePoint.substring(0, extenstionIndex)
}
// Split the unicode to get all the parts and then encode them from hex to utf8
const splitCodePoint = iconCodePoint.split('-')
let codePointParts = []
splitCodePoint.forEach(function (codePoint) {
codePointParts.push(`0x${codePoint}`)
})
const encodedIcon = String.fromCodePoint(...codePointParts);
return Emoji.parse(encodedIcon) + ' '
}
}
-4
View File
@@ -70,10 +70,6 @@ QtObject {
}
return strNumber.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1')
}
function isHtml(text) {
return (/<\/?[a-z][\s\S]*>/i.test(text))
}
}
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -1,5 +1,4 @@
module StatusQ.Core.Utils
EmojiJSON 1.0 emojiList.js
singleton Utils 0.1 Utils.qml
singleton Emoji 0.1 Emoji.qml
+2 -183
View File
@@ -5,186 +5,19 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import "statusModal" as Spares
/*!
\qmltype StatusModal
\inherits Popup
\inqmlmodule StatusQ.Popups
\since StatusQ.Popups 0.1
\brief The StatusModal provides a template for creating Modals.
Example of how to use it:
\qml
StatusModal {
anchors.centerIn: parent
header.title: "Some Title"
header.subTitle: "Subtitle"
headerActionButton: StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
width: 32
height: 32
icon.width: 20
icon.height: 20
icon.name: "info"
}
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
]
rightButtons: [
StatusButton {
text: "Button"
},
StatusButton {
text: "Button"
}
]
}
\endqml
For a list of components available see StatusQ.
*/
QC.Popup {
id: statusModal
/*!
\qmlproperty advancedHeader
This property represents the item loaded in header loader.
Can be used to read values from the component assigned to the loader.
\endqml
*/
property alias advancedHeader: advancedHeader.item
/*!
\qmlproperty advancedHeader
This property represents the item loaded in footer loader.
Can be used to read values from the component assigned to the loader.
\endqml
*/
property alias advancedFooter: advancedFooter.item
/*!
\qmlproperty advancedHeader
This property can be used to assign a Component to the advanced loader.
This was introduced to give more control to user on the Modal Header
example usage below
\qml
StatusModal {
id: advancedHeaderFooterModal
anchors.centerIn: parent
showHeader: false
showAdvancedHeader: true
advancedHeaderComponent: Rectangle {
width: parent.width
height: 50
color: Theme.palette.baseColor1
border.width: 1
StatusBaseText {
anchors.centerIn: parent
text: "Add any header here"
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
\endqml
*/
property alias advancedHeaderComponent: advancedHeader.sourceComponent
/*!
\qmlproperty advancedHeader
This property can be used to assign a Component to the advanced loader.
This was introduced to give more control to user on the Modal Footer.
example usage below
\qml
StatusModal {
id: advancedHeaderFooterModal
anchors.centerIn: parent
showFooter: false
showAdvancedFooter: true
advancedFooterComponent: Rectangle {
width: parent.width
height: 50
color: Theme.palette.baseColor1
border.width: 1
StatusBaseText {
anchors.centerIn: parent
text: "Add any footer here"
font.pixelSize: 15
color: Theme.palette.directColor1
}
}
\endqml
*/
property alias advancedFooterComponent: advancedFooter.sourceComponent
/*!
\qmlproperty headerActionButton
This property lets the user add a button to the header of the Modal.
This does not apply to the advanced header!
\endqml
*/
property alias headerActionButton: headerImpl.actionButton
/*!
\qmlproperty header
type: StatusModalHeaderSettings
This property exposes the different properties of the standard header.
\endqml
*/
property StatusModalHeaderSettings header: StatusModalHeaderSettings {}
/*!
\qmlproperty rightButtons
This property helps user assign the right buttons on the footer.
This doesn't not apply to the advanced footer!
\endqml
*/
property StatusModalHeaderSettings header: StatusModalHeaderSettings {}
property alias rightButtons: footerImpl.rightButtons
/*!
\qmlproperty rightButtons
This property helps user assign the left buttons on the footer.
This doesn't not apply to the advanced footer!
\endqml
*/
property alias leftButtons: footerImpl.leftButtons
/*!
\qmlproperty showHeader
This property to decides whether the standard header is shown.
default value is true
\endqml
*/
property bool showHeader: true
/*!
\qmlproperty showHeader
This property to decides whether the standard footer is shown.
default value is true
\endqml
*/
property bool showFooter: true
/*!
\qmlproperty showAdvancedHeader
This property to decides whether the advanced header is shown.
default value is false.
\endqml
*/
property bool showAdvancedHeader: false
/*!
\qmlproperty showAdvancedFooter
This property decides whether the advanced footer is shown.
default value is false.
\endqml
*/
property bool showAdvancedFooter: false
/*!
\qmlproperty hasCloseButton
This property decides whether the standard header has a close button.s
\endqml
*/
property alias hasCloseButton: headerImpl.hasCloseButton
signal editButtonClicked()
@@ -231,25 +64,11 @@ QC.Popup {
onClose: statusModal.close()
}
Loader {
id: advancedHeader
anchors.top: parent.top
width: visible ? parent.width : 0
active: showAdvancedHeader
}
Spares.StatusModalFooter {
id: footerImpl
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
showFooter: statusModal.showFooter
}
Loader {
id: advancedFooter
anchors.bottom: parent.bottom
width: visible ? parent.width : 0
active: showAdvancedFooter
}
}
}
@@ -10,7 +10,6 @@ StatusPopupMenu {
property var searchPopup
property var locationModel
readonly property int numDefaultItems: 2
signal itemClicked(string firstLevelItemValue, string secondLevelItemValue)
@@ -44,7 +43,7 @@ StatusPopupMenu {
color: model.iconColor,
isLetterIdenticon: !model.imageSource && !model.iconName
});
root.insertMenu(index + numDefaultItems, item);
root.insertMenu(index+2, item);
} else {
item.value = model.value
item.text = model.title;
@@ -53,7 +52,7 @@ StatusPopupMenu {
item.iconSettings.isLetterIdenticon = !model.imageSource && !model.iconName
item.image.source = model.imageSource;
item.image.isIdenticon = model.isIdenticon;
root.insertItem(index + numDefaultItems, item);
root.insertItem(index+2, item);
}
}
}
+4 -15
View File
@@ -20,13 +20,10 @@ StatusModal {
property string searchText: contentItem.searchText
property string noResultsLabel: "No results"
property string defaultSearchLocationText: "Anywhere"
property bool loading: false
property bool loading
property Menu searchOptionsPopupMenu: Menu { }
property var searchResults: [ ]
property var searchSelectionButton
// This function is called to know if the popup accepts clicks in the title
// If it does not, the clicks on the titles mousearea will be propagated to the main body instead
property var acceptsTitleClick: function(titleId) {return true}
signal resultItemClicked(string itemId)
signal resultItemTitleClicked(string titleId)
@@ -55,7 +52,7 @@ StatusModal {
}
function forceActiveFocus() {
contentItem.searchInput.edit.forceActiveFocus()
contentItem.searchInput.forceActiveFocus()
}
onOpened: {
@@ -85,8 +82,7 @@ StatusModal {
icon: "search"
color: Theme.palette.baseColor1
}
StatusBaseInput {
TextEdit {
id: inputText
anchors.left: statusIcon.right
anchors.leftMargin: 15
@@ -95,10 +91,6 @@ StatusModal {
anchors.verticalCenter: parent.verticalCenter
focus: true
font.pixelSize: 28
topPadding: 5 //smaller padding to handle bigger font
bottomPadding: 5
clearable: true
showBackground: false
font.family: Theme.palette.baseFont.name
color: Theme.palette.directColor1
Keys.onPressed: {
@@ -283,11 +275,8 @@ StatusModal {
root.resultItemClicked(itemId)
}
propagateTitleClicks: !root.acceptsTitleClick(titleId)
onTitleClicked: {
if (root.acceptsTitleClick(titleId)) {
root.resultItemTitleClicked(titleId)
}
root.resultItemTitleClicked(titleId)
}
}
section.property: "sectionName"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

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

Before

Width:  |  Height:  |  Size: 632 B

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

Before

Width:  |  Height:  |  Size: 820 B

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

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 843 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 906 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

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