839 lines
31 KiB
QML
839 lines
31 KiB
QML
import QtQuick 2.13
|
|
import QtQuick.Controls 2.13
|
|
import QtQuick.Layouts 1.13
|
|
import QtMultimedia 5.13
|
|
import Qt.labs.qmlmodels 1.0
|
|
|
|
import utils 1.0
|
|
import shared 1.0
|
|
import shared.panels 1.0
|
|
import shared.popups 1.0
|
|
import shared.status 1.0
|
|
import "./AppLayouts"
|
|
import "./AppLayouts/Timeline"
|
|
import "./AppLayouts/Wallet"
|
|
import "./AppLayouts/WalletV2"
|
|
import "./AppLayouts/Chat/popups"
|
|
import "./AppLayouts/Chat/popups/community"
|
|
import "./AppLayouts/Profile/Sections"
|
|
import "./AppLayouts/stores"
|
|
|
|
import Qt.labs.platform 1.1
|
|
import Qt.labs.settings 1.0
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
import StatusQ.Components 0.1
|
|
import StatusQ.Controls 0.1
|
|
import StatusQ.Layout 0.1
|
|
import StatusQ.Popups 0.1
|
|
import StatusQ.Core 0.1
|
|
|
|
Item {
|
|
id: appMain
|
|
anchors.fill: parent
|
|
|
|
property alias appLayout: appLayout
|
|
property var newVersionJSON: JSON.parse(utilsModel.newVersion)
|
|
property bool profilePopupOpened: false
|
|
property bool networkGuarded: profileModel.network.current === Constants.networkMainnet || (profileModel.network.current === Constants.networkRopsten && localAccountSensitiveSettings.stickersEnsRopsten)
|
|
property RootStore rootStore: RootStore { }
|
|
|
|
signal settingsLoaded()
|
|
signal openContactsPopup()
|
|
|
|
function changeAppSectionBySectionType(sectionType) {
|
|
mainModule.setActiveSectionBySectionType(sectionType)
|
|
}
|
|
|
|
function changeAppSectionBySectionId(sectionId) {
|
|
mainModule.setActiveSectionById(sectionId)
|
|
}
|
|
|
|
function getProfileImage(pubkey, isCurrentUser, useLargeImage) {
|
|
if (isCurrentUser || (isCurrentUser === undefined && pubkey === userProfile.pubKey)) {
|
|
return userProfile.thumbnailImage
|
|
}
|
|
|
|
const index = appMain.rootStore.contactsModuleInst.model.list.getContactIndexByPubkey(pubkey)
|
|
if (index === -1) {
|
|
return
|
|
}
|
|
|
|
if (localAccountSensitiveSettings.onlyShowContactsProfilePics) {
|
|
const isContact = appMain.rootStore.contactsModuleInst.model.list.rowData(index, "isContact")
|
|
if (isContact === "false") {
|
|
return
|
|
}
|
|
}
|
|
|
|
return appMain.rootStore.contactsModuleInst.model.list.rowData(index, useLargeImage ? "largeImage" : "thumbnailImage")
|
|
}
|
|
|
|
function openPopup(popupComponent, params = {}) {
|
|
const popup = popupComponent.createObject(appMain, params);
|
|
popup.open()
|
|
return popup
|
|
}
|
|
|
|
function getContactListObject(dataModel) {
|
|
const nbContacts = appMain.rootStore.contactsModuleInst.model.list.rowCount()
|
|
const contacts = []
|
|
let contact
|
|
for (let i = 0; i < nbContacts; i++) {
|
|
if (appMain.rootStore.contactsModuleInst.model.list.rowData(i, "isBlocked") === "true") {
|
|
continue
|
|
}
|
|
|
|
contact = {
|
|
name: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "name"),
|
|
localNickname: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "localNickname"),
|
|
pubKey: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "pubKey"),
|
|
address: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "address"),
|
|
identicon: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "identicon"),
|
|
thumbnailImage: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "thumbnailImage"),
|
|
isUser: false,
|
|
isContact: appMain.rootStore.contactsModuleInst.model.list.rowData(i, "isContact") !== "false"
|
|
}
|
|
|
|
contacts.push(contact)
|
|
if (dataModel) {
|
|
dataModel.append(contact);
|
|
}
|
|
}
|
|
return contacts
|
|
}
|
|
|
|
function getUserNickname(pubKey) {
|
|
// Get contact nickname
|
|
const contactList = appMain.rootStore.contactsModuleInst.model.list
|
|
const contactCount = contactList.rowCount()
|
|
for (let i = 0; i < contactCount; i++) {
|
|
if (contactList.rowData(i, 'pubKey') === pubKey) {
|
|
return contactList.rowData(i, 'localNickname')
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
function openLink(link) {
|
|
if (localAccountSensitiveSettings.showBrowserSelector) {
|
|
appMain.openPopup(chooseBrowserPopupComponent, {link: link})
|
|
} else {
|
|
if (localAccountSensitiveSettings.openLinksInStatus) {
|
|
appMain.changeAppSectionBySectionType(Constants.appSection.browser)
|
|
browserLayoutContainer.item.openUrlInNewTab(link)
|
|
} else {
|
|
Qt.openUrlExternally(link)
|
|
}
|
|
}
|
|
}
|
|
|
|
function openProfilePopup(userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam, parentPopup){
|
|
var popup = profilePopupComponent.createObject(appMain);
|
|
if(parentPopup){
|
|
popup.parentPopup = parentPopup;
|
|
}
|
|
popup.openPopup(userProfile.pubKey !== fromAuthorParam, userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam);
|
|
profilePopupOpened = true
|
|
}
|
|
|
|
property Component profilePopupComponent: ProfilePopup {
|
|
id: profilePopup
|
|
store: rootStore
|
|
onClosed: {
|
|
if(profilePopup.parentPopup){
|
|
profilePopup.parentPopup.close();
|
|
}
|
|
profilePopupOpened = false
|
|
destroy()
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: downloadModalComponent
|
|
DownloadModal {
|
|
onClosed: {
|
|
destroy();
|
|
}
|
|
}
|
|
}
|
|
|
|
Audio {
|
|
id: errorSound
|
|
track: "error.mp3"
|
|
}
|
|
|
|
Audio {
|
|
id: sendMessageSound
|
|
track: "send_message.wav"
|
|
}
|
|
|
|
Audio {
|
|
id: notificationSound
|
|
track: "notification.wav"
|
|
}
|
|
|
|
ModuleWarning {
|
|
id: versionWarning
|
|
width: parent.width
|
|
visible: newVersionJSON.available
|
|
color: Style.current.green
|
|
btnWidth: 100
|
|
text: qsTr("A new version of Status (%1) is available").arg(newVersionJSON.version)
|
|
btnText: qsTr("Download")
|
|
onClick: function(){
|
|
openPopup(downloadModalComponent, {newVersionAvailable: newVersionJSON.available, downloadURL: newVersionJSON.url})
|
|
}
|
|
}
|
|
|
|
AppSearch{
|
|
id: appSearch
|
|
store: mainModule.appSearchModule
|
|
}
|
|
|
|
StatusAppLayout {
|
|
id: appLayout
|
|
|
|
width: parent.width
|
|
anchors.top: parent.top
|
|
anchors.topMargin: versionWarning.visible ? 32 : 0
|
|
anchors.bottom: parent.bottom
|
|
|
|
appNavBar: StatusAppNavBar {
|
|
height: appMain.height
|
|
|
|
communityTypeRole: "sectionType"
|
|
communityTypeValue: Constants.appSection.community
|
|
sectionModel: mainModule.sectionsModel
|
|
|
|
property bool communityAdded: false
|
|
|
|
onAboutToUpdateFilteredRegularModel: {
|
|
communityAdded = false
|
|
}
|
|
|
|
filterRegularItem: function(item) {
|
|
if(!item.enabled)
|
|
return false
|
|
|
|
if(item.sectionType === Constants.appSection.community)
|
|
if(communityAdded)
|
|
return false
|
|
else
|
|
communityAdded = true
|
|
|
|
return true
|
|
}
|
|
|
|
filterCommunityItem: function(item) {
|
|
return item.sectionType === Constants.appSection.community
|
|
}
|
|
|
|
regularNavBarButton: StatusNavBarTabButton {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
name: model.icon.length > 0? "" : model.name
|
|
icon.name: model.icon
|
|
icon.source: model.image
|
|
tooltip.text: model.name
|
|
checked: model.active
|
|
badge.value: model.notificationsCount
|
|
badge.visible: model.hasNotification
|
|
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
|
|
badge.border.width: 2
|
|
onClicked: {
|
|
changeAppSectionBySectionId(model.id)
|
|
}
|
|
}
|
|
|
|
communityNavBarButton: StatusNavBarTabButton {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
name: model.icon.length > 0? "" : model.name
|
|
icon.name: model.icon
|
|
icon.source: model.image
|
|
tooltip.text: model.name
|
|
checked: model.active
|
|
badge.value: model.notificationsCount
|
|
badge.visible: model.hasNotification
|
|
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor
|
|
badge.border.width: 2
|
|
onClicked: {
|
|
changeAppSectionBySectionId(model.id)
|
|
}
|
|
|
|
popupMenu: StatusPopupMenu {
|
|
id: communityContextMenu
|
|
|
|
openHandler: function () {
|
|
chatsModel.communities.setObservedCommunity(model.id)
|
|
}
|
|
|
|
StatusMenuItem {
|
|
//% "Invite People"
|
|
text: qsTrId("invite-people")
|
|
icon.name: "share-ios"
|
|
enabled: chatsModel.communities.observedCommunity.canManageUsers
|
|
onTriggered: openPopup(inviteFriendsToCommunityPopup, {
|
|
community: chatsModel.communities.observedCommunity
|
|
})
|
|
}
|
|
|
|
StatusMenuItem {
|
|
//% "View Community"
|
|
text: qsTrId("view-community")
|
|
icon.name: "group-chat"
|
|
onTriggered: openPopup(communityProfilePopup, {
|
|
store: appMain.rootStore,
|
|
community: chatsModel.communities.observedCommunity
|
|
})
|
|
}
|
|
|
|
StatusMenuItem {
|
|
enabled: chatsModel.communities.observedCommunity.admin
|
|
//% "Edit Community"
|
|
text: qsTrId("edit-community")
|
|
icon.name: "edit"
|
|
onTriggered: openPopup(editCommunityPopup, {store: appMain.rootStore, community: chatsModel.communities.observedCommunity})
|
|
}
|
|
|
|
StatusMenuSeparator {}
|
|
|
|
StatusMenuItem {
|
|
//% "Leave Community"
|
|
text: qsTrId("leave-community")
|
|
icon.name: "arrow-right"
|
|
icon.width: 14
|
|
iconRotation: 180
|
|
type: StatusMenuItem.Type.Danger
|
|
onTriggered: chatsModel.communities.leaveCommunity(model.id)
|
|
}
|
|
}
|
|
}
|
|
|
|
navBarProfileButton: StatusNavBarTabButton {
|
|
id: profileButton
|
|
property bool opened: false
|
|
|
|
icon.source: userProfile.thumbnailImage
|
|
badge.visible: true
|
|
badge.anchors.rightMargin: 4
|
|
badge.anchors.topMargin: 25
|
|
badge.implicitHeight: 15
|
|
badge.implicitWidth: 15
|
|
badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusAppNavBar.backgroundColor
|
|
badge.color: {
|
|
return userProfile.sendUserStatus ? Style.current.green : Style.current.midGrey
|
|
/*
|
|
// Use this code once support for custom user status is added
|
|
switch(userProfile.currentUserStatus){
|
|
case Constants.statusType_Online:
|
|
return Style.current.green;
|
|
case Constants.statusType_DoNotDisturb:
|
|
return Style.current.red;
|
|
default:
|
|
return Style.current.midGrey;
|
|
}*/
|
|
}
|
|
badge.border.width: 3
|
|
onClicked: {
|
|
userStatusContextMenu.opened ?
|
|
userStatusContextMenu.close() :
|
|
userStatusContextMenu.open()
|
|
}
|
|
|
|
UserStatusContextMenu {
|
|
id: userStatusContextMenu
|
|
y: profileButton.y - userStatusContextMenu.height
|
|
store: appMain.rootStore
|
|
}
|
|
}
|
|
}
|
|
|
|
appView: StackLayout {
|
|
id: appView
|
|
anchors.fill: parent
|
|
currentIndex: {
|
|
if(mainModule.activeSection.sectionType === Constants.appSection.chat) {
|
|
return Constants.appViewStackIndex.chat
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.community) {
|
|
|
|
for(let i = this.children.length - 1; i >=0; i--)
|
|
{
|
|
var obj = this.children[i];
|
|
if(obj && obj.sectionId == mainModule.activeSection.id)
|
|
{
|
|
return i
|
|
}
|
|
}
|
|
|
|
// Should never be here, correct index must be returned from the for loop above
|
|
console.error("Wrong section type: ", mainModule.activeSection.sectionType,
|
|
" or section id: ", mainModule.activeSection.id)
|
|
return Constants.appViewStackIndex.community
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.wallet) {
|
|
return Constants.appViewStackIndex.wallet
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.walletv2) {
|
|
return Constants.appViewStackIndex.walletv2
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.browser) {
|
|
return Constants.appViewStackIndex.browser
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.timeline) {
|
|
return Constants.appViewStackIndex.timeline
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.profile) {
|
|
return Constants.appViewStackIndex.profile
|
|
}
|
|
else if(mainModule.activeSection.sectionType === Constants.appSection.node) {
|
|
return Constants.appViewStackIndex.node
|
|
}
|
|
|
|
// We should never end up here
|
|
console.error("Unknown section type")
|
|
}
|
|
|
|
onCurrentIndexChanged: {
|
|
var obj = this.children[currentIndex];
|
|
if(!obj)
|
|
return
|
|
|
|
if (obj.onActivated && typeof obj.onActivated === "function") {
|
|
this.children[currentIndex].onActivated()
|
|
}
|
|
|
|
if(obj === browserLayoutContainer && browserLayoutContainer.active == false){
|
|
browserLayoutContainer.active = true;
|
|
}
|
|
|
|
timelineLayoutContainer.active = obj === timelineLayoutContainer
|
|
|
|
if(obj === walletLayoutContainer){
|
|
walletLayoutContainer.showSigningPhrasePopup();
|
|
}
|
|
|
|
if(obj === walletV2LayoutContainer){
|
|
walletV2LayoutContainer.showSigningPhrasePopup();
|
|
}
|
|
}
|
|
|
|
// NOTE:
|
|
// If we ever change stack layout component order we need to updade
|
|
// Constants.appViewStackIndex accordingly
|
|
|
|
ChatLayout {
|
|
id: chatLayoutContainer
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
onProfileButtonClicked: {
|
|
appMain.changeAppSectionBySectionType(Constants.appSection.profile);
|
|
}
|
|
|
|
onOpenAppSearch: {
|
|
appSearch.openSearchPopup()
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
store = mainModule.getChatSectionModule()
|
|
}
|
|
}
|
|
|
|
WalletLayout {
|
|
id: walletLayoutContainer
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
}
|
|
|
|
Component {
|
|
id: browserLayoutComponent
|
|
BrowserLayout {
|
|
globalStore: appMain.rootStore
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: browserLayoutContainer
|
|
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
|
|
property var _chatsModel: chatsModel.messageView
|
|
property var _walletModel: walletModel
|
|
property var _utilsModel: utilsModel
|
|
property var _web3Provider: web3Provider
|
|
}
|
|
|
|
Loader {
|
|
id: timelineLayoutContainer
|
|
sourceComponent: Component {
|
|
TimelineLayout {
|
|
messageStore: appMain.rootStore.messageStore
|
|
rootStore: appMain.rootStore
|
|
}
|
|
}
|
|
onLoaded: timelineLayoutContainer.item.onActivated()
|
|
active: false
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
}
|
|
|
|
ProfileLayout {
|
|
id: profileLayoutContainer
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
globalStore: appMain.rootStore
|
|
}
|
|
|
|
NodeLayout {
|
|
id: nodeLayoutContainer
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
}
|
|
|
|
WalletV2Layout {
|
|
id: walletV2LayoutContainer
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
}
|
|
|
|
Repeater{
|
|
model: mainModule.sectionsModel
|
|
|
|
delegate: DelegateChooser {
|
|
id: delegateChooser
|
|
role: "sectionType"
|
|
DelegateChoice {
|
|
roleValue: Constants.appSection.community
|
|
delegate: ChatLayout {
|
|
property string sectionId: model.id
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
|
|
onProfileButtonClicked: {
|
|
appMain.changeAppSectionBySectionType(Constants.appSection.profile);
|
|
}
|
|
|
|
onOpenAppSearch: {
|
|
appSearch.openSearchPopup()
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
// we cannot return QVariant if we pass another parameter in a function call
|
|
// that's why we're using it this way
|
|
mainModule.prepareCommunitySectionModuleForCommunityId(model.id)
|
|
store = mainModule.getCommunitySectionModule()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: chatsModel
|
|
onNotificationClicked: {
|
|
applicationWindow.makeStatusAppActive()
|
|
|
|
switch(notificationType){
|
|
case Constants.osNotificationType.newContactRequest:
|
|
appView.currentIndex = Constants.appViewStackIndex.chat
|
|
appMain.openContactsPopup()
|
|
break
|
|
case Constants.osNotificationType.acceptedContactRequest:
|
|
appView.currentIndex = Constants.appViewStackIndex.chat
|
|
break
|
|
case Constants.osNotificationType.joinCommunityRequest:
|
|
case Constants.osNotificationType.acceptedIntoCommunity:
|
|
case Constants.osNotificationType.rejectedByCommunity:
|
|
// Not Refactored - Need to check what community exactly we need to switch to.
|
|
// appView.currentIndex = Utils.getAppSectionIndex(Constants.community)
|
|
break
|
|
case Constants.osNotificationType.newMessage:
|
|
appView.currentIndex = Constants.appViewStackIndex.chat
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: profileModel
|
|
ignoreUnknownSignals: true
|
|
enabled: removeMnemonicAfterLogin
|
|
onInitialized: {
|
|
mnemonicModule.remove()
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: appMain.rootStore.contactsModuleInst.model
|
|
onContactRequestAdded: {
|
|
if (!localAccountSensitiveSettings.notifyOnNewRequests) {
|
|
return
|
|
}
|
|
|
|
const isContact = appMain.rootStore.contactsModuleInst.model.isAdded(address)
|
|
|
|
// Note:
|
|
// Whole this Connection object should be moved to the nim side.
|
|
// Left here only cause we don't have a way to deal with translations on the nim side.
|
|
|
|
const title = isContact ? qsTrId("contact-request-accepted") :
|
|
//% "New contact request"
|
|
qsTrId("new-contact-request")
|
|
|
|
const message = //% "You can now chat with %1"
|
|
isContact ? qsTrId("you-can-now-chat-with--1").arg(Utils.removeStatusEns(name)) :
|
|
//% "%1 requests to become contacts"
|
|
qsTrId("-1-requests-to-become-contacts").arg(Utils.removeStatusEns(name))
|
|
|
|
if (Qt.platform.os === "linux") {
|
|
// Linux Notifications are not implemented in Nim/C++ yet
|
|
return systemTray.showMessage(title, message, systemTray.icon.source, 4000)
|
|
}
|
|
|
|
//% "Contact request accepted"
|
|
profileModel.showOSNotification(title,
|
|
message,
|
|
isContact? Constants.osNotificationType.acceptedContactRequest :
|
|
Constants.osNotificationType.newContactRequest,
|
|
localAccountSensitiveSettings.useOSNotifications)
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: chooseBrowserPopupComponent
|
|
ChooseBrowserPopup {
|
|
onClosed: {
|
|
destroy()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: inviteFriendsToCommunityPopup
|
|
InviteFriendsToCommunityPopup {
|
|
anchors.centerIn: parent
|
|
hasAddedContacts: appMain.rootStore.allContacts.hasAddedContacts()
|
|
onClosed: {
|
|
destroy()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: communityProfilePopup
|
|
|
|
CommunityProfilePopup {
|
|
anchors.centerIn: parent
|
|
|
|
onClosed: {
|
|
destroy()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: editCommunityPopup
|
|
CreateCommunityPopup {
|
|
anchors.centerIn: parent
|
|
isEdit: true
|
|
onClosed: {
|
|
destroy()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: editChannelPopup
|
|
CreateChannelPopup {
|
|
anchors.centerIn: parent
|
|
isEdit: true
|
|
// Not Refactored
|
|
// pinnedMessagesPopupComponent: chatLayoutContainer.chatColumn.pinnedMessagesPopupComponent
|
|
onClosed: {
|
|
destroy()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: genericConfirmationDialog
|
|
ConfirmationDialog {
|
|
onClosed: {
|
|
destroy()
|
|
}
|
|
}
|
|
}
|
|
|
|
ToastMessage {
|
|
id: toastMessage
|
|
}
|
|
|
|
// Add SendModal here as it is used by the Wallet as well as the Browser
|
|
Loader {
|
|
id: sendModal
|
|
active: false
|
|
|
|
function open() {
|
|
this.active = true
|
|
this.item.open()
|
|
}
|
|
function closed() {
|
|
// this.sourceComponent = undefined // kill an opened instance
|
|
this.active = false
|
|
}
|
|
sourceComponent: SendModal {
|
|
store: appMain.rootStore
|
|
onOpened: {
|
|
walletModel.gasView.getGasPrice()
|
|
}
|
|
onClosed: {
|
|
sendModal.closed()
|
|
}
|
|
}
|
|
}
|
|
|
|
Action {
|
|
shortcut: "Ctrl+1"
|
|
onTriggered: changeAppSectionBySectionType(Constants.appSection.chat)
|
|
}
|
|
Action {
|
|
shortcut: "Ctrl+2"
|
|
onTriggered: changeAppSectionBySectionType(Constants.appSection.browser)
|
|
}
|
|
Action {
|
|
shortcut: "Ctrl+3"
|
|
onTriggered: changeAppSectionBySectionType(Constants.appSection.wallet)
|
|
}
|
|
Action {
|
|
shortcut: "Ctrl+4, Ctrl+,"
|
|
onTriggered: changeAppSectionBySectionType(Constants.appSection.profile)
|
|
}
|
|
Action {
|
|
shortcut: "Ctrl+K"
|
|
onTriggered: {
|
|
if (channelPicker.opened) {
|
|
channelPicker.close()
|
|
} else {
|
|
channelPicker.open()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: statusSmartIdenticonComponent
|
|
StatusSmartIdenticon {
|
|
property string imageSource: ""
|
|
image: StatusImageSettings {
|
|
width: channelPicker.imageWidth
|
|
height: channelPicker.imageHeight
|
|
source: imageSource
|
|
isIdenticon: true
|
|
}
|
|
icon: StatusIconSettings {
|
|
width: channelPicker.imageWidth
|
|
height: channelPicker.imageHeight
|
|
letterSize: 15
|
|
color: Theme.palette.miscColor5
|
|
}
|
|
}
|
|
}
|
|
|
|
StatusInputListPopup {
|
|
id: channelPicker
|
|
//% "Where do you want to go?"
|
|
title: qsTrId("where-do-you-want-to-go-")
|
|
showSearchBox: true
|
|
width: 350
|
|
x: parent.width / 2 - width / 2
|
|
y: parent.height / 2 - height / 2
|
|
modelList: chatsModel.channelView.chats
|
|
getText: function (modelData) {
|
|
return modelData.name
|
|
}
|
|
getImageComponent: function (parent, modelData) {
|
|
return statusSmartIdenticonComponent.createObject(parent, {
|
|
imageSource: modelData.identicon,
|
|
name: modelData.name
|
|
});
|
|
}
|
|
onClicked: function (index) {
|
|
appMain.changeAppSectionBySectionType(Constants.appSection.chat)
|
|
chatsModel.channelView.setActiveChannelByIndex(index)
|
|
channelPicker.close()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
// Since https://github.com/status-im/status-desktop/commit/93668ff75
|
|
// we're hiding the setting to change appearance for compact normal mode
|
|
// of the UI. For now, compact mode is the new default.
|
|
//
|
|
// Prior to this change, most likely many users are still using the
|
|
// normal mode configuration, so we have to enforce compact mode for
|
|
// those.
|
|
if (!localAccountSensitiveSettings.useCompactMode) {
|
|
localAccountSensitiveSettings.useCompactMode = true
|
|
}
|
|
|
|
const whitelist = profileModel.getLinkPreviewWhitelist()
|
|
try {
|
|
const whiteListedSites = JSON.parse(whitelist)
|
|
let settingsUpdated = false
|
|
|
|
// Add Status links to whitelist
|
|
whiteListedSites.push({title: "Status", address: Constants.deepLinkPrefix, imageSite: false})
|
|
whiteListedSites.push({title: "Status", address: Constants.joinStatusLink, imageSite: false})
|
|
let settings = localAccountSensitiveSettings.whitelistedUnfurlingSites
|
|
|
|
if (!settings) {
|
|
settings = {}
|
|
}
|
|
|
|
// Set Status links as true. We intercept thoseURLs so it is privacy-safe
|
|
if (!settings[Constants.deepLinkPrefix] || !settings[Constants.joinStatusLink]) {
|
|
settings[Constants.deepLinkPrefix] = true
|
|
settings[Constants.joinStatusLink] = true
|
|
settingsUpdated = true
|
|
}
|
|
|
|
const whitelistedHostnames = []
|
|
|
|
// Add whitelisted sites in to app settings that are not already there
|
|
whiteListedSites.forEach(site => {
|
|
if (!settings.hasOwnProperty(site.address)) {
|
|
settings[site.address] = false
|
|
settingsUpdated = true
|
|
}
|
|
whitelistedHostnames.push(site.address)
|
|
})
|
|
// Remove any whitelisted sites from app settings that don't exist in the
|
|
// whitelist from status-go
|
|
Object.keys(settings).forEach(settingsHostname => {
|
|
if (!whitelistedHostnames.includes(settingsHostname)) {
|
|
delete settings[settingsHostname]
|
|
settingsUpdated = true
|
|
}
|
|
})
|
|
if (settingsUpdated) {
|
|
localAccountSensitiveSettings.whitelistedUnfurlingSites = settings
|
|
}
|
|
} catch (e) {
|
|
console.error('Could not parse the whitelist for sites', e)
|
|
}
|
|
appMain.settingsLoaded()
|
|
}
|
|
}
|