feat(desktop): Made activity button be visible everywhere

Closes #6635
This commit is contained in:
Alexandra Betouni 2022-08-09 18:08:39 +03:00 committed by Alexandra Betouni
parent b1259a83f4
commit b6ff7b9ded
17 changed files with 944 additions and 822 deletions

@ -1 +1 @@
Subproject commit 80a9cc9b3face23df65e7630afe5339a8acf8072
Subproject commit ecc44cfae0f3c06cad5e3f3d7c94f4d1488fdf9b

View File

@ -7,9 +7,10 @@ import Qt.labs.settings 1.0
import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.2
import StatusQ.Layout 0.1
import utils 1.0
import shared.controls 1.0
import shared 1.0
import shared.status 1.0
import shared.popups 1.0
@ -22,17 +23,13 @@ import "stores"
// Code based on https://code.qt.io/cgit/qt/qtwebengine.git/tree/examples/webengine/quicknanobrowser/BrowserWindow.qml?h=5.15
// Licensed under BSD
Rectangle {
id: browserWindow
StatusSectionLayout {
id: root
property var globalStore
property var sendTransactionModal
function openUrlInNewTab(url) {
var tab = _internal.addNewTab()
tab.item.url = _internal.determineRealURL(url)
}
onNotificationButtonClicked: Global.openActivityCenterPopup()
QtObject {
id: _internal
@ -57,9 +54,9 @@ Rectangle {
// TODO we'll need a new dialog at one point because this one is not using the same call, but it's good for now
property Component sendTransactionModalComponent: SignTransactionModal {
anchors.centerIn: parent
store: browserWindow.globalStore
contactsStore: browserWindow.globalStore.profileSectionStore.contactsStore
chainId: browserWindow.globalStore.getChainIdForBrowser()
store: root.globalStore
contactsStore: root.globalStore.profileSectionStore.contactsStore
chainId: root.globalStore.getChainIdForBrowser()
}
property Component signMessageModalComponent: SignMessageModal {}
@ -139,183 +136,331 @@ Rectangle {
}
}
Layout.fillHeight: true
Layout.fillWidth: true
centerPanel: Rectangle {
id: browserWindow
anchors.fill: parent
color: Style.current.inputBackground
color: Style.current.inputBackground
border.width: 0
WebProviderObj {
id: provider
createAccessDialogComponent: function() {
return _internal.accessDialogComponent.createObject(browserWindow)
function openUrlInNewTab(url) {
var tab = _internal.addNewTab()
tab.item.url = _internal.determineRealURL(url)
}
createSendTransactionModalComponent: function(request) {
return _internal.sendTransactionModalComponent.createObject(browserWindow, {
trxData: request.payload.params[0].data || "",
WebProviderObj {
id: provider
createAccessDialogComponent: function() {
return _internal.accessDialogComponent.createObject(root)
}
createSendTransactionModalComponent: function(request) {
return _internal.sendTransactionModalComponent.createObject(root, {
trxData: request.payload.params[0].data || "",
selectedAccount: {
name: WalletStore.dappBrowserAccount.name,
address: request.payload.params[0].from,
iconColor: WalletStore.dappBrowserAccount.color,
assets: WalletStore.dappBrowserAccount.assets
},
selectedRecipient: {
address: request.payload.params[0].to,
identicon: "",
name: RootStore.activeChannelName,
type: RecipientSelector.Type.Address
},
selectedAsset: {
name: "ETH",
symbol: "ETH",
address: Constants.zeroAddress
},
selectedFiatAmount: "42", // TODO calculate that
selectedAmount: RootStore.getWei2Eth(request.payload.params[0].value, 18)
})
}
createSignMessageModalComponent: function(request) {
return _internal.signMessageModalComponent.createObject(root, {
request,
selectedAccount: {
name: WalletStore.dappBrowserAccount.name,
address: request.payload.params[0].from,
iconColor: WalletStore.dappBrowserAccount.color,
assets: WalletStore.dappBrowserAccount.assets
},
selectedRecipient: {
address: request.payload.params[0].to,
identicon: "",
name: RootStore.activeChannelName,
type: RecipientSelector.Type.Address
},
selectedAsset: {
name: "ETH",
symbol: "ETH",
address: Constants.zeroAddress
},
selectedFiatAmount: "42", // TODO calculate that
selectedAmount: RootStore.getWei2Eth(request.payload.params[0].value, 18)
iconColor: WalletStore.dappBrowserAccount.color
}
})
}
createSignMessageModalComponent: function(request) {
return _internal.signMessageModalComponent.createObject(browserWindow, {
request,
selectedAccount: {
name: WalletStore.dappBrowserAccount.name,
iconColor: WalletStore.dappBrowserAccount.color
}
})
}
showSendingError: function(message) {
_internal.sendingError.text = message
return _internal.sendingError.open()
}
showSigningError: function(message) {
_internal.signingError.text = message
return _internal.signingError.open()
}
showToastMessage: function(result) {
// TODO: WIP under PR https://github.com/status-im/status-desktop/pull/4274
let url = `${WalletStore.getEtherscanLink()}/${result}`;
Global.displayToastMessage(qsTr("Transaction pending..."),
qsTr("View on etherscan"),
"",
true,
Constants.ephemeralNotificationType.normal,
url);
}
}
BrowserShortcutActions {
id: keyboardShortcutActions
currentWebView: _internal.currentWebView
findBarComponent: findBar
browserHeaderComponent: browserHeader
onAddNewDownloadTab: _internal.addNewDownloadTab()
onRemoveView: tabs.removeView(tabs.currentIndex)
}
WebChannel {
id: channel
registeredObjects: [provider]
}
BrowserHeader {
id: browserHeader
anchors.top: parent.top
anchors.topMargin: tabs.tabHeight + tabs.anchors.topMargin
z: 52
favoriteComponent: favoritesBar
currentFavorite: _internal.currentWebView && BookmarksStore.getCurrentFavorite(_internal.currentWebView.url)
dappBrowserAccName: WalletStore.dappBrowserAccount.name
dappBrowserAccIcon: WalletStore.dappBrowserAccount.color
settingMenu: settingsMenu
walletMenu: browserWalletMenu
currentUrl: _internal.currentWebView.url
isLoading: _internal.currentWebView.loading
canGoBack: _internal.currentWebView.canGoBack
canGoForward: _internal.currentWebView.canGoForward
currentTabConnected: RootStore.currentTabConnected
onOpenHistoryPopup: historyMenu.popup(xPos, yPos)
onGoBack: _internal.currentWebView.goBack()
onGoForward: _internal.currentWebView.goForward()
onReload: _internal.currentWebView.reload()
onStopLoading: _internal.currentWebView.stop()
onAddNewFavoritelClicked: {
Global.openPopup(addFavoriteModal,
{
x: xPos - 30,
y: browserHeader.y + browserHeader.height + 4,
modifiyModal: browserHeader.currentFavorite,
toolbarMode: true,
ogUrl: browserHeader.currentFavorite ? browserHeader.currentFavorite.url : _internal.currentWebView.url,
ogName: browserHeader.currentFavorite ? browserHeader.currentFavorite.name : _internal.currentWebView.title
})
}
onLaunchInBrowser: {
// TODO: disable browsing local files? file://
if (localAccountSensitiveSettings.useBrowserEthereumExplorer !== Constants.browserEthereumExplorerNone && url.startsWith("0x")) {
_internal.currentWebView.url = RootStore.get0xFormedUrl(localAccountSensitiveSettings.useBrowserEthereumExplorer, url)
return
}
if (localAccountSensitiveSettings.shouldShowBrowserSearchEngine !== Constants.browserSearchEngineNone && !Utils.isURL(url) && !Utils.isURLWithOptionalProtocol(url)) {
_internal.currentWebView.url = RootStore.getFormedUrl(localAccountSensitiveSettings.shouldShowBrowserSearchEngine, url)
return
} else if (Utils.isURLWithOptionalProtocol(url)) {
url = "https://" + url
showSendingError: function(message) {
_internal.sendingError.text = message
return _internal.sendingError.open()
}
showSigningError: function(message) {
_internal.signingError.text = message
return _internal.signingError.open()
}
showToastMessage: function(result) {
// TODO: WIP under PR https://github.com/status-im/status-desktop/pull/4274
let url = `${WalletStore.getEtherscanLink()}/${result}`;
Global.displayToastMessage(qsTr("Transaction pending..."),
qsTr("View on etherscan"),
"",
true,
Constants.ephemeralNotificationType.normal,
url);
}
_internal.currentWebView.url = _internal.determineRealURL(url);
}
}
BrowserTabView {
id: tabs
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
anchors.bottom: devToolsView.top
anchors.bottomMargin: browserHeader.height
anchors.left: parent.left
anchors.right: parent.right
z: 50
tabComponent: webEngineView
currentWebEngineProfile: _internal.currentWebView.profile
determineRealURL: function(url) {
return _internal.determineRealURL(url)
BrowserShortcutActions {
id: keyboardShortcutActions
currentWebView: _internal.currentWebView
findBarComponent: findBar
browserHeaderComponent: browserHeader
onAddNewDownloadTab: _internal.addNewDownloadTab()
onRemoveView: tabs.removeView(tabs.currentIndex)
}
onOpenNewTabTriggered: _internal.addNewTab()
Component.onCompleted: {
_internal.defaultProfile.downloadRequested.connect(_internal.onDownloadRequested);
_internal.otrProfile.downloadRequested.connect(_internal.onDownloadRequested);
var tab = createEmptyTab(_internal.defaultProfile);
// For Devs: Uncomment the next lien if you want to use the simpeldapp on first load
// tab.item.url = Web3ProviderStore.determineRealURL("https://simpledapp.eth");
}
}
ProgressBar {
id: progressBar
height: 3
from: 0
to: 100
visible: value != 0 && value != 100
value: (_internal.currentWebView && _internal.currentWebView.loadProgress < 100) ? _internal.currentWebView.loadProgress : 0
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.padding
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
}
WebEngineView {
id: devToolsView
visible: localAccountSensitiveSettings.devToolsEnabled
height: visible ? 400 : 0
inspectedView: visible && tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
onNewViewRequested: function(request) {
var tab = tabs.createEmptyTab(_internal.currentWebView.profile);
tabs.currentIndex = tabs.count - 1;
request.openIn(tab.item);
WebChannel {
id: channel
registeredObjects: [provider]
}
BrowserHeader {
id: browserHeader
anchors.top: parent.top
anchors.topMargin: tabs.tabHeight + tabs.anchors.topMargin
z: 52
favoriteComponent: favoritesBar
currentFavorite: _internal.currentWebView && BookmarksStore.getCurrentFavorite(_internal.currentWebView.url)
dappBrowserAccName: WalletStore.dappBrowserAccount.name
dappBrowserAccIcon: WalletStore.dappBrowserAccount.color
settingMenu: settingsMenu
walletMenu: browserWalletMenu
currentUrl: _internal.currentWebView.url
isLoading: _internal.currentWebView.loading
canGoBack: _internal.currentWebView.canGoBack
canGoForward: _internal.currentWebView.canGoForward
currentTabConnected: RootStore.currentTabConnected
onOpenHistoryPopup: historyMenu.popup(xPos, yPos)
onGoBack: _internal.currentWebView.goBack()
onGoForward: _internal.currentWebView.goForward()
onReload: _internal.currentWebView.reload()
onStopLoading: _internal.currentWebView.stop()
onAddNewFavoritelClicked: {
Global.openPopup(addFavoriteModal,
{
x: xPos - 30,
y: browserHeader.y + browserHeader.height + 4,
modifiyModal: browserHeader.currentFavorite,
toolbarMode: true,
ogUrl: browserHeader.currentFavorite ? browserHeader.currentFavorite.url : _internal.currentWebView.url,
ogName: browserHeader.currentFavorite ? browserHeader.currentFavorite.name : _internal.currentWebView.title
})
}
onLaunchInBrowser: {
// TODO: disable browsing local files? file://
if (localAccountSensitiveSettings.useBrowserEthereumExplorer !== Constants.browserEthereumExplorerNone && url.startsWith("0x")) {
_internal.currentWebView.url = RootStore.get0xFormedUrl(localAccountSensitiveSettings.useBrowserEthereumExplorer, url)
return
}
if (localAccountSensitiveSettings.shouldShowBrowserSearchEngine !== Constants.browserSearchEngineNone && !Utils.isURL(url) && !Utils.isURLWithOptionalProtocol(url)) {
_internal.currentWebView.url = RootStore.getFormedUrl(localAccountSensitiveSettings.shouldShowBrowserSearchEngine, url)
return
} else if (Utils.isURLWithOptionalProtocol(url)) {
url = "https://" + url
}
_internal.currentWebView.url = _internal.determineRealURL(url);
}
}
BrowserTabView {
id: tabs
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
anchors.bottom: devToolsView.top
anchors.bottomMargin: browserHeader.height
anchors.left: parent.left
anchors.right: parent.right
z: 50
tabComponent: webEngineView
currentWebEngineProfile: _internal.currentWebView.profile
determineRealURL: function(url) {
return _internal.determineRealURL(url)
}
onOpenNewTabTriggered: _internal.addNewTab()
Component.onCompleted: {
_internal.defaultProfile.downloadRequested.connect(_internal.onDownloadRequested);
_internal.otrProfile.downloadRequested.connect(_internal.onDownloadRequested);
var tab = createEmptyTab(_internal.defaultProfile);
// For Devs: Uncomment the next lien if you want to use the simpeldapp on first load
// tab.item.url = Web3ProviderStore.determineRealURL("https://simpledapp.eth");
}
}
ProgressBar {
id: progressBar
height: 3
from: 0
to: 100
visible: value != 0 && value != 100
value: (_internal.currentWebView && _internal.currentWebView.loadProgress < 100) ? _internal.currentWebView.loadProgress : 0
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.padding
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
}
WebEngineView {
id: devToolsView
visible: localAccountSensitiveSettings.devToolsEnabled
height: visible ? 400 : 0
inspectedView: visible && tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
onNewViewRequested: function(request) {
var tab = tabs.createEmptyTab(_internal.currentWebView.profile);
tabs.currentIndex = tabs.count - 1;
request.openIn(tab.item);
}
z: 100
}
FavoriteMenu {
id: favoriteMenu
openInNewTab: function (url) {
browserWindow.openUrlInNewTab(url)
}
onEditFavoriteTriggered: {
Global.openPopup(addFavoriteModal, {
modifiyModal: true,
ogUrl: favoriteMenu.currentFavorite ? favoriteMenu.currentFavorite.url : _internal.currentWebView.url,
ogName: favoriteMenu.currentFavorite ? favoriteMenu.currentFavorite.name : _internal.currentWebView.title})
}
}
DownloadBar {
id: downloadBar
anchors.bottom: parent.bottom
z: 60
downloadsModel: DownloadsStore.downloadModel
downloadsMenu: downloadMenu
onOpenDownloadClicked: {
if (downloadComplete) {
return DownloadsStore.openFile(index)
}
DownloadsStore.openDirectory(index)
}
onAddNewDownloadTab: _internal.addNewDownloadTab()
}
FindBar {
id: findBar
visible: false
anchors.right: parent.right
anchors.top: browserHeader.bottom
z: 60
onFindNext: {
if (text)
_internal.currentWebView && _internal.currentWebView.findText(text);
else if (!visible)
visible = true;
}
onFindPrevious: {
if (text)
_internal.currentWebView && _internal.currentWebView.findText(text, WebEngineView.FindBackward);
else if (!visible)
visible = true;
}
}
Rectangle {
id: statusBubble
color: "oldlace"
property int padding: 8
visible: false
anchors.left: parent.left
anchors.bottom: parent.bottom
width: statusText.paintedWidth + padding
height: statusText.paintedHeight + padding
Text {
id: statusText
anchors.centerIn: statusBubble
elide: Qt.ElideMiddle
Timer {
id: hideStatusText
interval: 750
onTriggered: {
statusText.text = "";
statusBubble.visible = false;
}
}
}
}
DownloadMenu {
id: downloadMenu
}
BrowserSettingsMenu {
id: settingsMenu
x: parent.width - width
y: browserHeader.y + (localAccountSensitiveSettings.shouldShowFavoritesBar ? browserHeader.height - 38 : browserHeader.height)
isIncognito: _internal.currentWebView && _internal.currentWebView.profile === _internal.otrProfile
onAddNewTab: _internal.addNewTab()
onGoIncognito: {
if (_internal.currentWebView) {
_internal.currentWebView.profile = checked ? _internal.otrProfile : _internal.defaultProfile;
}
}
onZoomIn: {
const newZoom = _internal.currentWebView.zoomFactor + 0.1
_internal.currentWebView.changeZoomFactor(newZoom)
}
onZoomOut: {
const newZoom = currentWebView.zoomFactor - 0.1
_internal.currentWebView.changeZoomFactor(newZoom)
}
onChangeZoomFactor: _internal.currentWebView.changeZoomFactor(1.0)
onLaunchFindBar: {
if (!findBar.visible) {
findBar.visible = true;
findBar.forceActiveFocus()
}
}
onToggleCompatibilityMode: {
for (let i = 0; i < tabs.count; ++i){
tabs.getTab(i).item.stop() // Stop all loading tabs
}
localAccountSensitiveSettings.compatibilityMode = checked;
for (let i = 0; i < tabs.count; ++i){
tabs.getTab(i).item.reload() // Reload them with new user agent
}
}
onLaunchBrowserSettings: {
Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.browserSettings);
}
}
BrowserWalletMenu {
id: browserWalletMenu
y: browserHeader.height + browserHeader.anchors.topMargin
x: parent.width - width - Style.current.halfPadding
onSendTriggered: {
sendTransactionModal.selectedAccount = selectedAccount
sendTransactionModal.open()
}
onReload: {
for (let i = 0; i < tabs.count; ++i){
tabs.getTab(i).item.reload();
}
}
onDisconnect: {
Web3ProviderStore.disconnect(Utils.getHostname(browserHeader.addressBar.text))
provider.postMessage("web3-disconnect-account", "{}");
_internal.currentWebView.reload()
close()
}
}
z: 100
}
Component {
@ -323,19 +468,6 @@ Rectangle {
AddFavoriteModal {}
}
FavoriteMenu {
id: favoriteMenu
openInNewTab: function (url) {
browserWindow.openUrlInNewTab(url)
}
onEditFavoriteTriggered: {
Global.openPopup(addFavoriteModal, {
modifiyModal: true,
ogUrl: favoriteMenu.currentFavorite ? favoriteMenu.currentFavorite.url : _internal.currentWebView.url,
ogName: favoriteMenu.currentFavorite ? favoriteMenu.currentFavorite.name : _internal.currentWebView.title})
}
}
MessageDialog {
id: sslDialog
@ -365,136 +497,6 @@ Rectangle {
}
}
DownloadBar {
id: downloadBar
anchors.bottom: parent.bottom
z: 60
downloadsModel: DownloadsStore.downloadModel
downloadsMenu: downloadMenu
onOpenDownloadClicked: {
if (downloadComplete) {
return DownloadsStore.openFile(index)
}
DownloadsStore.openDirectory(index)
}
onAddNewDownloadTab: _internal.addNewDownloadTab()
}
FindBar {
id: findBar
visible: false
anchors.right: parent.right
anchors.top: browserHeader.bottom
z: 60
onFindNext: {
if (text)
_internal.currentWebView && _internal.currentWebView.findText(text);
else if (!visible)
visible = true;
}
onFindPrevious: {
if (text)
_internal.currentWebView && _internal.currentWebView.findText(text, WebEngineView.FindBackward);
else if (!visible)
visible = true;
}
}
Rectangle {
id: statusBubble
color: "oldlace"
property int padding: 8
visible: false
anchors.left: parent.left
anchors.bottom: parent.bottom
width: statusText.paintedWidth + padding
height: statusText.paintedHeight + padding
Text {
id: statusText
anchors.centerIn: statusBubble
elide: Qt.ElideMiddle
Timer {
id: hideStatusText
interval: 750
onTriggered: {
statusText.text = "";
statusBubble.visible = false;
}
}
}
}
DownloadMenu {
id: downloadMenu
}
BrowserSettingsMenu {
id: settingsMenu
x: parent.width - width
y: browserHeader.y + (localAccountSensitiveSettings.shouldShowFavoritesBar ? browserHeader.height - 38 : browserHeader.height)
isIncognito: _internal.currentWebView && _internal.currentWebView.profile === _internal.otrProfile
onAddNewTab: _internal.addNewTab()
onGoIncognito: {
if (_internal.currentWebView) {
_internal.currentWebView.profile = checked ? _internal.otrProfile : _internal.defaultProfile;
}
}
onZoomIn: {
const newZoom = _internal.currentWebView.zoomFactor + 0.1
_internal.currentWebView.changeZoomFactor(newZoom)
}
onZoomOut: {
const newZoom = currentWebView.zoomFactor - 0.1
_internal.currentWebView.changeZoomFactor(newZoom)
}
onChangeZoomFactor: _internal.currentWebView.changeZoomFactor(1.0)
onLaunchFindBar: {
if (!findBar.visible) {
findBar.visible = true;
findBar.forceActiveFocus()
}
}
onToggleCompatibilityMode: {
for (let i = 0; i < tabs.count; ++i){
tabs.getTab(i).item.stop() // Stop all loading tabs
}
localAccountSensitiveSettings.compatibilityMode = checked;
for (let i = 0; i < tabs.count; ++i){
tabs.getTab(i).item.reload() // Reload them with new user agent
}
}
onLaunchBrowserSettings: {
Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.browserSettings);
}
}
BrowserWalletMenu {
id: browserWalletMenu
y: browserHeader.height + browserHeader.anchors.topMargin
x: parent.width - width - Style.current.halfPadding
onSendTriggered: {
sendTransactionModal.selectedAccount = selectedAccount
sendTransactionModal.open()
}
onReload: {
for (let i = 0; i < tabs.count; ++i){
tabs.getTab(i).item.reload();
}
}
onDisconnect: {
Web3ProviderStore.disconnect(Utils.getHostname(browserHeader.addressBar.text))
provider.postMessage("web3-disconnect-account", "{}");
_internal.currentWebView.reload()
close()
}
}
Menu {
id: historyMenu
Instantiator {
@ -570,10 +572,10 @@ Rectangle {
request.openIn(backgroundTab.item);
// Disabling popups temporarily since we need to set that webengineview settings / channel and other properties
/*} else if (request.destination === WebEngineView.NewViewInDialog) {
var dialog = browserDialogComponent.createObject();
dialog.currentWebView.profile = currentWebView.profile;
dialog.currentWebView.webChannel = channel;
request.openIn(dialog.currentWebView);*/
var dialog = browserDialogComponent.createObject();
dialog.currentWebView.profile = currentWebView.profile;
dialog.currentWebView.webChannel = channel;
request.openIn(dialog.currentWebView);*/
} else {
// Instead of opening a new window, we open a new tab
// TODO: remove "open in new window" from context menu
@ -588,7 +590,7 @@ Rectangle {
}
onJavaScriptDialogRequested: function(request) {
request.accepted = true;
var dialog = _internal.jsDialogComponent.createObject(browserWindow, {"request": request});
var dialog = _internal.jsDialogComponent.createObject(root, {"request": request});
dialog.open();
}
}

View File

@ -24,7 +24,6 @@ import "../../Wallet"
Item {
id: root
anchors.fill: parent
// Important: we have parent module in this context only cause qml components
// don't follow struct we have on the backend.
@ -214,8 +213,6 @@ Item {
sourceComponent: ChatContentView {
visible: !root.rootStore.openCreateChat && isActiveChannel
width: parent.width
height: parent.height
clip: true
rootStore: root.rootStore
contactsStore: root.contactsStore
@ -227,15 +224,10 @@ Item {
stickersLoaded: root.stickersLoaded
isBlocked: model.blocked
isActiveChannel: categoryChatLoader.isActiveChannel
activityCenterVisible: Global.activityCenterPopupOpened
activityCenterNotificationsCount: root.rootStore.unreadNotificationsCount
pinnedMessagesPopupComponent: root.pinnedMessagesListPopupComponent
onOpenStickerPackPopup: {
root.openStickerPackPopup(stickerPackId)
}
onNotificationButtonClicked: {
Global.openActivityCenterPopup()
}
onOpenAppSearch: {
root.openAppSearch();
}
@ -271,8 +263,6 @@ Item {
sourceComponent: ChatContentView {
visible: !root.rootStore.openCreateChat && isActiveChannel
width: parent.width
height: parent.height
clip: true
rootStore: root.rootStore
contactsStore: root.contactsStore
@ -284,15 +274,10 @@ Item {
stickersLoaded: root.stickersLoaded
isBlocked: model.blocked
isActiveChannel: chatLoader.isActiveChannel
activityCenterVisible: Global.activityCenterPopupOpened
activityCenterNotificationsCount: root.rootStore.unreadNotificationsCount
pinnedMessagesPopupComponent: root.pinnedMessagesListPopupComponent
onOpenStickerPackPopup: {
root.openStickerPackPopup(stickerPackId)
}
onNotificationButtonClicked: {
Global.openActivityCenterPopup()
}
onOpenAppSearch: {
root.openAppSearch();
}

View File

@ -37,8 +37,6 @@ ColumnLayout {
property bool isActiveChannel: false
property bool isConnected: false
property var emojiPopup
property bool activityCenterVisible: false
property int activityCenterNotificationsCount
property alias textInputField: chatInput
property UsersStore usersStore: UsersStore {}
property Component pinnedMessagesPopupComponent
@ -48,7 +46,6 @@ ColumnLayout {
}
signal openAppSearch()
signal notificationButtonClicked()
signal openStickerPackPopup(string stickerPackId)
property Component sendTransactionNoEnsModal
@ -67,250 +64,6 @@ ColumnLayout {
}
}
Keys.onEscapePressed: { topBar.toolbarComponent = statusChatInfoButton }
// Chat toolbar content option 1:
Component {
id: statusChatInfoButton
StatusChatInfoButton {
objectName: "chatInfoBtnInHeader"
width: Math.min(implicitWidth, parent.width)
title: chatContentModule? chatContentModule.chatDetails.name : ""
subTitle: {
if(!chatContentModule)
return ""
// In some moment in future this should be part of the backend logic.
// (once we add transaltion on the backend side)
switch (chatContentModule.chatDetails.type) {
case Constants.chatType.oneToOne:
return (chatContentModule.isMyContact(chatContentModule.chatDetails.id) ?
qsTr("Contact") :
qsTr("Not a contact"))
case Constants.chatType.publicChat:
return qsTr("Public chat")
case Constants.chatType.privateGroupChat:
const cnt = root.usersStore.usersModule.model.count
return qsTr("%n members(s)", "", cnt)
case Constants.chatType.communityChat:
return StatusQUtils.Utils.linkifyAndXSS(chatContentModule.chatDetails.description).trim()
default:
return ""
}
}
image.source: chatContentModule? chatContentModule.chatDetails.icon : ""
ringSettings.ringSpecModel: chatContentModule && chatContentModule.chatDetails.type === Constants.chatType.oneToOne ?
Utils.getColorHashAsJson(chatContentModule.chatDetails.id) : ""
icon.color: chatContentModule?
chatContentModule.chatDetails.type === Constants.chatType.oneToOne ?
Utils.colorForPubkey(chatContentModule.chatDetails.id)
: chatContentModule.chatDetails.color
: ""
icon.emoji: chatContentModule? chatContentModule.chatDetails.emoji : ""
icon.emojiSize: "24x24"
type: chatContentModule? chatContentModule.chatDetails.type : Constants.chatType.unknown
pinnedMessagesCount: chatContentModule? chatContentModule.pinnedMessagesModel.count : 0
muted: chatContentModule? chatContentModule.chatDetails.muted : false
onPinnedMessagesCountClicked: {
if(!chatContentModule) {
console.debug("error on open pinned messages - chat content module is not set")
return
}
Global.openPopup(pinnedMessagesPopupComponent, {
store: rootStore,
messageStore: messageStore,
pinnedMessagesModel: chatContentModule.pinnedMessagesModel,
messageToPin: ""
})
}
onUnmute: {
if(!chatContentModule) {
console.debug("error on unmute chat - chat content module is not set")
return
}
chatContentModule.unmuteChat()
}
sensor.enabled: {
if(!chatContentModule)
return false
return chatContentModule.chatDetails.type !== Constants.chatType.publicChat &&
chatContentModule.chatDetails.type !== Constants.chatType.communityChat
}
onClicked: {
switch (chatContentModule.chatDetails.type) {
case Constants.chatType.privateGroupChat:
Global.openPopup(root.rootStore.groupInfoPopupComponent, {
chatContentModule: chatContentModule,
chatDetails: chatContentModule.chatDetails
})
break;
case Constants.chatType.oneToOne:
Global.openProfilePopup(chatContentModule.chatDetails.id)
break;
}
}
}
}
// Chat toolbar content option 2:
Component {
id: contactsSelector
GroupChatPanel {
sectionModule: root.chatSectionModule
chatContentModule: root.chatContentModule
rootStore: root.rootStore
maxHeight: root.height
onPanelClosed: topBar.toolbarComponent = statusChatInfoButton
}
}
StatusChatToolBar {
id: topBar
z: parent.z + 1
Layout.fillWidth: true
toolbarComponent: statusChatInfoButton
membersButton.visible: {
if(!chatContentModule || chatContentModule.chatDetails.type === Constants.chatType.publicChat)
return false
return localAccountSensitiveSettings.showOnlineUsers &&
chatContentModule.chatDetails.isUsersListAvailable
}
membersButton.highlighted: localAccountSensitiveSettings.expandUsersList
notificationButton.tooltip.offset: localAccountSensitiveSettings.expandUsersList && membersButton.visible ? 0 : 14
notificationCount: root.activityCenterNotificationsCount
onSearchButtonClicked: root.openAppSearch()
onMembersButtonClicked: localAccountSensitiveSettings.expandUsersList = !localAccountSensitiveSettings.expandUsersList
notificationButton.highlighted: root.activityCenterVisible
onNotificationButtonClicked: root.notificationButtonClicked()
popupMenu: ChatContextMenuView {
objectName: "moreOptionsContextMenu"
emojiPopup: root.emojiPopup
openHandler: function () {
if(!chatContentModule) {
console.debug("error on open chat context menu handler - chat content module is not set")
return
}
currentFleet = chatContentModule.getCurrentFleet()
isCommunityChat = chatContentModule.chatDetails.belongsToCommunity
amIChatAdmin = chatContentModule.amIChatAdmin()
chatId = chatContentModule.chatDetails.id
chatName = chatContentModule.chatDetails.name
chatDescription = chatContentModule.chatDetails.description
chatEmoji = chatContentModule.chatDetails.emoji
chatColor = chatContentModule.chatDetails.color
chatIcon = chatContentModule.chatDetails.icon
chatType = chatContentModule.chatDetails.type
chatMuted = chatContentModule.chatDetails.muted
channelPosition = chatContentModule.chatDetails.position
}
onMuteChat: {
if(!chatContentModule) {
console.debug("error on mute chat from context menu - chat content module is not set")
return
}
chatContentModule.muteChat()
}
onUnmuteChat: {
if(!chatContentModule) {
console.debug("error on unmute chat from context menu - chat content module is not set")
return
}
chatContentModule.unmuteChat()
}
onMarkAllMessagesRead: {
if(!chatContentModule) {
console.debug("error on mark all messages read from context menu - chat content module is not set")
return
}
chatContentModule.markAllMessagesRead()
}
onClearChatHistory: {
if(!chatContentModule) {
console.debug("error on clear chat history from context menu - chat content module is not set")
return
}
chatContentModule.clearChatHistory()
}
onRequestAllHistoricMessages: {
// Not Refactored Yet - Check in the `master` branch if this is applicable here.
}
onLeaveChat: {
if(!chatContentModule) {
console.debug("error on leave chat from context menu - chat content module is not set")
return
}
chatContentModule.leaveChat()
}
onDeleteCommunityChat: root.rootStore.removeCommunityChat(chatId)
onDownloadMessages: {
if(!chatContentModule) {
console.debug("error on leave chat from context menu - chat content module is not set")
return
}
chatContentModule.downloadMessages(file)
}
onDisplayProfilePopup: {
Global.openProfilePopup(publicKey)
}
onDisplayGroupInfoPopup: {
Global.openPopup(root.rootStore.groupInfoPopupComponent, {
chatContentModule: chatContentModule,
chatDetails: chatContentModule.chatDetails
})
}
onEditCommunityChannel: {
root.rootStore.editCommunityChannel(
chatId,
newName,
newDescription,
newEmoji,
newColor,
newCategory,
channelPosition // TODO change this to the signal once it is modifiable
)
}
onAddRemoveGroupMember: {
topBar.toolbarComponent = contactsSelector
}
onFetchMoreMessages: {
root.rootStore.messageStore.requestMoreMessages();
}
onLeaveGroup: {
chatContentModule.leaveChat();
}
onUpdateGroupChatDetails: {
root.rootStore.chatCommunitySectionModule.updateGroupChatDetails(
chatId,
groupName,
groupColor,
groupImage
)
}
}
}
Rectangle {
id: connectedStatusRect
Layout.fillWidth: true

View File

@ -0,0 +1,339 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import utils 1.0
import "../panels"
RowLayout {
id: root
spacing: padding / 2
property alias menuButton: menuButton
property alias membersButton: membersButton
property alias searchButton: searchButton
property var rootStore
property var chatContentModule: root.rootStore.currentChatContentModule()
property int padding: 8
signal searchButtonClicked()
Loader {
id: loader
sourceComponent: statusChatInfoButton
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: padding
}
RowLayout {
id: actionButtons
Layout.alignment: Qt.AlignRight
Layout.rightMargin: padding
spacing: 8
StatusFlatRoundButton {
id: searchButton
icon.name: "search"
type: StatusFlatRoundButton.Type.Secondary
onClicked: root.searchButtonClicked()
// initializing the tooltip
tooltip.text: qsTr("Search")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
}
StatusFlatRoundButton {
id: membersButton
visible: {
if(!chatContentModule || chatContentModule.chatDetails.type === Constants.chatType.publicChat)
return false
return localAccountSensitiveSettings.showOnlineUsers &&
chatContentModule.chatDetails.isUsersListAvailable
}
highlighted: localAccountSensitiveSettings.expandUsersList
icon.name: "group-chat"
type: StatusFlatRoundButton.Type.Secondary
onClicked: {
localAccountSensitiveSettings.expandUsersList = !localAccountSensitiveSettings.expandUsersList;
}
// initializing the tooltip
tooltip.text: qsTr("Members")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
}
StatusFlatRoundButton {
id: menuButton
objectName: "chatToolbarMoreOptionsButton"
icon.name: "more"
type: StatusFlatRoundButton.Type.Secondary
// initializing the tooltip
tooltip.visible: !!tooltip.text && menuButton.hovered && !contextMenu.opened
tooltip.text: qsTr("More")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
property bool showMoreMenu: false
onClicked: {
menuButton.highlighted = true
let originalOpenHandler = contextMenu.openHandler
let originalCloseHandler = contextMenu.closeHandler
contextMenu.openHandler = function () {
if (!!originalOpenHandler) {
originalOpenHandler()
}
}
contextMenu.closeHandler = function () {
menuButton.highlighted = false
if (!!originalCloseHandler) {
originalCloseHandler()
}
}
contextMenu.openHandler = originalOpenHandler
contextMenu.popup(-contextMenu.width + menuButton.width, menuButton.height + 4)
}
ChatContextMenuView {
id: contextMenu
objectName: "moreOptionsContextMenu"
emojiPopup: root.emojiPopup
openHandler: function () {
if(!chatContentModule) {
console.debug("error on open chat context menu handler - chat content module is not set")
return
}
currentFleet = chatContentModule.getCurrentFleet()
isCommunityChat = chatContentModule.chatDetails.belongsToCommunity
amIChatAdmin = chatContentModule.amIChatAdmin()
chatId = chatContentModule.chatDetails.id
chatName = chatContentModule.chatDetails.name
chatDescription = chatContentModule.chatDetails.description
chatEmoji = chatContentModule.chatDetails.emoji
chatColor = chatContentModule.chatDetails.color
chatType = chatContentModule.chatDetails.type
chatMuted = chatContentModule.chatDetails.muted
channelPosition = chatContentModule.chatDetails.position
}
onMuteChat: {
if(!chatContentModule) {
console.debug("error on mute chat from context menu - chat content module is not set")
return
}
chatContentModule.muteChat()
}
onUnmuteChat: {
if(!chatContentModule) {
console.debug("error on unmute chat from context menu - chat content module is not set")
return
}
chatContentModule.unmuteChat()
}
onMarkAllMessagesRead: {
if(!chatContentModule) {
console.debug("error on mark all messages read from context menu - chat content module is not set")
return
}
chatContentModule.markAllMessagesRead()
}
onClearChatHistory: {
if(!chatContentModule) {
console.debug("error on clear chat history from context menu - chat content module is not set")
return
}
chatContentModule.clearChatHistory()
}
onRequestAllHistoricMessages: {
// Not Refactored Yet - Check in the `master` branch if this is applicable here.
}
onLeaveChat: {
if(!chatContentModule) {
console.debug("error on leave chat from context menu - chat content module is not set")
return
}
chatContentModule.leaveChat()
}
onDeleteCommunityChat: root.rootStore.removeCommunityChat(chatId)
onDownloadMessages: {
if(!chatContentModule) {
console.debug("error on leave chat from context menu - chat content module is not set")
return
}
chatContentModule.downloadMessages(file)
}
onDisplayProfilePopup: {
Global.openProfilePopup(publicKey)
}
onDisplayGroupInfoPopup: {
Global.openPopup(root.rootStore.groupInfoPopupComponent, {
chatContentModule: chatContentModule,
chatDetails: chatContentModule.chatDetails
})
}
onEditCommunityChannel: {
root.rootStore.editCommunityChannel(
chatId,
newName,
newDescription,
newEmoji,
newColor,
newCategory,
channelPosition // TODO change this to the signal once it is modifiable
)
}
onAddRemoveGroupMember: {
loader.sourceComponent = contactsSelector
}
onFetchMoreMessages: {
root.rootStore.messageStore.requestMoreMessages();
}
onLeaveGroup: {
chatContentModule.leaveChat();
}
onUpdateGroupChatDetails: {
root.rootStore.chatCommunitySectionModule.updateGroupChatDetails(
chatId,
groupName,
groupColor,
groupImage
)
}
}
}
Rectangle {
implicitWidth: 1
implicitHeight: 24
color: Theme.palette.directColor7
Layout.alignment: Qt.AlignVCenter
visible: (menuButton.visible || membersButton.visible || searchButton.visible)
}
}
Keys.onEscapePressed: { loader.sourceComponent = statusChatInfoButton }
// Chat toolbar content option 1:
Component {
id: statusChatInfoButton
StatusChatInfoButton {
objectName: "chatInfoBtnInHeader"
width: Math.min(implicitWidth, parent.width)
title: chatContentModule? chatContentModule.chatDetails.name : ""
subTitle: {
if(!chatContentModule)
return ""
// In some moment in future this should be part of the backend logic.
// (once we add transaltion on the backend side)
switch (chatContentModule.chatDetails.type) {
case Constants.chatType.oneToOne:
return (chatContentModule.isMyContact(chatContentModule.chatDetails.id) ?
qsTr("Contact") :
qsTr("Not a contact"))
case Constants.chatType.publicChat:
return qsTr("Public chat")
case Constants.chatType.privateGroupChat:
let cnt = root.usersStore.usersModule.model.count
if(cnt > 1) return qsTr("%n member(s)", "", cnt);
return qsTr("1 member");
case Constants.chatType.communityChat:
return Utils.linkifyAndXSS(chatContentModule.chatDetails.description).trim()
default:
return ""
}
}
image.source: chatContentModule? chatContentModule.chatDetails.icon : ""
ringSettings.ringSpecModel: chatContentModule && chatContentModule.chatDetails.type === Constants.chatType.oneToOne ?
Utils.getColorHashAsJson(chatContentModule.chatDetails.id) : ""
icon.color: chatContentModule?
chatContentModule.chatDetails.type === Constants.chatType.oneToOne ?
Utils.colorForPubkey(chatContentModule.chatDetails.id)
: chatContentModule.chatDetails.color
: ""
icon.emoji: chatContentModule? chatContentModule.chatDetails.emoji : ""
icon.emojiSize: "24x24"
type: chatContentModule? chatContentModule.chatDetails.type : Constants.chatType.unknown
pinnedMessagesCount: chatContentModule? chatContentModule.pinnedMessagesModel.count : 0
muted: chatContentModule? chatContentModule.chatDetails.muted : false
onPinnedMessagesCountClicked: {
if(!chatContentModule) {
console.debug("error on open pinned messages - chat content module is not set")
return
}
Global.openPopup(pinnedMessagesPopupComponent, {
store: rootStore,
messageStore: messageStore,
pinnedMessagesModel: chatContentModule.pinnedMessagesModel,
messageToPin: ""
})
}
onUnmute: {
if(!chatContentModule) {
console.debug("error on unmute chat - chat content module is not set")
return
}
chatContentModule.unmuteChat()
}
sensor.enabled: {
if(!chatContentModule)
return false
return chatContentModule.chatDetails.type !== Constants.chatType.publicChat &&
chatContentModule.chatDetails.type !== Constants.chatType.communityChat
}
onClicked: {
switch (chatContentModule.chatDetails.type) {
case Constants.chatType.privateGroupChat:
Global.openPopup(root.rootStore.groupInfoPopupComponent, {
chatContentModule: chatContentModule,
chatDetails: chatContentModule.chatDetails
})
break;
case Constants.chatType.oneToOne:
Global.openProfilePopup(chatContentModule.chatDetails.id)
break;
}
}
}
}
// Chat toolbar content option 2:
Component {
id: contactsSelector
GroupChatPanel {
sectionModule: root.chatSectionModule
chatContentModule: root.chatContentModule
rootStore: root.rootStore
maxHeight: root.height
onPanelClosed: loader.sourceComponent = statusChatInfoButton
}
}
}

View File

@ -11,6 +11,7 @@ import shared.views.chat 1.0
import StatusQ.Layout 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls 0.1
import "."
import "../panels"
@ -20,7 +21,7 @@ import "../helpers"
import "../controls"
import "../stores"
StatusAppThreePanelLayout {
StatusSectionLayout {
id: root
property var contactsStore
@ -57,6 +58,18 @@ StatusAppThreePanelLayout {
}
}
notificationButton.tooltip.offset: localAccountSensitiveSettings.expandUsersList && headerContent.membersButton.visible ? 0 : 14
notificationButton.highlighted: activityCenter.visible
onNotificationButtonClicked: Global.openActivityCenterPopup()
notificationCount: root.rootStore.unreadNotificationsCount
headerContent: ChatHeaderContentView {
id: headerContent
visible: !!root.rootStore.currentChatContentModule()
rootStore: root.rootStore
onSearchButtonClicked: root.openAppSearch()
}
leftPanel: Loader {
id: contactColumnLoader
sourceComponent: root.rootStore.chatCommunitySectionModule.isCommunity()?
@ -66,6 +79,7 @@ StatusAppThreePanelLayout {
centerPanel: ChatColumnView {
id: chatColumn
anchors.fill: parent
parentModule: root.rootStore.chatCommunitySectionModule
rootStore: root.rootStore
contactsStore: root.contactsStore
@ -82,8 +96,8 @@ StatusAppThreePanelLayout {
showRightPanel: {
if (root.rootStore.openCreateChat ||
!localAccountSensitiveSettings.showOnlineUsers ||
!localAccountSensitiveSettings.expandUsersList) {
!localAccountSensitiveSettings.showOnlineUsers ||
!localAccountSensitiveSettings.expandUsersList) {
return false
}
@ -98,9 +112,7 @@ StatusAppThreePanelLayout {
return chatContentModule.chatDetails.isUsersListAvailable
}
rightPanel: userListComponent
Component {
rightPanel: Component {
id: userListComponent
UserListPanel {
rootStore: root.rootStore
@ -203,4 +215,17 @@ StatusAppThreePanelLayout {
Component.onCompleted: {
rootStore.groupInfoPopupComponent = groupInfoPopupComponent;
}
ActivityCenterPopup {
id: activityCenter
y: 56
height: (root.height - 56) * 2 // TODO get screen size // Taken from old code top bar height was fixed there to 56
store: root.rootStore
chatSectionModule: root.rootStore.currentChatContentModule()
messageContextMenu: MessageContextMenuView {
id: contextmenu
store: root.rootStore
reactionModel: root.rootStore.emojiReactionsModel
}
}
}

View File

@ -20,14 +20,16 @@ import "../panels/communities"
import "../popups/community"
import "../layouts"
StatusAppTwoPanelLayout {
StatusSectionLayout {
id: root
notificationCount: root.rootStore.unreadNotificationsCount
onNotificationButtonClicked: Global.openActivityCenterPopup()
// TODO: get this model from backend?
property var settingsMenuModel: root.rootStore.communityPermissionsEnabled ? [{name: qsTr("Overview"), icon: "help"},
{name: qsTr("Members"), icon: "group-chat"},
{name: qsTr("Permissions"), icon: "objects"}] :
[{name: qsTr("Overview"), icon: "help"},
[{name: qsTr("Overview"), icon: "help"},
{name: qsTr("Members"), icon: "group-chat"}]
// TODO: Next community settings options:
// {name: qsTr("Tokens"), icon: "token"},
@ -122,9 +124,14 @@ StatusAppTwoPanelLayout {
}
}
rightPanel: Loader {
centerPanel: Loader {
anchors.fill: parent
anchors.margins: 32
//anchors.margins: 32
anchors {
leftMargin: 28
rightMargin: 16
bottomMargin: 16
}
active: root.community
sourceComponent: StackLayout {
currentIndex: d.currentIndex

View File

@ -8,6 +8,7 @@ import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Layout 0.1
import utils 1.0
import shared.popups 1.0
@ -17,7 +18,7 @@ import "controls"
import "stores"
import "popups"
StatusScrollView {
StatusSectionLayout {
id: root
objectName: "communitiesPortalLayout"
@ -26,6 +27,9 @@ StatusScrollView {
property var createCommunitiesPopup: createCommunitiesPopupComponent
property int contentPrefferedWidth: 100
notificationCount: root.communitiesStore.unreadNotificationsCount
onNotificationButtonClicked: Global.openActivityCenterPopup()
QtObject {
id: d
@ -40,146 +44,155 @@ StatusScrollView {
}
}
contentHeight: column.height + d.layoutVMargin
contentWidth: root.contentPrefferedWidth - d.layoutHMargin
centerPanel: Item {
implicitWidth: parent.width
implicitHeight: parent.height
clip: true
ColumnLayout {
id: column
width: parent.width
spacing: 18
StatusScrollView {
contentHeight: column.height + d.layoutVMargin
contentWidth: root.contentPrefferedWidth - d.layoutHMargin
StatusBaseText {
Layout.topMargin: d.layoutVMargin
Layout.leftMargin: d.layoutHMargin
text: qsTr("Find community")
font.weight: Font.Bold
font.pixelSize: d.titlePixelSize
color: Theme.palette.directColor1
}
ColumnLayout {
id: column
width: parent.availableWidth
height: childrenRect.height
RowLayout {
implicitWidth: parent.width
implicitHeight: 38
spacing: Style.current.bigPadding
spacing: 18
StatusInput {
id: searcher
implicitWidth: 327
Layout.leftMargin: d.layoutHMargin
Layout.alignment: Qt.AlignVCenter
enabled: false // Out of scope
placeholderText: qsTr("Search")
input.icon.name: "search"
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
minimumHeight: 36
maximumHeight: 36
text: d.searchText
onTextChanged: {
console.warn("TODO: Community Cards searcher algorithm.")
// 1. Filter Community Cards by title, description or tags category.
// 2. Once some filter is applyed, update main tags row only showing the tags that are part of the categories of the filtered Community Cards.
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
text: qsTr("Find community")
font.weight: Font.Bold
font.pixelSize: d.titlePixelSize
color: Theme.palette.directColor1
}
}
// Just a row filler to fit design
Item { Layout.fillWidth: true }
RowLayout {
Layout.fillWidth: true
Layout.preferredHeight: 38
spacing: Style.current.bigPadding
StatusButton {
id: importBtn
Layout.fillHeight: true
text: qsTr("Import using key")
onClicked: Global.openPopup(importCommunitiesPopupComponent)
}
StatusInput {
id: searcher
implicitWidth: 327
Layout.leftMargin: d.layoutHMargin
Layout.alignment: Qt.AlignVCenter
enabled: false // Out of scope
placeholderText: qsTr("Search")
input.icon.name: "search"
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
minimumHeight: 36
maximumHeight: 36
text: d.searchText
onTextChanged: {
console.warn("TODO: Community Cards searcher algorithm.")
// 1. Filter Community Cards by title, description or tags category.
// 2. Once some filter is applyed, update main tags row only showing the tags that are part of the categories of the filtered Community Cards.
}
}
StatusButton {
id: createBtn
objectName: "createCommunityButton"
Layout.fillHeight: true
text: qsTr("Create New Community")
onClicked: {
if (localAccountSensitiveSettings.isDiscordImportToolEnabled) {
Global.openPopup(chooseCommunityCreationTypePopupComponent)
} else {
Global.openPopup(createCommunitiesPopupComponent)
// Just a row filler to fit design
Item { Layout.fillWidth: true }
StatusButton {
id: importBtn
Layout.fillHeight: true
text: qsTr("Import using key")
onClicked: Global.openPopup(importCommunitiesPopupComponent)
}
StatusButton {
id: createBtn
objectName: "createCommunityButton"
Layout.fillHeight: true
text: qsTr("Create New Community")
onClicked: {
if (localAccountSensitiveSettings.isDiscordImportToolEnabled) {
Global.openPopup(chooseCommunityCreationTypePopupComponent)
} else {
Global.openPopup(createCommunitiesPopupComponent)
}
}
}
}
}
}
CommunityTagsRow {
tags: root.communitiesStore.communityTags
Layout.leftMargin: d.layoutHMargin
Layout.fillWidth: true
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Featured")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
id: featuredGrid
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: Style.current.padding
rowSpacing: Style.current.padding
Repeater {
model: root.communitiesStore.curatedCommunitiesModel
delegate: StatusCommunityCard {
visible: model.featured
locale: communitiesStore.locale
communityId: model.id
loaded: model.available
logo: model.icon
name: model.name
description: model.description
members: model.members
popularity: model.popularity
// <out of scope> categories: model.categories
onClicked: { d.navigateToCommunity(communityId) }
CommunityTagsRow {
tags: root.communitiesStore.communityTags
Layout.leftMargin: d.layoutHMargin
Layout.fillWidth: true
}
}
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Popular")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Featured")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: Style.current.padding
rowSpacing: Style.current.padding
GridLayout {
id: featuredGrid
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: Style.current.padding
rowSpacing: Style.current.padding
Repeater {
model: root.communitiesStore.curatedCommunitiesModel
delegate: StatusCommunityCard {
visible: !model.featured
locale: communitiesStore.locale
communityId: model.id
loaded: model.available
logo: model.icon
name: model.name
description: model.description
members: model.members
popularity: model.popularity
// <out of scope> categories: model.categories
Repeater {
model: root.communitiesStore.curatedCommunitiesModel
delegate: StatusCommunityCard {
visible: model.featured
locale: communitiesStore.locale
communityId: model.id
loaded: model.available
logo: model.icon
name: model.name
description: model.description
members: model.members
popularity: model.popularity
// <out of scope> categories: model.categories
onClicked: { d.navigateToCommunity(communityId) }
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Popular")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: Style.current.padding
rowSpacing: Style.current.padding
Repeater {
model: root.communitiesStore.curatedCommunitiesModel
delegate: StatusCommunityCard {
visible: !model.featured
locale: communitiesStore.locale
communityId: model.id
loaded: model.available
logo: model.icon
name: model.name
description: model.description
members: model.members
popularity: model.popularity
// <out of scope> categories: model.categories
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
}
}

View File

@ -17,6 +17,7 @@ QtObject {
property var advancedModule: profileSectionModule.advancedModule
property bool isCommunityHistoryArchiveSupportEnabled: advancedModule? advancedModule.isCommunityHistoryArchiveSupportEnabled : false
property int unreadNotificationsCount: activityCenterList.unreadCount
// TODO: Could the backend provide directly 2 filtered models??
//property var featuredCommunitiesModel: root.communitiesModuleInst.curatedFeaturedCommunities
//property var popularCommunitiesModel: root.communitiesModuleInst.curatedPopularCommunities

View File

@ -2,6 +2,7 @@ import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import StatusQ.Layout 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@ -13,14 +14,14 @@ import shared.controls 1.0
import "stores"
import "views"
Item {
StatusSectionLayout {
id: root
Layout.fillHeight: true
Layout.fillWidth: true
property RootStore store: RootStore {}
ColumnLayout {
notificationCount: root.store.unreadNotificationsCount
onNotificationButtonClicked: Global.openActivityCenterPopup()
centerPanel: ColumnLayout {
id: rpcColumn
spacing: 0
anchors.fill: parent

View File

@ -5,6 +5,7 @@ import utils 1.0
QtObject {
id: root
property int unreadNotificationsCount: activityCenterList.unreadCount
property var nodeModelInst: nodeModel
// property var profileModelInst: profileModel

View File

@ -13,14 +13,16 @@ import "views"
import StatusQ.Layout 0.1
import StatusQ.Controls 0.1
StatusAppTwoPanelLayout {
id: profileView
StatusSectionLayout {
id: root
property ProfileSectionStore store
property var globalStore
property var systemPalette
property var emojiPopup
notificationCount: root.store.unreadNotificationsCount
onNotificationButtonClicked: Global.openActivityCenterPopup()
Component.onCompleted: {
Global.privacyModuleInst = store.privacyStore.privacyModule
}
@ -38,7 +40,7 @@ StatusAppTwoPanelLayout {
leftPanel: LeftTabView {
id: leftTab
store: profileView.store
store: root.store
anchors.fill: parent
anchors.topMargin: d.topMargin
onMenuItemClicked: {
@ -49,16 +51,42 @@ StatusAppTwoPanelLayout {
}
}
rightPanel: Item {
centerPanel: Item {
anchors.fill: parent
ModuleWarning {
id: secureYourSeedPhrase
width: parent.width
visible: {
if (profileContainer.currentIndex !== Constants.settingsSubsection.profile) {
return false
}
if (root.store.profileStore.userDeclinedBackupBanner) {
return false
}
return !root.store.profileStore.privacyStore.mnemonicBackedUp
}
color: Style.current.red
btnWidth: 100
text: qsTr("Secure your seed phrase")
btnText: qsTr("Back up now")
onClick: function(){
Global.openBackUpSeedPopup();
}
onClosed: {
root.store.profileStore.userDeclinedBackupBanner = true
}
}
StatusBanner {
id: banner
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: visible ? childrenRect.height : 0
visible: profileContainer.currentIndex === Constants.settingsSubsection.wallet &&
profileView.store.walletStore.areTestNetworksEnabled
root.store.walletStore.areTestNetworksEnabled
type: StatusBanner.Type.Danger
statusText: qsTr("Testnet mode is enabled. All balances, transactions and dApp interactions will be on testnets.")
}
@ -72,7 +100,6 @@ StatusAppTwoPanelLayout {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.topMargin: d.topMargin
anchors.bottomMargin: d.bottomMargin
anchors.leftMargin: d.leftMargin
anchors.rightMargin: d.rightMargin
@ -89,20 +116,20 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
walletStore: profileView.store.walletStore
profileStore: profileView.store.profileStore
privacyStore: profileView.store.privacyStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.profile)
walletStore: root.store.walletStore
profileStore: root.store.profileStore
privacyStore: root.store.privacyStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile)
contentWidth: d.contentWidth
}
ContactsView {
implicitWidth: parent.width
implicitHeight: parent.height
contactsStore: profileView.store.contactsStore
contactsStore: root.store.contactsStore
sectionTitle: qsTr("Contacts")
contentWidth: d.contentWidth
backButtonName: profileView.store.getNameForSubsection(Constants.settingsSubsection.messaging)
backButtonName: root.store.getNameForSubsection(Constants.settingsSubsection.messaging)
onBackButtonClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.messaging)
@ -117,9 +144,9 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
ensUsernamesStore: profileView.store.ensUsernamesStore
contactsStore: profileView.store.contactsStore
stickersStore: profileView.store.stickersStore
ensUsernamesStore: root.store.ensUsernamesStore
contactsStore: root.store.contactsStore
stickersStore: root.store.stickersStore
profileContentWidth: d.contentWidth
}
@ -127,11 +154,10 @@ StatusAppTwoPanelLayout {
MessagingView {
implicitWidth: parent.width
implicitHeight: parent.height
messagingStore: profileView.store.messagingStore
advancedStore: profileView.store.advancedStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.messaging)
contactsStore: profileView.store.contactsStore
advancedStore: root.store.advancedStore
messagingStore: root.store.messagingStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.messaging)
contactsStore: root.store.contactsStore
contentWidth: d.contentWidth
}
@ -139,9 +165,9 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
walletStore: profileView.store.walletStore
emojiPopup: profileView.emojiPopup
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.wallet)
walletStore: root.store.walletStore
emojiPopup: root.emojiPopup
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.wallet)
contentWidth: d.contentWidth
}
@ -149,19 +175,19 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
appearanceStore: profileView.store.appearanceStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.appearance)
appearanceStore: root.store.appearanceStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.appearance)
contentWidth: d.contentWidth
systemPalette: profileView.systemPalette
systemPalette: root.systemPalette
}
LanguageView {
implicitWidth: parent.width
implicitHeight: parent.height
languageStore: profileView.store.languageStore
currencyStore: profileView.store.walletStore.currencyStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.language)
languageStore: root.store.languageStore
currencyStore: root.store.walletStore.currencyStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.language)
contentWidth: d.contentWidth
}
@ -169,9 +195,9 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
notificationsStore: profileView.store.notificationsStore
devicesStore: profileView.store.devicesStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.notifications)
notificationsStore: root.store.notificationsStore
devicesStore: root.store.devicesStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.notifications)
contentWidth: d.contentWidth
}
@ -179,8 +205,8 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
devicesStore: profileView.store.devicesStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.devicesSettings)
devicesStore: root.store.devicesStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.devicesSettings)
contentWidth: d.contentWidth
}
@ -188,8 +214,8 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
store: profileView.store
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.browserSettings)
store: root.store
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.browserSettings)
contentWidth: d.contentWidth
}
@ -197,8 +223,8 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
advancedStore: profileView.store.advancedStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.advanced)
advancedStore: root.store.advancedStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.advanced)
contentWidth: d.contentWidth
}
@ -206,9 +232,9 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
store: profileView.store
globalStore: profileView.globalStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.about)
store: root.store
globalStore: root.globalStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.about)
contentWidth: d.contentWidth
}
@ -216,10 +242,10 @@ StatusAppTwoPanelLayout {
implicitWidth: parent.width
implicitHeight: parent.height
profileSectionStore: profileView.store
rootStore: profileView.globalStore
contactStore: profileView.store.contactsStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.communitiesSettings)
profileSectionStore: root.store
rootStore: root.globalStore
contactStore: root.store.contactsStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.communitiesSettings)
contentWidth: d.contentWidth
}
@ -233,30 +259,5 @@ StatusAppTwoPanelLayout {
}
}
} // Item
ModuleWarning {
id: secureYourSeedPhrase
width: parent.width
visible: {
if (profileContainer.currentIndex !== Constants.settingsSubsection.profile) {
return false
}
if (profileView.store.profileStore.userDeclinedBackupBanner) {
return false
}
return !profileView.store.profileStore.privacyStore.mnemonicBackedUp
}
color: Style.current.red
btnWidth: 100
text: qsTr("Secure your seed phrase")
btnText: qsTr("Back up now")
onClick: function(){
Global.openBackUpSeedPopup();
}
onClosed: {
profileView.store.profileStore.userDeclinedBackupBanner = true
}
}
} // StatusAppTwoPanelLayout

View File

@ -5,6 +5,7 @@ import AppLayouts.Chat.stores 1.0
QtObject {
id: root
property int unreadNotificationsCount: activityCenterList.unreadCount
property var aboutModuleInst: aboutModule

View File

@ -13,7 +13,7 @@ import "views"
import "stores"
Item {
id: walletView
id: root
property bool hideSignPhraseModal: false
property var store
@ -45,25 +45,27 @@ Item {
anchors.top: parent ? parent.top: undefined
anchors.left: parent ? parent.left: undefined
anchors.right: parent ? parent.right: undefined
contactsStore: walletView.contactsStore
sendModal: walletView.sendModal
contactsStore: root.contactsStore
sendModal: root.sendModal
}
}
Component {
id: walletContainer
RightTabView {
store: walletView.store
sendModal: walletView.sendModal
store: root.store
sendModal: root.sendModal
}
}
StatusAppTwoPanelLayout {
StatusSectionLayout {
anchors.top: seedPhraseWarning.bottom
height: walletView.height - seedPhraseWarning.height
width: walletView.width
height: root.height - seedPhraseWarning.height
width: root.width
notificationCount: RootStore.unreadNotificationsCount
onNotificationButtonClicked: Global.openActivityCenterPopup()
Component.onCompleted: {
// Read in RootStore
// if(RootStore.firstTimeLogin){
@ -96,13 +98,12 @@ Item {
else
rightPanelStackView.replace(walletContainer)
}
emojiPopup: walletView.emojiPopup
emojiPopup: root.emojiPopup
}
rightPanel: StackView {
centerPanel: StackView {
id: rightPanelStackView
anchors.fill: parent
anchors.topMargin: 49
anchors.leftMargin: 49
anchors.rightMargin: 49
initialItem: walletContainer

View File

@ -10,8 +10,8 @@ import "../stores"
Rectangle {
id: root
visible: !RootStore.mnemonicBackedUp
height: visible ? 32 : 0
visible: !RootStore.mnemonicBackedUp
color: Style.current.red
Row {
@ -61,8 +61,7 @@ Rectangle {
SVGImage {
id: closeImg
anchors.top: parent.top
anchors.topMargin: 6
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 18
source: Style.svg("close-white")

View File

@ -7,6 +7,8 @@ import shared.stores 1.0 as SharedStore
QtObject {
id: root
property int unreadNotificationsCount: activityCenterList.unreadCount
property var currentAccount: Constants.isCppApp ? walletSectionAccounts.currentAccount: walletSectionCurrent
property var accounts: walletSectionAccounts.model
property var generatedAccounts: walletSectionAccounts.generated

View File

@ -227,13 +227,12 @@ Item {
height: 440
}
StatusAppLayout {
StatusMainLayout {
id: appLayout
anchors.fill: parent
appNavBar: StatusAppNavBar {
height: parent.height
leftPanel: StatusAppNavBar {
communityTypeRole: "sectionType"
communityTypeValue: Constants.appSection.community
sectionModel: mainModule.sectionsModel
@ -396,9 +395,8 @@ Item {
}
}
appView: ColumnLayout {
anchors.fill: parent
rightPanel: ColumnLayout {
spacing: 0
ModuleWarning {
id: versionWarning
width: parent.width
@ -452,7 +450,6 @@ Item {
StackLayout {
id: appView
anchors.fill: parent
currentIndex: {
@ -520,7 +517,6 @@ Item {
ChatLayout {
id: chatLayoutContainer
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
chatView.pinnedMessagesListPopupComponent: pinnedMessagesPopupComponent
@ -554,7 +550,6 @@ Item {
CommunitiesPortalLayout {
id: communitiesPortalLayoutContainer
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
contentPrefferedWidth: appView.width
}
@ -562,7 +557,6 @@ Item {
WalletLayout {
id: walletLayoutContainer
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
store: appMain.rootStore
contactsStore: appMain.rootStore.profileSectionStore.contactsStore
@ -583,7 +577,6 @@ Item {
sourceComponent: browserLayoutComponent
active: false
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
// Loaders do not have access to the context, so props need to be set
// Adding a "_" to avoid a binding loop
@ -599,7 +592,6 @@ Item {
ProfileLayout {
id: profileLayoutContainer
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
store: appMain.rootStore.profileSectionStore
@ -611,7 +603,6 @@ Item {
NodeLayout {
id: nodeLayoutContainer
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
}