feat(storybook): add MembersSelector to storybook
closes: #8178 fixes: #8210
This commit is contained in:
parent
d26ca0baf9
commit
bd7f890cce
|
@ -68,6 +68,9 @@ ApplicationWindow {
|
|||
ListElement {
|
||||
title: "ProfileFetchingView"
|
||||
}
|
||||
ListElement {
|
||||
title: "MembersSelector"
|
||||
}
|
||||
}
|
||||
|
||||
SplitView {
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property alias model: listView.model
|
||||
|
||||
implicitWidth: layout.implicitWidth
|
||||
implicitHeight: layout.implicitHeight
|
||||
|
||||
signal removeClicked(int index)
|
||||
signal removeAllClicked
|
||||
signal addClicked
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
clip: true
|
||||
spacing: 32
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: delegate
|
||||
|
||||
spacing: 0
|
||||
width: ListView.view.width
|
||||
|
||||
Row {
|
||||
Label {
|
||||
width: delegate.width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "displayName:\t"
|
||||
}
|
||||
TextField {
|
||||
width: delegate.width / 2
|
||||
text: model.displayName
|
||||
onTextChanged: model.displayName = text
|
||||
}
|
||||
}
|
||||
Row {
|
||||
Label {
|
||||
width: delegate.width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "localNickname:\t"
|
||||
}
|
||||
TextField {
|
||||
width: delegate.width / 2
|
||||
text: model.localNickname
|
||||
onTextChanged: model.localNickname = text
|
||||
}
|
||||
}
|
||||
Row {
|
||||
Label {
|
||||
width: delegate.width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "isVerified:\t"
|
||||
}
|
||||
Switch {
|
||||
width: delegate.width / 2
|
||||
checked: model.isVerified
|
||||
onCheckedChanged: model.isVerified = checked
|
||||
}
|
||||
}
|
||||
Row {
|
||||
Label {
|
||||
width: delegate.width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "isUntrustworthy:\t"
|
||||
}
|
||||
Switch {
|
||||
width: delegate.width / 2
|
||||
checked: model.isUntrustworthy
|
||||
onCheckedChanged: model.isUntrustworthy = checked
|
||||
}
|
||||
}
|
||||
Row {
|
||||
Label {
|
||||
width: delegate.width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "onlineStatus:\t"
|
||||
}
|
||||
SpinBox {
|
||||
width: delegate.width / 2
|
||||
from: 0
|
||||
to: 1
|
||||
value: model.onlineStatus
|
||||
onValueChanged: model.onlineStatus = value
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "remove"
|
||||
onClicked: root.removeClicked(index)
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: "remove all"
|
||||
onClicked: root.removeAllClicked()
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: "add"
|
||||
onClicked: root.addClicked()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import AppLayouts.Chat.views 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
import utils 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
property bool globalUtilsReady: false
|
||||
property bool mainModuleReady: false
|
||||
|
||||
QtObject {
|
||||
function isCompressedPubKey(publicKey) {
|
||||
return true
|
||||
}
|
||||
|
||||
function getCompressedPk(publicKey) {
|
||||
return "123456789"
|
||||
}
|
||||
|
||||
function getColorHashAsJson(publicKey) {
|
||||
return JSON.stringify([{colorId: 0, segmentLength: 1},
|
||||
{colorId: 19, segmentLength: 2}])
|
||||
}
|
||||
|
||||
function getColorId(publicKey) {
|
||||
return Math.floor(Math.random() * 10)
|
||||
}
|
||||
|
||||
function isEnsVerified(publicKey) {
|
||||
return false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Utils.globalUtilsInst = this
|
||||
root.globalUtilsReady = true
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
root.globalUtilsReady = false
|
||||
Utils.globalUtilsInst = {}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
function getContactDetailsAsJson() {
|
||||
return JSON.stringify({ ensVerified: false })
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Utils.mainModuleInst = this
|
||||
root.mainModuleReady = true
|
||||
}
|
||||
Component.onDestruction: {
|
||||
root.mainModuleReady = false
|
||||
Utils.mainModuleInst = {}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: rootStoreMock
|
||||
|
||||
readonly property var contactsModel: ListModel {
|
||||
id: contactsModel
|
||||
|
||||
Component.onCompleted: {
|
||||
for(let i=0; i < 20; i++) {
|
||||
append(d.createUserDict(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var contactsStore: QtObject {
|
||||
readonly property var mainModuleInst: null
|
||||
}
|
||||
|
||||
function amIChatAdmin() {
|
||||
return chatAdminSwitch.checked
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: usersStoreMock
|
||||
|
||||
readonly property var usersModel: ListModel {
|
||||
Component.onCompleted: {
|
||||
for(let i=0; i < 4; i++) {
|
||||
append(d.createMemberDict(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var temporaryModel: ListModel {
|
||||
Component.onCompleted: usersStoreMock.resetTemporaryModel()
|
||||
}
|
||||
|
||||
function appendTemporaryModel(pubKey, displayName) {
|
||||
temporaryModel.append({
|
||||
pubKey: pubKey,
|
||||
displayName: displayName,
|
||||
})
|
||||
}
|
||||
|
||||
function removeFromTemporaryModel(pubKey) {
|
||||
for(let i = 0; i < temporaryModel.count; i++) {
|
||||
if (temporaryModel.get(i).pubKey === pubKey) {
|
||||
temporaryModel.remove(i, 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetTemporaryModel() {
|
||||
temporaryModel.clear()
|
||||
for(let i = 0; i < usersModel.count; i++) {
|
||||
const obj = usersModel.get(i)
|
||||
temporaryModel.append(obj)
|
||||
}
|
||||
}
|
||||
|
||||
function updateGroupMembers() {
|
||||
const users = []
|
||||
for(let i = 0; i < temporaryModel.count; i++) {
|
||||
const obj = temporaryModel.get(i)
|
||||
users.push({
|
||||
pubKey: obj.pubKey,
|
||||
displayName: obj.displayName,
|
||||
localNickname: "",
|
||||
alias: "three word name(%1)".arg(obj.pubKey),
|
||||
isVerified: false,
|
||||
isUntrustworthy: false,
|
||||
isContact: true,
|
||||
icon: "",
|
||||
color: "red",
|
||||
onlineStatus: 0,
|
||||
isAdmin: i == 0 ? true : false
|
||||
})
|
||||
}
|
||||
usersModel.clear()
|
||||
usersModel.append(users)
|
||||
|
||||
logs.logEvent("UsersStore::updateGroupMembers")
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
function createUserDict(seed: int) {
|
||||
const pubKey = "0x%1".arg(seed)
|
||||
return {
|
||||
pubKey: pubKey,
|
||||
displayName: seed%8 ? "user%1".arg(seed) : "",
|
||||
localNickname: seed%3 ? "" : "nickname%1".arg(seed),
|
||||
alias: "three word name(%1)".arg(pubKey),
|
||||
isVerified: seed%3 ? false : true,
|
||||
isUntrustworthy: seed%5 ? false : true,
|
||||
isContact: true,
|
||||
icon: "",
|
||||
color: seed%2 ? "white" : "red",
|
||||
onlineStatus: seed%2,
|
||||
}
|
||||
}
|
||||
|
||||
function createMemberDict(seed: int) {
|
||||
var member = createUserDict(seed)
|
||||
member["isAdmin"] = seed === 0
|
||||
return member
|
||||
}
|
||||
}
|
||||
|
||||
SplitView {
|
||||
orientation: Qt.Vertical
|
||||
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
SwipeView {
|
||||
id: swipeView
|
||||
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
interactive: false
|
||||
currentIndex: selectorsSwitch.checked
|
||||
|
||||
Item {
|
||||
Loader {
|
||||
active: root.globalUtilsReady && root.mainModuleReady
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 64
|
||||
}
|
||||
|
||||
sourceComponent: MembersSelectorView {
|
||||
rootStore: rootStoreMock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Loader {
|
||||
active: root.globalUtilsReady && root.mainModuleReady
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 64
|
||||
}
|
||||
|
||||
sourceComponent: MembersEditSelectorView {
|
||||
rootStore: rootStoreMock
|
||||
usersStore: usersStoreMock
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
id: logsAndControlsPanel
|
||||
|
||||
SplitView.minimumHeight: 100
|
||||
SplitView.preferredHeight: 200
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
ColumnLayout {
|
||||
Switch {
|
||||
id: selectorsSwitch
|
||||
text: "members editor"
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: chatAdminSwitch
|
||||
visible: selectorsSwitch.checked
|
||||
text: "chat admin"
|
||||
onCheckedChanged: usersStore.resetTemporaryModel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pane {
|
||||
SplitView.minimumWidth: 300
|
||||
SplitView.preferredWidth: 300
|
||||
|
||||
MembersSelectorModelEditor {
|
||||
anchors.fill: parent
|
||||
model: contactsModel
|
||||
|
||||
onRemoveClicked: contactsModel.remove(index, 1)
|
||||
onRemoveAllClicked: contactsModel.clear()
|
||||
onAddClicked: contactsModel.append(d.createUserDict(contactsModel.count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,8 +70,8 @@ SplitView {
|
|||
})
|
||||
}
|
||||
Component.onCompleted: {
|
||||
root.mainModuleReady = true
|
||||
Utils.mainModuleInst = this
|
||||
root.mainModuleReady = true
|
||||
}
|
||||
Component.onDestruction: {
|
||||
root.mainModuleReady = false
|
||||
|
|
|
@ -33,6 +33,8 @@ ListView {
|
|||
|
||||
readonly property int availableWidth: width - leftMargin - rightMargin
|
||||
readonly property int availableHeight: height - topMargin - bottomMargin
|
||||
readonly property alias horizontalScrollBar: horizontalScrollBar
|
||||
readonly property alias verticalScrollBar: verticalScrollBar
|
||||
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
@ -40,11 +42,13 @@ ListView {
|
|||
synchronousDrag: true
|
||||
|
||||
ScrollBar.horizontal: StatusScrollBar {
|
||||
id: horizontalScrollBar
|
||||
policy: ScrollBar.AsNeeded
|
||||
visible: resolveVisibility(policy, root.width, root.contentWidth)
|
||||
}
|
||||
|
||||
ScrollBar.vertical: StatusScrollBar {
|
||||
id: verticalScrollBar
|
||||
policy: ScrollBar.AsNeeded
|
||||
visible: resolveVisibility(policy, root.height, root.contentHeight)
|
||||
}
|
||||
|
|
|
@ -19,13 +19,12 @@ Item {
|
|||
|
||||
property alias suggestionsModel: suggestionsListView.model
|
||||
property alias suggestionsDelegate: suggestionsListView.delegate
|
||||
property size suggestionsDelegateSize: Qt.size(344, 64)
|
||||
|
||||
readonly property alias label: label
|
||||
readonly property alias warningLabel: warningLabel
|
||||
readonly property alias edit: edit
|
||||
|
||||
property bool confirmBtnEnabled: (listView.count > 0)
|
||||
|
||||
signal confirmed()
|
||||
signal rejected()
|
||||
|
||||
|
@ -66,105 +65,109 @@ Item {
|
|||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onWidthChanged: {
|
||||
listView.positionViewAtEnd();
|
||||
}
|
||||
StatusScrollView {
|
||||
id: scrollView
|
||||
|
||||
function positionViewAtEnd() {
|
||||
if (scrollView.contentWidth > scrollView.width) {
|
||||
scrollView.contentX = scrollView.contentWidth - scrollView.width
|
||||
} else {
|
||||
scrollView.contentX = 0
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
Item {
|
||||
//40 px least space for input
|
||||
Layout.preferredWidth: (listView.contentWidth < (parent.width - 40)) ?
|
||||
listView.contentWidth : (parent.width - 40)
|
||||
Layout.preferredHeight: 44
|
||||
padding: 0
|
||||
|
||||
onContentWidthChanged: positionViewAtEnd()
|
||||
onWidthChanged: positionViewAtEnd()
|
||||
|
||||
RowLayout {
|
||||
height: scrollView.height
|
||||
StatusListView {
|
||||
clip: true
|
||||
id: listView
|
||||
width: parent.width
|
||||
height: 30
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 30
|
||||
implicitWidth: contentWidth
|
||||
orientation: ListView.Horizontal
|
||||
spacing: Style.current.halfPadding
|
||||
ScrollBar.horizontal: scrollBar
|
||||
onCountChanged: {
|
||||
positionViewAtEnd();
|
||||
}
|
||||
}
|
||||
StatusScrollBar {
|
||||
id: scrollBar
|
||||
parent: listView.parent
|
||||
anchors.top: listView.bottom
|
||||
anchors.left: listView.left
|
||||
anchors.right: listView.right
|
||||
policy: ScrollBar.AsNeeded
|
||||
visible: resolveVisibility(policy, listView.width, listView.contentWidth)
|
||||
}
|
||||
}
|
||||
TextInput {
|
||||
id: edit
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: 15
|
||||
color: Theme.palette.directColor1
|
||||
clip: true
|
||||
|
||||
selectByMouse: true
|
||||
selectionColor: Theme.palette.primaryColor2
|
||||
selectedTextColor: color
|
||||
|
||||
cursorDelegate: Rectangle {
|
||||
color: Theme.palette.primaryColor1
|
||||
implicitWidth: 2
|
||||
radius: 1
|
||||
visible: edit.cursorVisible
|
||||
SequentialAnimation on visible {
|
||||
loops: Animation.Infinite
|
||||
running: edit.cursorVisible
|
||||
PropertyAnimation { to: false; duration: 600; }
|
||||
PropertyAnimation { to: true; duration: 600; }
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.matches(StandardKey.Paste)) {
|
||||
event.accepted = true
|
||||
const previousText = text;
|
||||
const previousSelectedText = selectedText;
|
||||
paste()
|
||||
if (previousText === "" || previousSelectedText.length === previousText.length)
|
||||
root.textPasted(text)
|
||||
return;
|
||||
}
|
||||
TextInput {
|
||||
id: edit
|
||||
Layout.minimumWidth: 4
|
||||
Layout.fillHeight: true
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: 15
|
||||
color: Theme.palette.directColor1
|
||||
|
||||
if (suggestionsDialog.visible) {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
root.entryAccepted(suggestionsListView.itemAtIndex(suggestionsListView.currentIndex))
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
suggestionsListView.decrementCurrentIndex()
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
suggestionsListView.incrementCurrentIndex()
|
||||
selectByMouse: true
|
||||
selectionColor: Theme.palette.primaryColor2
|
||||
selectedTextColor: color
|
||||
|
||||
cursorDelegate: Rectangle {
|
||||
color: Theme.palette.primaryColor1
|
||||
implicitWidth: 2
|
||||
radius: 1
|
||||
visible: edit.cursorVisible
|
||||
SequentialAnimation on visible {
|
||||
loops: Animation.Infinite
|
||||
running: edit.cursorVisible
|
||||
PropertyAnimation { to: false; duration: 600; }
|
||||
PropertyAnimation { to: true; duration: 600; }
|
||||
}
|
||||
} else {
|
||||
if (event.key === Qt.Key_Backspace && edit.text === "" && listView.count > 0) {
|
||||
root.entryRemoved(listView.itemAtIndex(listView.count - 1))
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Enter) {
|
||||
root.enterKeyPressed()
|
||||
} else if (event.key === Qt.Key_Escape) {
|
||||
root.rejected()
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.upKeyPressed();
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.downKeyPressed();
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.matches(StandardKey.Paste)) {
|
||||
event.accepted = true
|
||||
const previousText = text;
|
||||
const previousSelectedText = selectedText;
|
||||
paste()
|
||||
if (previousText === "" || previousSelectedText.length === previousText.length)
|
||||
root.textPasted(text)
|
||||
return;
|
||||
}
|
||||
|
||||
if (suggestionsDialog.visible) {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
root.entryAccepted(suggestionsListView.itemAtIndex(suggestionsListView.currentIndex))
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
suggestionsListView.decrementCurrentIndex()
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
suggestionsListView.incrementCurrentIndex()
|
||||
}
|
||||
} else {
|
||||
if (event.key === Qt.Key_Backspace && edit.text === "") {
|
||||
root.entryRemoved(listView.itemAtIndex(listView.count - 1))
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Enter) {
|
||||
root.enterKeyPressed()
|
||||
} else if (event.key === Qt.Key_Escape) {
|
||||
root.rejected()
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.upKeyPressed()
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.downKeyPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure edit cursor is visible
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 1
|
||||
}
|
||||
}
|
||||
|
||||
// ensure edit cursor is visible
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 1
|
||||
ScrollBar.horizontal: StatusScrollBar {
|
||||
id: scrollBar
|
||||
parent: scrollView.parent
|
||||
anchors.top: scrollView.bottom
|
||||
anchors.left: scrollView.left
|
||||
anchors.right: scrollView.right
|
||||
policy: ScrollBar.AsNeeded
|
||||
visible: resolveVisibility(policy, scrollView.width, scrollView.contentWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +195,7 @@ Item {
|
|||
StatusButton {
|
||||
objectName: "inlineSelectorConfirmButton"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
enabled: root.confirmBtnEnabled
|
||||
enabled: (listView.count > 0)
|
||||
text: qsTr("Confirm")
|
||||
onClicked: root.confirmed()
|
||||
}
|
||||
|
@ -207,9 +210,9 @@ Item {
|
|||
|
||||
Popup {
|
||||
id: suggestionsDialog
|
||||
parent: edit
|
||||
x: (parent.contentWidth - Style.current.halfPadding)
|
||||
y: (parent.height + Style.current.halfPadding)
|
||||
parent: scrollView
|
||||
x: Math.min(parent.width, parent.contentWidth)
|
||||
y: parent.height + Style.current.halfPadding
|
||||
visible: edit.text !== ""
|
||||
padding: Style.current.halfPadding
|
||||
background: StatusDialogBackground {
|
||||
|
@ -226,10 +229,19 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
height: suggestionsListView.count ?
|
||||
Math.min(400, suggestionsListView.count * suggestionsDelegateSize.height + 2 * padding) :
|
||||
noResultsFoundText.height + 2 * padding
|
||||
width: suggestionsDelegateSize.width
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
StatusBaseText {
|
||||
id: noResultsFoundText
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: root.suggestionsModel.count === 0
|
||||
text: qsTr("No results found")
|
||||
color: Theme.palette.baseColor1
|
||||
|
@ -237,11 +249,22 @@ Item {
|
|||
|
||||
StatusListView {
|
||||
id: suggestionsListView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
visible: root.suggestionsModel.count
|
||||
|
||||
implicitWidth: contentItem.childrenRect.width
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
highlightMoveDuration: 0
|
||||
highlightMoveVelocity: -1
|
||||
|
||||
verticalScrollBar {
|
||||
visible: contentHeight > height
|
||||
policy: ScrollBar.AlwaysOn
|
||||
}
|
||||
|
||||
onVisibleChanged: currentIndex = 0
|
||||
onCountChanged: currentIndex = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ QtObject {
|
|||
return chatCommunitySectionModule.getMySectionId()
|
||||
}
|
||||
|
||||
function amIChatAdmin() {
|
||||
return currentChatContentModule().amIChatAdmin()
|
||||
}
|
||||
|
||||
function acceptContactRequest(pubKey) {
|
||||
chatCommunitySectionModule.acceptContactRequest(pubKey)
|
||||
}
|
||||
|
|
|
@ -4,11 +4,20 @@ QtObject {
|
|||
id: root
|
||||
|
||||
property var usersModule
|
||||
property var usersModel
|
||||
|
||||
onUsersModuleChanged: {
|
||||
if(!usersModule)
|
||||
return
|
||||
root.usersModel = usersModule.model
|
||||
readonly property var usersModel: usersModule ? usersModule.model : null
|
||||
readonly property var temporaryModel: usersModule ? usersModule.temporaryModel : null
|
||||
|
||||
function appendTemporaryModel(pubKey, displayName) {
|
||||
usersModule.appendTemporaryModel(pubKey, displayName)
|
||||
}
|
||||
function removeFromTemporaryModel(pubKey) {
|
||||
usersModule.removeFromTemporaryModel(pubKey)
|
||||
}
|
||||
function resetTemporaryModel() {
|
||||
usersModule.resetTemporaryModel()
|
||||
}
|
||||
function updateGroupMembers() {
|
||||
usersModule.updateGroupMembers()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,9 +345,10 @@ Item {
|
|||
id: membersSelector
|
||||
|
||||
MembersEditSelectorView {
|
||||
sectionModule: root.chatSectionModule
|
||||
chatContentModule: root.chatContentModule
|
||||
rootStore: root.rootStore
|
||||
usersStore: UsersStore {
|
||||
usersModule: root.chatContentModule.usersModule
|
||||
}
|
||||
|
||||
onConfirmed: root.state = d.stateInfoButtonContent
|
||||
onRejected: root.state = d.stateInfoButtonContent
|
||||
|
|
|
@ -19,35 +19,32 @@ import SortFilterProxyModel 0.2
|
|||
MembersSelectorBase {
|
||||
id: root
|
||||
|
||||
// TODO: use stores instead of modules
|
||||
property var sectionModule
|
||||
property var chatContentModule
|
||||
property var usersStore
|
||||
|
||||
confirmBtnEnabled: true
|
||||
onConfirmed: {
|
||||
d.updateGroupMembers()
|
||||
d.resetTemporaryModel()
|
||||
usersStore.updateGroupMembers()
|
||||
usersStore.resetTemporaryModel()
|
||||
}
|
||||
|
||||
onRejected: {
|
||||
d.resetTemporaryModel()
|
||||
usersStore.resetTemporaryModel()
|
||||
}
|
||||
limitReached: (model.count === membersLimit)
|
||||
onEntryAccepted: {
|
||||
|
||||
onEntryAccepted: if (suggestionsDelegate) {
|
||||
if (!root.limitReached) {
|
||||
d.appendTemporaryModel(suggestionsDelegate._pubKey, suggestionsDelegate.userName)
|
||||
usersStore.appendTemporaryModel(suggestionsDelegate._pubKey, suggestionsDelegate.userName)
|
||||
root.edit.clear()
|
||||
}
|
||||
}
|
||||
|
||||
onEntryRemoved: {
|
||||
onEntryRemoved: if (delegate) {
|
||||
if (!delegate.isReadonly) {
|
||||
d.removeFromTemporaryModel(delegate._pubKey)
|
||||
usersStore.removeFromTemporaryModel(delegate._pubKey)
|
||||
}
|
||||
}
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: root.chatContentModule.usersModule.temporaryModel
|
||||
sourceModel: root.usersStore.temporaryModel
|
||||
sorters: RoleSorter {
|
||||
roleName: "isAdmin"
|
||||
sortOrder: Qt.DescendingOrder
|
||||
|
@ -58,35 +55,19 @@ MembersSelectorBase {
|
|||
readonly property string _pubKey: model.pubKey
|
||||
|
||||
height: ListView.view.height
|
||||
text: model.displayName !== "" ? model.displayName : model.alias
|
||||
text: root.tagText(model.localNickname, model.displayName, model.alias)
|
||||
|
||||
isReadonly: {
|
||||
if (model.isAdmin) return true
|
||||
if (root.chatContentModule.amIChatAdmin()) return false
|
||||
return index < root.chatContentModule.usersModule.model.count
|
||||
if (root.rootStore.amIChatAdmin()) return false
|
||||
return index < root.usersStore.usersModel.count
|
||||
}
|
||||
icon: model.isAdmin ? "crown" : ""
|
||||
|
||||
onClicked: root.entryRemoved(this)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
function appendTemporaryModel(pubKey, displayName) {
|
||||
root.chatContentModule.usersModule.appendTemporaryModel(pubKey, displayName)
|
||||
}
|
||||
function removeFromTemporaryModel(pubKey) {
|
||||
root.chatContentModule.usersModule.removeFromTemporaryModel(pubKey)
|
||||
}
|
||||
function resetTemporaryModel() {
|
||||
root.chatContentModule.usersModule.resetTemporaryModel()
|
||||
}
|
||||
function updateGroupMembers() {
|
||||
root.chatContentModule.usersModule.updateGroupMembers()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
d.resetTemporaryModel()
|
||||
usersStore.resetTemporaryModel()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,19 +14,21 @@ import SortFilterProxyModel 0.2
|
|||
MembersSelectorBase {
|
||||
id: root
|
||||
|
||||
limitReached: model.count >= membersLimit - 1 // -1 because creator is not on the list of members when creating chat
|
||||
|
||||
function cleanup() {
|
||||
root.edit.clear();
|
||||
d.selectedMembers.clear();
|
||||
root.edit.clear()
|
||||
d.selectedMembers.clear()
|
||||
}
|
||||
|
||||
onEntryAccepted: {
|
||||
onEntryAccepted: if (suggestionsDelegate) {
|
||||
if (root.limitReached)
|
||||
return
|
||||
if (d.addMember(suggestionsDelegate._pubKey, suggestionsDelegate.userName, suggestionsDelegate.isAdmin))
|
||||
if (d.addMember(suggestionsDelegate._pubKey, suggestionsDelegate.userName, suggestionsDelegate.nickName))
|
||||
root.edit.clear()
|
||||
}
|
||||
|
||||
onEntryRemoved: {
|
||||
onEntryRemoved: if (delegate) {
|
||||
d.removeMember(delegate._pubKey)
|
||||
}
|
||||
|
||||
|
@ -40,10 +42,10 @@ MembersSelectorBase {
|
|||
|
||||
delegate: StatusTagItem {
|
||||
readonly property string _pubKey: model.pubKey
|
||||
|
||||
height: ListView.view.height
|
||||
text: model.displayName
|
||||
isReadonly: model.isAdmin
|
||||
icon: model.isAdmin ? "crown" : ""
|
||||
text: root.tagText(model.localNickname, model.displayName, model.alias)
|
||||
|
||||
onClicked: root.entryRemoved(this)
|
||||
}
|
||||
|
||||
|
@ -58,7 +60,7 @@ MembersSelectorBase {
|
|||
root.rootStore.contactsStore.resolveENS(value)
|
||||
}
|
||||
|
||||
function addMember(pubKey, displayName, isAdmin) {
|
||||
function addMember(pubKey, displayName, localNickname) {
|
||||
for (let i = 0; i < d.selectedMembers.count; ++i) {
|
||||
if (d.selectedMembers.get(i).pubKey === pubKey)
|
||||
return false
|
||||
|
@ -67,7 +69,7 @@ MembersSelectorBase {
|
|||
d.selectedMembers.append({
|
||||
"pubKey": pubKey,
|
||||
"displayName": displayName,
|
||||
"isAdmin": isAdmin
|
||||
"localNickname": localNickname
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -21,7 +21,11 @@ InlineSelectorPanel {
|
|||
property var rootStore
|
||||
|
||||
readonly property int membersLimit: 20 // see: https://github.com/status-im/status-mobile/issues/13066
|
||||
property bool limitReached: (model.count === (membersLimit-1))
|
||||
property bool limitReached: model.count >= membersLimit
|
||||
|
||||
function tagText(localNickname, displayName, aliasName) {
|
||||
return localNickname || displayName || aliasName
|
||||
}
|
||||
|
||||
label.text: qsTr("To:")
|
||||
warningLabel.text: qsTr("%1 USER LIMIT REACHED").arg(membersLimit)
|
||||
|
@ -32,8 +36,10 @@ InlineSelectorPanel {
|
|||
|
||||
sourceModel: root.rootStore.contactsModel
|
||||
|
||||
function searchPredicate(displayName) {
|
||||
return displayName.toLowerCase().includes(root.edit.text.toLowerCase())
|
||||
function searchPredicate(displayName, localNickname, nameAlias) {
|
||||
return displayName.toLowerCase().includes(root.edit.text.toLowerCase()) ||
|
||||
localNickname.toLowerCase().includes(root.edit.text.toLowerCase()) ||
|
||||
(!displayName && nameAlias.toLowerCase().includes(root.edit.text.toLowerCase()))
|
||||
}
|
||||
|
||||
function notAMemberPredicate(pubKey) {
|
||||
|
@ -49,7 +55,7 @@ InlineSelectorPanel {
|
|||
enabled: root.edit.text !== ""
|
||||
expression: {
|
||||
root.edit.text // ensure expression is reevaluated when edit.text changes
|
||||
return _suggestionsModel.searchPredicate(model.displayName)
|
||||
return _suggestionsModel.searchPredicate(model.displayName, model.localNickname, model.alias)
|
||||
}
|
||||
},
|
||||
ExpressionFilter {
|
||||
|
@ -59,13 +65,22 @@ InlineSelectorPanel {
|
|||
}
|
||||
}
|
||||
]
|
||||
|
||||
proxyRoles: ExpressionRole {
|
||||
name: "title"
|
||||
expression: model.localNickname || model.displayName || model.alias
|
||||
}
|
||||
|
||||
sorters: StringSorter {
|
||||
roleName: "displayName"
|
||||
roleName: "title"
|
||||
numericMode: true
|
||||
}
|
||||
}
|
||||
|
||||
suggestionsDelegate: ContactListItemDelegate {
|
||||
highlighted: ListView.isCurrentItem
|
||||
height: root.suggestionsDelegateSize.height
|
||||
width: root.suggestionsDelegateSize.width
|
||||
onClicked: root.entryAccepted(this)
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
CreateChatView 1.0 CreateChatView.qml
|
||||
MembersSelectorView 1.0 MembersSelectorView.qml
|
||||
MembersEditSelectorView 1.0 MembersEditSelectorView.qml
|
||||
|
|
|
@ -18,7 +18,7 @@ StatusMemberListItem {
|
|||
|
||||
pubKey: hasEnsName ? "" : Utils.getCompressedPk(model.pubKey)
|
||||
nickName: model.localNickname
|
||||
userName: model.displayName
|
||||
userName: model.displayName || model.alias
|
||||
isVerified: model.isVerified
|
||||
isUntrustworthy: model.isUntrustworthy
|
||||
isContact: model.isContact
|
||||
|
|
Loading…
Reference in New Issue