chore: Remove the Browser from the app completely for now

- completely removes the `ui/app/AppLayouts/Browser` QML app section
- removes the `app_service/service/bookmarks`,
`app/modules/main/browser_section` and
`src/app_service/service/dapp_permissions` NIM modules
- remove the Browser settings page and associated popups/components
- HTML links now always open in an external browser
- adjust the section indexes in `Constants`
- fixup the e2e tests

Fixes #14614
This commit is contained in:
Lukáš Tinkl 2024-08-05 12:55:28 +02:00 committed by Lukáš Tinkl
parent b8bcab79a9
commit ed650d32dd
106 changed files with 26 additions and 7806 deletions

View File

@ -14,8 +14,6 @@ import app_service/service/collectible/service as collectible_service
import app_service/service/currency/service as currency_service
import app_service/service/transaction/service as transaction_service
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/bookmarks/service as bookmark_service
import app_service/service/dapp_permissions/service as dapp_permissions_service
import app_service/service/privacy/service as privacy_service
import app_service/service/provider/service as provider_service
import app_service/service/node/service as node_service
@ -81,8 +79,6 @@ type
currencyService: currency_service.Service
transactionService: transaction_service.Service
walletAccountService: wallet_account_service.Service
bookmarkService: bookmark_service.Service
dappPermissionsService: dapp_permissions_service.Service
providerService: provider_service.Service
profileService: profile_service.Service
settingsService: settings_service.Service
@ -204,7 +200,6 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.communityService = community_service.newService(statusFoundation.events,
statusFoundation.threadpool, result.chatService, result.activityCenterService, result.messageService)
result.transactionService = transaction_service.newService(statusFoundation.events, statusFoundation.threadpool, result.networkService, result.settingsService, result.tokenService)
result.bookmarkService = bookmark_service.newService(statusFoundation.events)
result.profileService = profile_service.newService(statusFoundation.events, statusFoundation.threadpool, result.settingsService)
result.stickersService = stickers_service.newService(
statusFoundation.events,
@ -217,7 +212,6 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.tokenService
)
result.aboutService = about_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.dappPermissionsService = dapp_permissions_service.newService()
result.languageService = language_service.newService(statusFoundation.events)
# result.mnemonicService = mnemonic_service.newService()
result.privacyService = privacy_service.newService(statusFoundation.events, result.settingsService,
@ -265,12 +259,10 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.currencyService,
result.transactionService,
result.walletAccountService,
result.bookmarkService,
result.profileService,
result.settingsService,
result.contactsService,
result.aboutService,
result.dappPermissionsService,
result.languageService,
# result.mnemonicService,
result.privacyService,
@ -304,7 +296,6 @@ proc delete*(self: AppController) =
self.notificationsManager.delete
self.keychainService.delete
self.contactsService.delete
self.bookmarkService.delete
self.gifService.delete
if not self.startupModule.isNil:
self.startupModule.delete
@ -331,7 +322,6 @@ proc delete*(self: AppController) =
self.aboutService.delete
self.networkService.delete
self.activityCenterService.delete
self.dappPermissionsService.delete
self.providerService.delete
self.nodeConfigurationService.delete
self.nodeService.delete
@ -431,8 +421,6 @@ proc load(self: AppController) =
self.chatService.init()
self.messageService.init()
self.communityService.init()
self.bookmarkService.init()
self.dappPermissionsService.init()
self.providerService.init()
self.transactionService.init()
self.stickersService.init()

View File

@ -4,7 +4,6 @@ import base
import ../../../../app_service/service/message/dto/[message, pinned_message_update, reaction, removed_message]
import ../../../../app_service/service/chat/dto/[chat]
import ../../../../app_service/service/bookmarks/dto/[bookmark]
import ../../../../app_service/service/community/dto/[community]
import ../../../../app_service/service/activity_center/dto/[notification]
import ../../../../app_service/service/contacts/dto/[contacts, status_update]
@ -14,7 +13,6 @@ import ../../../../app_service/service/saved_address/dto as saved_address_dto
import ../../../../app_service/service/wallet_account/dto/[keypair_dto]
type MessageSignal* = ref object of Signal
bookmarks*: seq[BookmarkDto]
messages*: seq[MessageDto]
pinnedMessages*: seq[PinnedMessageUpdateDto]
chats*: seq[ChatDto]
@ -88,11 +86,6 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
var currentStatus = e["currentStatus"].toStatusUpdateDto()
signal.currentStatus.add(currentStatus)
if e.contains("bookmarks"):
for jsonBookmark in e["bookmarks"]:
var bookmark = jsonBookmark.toBookmarkDto()
signal.bookmarks.add(bookmark)
if e.contains("installations"):
for jsonDevice in e["installations"]:
signal.installations.add(jsonDevice.toInstallationDto())

View File

@ -11,10 +11,6 @@ const WALLET_SECTION_ID* = "wallet"
const WALLET_SECTION_NAME* = "Wallet"
const WALLET_SECTION_ICON* = "wallet"
const BROWSER_SECTION_ID* = "browser"
const BROWSER_SECTION_NAME* = "Browser"
const BROWSER_SECTION_ICON* = "browser"
const NODEMANAGEMENT_SECTION_ID* = "nodeManagement"
const NODEMANAGEMENT_SECTION_NAME* = "Node Management"
const NODEMANAGEMENT_SECTION_ICON* = "node"

View File

@ -14,8 +14,6 @@ const LSS_KEY_NODE_MANAGEMENT_ENABLED* = "nodeManagementEnabled"
const DEFAULT_NODE_MANAGEMENT_ENABLED = false
const LSS_KEY_ENS_COMMUNITY_PERMISSIONS_ENABLED* = "ensCommunityPermissionsEnabled"
const DEFAULT_COMMUNITY_PERMISSIONS_ENABLED = false
const LSS_KEY_IS_BROWSER_ENABLED* = "isExperimentalBrowserEnabled"
const DEFAULT_IS_BROWSER_ENABLED = false
const LSS_KEY_SHOW_ONLINE_USERS* = "showOnlineUsers"
const DEFAULT_SHOW_ONLINE_USERS = true
const LSS_KEY_EXPAND_USERS_LIST* = "expandUsersList"
@ -49,18 +47,6 @@ const LSS_KEY_ACTIVE_SECTION* = "activeSection"
const DEFAULT_ACTIVE_SECTION = ""
const LAST_SECTION_CHAT = "LastSectionChat"
const DEFAULT_ACTIVE_CHAT = ""
const LSS_KEY_SHOW_BROWSER_SELECTOR* = "showBrowserSelector"
const DEFAULT_SHOW_BROWSER_SELECTOR = true
const LSS_KEY_OPEN_LINKS_IN_STATUS* = "openLinksInStatus"
const DEFAULT_OPEN_LINKS_IN_STATUS = true
const LSS_KEY_SHOULD_SHOW_FAVORITES_BAR* = "shouldShowFavoritesBar"
const DEFAULT_SHOULD_SHOW_FAVORITES_BAR = true
const LSS_KEY_BROWSER_HOMEPAGE* = "browserHomepage"
const DEFAULT_BROWSER_HOMEPAGE = ""
const LSS_KEY_SHOULD_SHOW_BROWSER_SEARCH_ENGINE* = "shouldShowBrowserSearchEngine"
const DEFAULT_SHOULD_SHOW_BROWSER_SEARCH_ENGINE = 3 #browserSearchEngineDuckDuckGo from qml
const LSS_KEY_USE_BROWSER_ETHEREUM_EXPLORER* = "useBrowserEthereumExplorer"
const DEFAULT_USE_BROWSER_ETHEREUM_EXPLORER = 1 #browserEthereumExplorerEtherscan from qml
const LSS_KEY_AUTO_LOAD_IMAGES* = "autoLoadImages"
const DEFAULT_AUTO_LOAD_IMAGES = true
const LSS_KEY_JAVA_SCRIPT_ENABLED* = "javaScriptEnabled"
@ -233,18 +219,6 @@ QtObject:
write = setNodeManagementEnabled
notify = nodeManagementEnabledChanged
proc isBrowserEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsBrowserEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_IS_BROWSER_ENABLED, newQVariant(DEFAULT_IS_BROWSER_ENABLED))
proc setIsBrowserEnabled*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_IS_BROWSER_ENABLED, newQVariant(value)):
self.isBrowserEnabledChanged()
QtProperty[bool] isBrowserEnabled:
read = getIsBrowserEnabled
write = setIsBrowserEnabled
notify = isBrowserEnabledChanged
proc ensCommunityPermissionsEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getEnsCommunityPermissionsEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_ENS_COMMUNITY_PERMISSIONS_ENABLED, newQVariant(DEFAULT_COMMUNITY_PERMISSIONS_ENABLED))
@ -448,85 +422,6 @@ QtObject:
write = setActiveSection
notify = activeSectionChanged
proc showBrowserSelectorChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getShowBrowserSelector*(self: LocalAccountSensitiveSettings): bool {.slot.} =
# getSettingsProp[bool](self, LSS_KEY_SHOW_BROWSER_SELECTOR, newQVariant(DEFAULT_SHOW_BROWSER_SELECTOR)) # https://github.com/status-im/status-desktop/issues/8568
return false
proc setShowBrowserSelector*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_SHOW_BROWSER_SELECTOR, newQVariant(value)):
self.showBrowserSelectorChanged()
QtProperty[bool] showBrowserSelector:
read = getShowBrowserSelector
write = setShowBrowserSelector
notify = showBrowserSelectorChanged
proc openLinksInStatusChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getOpenLinksInStatus*(self: LocalAccountSensitiveSettings): bool {.slot.} =
# getSettingsProp[bool](self, LSS_KEY_OPEN_LINKS_IN_STATUS, newQVariant(DEFAULT_OPEN_LINKS_IN_STATUS)) # https://github.com/status-im/status-desktop/issues/8568
return false
proc setOpenLinksInStatus*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_OPEN_LINKS_IN_STATUS, newQVariant(value)):
self.openLinksInStatusChanged()
QtProperty[bool] openLinksInStatus:
read = getOpenLinksInStatus
write = setOpenLinksInStatus
notify = openLinksInStatusChanged
proc shouldShowFavoritesBarChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getShouldShowFavoritesBar*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_SHOULD_SHOW_FAVORITES_BAR, newQVariant(DEFAULT_SHOULD_SHOW_FAVORITES_BAR))
proc setShouldShowFavoritesBar*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_SHOULD_SHOW_FAVORITES_BAR, newQVariant(value)):
self.shouldShowFavoritesBarChanged()
QtProperty[bool] shouldShowFavoritesBar:
read = getShouldShowFavoritesBar
write = setShouldShowFavoritesBar
notify = shouldShowFavoritesBarChanged
proc browserHomepageChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getBrowserHomepage*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_BROWSER_HOMEPAGE, newQVariant(DEFAULT_BROWSER_HOMEPAGE))
proc setBrowserHomepage*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_BROWSER_HOMEPAGE, newQVariant(value)):
self.browserHomepageChanged()
QtProperty[string] browserHomepage:
read = getBrowserHomepage
write = setBrowserHomepage
notify = browserHomepageChanged
proc shouldShowBrowserSearchEngineChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getShouldShowBrowserSearchEngine*(self: LocalAccountSensitiveSettings): int {.slot.} =
getSettingsProp[int](self, LSS_KEY_SHOULD_SHOW_BROWSER_SEARCH_ENGINE, newQVariant(DEFAULT_SHOULD_SHOW_BROWSER_SEARCH_ENGINE))
proc setShouldShowBrowserSearchEngine*(self: LocalAccountSensitiveSettings, value: int) {.slot.} =
setSettingsProp(self, LSS_KEY_SHOULD_SHOW_BROWSER_SEARCH_ENGINE, newQVariant(value)):
self.shouldShowBrowserSearchEngineChanged()
QtProperty[int] shouldShowBrowserSearchEngine:
read = getShouldShowBrowserSearchEngine
write = setShouldShowBrowserSearchEngine
notify = shouldShowBrowserSearchEngineChanged
proc useBrowserEthereumExplorerChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getUseBrowserEthereumExplorer*(self: LocalAccountSensitiveSettings): int {.slot.} =
getSettingsProp[int](self, LSS_KEY_USE_BROWSER_ETHEREUM_EXPLORER, newQVariant(DEFAULT_USE_BROWSER_ETHEREUM_EXPLORER))
proc setUseBrowserEthereumExplorer*(self: LocalAccountSensitiveSettings, value: int) {.slot.} =
setSettingsProp(self, LSS_KEY_USE_BROWSER_ETHEREUM_EXPLORER, newQVariant(value)):
self.useBrowserEthereumExplorerChanged()
QtProperty[int] useBrowserEthereumExplorer:
read = getUseBrowserEthereumExplorer
write = setUseBrowserEthereumExplorer
notify = useBrowserEthereumExplorerChanged
proc autoLoadImagesChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getAutoLoadImages*(self: LocalAccountSensitiveSettings): bool {.slot.} =
@ -706,7 +601,6 @@ QtObject:
of LSS_KEY_PROFILE_SPLIT_VIEW: self.profileSplitViewChanged()
of LSS_KEY_NODE_MANAGEMENT_ENABLED: self.nodeManagementEnabledChanged()
of LSS_KEY_ENS_COMMUNITY_PERMISSIONS_ENABLED: self.ensCommunityPermissionsEnabledChanged()
of LSS_KEY_IS_BROWSER_ENABLED: self.isBrowserEnabledChanged()
of LSS_KEY_SHOW_ONLINE_USERS: self.showOnlineUsersChanged()
of LSS_KEY_EXPAND_USERS_LIST: self.expandUsersListChanged()
of LSS_KEY_RECENT_EMOJIS: self.recentEmojisChanged()
@ -722,12 +616,6 @@ QtObject:
of LSS_KEY_SHOW_DELETE_MESSAGE_WARNING: self.showDeleteMessageWarningChanged()
of LSS_KEY_DOWNLOAD_CHANNEL_MESSAGES_ENABLED: self.downloadChannelMessagesEnabledChanged()
of LSS_KEY_ACTIVE_SECTION: self.activeSectionChanged()
of LSS_KEY_SHOW_BROWSER_SELECTOR: self.showBrowserSelectorChanged()
of LSS_KEY_OPEN_LINKS_IN_STATUS: self.openLinksInStatusChanged()
of LSS_KEY_SHOULD_SHOW_FAVORITES_BAR: self.shouldShowFavoritesBarChanged()
of LSS_KEY_BROWSER_HOMEPAGE: self.browserHomepageChanged()
of LSS_KEY_SHOULD_SHOW_BROWSER_SEARCH_ENGINE: self.shouldShowBrowserSearchEngineChanged()
of LSS_KEY_USE_BROWSER_ETHEREUM_EXPLORER: self.useBrowserEthereumExplorerChanged()
of LSS_KEY_AUTO_LOAD_IMAGES: self.autoLoadImagesChanged()
of LSS_KEY_JAVA_SCRIPT_ENABLED: self.javaScriptEnabledChanged()
of LSS_KEY_ERROR_PAGE_ENABLED: self.errorPageEnabledChanged()

View File

@ -1,53 +0,0 @@
import results
import io_interface
import ../../../../../app_service/service/bookmarks/service as bookmark_service
import ../../../../core/eventemitter
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
events: EventEmitter
bookmarkService: bookmark_service.Service
proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter,
bookmarkService: bookmark_service.Service):
Controller =
result = Controller()
result.events = events
result.delegate = delegate
result.bookmarkService = bookmarkService
proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
self.events.on(SIGNAL_BOOKMARK_REMOVED) do(e: Args):
let args = BookmarkRemovedArgs(e)
self.delegate.onBookmarkDeleted(args.url)
self.events.on(SIGNAL_BOOKMARK_ADDED) do(e: Args):
let args = BookmarkArgs(e)
self.delegate.onBoomarkStored(args.bookmark.url, args.bookmark.name, args.bookmark.imageUrl)
self.events.on(SIGNAL_BOOKMARK_UPDATED) do(e: Args):
let args = BookmarkArgs(e)
self.delegate.onBookmarkUpdated(args.bookmark.url, args.bookmark.url, args.bookmark.name, args.bookmark.imageUrl)
proc getBookmarks*(self: Controller): seq[bookmark_service.BookmarkDto] =
return self.bookmarkService.getBookmarks()
proc storeBookmark*(self: Controller, url, name: string) =
let b = self.bookmarkService.storeBookmark(url, name)
if b.isOk:
self.delegate.onBoomarkStored(url, name, b.get().imageUrl)
proc deleteBookmark*(self: Controller, url: string) =
if self.bookmarkService.deleteBookmark(url):
self.delegate.onBookmarkDeleted(url)
proc updateBookmark*(self: Controller, oldUrl, newUrl, newName: string) =
let b = self.bookmarkService.updateBookmark(oldUrl, newUrl, newName)
if b.isOk:
self.delegate.onBookmarkUpdated(oldUrl, newUrl, newName, b.get().imageUrl)

View File

@ -1,40 +0,0 @@
import ../../../../../app_service/service/bookmarks/service as bookmark_service
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onActivated*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getBookmarks*(self: AccessInterface): seq[bookmark_service.BookmarkDto] {.base.} =
raise newException(ValueError, "No implementation available")
method storeBookmark*(self: AccessInterface, url, name: string) {.base.} =
raise newException(ValueError, "No implementation available")
method deleteBookmark*(self: AccessInterface, url: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateBookmark*(self: AccessInterface, oldUrl, newUrl, newName: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onBoomarkStored*(self: AccessInterface, url: string, name: string, imageUrl: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onBookmarkDeleted*(self: AccessInterface, url: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onBookmarkUpdated*(self: AccessInterface, oldUrl: string, newUrl: string, newName: string, newImageUrl: string) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,28 +0,0 @@
import stew/shims/strformat
type
Item* = object
name: string
url: string
imageUrl: string
proc initItem*(name, url, imageUrl: string): Item =
result.name = name
result.url = url
result.imageUrl = imageUrl
proc `$`*(self: Item): string =
result = fmt"""BrowserItem(
name: {self.name},
url: {self.url},
imageUrl: {self.imageUrl}
]"""
proc getName*(self: Item): string =
return self.name
proc getUrl*(self: Item): string =
return self.url
proc getImageUrl*(self: Item): string =
return self.imageUrl

View File

@ -1,118 +0,0 @@
import NimQml, Tables, strutils, stew/shims/strformat
import item
type
ModelRole {.pure.} = enum
Name = UserRole + 1
Url = UserRole + 2
ImageUrl = UserRole + 3
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[Item]
proc delete(self: Model) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newModel*(): Model =
new(result, delete)
result.setup
proc `$`*(self: Model): string =
for i in 0 ..< self.items.len:
result &= fmt"""
[{i}]:({$self.items[i]})
"""
proc modelChanged(self: Model) {.signal.}
proc getCount(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: Model, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: Model): Table[int, string] =
{
ModelRole.Name.int:"name",
ModelRole.Url.int:"url",
ModelRole.ImageUrl.int:"imageUrl"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Name:
result = newQVariant(item.getName())
of ModelRole.Url:
result = newQVariant(item.getUrl())
of ModelRole.ImageUrl:
result = newQVariant(item.getImageUrl())
proc addItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
for i in self.items:
if i.getUrl() == item.getUrl():
return
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.modelChanged()
proc getBookmarkIndexByUrl*(self: Model, url: string): int {.slot.} =
var index = -1
var i = -1
for item in self.items:
i += 1
if item.getUrl() == url:
index = i
break
return index
proc removeItemByUrl*(self: Model, url: string) =
var index = self.getBookmarkIndexByUrl(url)
if index == -1:
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, index, index)
self.items.delete(index)
self.endRemoveRows()
self.modelChanged()
proc updateItemByUrl*(self: Model, oldUrl: string, item: Item) =
var index = self.getBookmarkIndexByUrl(oldUrl)
if index == -1:
return
let topLeft = self.createIndex(index, index, nil)
let bottomRight = self.createIndex(index, index, nil)
defer: topLeft.delete
defer: bottomRight.delete
self.items[index] = item
self.dataChanged(topLeft, bottomRight)
self.modelChanged()

View File

@ -1,77 +0,0 @@
import NimQml
import io_interface
import ../io_interface as delegate_interface
import item
import view
import controller
import ../../../../global/global_singleton
import ../../../../../app_service/service/bookmarks/service as bookmark_service
import ../../../../core/eventemitter
export io_interface
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
view: View
viewVariant: QVariant
moduleLoaded: bool
bookmarksLoaded: bool
controller: Controller
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, bookmarkService: bookmark_service.Service): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.bookmarksLoaded = false
result.controller = controller.newController(result, events, bookmarkService)
method delete*(self: Module) =
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("bookmarkModule", self.viewVariant)
self.controller.init()
self.view.load()
method onActivated*(self: Module) =
if self.bookmarksLoaded:
return
let bookmarks = self.controller.getBookmarks()
for b in bookmarks:
self.view.addItem(initItem(b.name, b.url, b.imageUrl))
self.bookmarksLoaded = true
method isLoaded*(self: Module): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.bookmarkDidLoad()
method storeBookmark*(self: Module, url: string, name: string) =
if url == "":
self.view.addItem(initItem(name, url, "")) # These URLs are not stored but added direclty to the UI
else:
self.controller.storeBookmark(url, name)
method onBoomarkStored*(self: Module, url: string, name: string, imageUrl: string) =
self.view.addItem(initItem(name, url, imageUrl))
method deleteBookmark*(self: Module, url: string) =
self.controller.deleteBookmark(url)
method onBookmarkDeleted*(self: Module, url: string) =
self.view.removeBookmarkByUrl(url)
method updateBookmark*(self: Module, oldUrl: string, newUrl: string, newName: string) =
self.controller.updateBookmark(oldUrl, newUrl, newName)
method onBookmarkUpdated*(self: Module, oldUrl: string, newUrl: string, newName: string, newImageUrl: string) =
self.view.updateBookmarkByUrl(oldUrl, initItem(newName, newUrl, newImageUrl))

View File

@ -1,56 +0,0 @@
import NimQml
import io_interface
import model
import item
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
model: Model
modelVariant: QVariant
proc setup(self: View) =
self.QObject.setup
proc delete*(self: View) =
self.model.delete
self.modelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.delegate = delegate
result.model = newModel()
result.modelVariant = newQVariant(result.model)
result.setup()
proc load*(self: View) =
self.delegate.viewDidLoad()
proc addItem*(self: View, item: Item) =
self.model.addItem(item)
proc modelChanged*(self: View) {.signal.}
proc getModel(self: View): QVariant {.slot.} =
return self.modelVariant
QtProperty[QVariant] model:
read = getModel
notify = modelChanged
proc addBookmark(self: View, url: string, name: string,) {.slot.} =
self.delegate.storeBookmark(url, name)
proc deleteBookmark(self: View, url: string) {.slot.} =
self.delegate.deleteBookmark(url)
proc removeBookmarkByUrl*(self: View, url: string) =
self.model.removeItemByUrl(url)
proc updateBookmark(self: View, oldUrl: string, newUrl: string, newName: string) {.slot.} =
self.delegate.updateBookmark(oldUrl, newUrl, newName)
proc updateBookmarkByUrl*(self: View, oldUrl: string, item: Item) =
self.model.updateItemByUrl(oldUrl, item)

View File

@ -1,63 +0,0 @@
import io_interface
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/network/service as network_service
import app_service/service/token/service as token_service
import app_service/service/currency/service as currency_service
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
walletAccountService: wallet_account_service.Service
networkService: network_service.Service
tokenService: token_service.Service
currencyService: currency_service.Service
proc newController*(
delegate: io_interface.AccessInterface,
walletAccountService: wallet_account_service.Service,
networkService: network_service.Service,
tokenService: token_service.Service,
currencyService: currency_service.Service,
): Controller =
result = Controller()
result.delegate = delegate
result.walletAccountService = walletAccountService
result.networkService = networkService
result.tokenService = tokenService
result.currencyService = currencyService
proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
discard
proc getWalletAccount*(self: Controller, accountIndex: int): wallet_account_service.WalletAccountDto =
return self.walletAccountService.getWalletAccount(accountIndex)
proc isKeycardAccount*(self: Controller, account: WalletAccountDto): bool =
return self.walletAccountService.isKeycardAccount(account)
proc getIndex*(self: Controller, address: string): int =
return self.walletAccountService.getIndex(address)
proc getChainIds*(self: Controller): seq[int] =
return self.networkService.getCurrentNetworksChainIds()
proc getEnabledChainIds*(self: Controller): seq[int] =
return self.networkService.getEnabledChainIds()
proc getCurrentCurrency*(self: Controller): string =
return self.walletAccountService.getCurrency()
proc getCurrencyFormat*(self: Controller, symbol: string): CurrencyFormatDto =
return self.currencyService.getCurrencyFormat(symbol)
proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled()
proc getTotalCurrencyBalance*(self: Controller, address: string, chainIds: seq[int]): float64 =
return self.walletAccountService.getTotalCurrencyBalance(@[address], chainIds)
proc getTokensMarketValuesLoading*(self: Controller): bool =
return self.walletAccountService.getTokensMarketValuesLoading()

View File

@ -1,21 +0,0 @@
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for any input/interaction with this module.
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method switchAccountByAddress*(self: AccessInterface, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim.
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,106 +0,0 @@
import NimQml, strutils
import app/global/global_singleton
import app/core/eventemitter
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/network/service as network_service
import app_service/service/token/service as token_service
import app_service/service/currency/service as currency_service
import app/modules/shared/wallet_utils
import ./io_interface, ./view, ./controller
import ../io_interface as delegate_interface
export io_interface
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
events: EventEmitter
view: View
viewVariant: QVariant
controller: Controller
moduleLoaded: bool
currentAccountIndex: int
proc newModule*(
delegate: delegate_interface.AccessInterface,
events: EventEmitter,
walletAccountService: wallet_account_service.Service,
networkService: network_service.Service,
tokenService: token_service.Service,
currencyService: currency_service.Service,
): Module =
result = Module()
result.delegate = delegate
result.events = events
result.currentAccountIndex = 0
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = newController(result, walletAccountService, networkService, tokenService, currencyService)
result.moduleLoaded = false
method delete*(self: Module) =
self.viewVariant.delete
self.view.delete
proc switchAccount*(self: Module, accountIndex: int) =
self.currentAccountIndex = accountIndex
let walletAccount = self.controller.getWalletAccount(accountIndex)
if walletAccount.isNil:
return
let keycardAccount = self.controller.isKeycardAccount(walletAccount)
let currency = self.controller.getCurrentCurrency()
let enabledChainIds = self.controller.getEnabledChainIds()
let chainIds = self.controller.getChainIds()
let areTestNetworksEnabled = self.controller.areTestNetworksEnabled()
let currencyFormat = self.controller.getCurrencyFormat(currency)
let currencyBalance = self.controller.getTotalCurrencyBalance(walletAccount.address, enabledChainIds)
let accountItem = walletAccountToWalletAccountsItem(
walletAccount,
keycardAccount,
chainIds,
enabledChainIds,
currencyBalance,
currencyFormat,
areTestNetworksEnabled,
self.controller.getTokensMarketValuesLoading()
)
self.view.setData(accountItem)
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("browserSectionCurrentAccount", self.viewVariant)
self.events.on(SIGNAL_KEYPAIR_SYNCED) do(e: Args):
let args = KeypairArgs(e)
let walletAccount = self.controller.getWalletAccount(self.currentAccountIndex)
if walletAccount.isNil:
self.switchAccount(0)
return
for acc in args.keypair.accounts:
if cmpIgnoreCase(acc.address, walletAccount.address) == 0:
return
self.switchAccount(0)
self.view.connectedAccountDeleted()
self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e:Args):
if(self.view.isAddressCurrentAccount(AccountArgs(e).account.address)):
self.switchAccount(0)
self.view.connectedAccountDeleted()
self.controller.init()
self.view.load()
self.switchAccount(0)
method isLoaded*(self: Module): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
method switchAccountByAddress*(self: Module, address: string) =
let accountIndex = self.controller.getIndex(address)
self.switchAccount(accountIndex)

View File

@ -1,121 +0,0 @@
import NimQml, sequtils
import ./io_interface
import ../../../shared_models/currency_amount
import ../../wallet_section/accounts/item as account_item
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
name: string
address: string
path: string
colorId: string
walletType: string
currencyBalance: CurrencyAmount
emoji: string
proc setup(self: View) =
self.QObject.setup
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.setup()
result.delegate = delegate
proc load*(self: View) =
self.delegate.viewDidLoad()
proc getName(self: View): QVariant {.slot.} =
return newQVariant(self.name)
proc nameChanged(self: View) {.signal.}
QtProperty[QVariant] name:
read = getName
notify = nameChanged
proc getAddress(self: View): QVariant {.slot.} =
return newQVariant(self.address)
proc addressChanged(self: View) {.signal.}
QtProperty[QVariant] address:
read = getAddress
notify = addressChanged
proc getPath(self: View): QVariant {.slot.} =
return newQVariant(self.path)
proc pathChanged(self: View) {.signal.}
QtProperty[QVariant] path:
read = getPath
notify = pathChanged
proc getColorId(self: View): QVariant {.slot.} =
return newQVariant(self.colorId)
proc colorIdChanged(self: View) {.signal.}
QtProperty[QVariant] colorId:
read = getColorId
notify = colorIdChanged
proc getWalletType(self: View): QVariant {.slot.} =
return newQVariant(self.walletType)
proc walletTypeChanged(self: View) {.signal.}
QtProperty[QVariant] walletType:
read = getWalletType
notify = walletTypeChanged
proc getCurrencyBalance(self: View): QVariant {.slot.} =
return newQVariant(self.currencyBalance)
proc currencyBalanceChanged(self: View) {.signal.}
QtProperty[QVariant] currencyBalance:
read = getCurrencyBalance
notify = currencyBalanceChanged
proc getEmoji(self: View): QVariant {.slot.} =
return newQVariant(self.emoji)
proc emojiChanged(self: View) {.signal.}
QtProperty[QVariant] emoji:
read = getEmoji
notify = emojiChanged
proc switchAccountByAddress*(self: View, address: string) {.slot.} =
self.delegate.switchAccountByAddress(address)
proc connectedAccountDeleted*(self: View) {.signal.}
proc setData*(self: View, item: account_item.Item) =
self.name = item.name()
self.nameChanged()
self.address = item.address()
self.addressChanged()
self.path = item.path()
self.pathChanged()
self.colorId = item.colorId()
self.colorIdChanged()
self.walletType = item.walletType()
self.walletTypeChanged()
self.currencyBalance = item.currencyBalance()
self.currencyBalanceChanged()
self.emoji = item.emoji()
self.emojiChanged()
proc isAddressCurrentAccount*(self: View, address: string): bool =
return self.address == address

View File

@ -1,91 +0,0 @@
import NimQml, Tables, strutils, stew/shims/strformat
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
type
ModelRole {.pure.} = enum
Name = UserRole + 1
Address
ColorId
Emoji
QtObject:
type
AccountsModel* = ref object of QAbstractListModel
items: seq[WalletAccountDto]
proc delete(self: AccountsModel) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: AccountsModel) =
self.QAbstractListModel.setup
proc newAccountsModel*(): AccountsModel =
new(result, delete)
result.setup
proc `$`*(self: AccountsModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""
[{i}]:({$self.items[i].name})
"""
proc modelChanged(self: AccountsModel) {.signal.}
proc countChanged(self: AccountsModel) {.signal.}
proc getCount(self: AccountsModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: AccountsModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: AccountsModel): Table[int, string] =
{
ModelRole.Name.int:"name",
ModelRole.Address.int:"address",
ModelRole.ColorId.int:"colorId",
ModelRole.Emoji.int:"emoji"
}.toTable
method data(self: AccountsModel, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.Address:
result = newQVariant(item.address)
of ModelRole.ColorId:
result = newQVariant(item.colorId)
of ModelRole.Emoji:
result = newQVariant(item.emoji)
proc addItem*(self: AccountsModel, item: WalletAccountDto) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
for i in self.items:
if i == item:
return
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.modelChanged()
self.countChanged()
proc clear*(self: AccountsModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()

View File

@ -1,51 +0,0 @@
import io_interface
import options
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
dappPermissionsService: dapp_permissions_service.Service
walletAccountService: wallet_account_service.Service
proc newController*(
delegate: io_interface.AccessInterface,
dappPermissionsService: dapp_permissions_service.Service,
walletAccountService: wallet_account_service.Service,
): Controller =
result = Controller()
result.delegate = delegate
result.dappPermissionsService = dappPermissionsService
result.walletAccountService = walletAccountService
proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
discard
proc getDapps*(self: Controller): seq[dapp_permissions_service.Dapp] =
return self.dappPermissionsService.getDapps()
proc getDapp*(self: Controller, dapp:string, address: string): Option[dapp_permissions_service.Dapp] =
return self.dappPermissionsService.getDapp(dapp, address)
proc hasPermission*(self: Controller, dapp: string, address: string, permission: dapp_permissions_service.Permission):bool =
return self.dappPermissionsService.hasPermission(dapp, address, permission)
proc addPermission*(self: Controller, dapp: string, address: string, permission: dapp_permissions_service.Permission) =
discard self.dappPermissionsService.addPermission(dapp, address, permission)
proc disconnectAddress*(self: Controller, dappName: string, address: string) =
discard self.dappPermissionsService.disconnectAddress(dappName, address)
proc disconnect*(self: Controller, dappName: string) =
discard self.dappPermissionsService.disconnect(dappName)
proc removePermission*(self: Controller, dappName: string, address: string, permission: dapp_permissions_service.Permission) =
discard self.dappPermissionsService.removePermission(dappName, address, permission)
proc getAccountForAddress*(self: Controller, address: string): WalletAccountDto =
return self.walletAccountService.getAccountByAddress(address)

View File

@ -1,84 +0,0 @@
import NimQml, Tables, strutils, stew/shims/strformat, json
import ./item
type
ModelRole {.pure.} = enum
Name = UserRole + 1
Accounts
QtObject:
type
DappsModel* = ref object of QAbstractListModel
items: seq[Item]
proc delete(self: DappsModel) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: DappsModel) =
self.QAbstractListModel.setup
proc newDappsModel*(): DappsModel =
new(result, delete)
result.setup
proc `$`*(self: DappsModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""
[{i}]:({$self.items[i]})
"""
proc modelChanged(self: DappsModel) {.signal.}
proc countChanged(self: DappsModel) {.signal.}
proc getCount(self: DappsModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: DappsModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: DappsModel): Table[int, string] =
{
ModelRole.Name.int:"name",
ModelRole.Accounts.int:"accounts"
}.toTable
method data(self: DappsModel, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.Accounts:
result = newQVariant(item.accounts)
proc addItem*(self: DappsModel, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
for i in self.items:
if i == item:
return
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.modelChanged()
self.countChanged()
proc clear*(self: DappsModel) =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()

View File

@ -1,41 +0,0 @@
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method onActivated*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method loadDapps*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method hasPermission*(self: AccessInterface, hostname: string, address: string, permission: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method disconnectAddress*(self: AccessInterface, dapp: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method removePermission*(self: AccessInterface, dapp: string, address: string, permission: string) {.base.} =
raise newException(ValueError, "No implementation available")
method disconnect*(self: AccessInterface, dapp: string) {.base.} =
raise newException(ValueError, "No implementation available")
method fetchDapps*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method fetchPermissions*(self: AccessInterface, dapp: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method addPermission*(self: AccessInterface, hostname: string, address: string, permission: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,28 +0,0 @@
import stew/shims/strformat
import ./permissions
import ./accounts
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
type
Item* = object
name*: string
accounts*: AccountsModel
permissions*: PermissionsModel
proc initItem*(
name: string,
permissions: seq[string]
): Item =
result.name = name
result.accounts = newAccountsModel()
result.permissions = newPermissionsModel()
for p in permissions:
result.permissions.addItem(p)
proc `$`*(self: Item): string =
result = fmt"""Dapps(
name: {self.name}
]"""
proc addAccount*(self: Item, account: WalletAccountDto): void =
self.accounts.addItem(account)

View File

@ -1,111 +0,0 @@
import NimQml
import io_interface
import sequtils
import ../io_interface as delegate_interface
import view
import ./item
import sets
import controller
import ../../../../global/global_singleton
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
export io_interface
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
view: View
viewVariant: QVariant
moduleLoaded: bool
dappsLoaded: bool
controller: Controller
proc newModule*(
delegate: delegate_interface.AccessInterface,
dappPermissionsService: dapp_permissions_service.Service,
walletAccountServive: wallet_account_service.Service,
): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.dappsLoaded = false
result.controller = controller.newController(result, dappPermissionsService, walletAccountServive)
method delete*(self: Module) =
self.view.delete
self.viewVariant.delete
self.controller.delete
method fetchDapps*(self: Module) =
self.view.clearDapps()
let dapps = self.controller.getDapps()
var items: seq[Item] = @[]
for dapp in dapps:
var found = false
for item in items:
if item.name == dapp.name:
found = true
let account = self.controller.getAccountForAddress(dapp.address)
if account.isNil:
break
item.addAccount(account)
break
if not found:
let item = initItem(
dapp.name, dapp.permissions.mapIt($it)
)
items.add(item)
let account = self.controller.getAccountForAddress(dapp.address)
item.addAccount(account)
for item in items:
self.view.addDapp(item)
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("dappPermissionsModule", self.viewVariant)
self.view.load()
method isLoaded*(self: Module): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.dappsDidLoad()
method loadDapps*(self: Module) =
if self.dappsLoaded:
return
self.fetchDapps()
self.dappsLoaded = true
method onActivated*(self: Module) =
self.loadDapps()
method hasPermission*(self: Module, hostname: string, address: string, permission: string): bool =
self.controller.hasPermission(hostname, address, permission.toPermission())
method addPermission*(self: Module, hostname: string, address: string, permission: string) =
self.controller.addPermission(hostname, address, permission.toPermission())
self.fetchDapps()
method removePermission*(self: Module, dapp: string, address: string, permission: string) =
self.controller.removePermission(dapp, address, permission.toPermission())
self.fetchDapps()
method disconnectAddress*(self: Module, dapp: string, address: string) =
self.controller.disconnectAddress(dapp, address)
self.fetchDapps()
method disconnect*(self: Module, dapp: string) =
self.controller.disconnect(dapp)
self.fetchDapps()

View File

@ -1,69 +0,0 @@
import NimQml, Tables, strutils, stew/shims/strformat
type
ModelRole {.pure.} = enum
Name = UserRole + 1
QtObject:
type
PermissionsModel* = ref object of QAbstractListModel
items: seq[string]
proc delete(self: PermissionsModel) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: PermissionsModel) =
self.QAbstractListModel.setup
proc newPermissionsModel*(): PermissionsModel =
new(result, delete)
result.setup
proc `$`*(self: PermissionsModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""
[{i}]:({$self.items[i]})
"""
proc modelChanged(self: PermissionsModel) {.signal.}
proc getCount(self: PermissionsModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: PermissionsModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: PermissionsModel): Table[int, string] =
{
ModelRole.Name.int:"name"
}.toTable
method data(self: PermissionsModel, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
result = newQVariant(self.items[index.row])
proc addItem*(self: PermissionsModel, item: string) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
for i in self.items:
if i == item:
return
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.modelChanged()
proc clear*(self: PermissionsModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()

View File

@ -1,65 +0,0 @@
import NimQml
import io_interface
import ./dapps
import ./item
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
dappsModel: DappsModel
dappsModelVariant: QVariant
proc setup(self: View) =
self.QObject.setup
proc delete*(self: View) =
self.dappsModel.delete
self.dappsModelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.delegate = delegate
result.dappsModel = newDappsModel()
result.dappsModelVariant = newQVariant(result.dappsModel)
result.setup()
proc load*(self: View) =
self.delegate.viewDidLoad()
proc addDapp*(self: View, item: Item) =
self.dappsModel.addItem(item)
proc modelChanged*(self: View) {.signal.}
proc getDappsModel(self: View): QVariant {.slot.} =
return self.dappsModelVariant
QtProperty[QVariant] dapps:
read = getDappsModel
notify = modelChanged
proc loadDapps(self: View) {.slot.} =
self.delegate.loadDapps()
proc hasPermission(self: View, hostname: string, address: string, permission: string): bool {.slot.} =
return self.delegate.hasPermission(hostname, address, permission)
proc addPermission(self: View, hostname: string, address: string, permission: string) {.slot.} =
self.delegate.addPermission(hostname, address, permission)
proc removePermission(self: View, dapp: string, address: string, permission: string): string {.slot.} =
self.delegate.removePermission(dapp, address, permission)
proc disconnectAddress(self: View, dapp: string, address: string): string {.slot.} =
self.delegate.disconnectAddress(dapp, address)
proc disconnect(self: View, dapp: string) {.slot.} =
self.delegate.disconnect(dapp)
proc clearDapps*(self: View) =
self.dappsModel.clear()
proc fetchDapps(self: View) {.slot.} =
self.delegate.fetchDapps()

View File

@ -1,29 +0,0 @@
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onActivated*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method bookmarkDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method dappsDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method providerDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method openUrl*(self: AccessInterface, url: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,108 +0,0 @@
import NimQml
import io_interface
import ../io_interface as delegate_interface
import view
import ../../../global/global_singleton
import ../../../core/eventemitter
import provider/module as provider_module
import bookmark/module as bookmark_module
import dapps/module as dapps_module
import current_account/module as current_account_module
import ../../../../app_service/service/bookmarks/service as bookmark_service
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/network/service as network_service
import ../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../app_service/service/provider/service as provider_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
import ../../../../app_service/service/token/service as token_service
import ../../../../app_service/service/currency/service as currency_service
export io_interface
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
events: EventEmitter
view: View
viewVariant: QVariant
moduleLoaded: bool
providerModule: provider_module.AccessInterface
bookmarkModule: bookmark_module.AccessInterface
dappsModule: dapps_module.AccessInterface
currentAccountModule: current_account_module.AccessInterface
proc newModule*(delegate: delegate_interface.AccessInterface,
events: EventEmitter,
bookmarkService: bookmark_service.Service,
settingsService: settings_service.Service,
networkService: network_service.Service,
dappPermissionsService: dapp_permissions_service.Service,
providerService: provider_service.Service,
walletAccountService: wallet_account_service.Service,
tokenService: token_service.Service,
currencyService: currency_service.Service
): Module =
result = Module()
result.delegate = delegate
result.events = events
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.providerModule = provider_module.newModule(result, events, settingsService, networkService, providerService)
result.bookmarkModule = bookmark_module.newModule(result, events, bookmarkService)
result.dappsModule = dapps_module.newModule(result, dappPermissionsService, walletAccountService)
result.currentAccountModule = current_account_module.newModule(result, events, walletAccountService, networkService, tokenService, currencyService)
method delete*(self: Module) =
self.view.delete
self.viewVariant.delete
self.providerModule.delete
self.bookmarkModule.delete
self.dappsModule.delete
self.currentAccountModule.delete
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("browserSection", self.viewVariant)
self.currentAccountModule.load()
self.providerModule.load()
self.bookmarkModule.load()
self.dappsModule.load()
self.view.load()
method onActivated*(self: Module) =
self.bookmarkModule.onActivated()
self.dappsModule.onActivated()
method isLoaded*(self: Module): bool =
return self.moduleLoaded
proc checkIfModuleDidLoad(self: Module) =
if(not self.providerModule.isLoaded()):
return
if(not self.bookmarkModule.isLoaded()):
return
if(not self.dappsModule.isLoaded()):
return
if(not self.currentAccountModule.isLoaded()):
return
self.moduleLoaded = true
self.delegate.browserSectionDidLoad()
method providerDidLoad*(self: Module) =
self.checkIfModuleDidLoad()
method bookmarkDidLoad*(self: Module) =
self.checkIfModuleDidLoad()
method dappsDidLoad*(self: Module) =
self.checkIfModuleDidLoad()
method viewDidLoad*(self: Module) =
self.checkIfModuleDidLoad()
method openUrl*(self: Module, url: string) =
self.view.sendOpenUrlSignal(url)

View File

@ -1,71 +0,0 @@
import io_interface
import ../../../../core/eventemitter
import ../../../../../app_service/service/network/service as network_service
import ../../../../../app_service/service/settings/service as settings_service
import ../../../../../app_service/service/provider/service as provider_service
import ../../../../../app_service/service/wallet_account/service
import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module
import app_service/service/network/network_item
const UNIQUE_BROWSER_SECTION_TRANSACTION_MODULE_IDENTIFIER* = "BrowserSection-TransactionModule"
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
events: EventEmitter
settingsService: settings_service.Service
networkService: network_service.Service
providerService: provider_service.Service
proc newController*(
delegate: io_interface.AccessInterface,
events: EventEmitter,
settingsService: settings_service.Service,
networkService: network_service.Service,
providerService: provider_service.Service,
): Controller =
result = Controller()
result.events = events
result.delegate = delegate
result.settingsService = settingsService
result.networkService = networkService
result.providerService = providerService
proc delete*(self: Controller) =
discard
proc getAppNetwork*(self: Controller): NetworkItem =
return self.networkService.getAppNetwork()
proc init*(self: Controller) =
self.events.on(PROVIDER_SIGNAL_ON_POST_MESSAGE) do(e:Args):
let args = OnPostMessageArgs(e)
self.delegate.onPostMessage(args.payloadMethod, args.result, args.chainId)
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args):
self.delegate.updateNetwork(self.getAppNetwork())
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_BROWSER_SECTION_TRANSACTION_MODULE_IDENTIFIER:
return
self.delegate.onUserAuthenticated(args.password)
proc getDappsAddress*(self: Controller): string =
return self.settingsService.getDappsAddress()
proc setDappsAddress*(self: Controller, address: string) =
if self.settingsService.saveDappsAddress(address):
self.delegate.onDappAddressChanged(address)
proc postMessage*(self: Controller, payloadMethod: string, requestType: string, message: string) =
self.providerService.postMessage(payloadMethod, requestType, message)
proc ensResourceURL*(self: Controller, ens: string, url: string): (string, string, string, string, bool) =
return self.providerService.ensResourceURL(ens, url)
proc authenticateUser*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_BROWSER_SECTION_TRANSACTION_MODULE_IDENTIFIER,
keyUid: keyUid)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)

View File

@ -1,43 +0,0 @@
import app_service/service/network/network_item
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method setDappsAddress*(self: AccessInterface, newDappAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onDappAddressChanged*(self: AccessInterface, newDappAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method disconnect*(self: AccessInterface, dappName: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method postMessage*(self: AccessInterface, payloadMethod: string, requestType: string, message: string) {.base.} =
raise newException(ValueError, "No implementation available")
method ensResourceURL*(self: AccessInterface, ens: string, url: string): (string, string, string, string, bool) {.base.} =
raise newException(ValueError, "No implementation available")
method onPostMessage*(self: AccessInterface, payloadMethod: string, result: string, chainId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method updateNetwork*(self: AccessInterface, network: NetworkItem) {.base.} =
raise newException(ValueError, "No implementation available")
method authenticateToPostMessage*(self: AccessInterface, payloadMethod: string, requestType: string, message: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,104 +0,0 @@
import NimQml
import io_interface
import view
import controller
import std/json
import ../../../../core/eventemitter
import ../io_interface as delegate_interface
import app_service/service/settings/service as settings_service
import app_service/service/network/service as network_service
import app_service/service/provider/service as provider_service
import app_service/service/network/network_item
import app/global/global_singleton
export io_interface
# Shouldn't be public ever, use only within this module.
type TmpSendTransactionDetails = object
payloadMethod: string
requestType: string
message: string
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
view: View
viewVariant: QVariant
moduleLoaded: bool
controller: Controller
tmpSendTransactionDetails: TmpSendTransactionDetails
proc newModule*(
delegate: delegate_interface.AccessInterface,
events: EventEmitter,
settingsService: settings_service.Service,
networkService: network_service.Service,
providerService: provider_service.Service
): Module =
result = Module()
result.delegate = delegate
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.controller = controller.newController(result, events, settingsService, networkService, providerService)
method delete*(self: Module) =
self.controller.delete
self.viewVariant.delete
self.view.delete
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("providerModule", self.viewVariant)
self.view.dappsAddress = self.controller.getDappsAddress()
let network = self.controller.getAppNetwork()
self.view.chainId = network.chainId
self.view.chainName = network.chainName
self.view.load()
self.controller.init()
method isLoaded*(self: Module): bool =
return self.moduleLoaded
method setDappsAddress*(self: Module, value: string) =
self.controller.setDappsAddress(value)
method onDappAddressChanged*(self: Module, value: string) =
self.view.dappsAddress = value
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.providerDidLoad()
method postMessage*(self: Module, payloadMethod: string, requestType: string, message: string) =
self.controller.postMessage(payloadMethod, requestType, message)
method onPostMessage*(self: Module, payloadMethod: string, result: string, chainId: string) =
self.view.postMessageResult(payloadMethod, result, chainId)
method ensResourceURL*(self: Module, ens: string, url: string): (string, string, string, string, bool) =
return self.controller.ensResourceURL(ens, url)
method updateNetwork*(self: Module, network: NetworkItem) =
self.view.chainId = network.chainId
self.view.chainName = network.chainName
method authenticateToPostMessage*(self: Module, payloadMethod: string, requestType: string, message: string) {.slot.} =
self.tmpSendTransactionDetails.payloadMethod = payloadMethod
self.tmpSendTransactionDetails.requestType = requestType
self.tmpSendTransactionDetails.message = message
if singletonInstance.userProfile.getIsKeycardUser():
let keyUid = singletonInstance.userProfile.getKeyUid()
self.controller.authenticateUser(keyUid)
else:
self.controller.authenticateUser()
method onUserAuthenticated*(self: Module, password: string) =
let jsonNode = parseJson(self.tmpSendTransactionDetails.message)
if jsonNode.kind == JObject and jsonNode.contains("payload"):
jsonNode["payload"]["password"] = %* password
self.tmpSendTransactionDetails.message = $jsonNode
self.postMessage(self.tmpSendTransactionDetails.payloadMethod,
self.tmpSendTransactionDetails.requestType,
self.tmpSendTransactionDetails.message)

View File

@ -1,91 +0,0 @@
import NimQml, strutils
import ./io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
dappsAddress: string
chainId: int
chainName: string
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate
proc load*(self: View) =
self.delegate.viewDidLoad()
proc dappsAddressChanged(self: View, value: string) {.signal.}
proc `dappsAddress=`*(self: View, value: string) =
self.dappsAddress = value
self.dappsAddressChanged(value)
proc dappsAddress*(self: View): string {.slot.} =
result = self.dappsAddress
proc setDappsAddress(self: View, value: string) {.slot.} =
self.delegate.setDappsAddress(value)
QtProperty[string] dappsAddress:
read = dappsAddress
write = setDappsAddress
notify = dappsAddressChanged
proc chainIdChanged(self: View, chainId: int) {.signal.}
proc `chainId=`*(self: View, value: int) =
self.chainId = value
self.chainIdChanged(value)
proc chainId*(self: View): int {.slot.} =
result = self.chainId
QtProperty[int] chainId:
read = chainId
notify = chainIdChanged
proc chainNameChanged(self: View) {.signal.}
proc `chainName=`*(self: View, value: string) =
self.chainName = value
self.chainNameChanged()
proc chainName*(self: View): string {.slot.} =
result = self.chainName
QtProperty[string] chainName:
read = chainName
notify = chainNameChanged
proc replaceHostByENS*(self: View, url: string, ens: string): string {.slot.} =
result = url_replaceHostAndAddPath(url, ens)
proc getHost*(self: View, url: string): string {.slot.} =
result = url_host(url)
proc postMessageResult*(self: View, payloadMethod: string, result: string, chainId: string) {.signal.}
proc postMessage*(self: View, payloadMethod: string, requestType: string, message: string) {.slot.} =
self.delegate.postMessage(payloadMethod, requestType, message)
proc ensResourceURL*(self: View, ens: string, url: string): string {.slot.} =
let (url, base, http_scheme, _, hasContentHash) = self.delegate.ensResourceURL(ens, url)
var newHost = url_host(base)
if hasContentHash:
if strutils.endsWith(base, "/"):
newHost = base[0.. ^2]
else:
newHost = base
result = url_replaceHostAndAddPath(url, newHost, http_scheme, "")
proc authenticateToPostMessage*(self: View, payloadMethod: string, requestType: string, message: string) {.slot.} =
self.delegate.authenticateToPostMessage(payloadMethod, requestType, message)

View File

@ -1,25 +0,0 @@
import NimQml
import io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
proc setup(self: View) =
self.QObject.setup
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.delegate = delegate
result.setup()
proc load*(self: View) =
self.delegate.viewDidLoad()
proc openUrl*(self: View, url: string) {.signal.}
proc sendOpenUrlSignal*(self: View, url: string) =
self.openUrl(url)

View File

@ -69,9 +69,6 @@ method profileSectionDidLoad*(self: AccessInterface) {.base.} =
method walletSectionDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method browserSectionDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method networkConnectionModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -16,7 +16,6 @@ import chat_section/model as chat_model
import chat_section/item as chat_item
import chat_section/module as chat_section_module
import wallet_section/module as wallet_section_module
import browser_section/module as browser_section_module
import profile_section/module as profile_section_module
import app_search/module as app_search_module
import stickers/module as stickers_module
@ -41,8 +40,6 @@ import ../../../app_service/service/collectible/service as collectible_service
import ../../../app_service/service/currency/service as currency_service
import ../../../app_service/service/transaction/service as transaction_service
import ../../../app_service/service/wallet_account/service as wallet_account_service
import ../../../app_service/service/bookmarks/service as bookmark_service
import ../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../app_service/service/provider/service as provider_service
import ../../../app_service/service/profile/service as profile_service
import ../../../app_service/service/accounts/service as accounts_service
@ -104,7 +101,6 @@ type
keychainService: keychain_service.Service
networkConnectionService: network_connection_service.Service
walletSectionModule: wallet_section_module.AccessInterface
browserSectionModule: browser_section_module.AccessInterface
profileSectionModule: profile_section_module.AccessInterface
stickersModule: stickers_module.AccessInterface
gifsModule: gifs_module.AccessInterface
@ -146,12 +142,10 @@ proc newModule*[T](
currencyService: currency_service.Service,
transactionService: transaction_service.Service,
walletAccountService: wallet_account_service.Service,
bookmarkService: bookmark_service.Service,
profileService: profile_service.Service,
settingsService: settings_service.Service,
contactsService: contacts_service.Service,
aboutService: about_service.Service,
dappPermissionsService: dapp_permissions_service.Service,
languageService: language_service.Service,
privacyService: privacy_service.Service,
providerService: provider_service.Service,
@ -219,11 +213,6 @@ proc newModule*[T](
keycardService, nodeService, networkConnectionService, devicesService,
communityTokensService, threadpool
)
result.browserSectionModule = browser_section_module.newModule(
result, events, bookmarkService, settingsService, networkService,
dappPermissionsService, providerService, walletAccountService,
tokenService, currencyService
)
result.profileSectionModule = profile_section_module.newModule(
result, events, accountsService, settingsService, stickersService,
profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService,
@ -254,7 +243,6 @@ method delete*[T](self: Module[T]) =
cModule.delete
self.chatSectionModules.clear
self.walletSectionModule.delete
self.browserSectionModule.delete
self.appSearchModule.delete
self.nodeSectionModule.delete
if not self.keycardSharedModuleForAuthenticationOrSigning.isNil:
@ -539,27 +527,6 @@ method load*[T](
if(activeSectionId == walletSectionItem.id):
activeSection = walletSectionItem
# Browser Section
let browserSectionItem = initItem(
conf.BROWSER_SECTION_ID,
SectionType.Browser,
conf.BROWSER_SECTION_NAME,
memberRole = MemberRole.Owner,
description = "",
introMessage = "",
outroMessage = "",
image = "",
icon = conf.BROWSER_SECTION_ICON,
color = "",
hasNotification = false,
notificationsCount = 0,
active = false,
enabled = singletonInstance.localAccountSensitiveSettings.getIsBrowserEnabled(),
)
self.view.model().addItem(browserSectionItem)
if(activeSectionId == browserSectionItem.id):
activeSection = browserSectionItem
# Node Management Section
let nodeManagementSectionItem = initItem(
conf.NODEMANAGEMENT_SECTION_ID,
@ -602,7 +569,6 @@ method load*[T](
if(activeSectionId == profileSettingsSectionItem.id):
activeSection = profileSettingsSectionItem
self.browserSectionModule.load()
self.profileSectionModule.load()
self.stickersModule.load()
self.gifsModule.load()
@ -803,9 +769,6 @@ proc checkIfModuleDidLoad [T](self: Module[T]) =
if (not self.walletSectionModule.isLoaded()):
return
if(not self.browserSectionModule.isLoaded()):
return
if(not self.nodeSectionModule.isLoaded()):
return
@ -860,9 +823,6 @@ method communitiesModuleDidLoad*[T](self: Module[T]) =
method walletSectionDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
method browserSectionDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
method profileSectionDidLoad*[T](self: Module[T]) =
self.checkIfModuleDidLoad()
@ -921,8 +881,6 @@ method activeSectionSet*[T](self: Module[T], sectionId: string, skipSavingInSett
case sectionId:
of conf.COMMUNITIESPORTAL_SECTION_ID:
self.communitiesModule.onActivated()
of conf.BROWSER_SECTION_ID:
self.browserSectionModule.onActivated()
self.view.model().setActiveSection(sectionId)
self.view.activeSectionSet(item)
@ -939,11 +897,7 @@ proc setSectionAvailability[T](self: Module[T], sectionType: SectionType, availa
self.view.model().disableSection(sectionType)
method toggleSection*[T](self: Module[T], sectionType: SectionType) =
if (sectionType == SectionType.Browser):
let enabled = singletonInstance.localAccountSensitiveSettings.getIsBrowserEnabled()
self.setSectionAvailability(sectionType, not enabled)
singletonInstance.localAccountSensitiveSettings.setIsBrowserEnabled(not enabled)
elif (sectionType == SectionType.NodeManagement):
if (sectionType == SectionType.NodeManagement):
let enabled = singletonInstance.localAccountSensitiveSettings.getNodeManagementEnabled()
self.setSectionAvailability(sectionType, not enabled)
singletonInstance.localAccountSensitiveSettings.setNodeManagementEnabled(not enabled)
@ -1518,12 +1472,6 @@ method onStatusUrlRequested*[T](self: Module[T], action: StatusUrlAction, commun
else:
return
# enable after MVP
#else(action == StatusUrlAction.OpenLinkInBrowser and singletonInstance.localAccountSensitiveSettings.getIsBrowserEnabled()):
# let item = self.view.model().getItemById(conf.BROWSER_SECTION_ICON)
# self.setActiveSection(item)
# self.browserSectionModule.openUrl(url)
################################################################################
## keycard shared module - authentication/sign purpose
################################################################################

View File

@ -134,9 +134,6 @@ proc toggleCommunitiesPortalSection*(self: Controller) =
proc toggleWalletSection*(self: Controller) =
self.events.emit(TOGGLE_SECTION, ToggleSectionArgs(sectionType: SectionType.Wallet))
proc toggleBrowserSection*(self: Controller) =
self.events.emit(TOGGLE_SECTION, ToggleSectionArgs(sectionType: SectionType.Browser))
proc toggleCommunitySection*(self: Controller) =
self.events.emit(TOGGLE_SECTION, ToggleSectionArgs(sectionType: SectionType.Community))

View File

@ -93,9 +93,6 @@ method toggleCommunitiesPortalSection*(self: AccessInterface) {.base.} =
method toggleWalletSection*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method toggleBrowserSection*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method toggleCommunitySection*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -131,9 +131,6 @@ method disableCommunityHistoryArchiveSupport*(self: Module) =
method toggleWalletSection*(self: Module) =
self.controller.toggleWalletSection()
method toggleBrowserSection*(self: Module) =
self.controller.toggleBrowserSection()
method toggleCommunitySection*(self: Module) =
self.controller.toggleCommunitySection()

View File

@ -119,9 +119,6 @@ QtObject:
proc toggleWalletSection*(self: View) {.slot.} =
self.delegate.toggleWalletSection()
proc toggleBrowserSection*(self: View) {.slot.} =
self.delegate.toggleBrowserSection()
proc toggleCommunitySection*(self: View) {.slot.} =
self.delegate.toggleCommunitySection()

View File

@ -15,7 +15,6 @@ type
Chat = 0
Community,
Wallet,
Browser,
ProfileSettings,
NodeManagement,
CommunitiesPortal

View File

@ -1,18 +0,0 @@
import json
include ../../../common/json_utils
type BookmarkDto* = object
name*: string
url*: string
imageUrl*: string
removed*: bool
deletedAt*: int
proc toBookmarkDto*(jsonObj: JsonNode): BookmarkDto =
result = BookmarkDto()
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("url", result.url)
discard jsonObj.getProp("imageUrl", result.imageUrl)
discard jsonObj.getProp("removed", result.removed)
discard jsonObj.getProp("deletedAt", result.deletedAt)

View File

@ -1,133 +0,0 @@
import Tables, json, sequtils, chronicles, strutils
import results
include ../../common/json_utils
import ./dto/bookmark as bookmark_dto
import ../../../app/core/eventemitter
import ../../../app/core/signals/types
import ../../../backend/backend
import ../../../backend/browser
export bookmark_dto
logScope:
topics = "bookmarks-service"
const SIGNAL_BOOKMARK_ADDED* = "bookmarkAdded"
const SIGNAL_BOOKMARK_REMOVED* = "bookmarkRemoved"
const SIGNAL_BOOKMARK_UPDATED* = "bookmarkUpdated"
type
Service* = ref object of RootObj
bookmarks: Table[string, BookmarkDto] # [url, BookmarkDto]
bookmarksFetched: bool
events: EventEmitter
type R = Result[BookmarkDto, string]
type
BookmarkArgs* = ref object of Args
bookmark*: BookmarkDto
type
BookmarkRemovedArgs* = ref object of Args
url*: string
proc delete*(self: Service) =
discard
proc newService*(events: EventEmitter): Service =
result = Service()
result.events = events
result.bookmarks = initTable[string, BookmarkDto]()
result.bookmarksFetched = false
proc init*(self: Service) =
self.events.on(SignalType.Message.event) do(e: Args):
var receivedData = MessageSignal(e)
if receivedData.bookmarks.len > 0:
for bookmark in receivedData.bookmarks:
let url = bookmark.url
if bookmark.removed and not self.bookmarks.hasKey(url):
return
if self.bookmarks.hasKey(url) and bookmark.removed:
self.bookmarks.del(url)
self.events.emit(SIGNAL_BOOKMARK_REMOVED, BookmarkRemovedArgs(url: url))
return
let emitUpdateEvent = self.bookmarks.hasKey(url)
self.bookmarks[url] = BookmarkDto()
self.bookmarks[url].url = bookmark.url
self.bookmarks[url].name = bookmark.name
self.bookmarks[url].imageUrl = bookmark.imageUrl
self.bookmarks[url].removed = bookmark.removed
if emitUpdateEvent:
self.events.emit(SIGNAL_BOOKMARK_UPDATED, BookmarkArgs(bookmark: self.bookmarks[url]))
return
self.events.emit(SIGNAL_BOOKMARK_ADDED, BookmarkArgs(bookmark: self.bookmarks[url]))
proc fetchBookmarks*(self: Service) =
# TODO later we can make this async, but it's not worth it for now
try:
let response = backend.getBookmarks()
for bookmark in response.result.getElems().mapIt(it.toBookmarkDto()):
if not bookmark.removed:
self.bookmarks[bookmark.url] = bookmark
self.bookmarksFetched = true
except Exception as e:
error "error fetching bookmarks: ", msg=e.msg
proc getBookmarks*(self: Service): seq[BookmarkDto] =
if not self.bookmarksFetched:
self.fetchBookmarks()
return toSeq(self.bookmarks.values)
proc storeBookmark*(self: Service, url, name: string): R =
try:
if not url.isEmptyOrWhitespace:
let response = browser.addBookmark(backend.Bookmark(name: name, url: url)).result
self.bookmarks[url] = BookmarkDto()
self.bookmarks[url].url = url
self.bookmarks[url].name = name
discard response.getProp("imageUrl", self.bookmarks[url].imageUrl)
discard response.getProp("removed", self.bookmarks[url].removed)
discard response.getProp("deletedAt", self.bookmarks[url].deletedAt)
result.ok self.bookmarks[url]
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
result.err errDescription
proc deleteBookmark*(self: Service, url: string): bool =
try:
if not self.bookmarks.hasKey(url):
return
discard browser.removeBookmark(url).result
self.bookmarks.del(url)
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
return
return true
proc updateBookmark*(self: Service, oldUrl, newUrl, newName: string): R =
try:
if not self.bookmarks.hasKey(oldUrl):
return
let response = browser.updateBookmark(oldUrl, backend.Bookmark(name: newName, url: newUrl)).result
self.bookmarks.del(oldUrl)
self.bookmarks[newUrl] = BookmarkDto()
self.bookmarks[newUrl].url = newUrl
self.bookmarks[newUrl].name = newName
discard response.getProp("imageUrl", self.bookmarks[newurl].imageUrl)
discard response.getProp("removed", self.bookmarks[newurl].removed)
discard response.getProp("deletedAt", self.bookmarks[newurl].deletedAt)
result.ok self.bookmarks[newUrl]
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
result.err errDescription

View File

@ -1,17 +0,0 @@
import json
import sets
import permission
include ../../../common/json_utils
type Dapp* = object
name*: string
address*: string
permissions*: HashSet[Permission]
proc toDapp*(jsonObj: JsonNode): Dapp =
result = Dapp()
result.permissions = initHashSet[Permission]()
discard jsonObj.getProp("dapp", result.name)
discard jsonObj.getProp("address", result.address)
for permission in jsonObj["permissions"].getElems():
result.permissions.incl(permission.getStr().toPermission())

View File

@ -1,17 +0,0 @@
import json
import chronicles
import strutils
include ../../../common/json_utils
type
Permission* {.pure.} = enum
Web3 = "web3",
ContactCode = "contact-code"
Unknown = "unknown"
proc toPermission*(value: string): Permission =
result = Permission.Unknown
try:
result = parseEnum[Permission](value)
except:
warn "Unknown permission requested", value

View File

@ -1,141 +0,0 @@
import Tables, json, sequtils, chronicles
import sets
import results
import options
include ../../common/json_utils
import ../../../backend/backend
import dto/dapp
import dto/permission
export dapp
export permission
logScope:
topics = "dapp-permissions-service"
type
Service* = ref object
dapps: Table[string, Dapp]
permissionsFetched: bool
type R = Result[Dapp, string]
proc delete*(self: Service) =
discard
proc newService*(): Service =
result = Service()
result.dapps = initTable[string, Dapp]()
result.permissionsFetched = false
proc init*(self: Service) =
discard
proc fetchDappPermissions*(self: Service) =
# TODO later we can make this async, but it's not worth it for now
try:
let response = backend.getDappPermissions()
for dapp in response.result.getElems().mapIt(it.toDapp()):
if dapp.address == "":
continue
self.dapps[dapp.name & dapp.address] = dapp
self.permissionsFetched = true
except Exception as e:
error "error fetching permissions: ", msg=e.msg
proc getDapps*(self: Service): seq[Dapp] =
if not self.permissionsFetched:
self.fetchDappPermissions()
return toSeq(self.dapps.values)
proc getDapp*(self: Service, name: string, address: string): Option[Dapp] =
let key = name & address
if self.dapps.hasKey(key):
return some(self.dapps[key])
return none(Dapp)
proc addPermission*(self: Service, name: string, address: string, perm: permission.Permission): R =
let key = name & address
try:
if not self.dapps.hasKey(key):
self.dapps[key] = Dapp(
name: name,
address: address,
permissions: initHashSet[permission.Permission]()
)
self.dapps[key].permissions.incl(perm)
let permissions = self.dapps[key].permissions.toSeq().mapIt($it)
discard backend.addDappPermissions(backend.Permission(
dapp: name,
address: address,
permissions: permissions
))
result.ok self.dapps[key]
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
result.err errDescription
proc hasPermission*(self: Service, dapp: string, address: string, perm: permission.Permission): bool =
let key = dapp & address
if not self.dapps.hasKey(key):
return false
return self.dapps[key].permissions.contains(perm)
proc disconnect*(self: Service, dappName: string): bool =
try:
var addresses: seq[string] = @[]
for dapp in self.dapps.values:
if dapp.name != dappName:
continue
discard backend.deleteDappPermissionsByNameAndAddress(dapp.name, dapp.address)
addresses.add(dapp.address)
for address in addresses:
self.dapps.del(dappName & address)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
proc disconnectAddress*(self: Service, dappName: string, address: string): bool =
let key = dappName & address
if not self.dapps.hasKey(key):
return
try:
discard backend.deleteDappPermissionsByNameAndAddress(dappName, address)
self.dapps.del(key)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
proc removePermission*(self: Service, name: string, address: string, perm: permission.Permission): bool =
let key = name & address
if not self.dapps.hasKey(key):
return
try:
if self.dapps[key].permissions.contains(perm):
self.dapps[key].permissions.excl(perm)
if self.dapps[key].permissions.len > 0:
discard backend.addDappPermissions(backend.Permission(
dapp: name,
address: address,
permissions: self.dapps[key].permissions.toSeq().mapIt($it)
))
else:
discard backend.deleteDappPermissionsByNameAndAddress(name, address)
self.dapps.del(key)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription

View File

@ -1,5 +1,4 @@
import json
import ../dapp_permissions/service as dapp_permissions_service
const HTTPS_SCHEME* = "https"
const IPFS_GATEWAY* = ".infura.status.im"

View File

@ -15,18 +15,6 @@ type
decimals* {.serializedFieldName("decimals").}: int
color* {.serializedFieldName("color").}: string
Bookmark* = ref object of RootObj
name* {.serializedFieldName("name").}: string
url* {.serializedFieldName("url").}: string
imageUrl* {.serializedFieldName("imageUrl").}: string
removed* {.serializedFieldName("removed").}: bool
deletedAt* {.serializedFieldName("deletedAt").}: int
Permission* = ref object of RootObj
dapp* {.serializedFieldName("dapp").}: string
address* {.serializedFieldName("address").}: string
permissions* {.serializedFieldName("permissions").}: seq[string]
Network* = ref object of RootObj
chainId* {.serializedFieldName("chainId").}: int
nativeCurrencyDecimals* {.serializedFieldName("nativeCurrencyDecimals").}: int
@ -187,19 +175,6 @@ rpc(hasUnseenActivityCenterNotifications, "wakuext"):
rpc(markAsSeenActivityCenterNotifications, "wakuext"):
discard
rpc(getBookmarks, "browsers"):
discard
rpc(storeBookmark, "browsers"):
bookmark: Bookmark
rpc(updateBookmark, "browsers"):
originalUrl: string
bookmark: Bookmark
rpc(deleteBookmark, "browsers"):
url: string
rpc(setTenorAPIKey, "gif"):
key: string
@ -218,16 +193,6 @@ rpc(getRecentGifs, "gif"):
rpc(getFavoriteGifs, "gif"):
discard
rpc(getDappPermissions, "permissions"):
discard
rpc(addDappPermissions, "permissions"):
permission: Permission
rpc(deleteDappPermissionsByNameAndAddress, "permissions"):
dapp: string
address: string
rpc(fetchMarketValues, "wallet"):
symbols: seq[string]
currencies: seq[string]

View File

@ -1,28 +0,0 @@
import json
import core, ../app_service/common/utils
import response_type
import ./backend
export response_type
proc addBookmark*(bookmark: backend.Bookmark): RpcResponse[JsonNode] =
result = callPrivateRPC("addBookmark".prefix, %*[{
"url": bookmark.url,
"name": bookmark.name,
"imageUrl": bookmark.imageUrl,
"removed": bookmark.removed,
"deletedAt": bookmark.deletedAt
}])
proc removeBookmark*(url: string): RpcResponse[JsonNode] =
result = callPrivateRPC("removeBookmark".prefix, %*[url])
proc updateBookmark*(oldUrl: string, bookmark: backend.Bookmark): RpcResponse[JsonNode] =
result = callPrivateRPC("updateBookmark".prefix, %*[oldUrl, {
"url": bookmark.url,
"name": bookmark.name,
"imageUrl": bookmark.imageUrl,
"removed": bookmark.removed,
"deletedAt": bookmark.deletedAt
}])

View File

@ -1,157 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import AppLayouts.Profile.views 1.0
import AppLayouts.Profile.stores 1.0
import Storybook 1.0
import utils 1.0
SplitView {
Logs { id: logs }
ListModel {
id: dappsModel
ListElement {
name: "http://simpledapp.eth"
accounts: [
ListElement {
name: "Main Account"
address: "0x2B748A02e06B159C7C3E98F5064577B96E55A7b4"
color: "#4360DF"
emoji: "😎"
},
ListElement {
name: "Account 2"
address: "0x5aD88F52b5cb0E4120c0Dd32CFeE782436F492E5"
color: "#887AF9"
emoji: "😋"
}
]
}
}
property QtObject mockData: QtObject {
property QtObject accountSettings: QtObject {
property string browserHomepage: "https://status.im/"
property int shouldShowBrowserSearchEngine: 3
property bool shouldShowFavoritesBar: true
property int useBrowserEthereumExplorer: 1
}
}
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
BrowserView {
SplitView.fillWidth: true
SplitView.fillHeight: true
contentWidth: parent.width
sectionTitle: "Browser section"
accountSettings: mockData.accountSettings
store: ProfileSectionStore {
property WalletStore walletStore: WalletStore {
property var accountSensitiveSettings: mockData.accountSettings
property var dappList: dappsModel
function disconnect(dappName) {
for (let i = 0; i < dappsModel.count; i++) {
if (dappsModel.get(i).name === dappName) {
dappsModel.remove(i)
return
}
}
}
function disconnectAddress(dappName, address) {
for (let i = 0; i < dappsModel.count; i++) {
const dapp = dappsModel.get(i)
if (dapp.name === dappName) {
for (let i = 0; i < dapp.accounts.count; i++) {
if (dapp.accounts.get(i).address === address) {
dapp.accounts.remove(i)
return
}
}
return
}
}
}
}
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 200
logsView.logText: logs.logText
}
}
Pane {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
font.pixelSize: 13
ColumnLayout {
spacing: 6
Label {
text: "Browser Homepage"
}
TextField {
Layout.fillWidth: true
text: mockData.accountSettings.browserHomepage
onTextChanged: mockData.accountSettings.browserHomepage = text
}
Label {
text: "Browser Search Engine ID"
}
TextField {
Layout.fillWidth: true
text: mockData.accountSettings.shouldShowBrowserSearchEngine
onTextChanged: {
if (text !== "") {
mockData.accountSettings.shouldShowBrowserSearchEngine = parseInt(text)
}
}
}
Label {
text: "Browser Ethereum Explorer ID"
}
TextField {
Layout.fillWidth: true
text: mockData.accountSettings.useBrowserEthereumExplorer
onTextChanged: {
if (text !== "") {
mockData.accountSettings.useBrowserEthereumExplorer = parseInt(text)
}
}
}
CheckBox {
text: "Should show Favorites bar"
checked: mockData.accountSettings.shouldShowFavoritesBar
onToggled: mockData.accountSettings.shouldShowFavoritesBar = !mockData.accountSettings.shouldShowFavoritesBar
}
}
}
}
// category: Components
// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=448%3A36296
// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1573%3A296338

View File

@ -15,7 +15,7 @@ mainWindow_Settings_StatusNavigationPanelHeadline = {"container": mainWindow_Lef
mainWindow_scrollView_StatusScrollView = {"container": mainWindow_LeftTabView, "id": "scrollView", "type": "StatusScrollView", "unnamed": 1, "visible": True}
scrollView_MenuItem_StatusNavigationListItem = {"container": mainWindow_scrollView_StatusScrollView, "type": "StatusNavigationListItem", "visible": True}
scrollView_Flickable = {"container": mainWindow_scrollView_StatusScrollView, "type": "Flickable", "unnamed": 1, "visible": True}
settingsBackUpSeedPhraseOption = {"container": mainWindow_scrollView_StatusScrollView, "objectName": "19-MainMenuItem", "type": "StatusNavigationListItem", "visible": True}
settingsBackUpSeedPhraseOption = {"container": mainWindow_scrollView_StatusScrollView, "objectName": "18-MainMenuItem", "type": "StatusNavigationListItem", "visible": True}
settingsWalletOption = {"container": LeftTabView_ScrollView, "objectName": "5-AppMenuItem", "type": "StatusNavigationListItem", "visible": True}
# Communities View

View File

@ -67,7 +67,7 @@ class LeftPanel(QObject):
return MessagingSettingsView()
@allure.step('Open communities settings')
@handle_settings_opening(CommunitiesSettingsView, '13-AppMenuItem')
@handle_settings_opening(CommunitiesSettingsView, '12-AppMenuItem')
def open_communities_settings(self, attempts: int = 2) -> 'CommunitiesSettingsView':
assert CommunitiesSettingsView().exists, 'Community settings view was not opened'
return CommunitiesSettingsView()
@ -91,7 +91,7 @@ class LeftPanel(QObject):
return ChangePasswordView()
@allure.step('Choose back up seed phrase in settings')
@handle_settings_opening(BackUpYourSeedPhrasePopUp, '19-MainMenuItem')
@handle_settings_opening(BackUpYourSeedPhrasePopUp, '18-MainMenuItem')
def open_back_up_seed_phrase(self, click_attempts: int = 2) -> 'BackUpYourSeedPhrasePopUp':
assert BackUpYourSeedPhrasePopUp().exists, 'Back up your seed phrase modal was not opened'
return BackUpYourSeedPhrasePopUp()
@ -103,13 +103,13 @@ class LeftPanel(QObject):
return SyncingSettingsView()
@allure.step('Choose sign out and quit in settings')
@handle_settings_opening(SignOutPopup, '18-ExtraMenuItem')
@handle_settings_opening(SignOutPopup, '17-ExtraMenuItem')
def open_sign_out_and_quit(self, click_attempts: int = 2) -> 'SignOutPopup':
assert SignOutPopup().exists, 'Sign out modal was not opened'
return SignOutPopup()
@allure.step('Open keycard settings')
@handle_settings_opening(KeycardSettingsView, '14-MainMenuItem')
@handle_settings_opening(KeycardSettingsView, '13-MainMenuItem')
def open_keycard_settings(self, click_attempts: int = 2) -> 'KeycardSettingsView':
assert KeycardSettingsView().wait_until_appears(), f'Keycard settings view was not opened'
return KeycardSettingsView()
@ -121,7 +121,7 @@ class LeftPanel(QObject):
return ENSSettingsView()
@allure.step('Open advanced settings')
@handle_settings_opening(AdvancedSettingsView, '11-SettingsMenuItem')
@handle_settings_opening(AdvancedSettingsView, '10-SettingsMenuItem')
def open_advanced_settings(self, click_attempts: int = 2) -> 'AdvancedSettingsView':
assert AdvancedSettingsView().exists, 'Advanced settings view was not opened'
return AdvancedSettingsView()

View File

@ -1,616 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtWebEngine 1.10
import QtWebChannel 1.13
import Qt.labs.settings 1.0
import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.2
import StatusQ.Core 0.1
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.send 1.0
import shared.stores.send 1.0
import "popups"
import "controls"
import "views"
import "panels"
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
StatusSectionLayout {
id: root
property var globalStore
property var sendTransactionModal
required property TransactionStore transactionStore
required property var assetsStore
required property var currencyStore
required property var tokensStore
function openUrlInNewTab(url) {
var tab = _internal.addNewTab()
tab.item.url = _internal.determineRealURL(url)
}
notificationCount: activityCenterStore.unreadNotificationsCount
hasUnseenNotifications: activityCenterStore.hasUnseenNotifications
onNotificationButtonClicked: Global.openActivityCenterPopup()
QtObject {
id: _internal
property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
property Component browserDialogComponent: BrowserDialog {
onClosing: destroy()
}
property Component jsDialogComponent: JSDialogWindow {}
property Component accessDialogComponent: BrowserConnectionModal {
currentTab: tabs.getTab(tabs.currentIndex) && tabs.getTab(tabs.currentIndex).item
parent: browserWindow
x: browserWindow.width - width - Style.current.halfPadding
y: browserWindow.y + browserHeader.height + Style.current.halfPadding
web3Response: function(message) {
provider.web3Response(message)
}
}
property Component sendTransactionModalComponent: SendModal {
anchors.centerIn: parent
preSelectedHoldingID: "ETH"
preSelectedHoldingType: Constants.TokenType.ERC20
store: root.transactionStore
}
property Component signMessageModalComponent: SignMessageModal {}
property MessageDialog sendingError: MessageDialog {
title: qsTr("Error sending the transaction")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
property MessageDialog signingError: MessageDialog {
title: qsTr("Error signing message")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
property QtObject defaultProfile: WebEngineProfile {
storageName: "Profile"
offTheRecord: false
httpUserAgent: {
if (localAccountSensitiveSettings.compatibilityMode) {
// Google doesn't let you connect if the user agent is Chrome-ish and doesn't satisfy some sort of hidden requirement
return "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0"
}
return ""
}
useForGlobalCertificateVerification: true
userScripts: [
WebEngineScript {
injectionPoint: WebEngineScript.DocumentCreation
sourceUrl: Qt.resolvedUrl("./helpers/provider.js")
worldId: WebEngineScript.MainWorld // TODO: check https://doc.qt.io/qt-5/qml-qtwebengine-webenginescript.html#worldId-prop
}
]
}
property QtObject otrProfile: WebEngineProfile {
offTheRecord: true
persistentCookiesPolicy: WebEngineProfile.NoPersistentCookies
httpUserAgent: _internal.defaultProfile.httpUserAgent
userScripts: [
WebEngineScript {
injectionPoint: WebEngineScript.DocumentCreation
sourceUrl: Qt.resolvedUrl("./helpers/provider.js")
worldId: WebEngineScript.MainWorld // TODO: check https://doc.qt.io/qt-5/qml-qtwebengine-webenginescript.html#worldId-prop
}
]
}
function addNewDownloadTab() {
tabs.createDownloadTab(tabs.count !== 0 ? currentWebView.profile : defaultProfile);
tabs.currentIndex = tabs.count - 1;
}
function addNewTab() {
var tab = tabs.createEmptyTab(tabs.count !== 0 ? currentWebView.profile : defaultProfile);
tabs.currentIndex = tabs.count - 1;
browserHeader.addressBar.forceActiveFocus();
browserHeader.addressBar.selectAll();
return tab;
}
function onDownloadRequested(download) {
downloadBar.isVisible = true
download.accept();
DownloadsStore.addDownload(download)
}
function determineRealURL(url) {
return Web3ProviderStore.determineRealURL(url)
}
onCurrentWebViewChanged: {
findBar.reset();
browserHeader.addressBar.text = Web3ProviderStore.obtainAddress(currentWebView.url)
}
}
centerPanel: Rectangle {
id: browserWindow
anchors.fill: parent
color: Style.current.inputBackground
WebProviderObj {
id: provider
createAccessDialogComponent: function() {
return _internal.accessDialogComponent.createObject(root)
}
createSendTransactionModalComponent: function(request) {
return _internal.sendTransactionModalComponent.createObject(root, {
preSelectedRecipient: request.payload.params[0].to,
preDefinedAmountToSend: LocaleUtils.numberToLocaleString(RootStore.getWei2Eth(request.payload.params[0].value, 18)),
})
}
createSignMessageModalComponent: function(request) {
return _internal.signMessageModalComponent.createObject(root, {
request,
selectedAccount: {
name: WalletStore.dappBrowserAccount.name,
iconColor: Utils.getColorForId(WalletStore.dappBrowserAccount.colorId)
}
})
}
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, chainId) {
let url = "%1/%2".arg(WalletStore.getEtherscanLink(chainId)).arg(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: Utils.getColorForId(WalletStore.dappBrowserAccount.colorId)
settingMenu: settingsMenu
currentUrl: !!_internal.currentWebView ? _internal.currentWebView.url : ""
isLoading: (!!_internal.currentWebView && _internal.currentWebView.loading)
canGoBack: (!!_internal.currentWebView && _internal.currentWebView.canGoBack)
canGoForward: (!!_internal.currentWebView && _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);
}
onOpenWalletMenu: Global.openPopup(browserWalletMenu)
}
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 ? webEngineView : null
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) {
root.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);
}
}
Component {
id: browserWalletMenu
BrowserWalletMenu {
assetsStore: root.assetsStore
currencyStore: root.currencyStore
tokensStore: root.tokensStore
property point headerPoint: Qt.point(browserHeader.x, browserHeader.y)
x: (parent.width - width - Style.current.halfPadding)
y: (Math.abs(browserHeader.mapFromGlobal(headerPoint).y) +
browserHeader.anchors.topMargin + Style.current.halfPadding)
onSendTriggered: {
sendTransactionModal.preSelectedAccountAddress = selectedAccount.address
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()
}
}
}
}
Component {
id: addFavoriteModal
AddFavoriteModal {}
}
MessageDialog {
id: sslDialog
property var certErrors: []
icon: StandardIcon.Warning
standardButtons: StandardButton.No | StandardButton.Yes
title: qsTr("Server's certificate not trusted")
text: qsTr("Do you wish to continue?")
detailedText: qsTr("If you wish so, you may continue with an unverified certificate. Accepting an unverified certificate means you may not be connected with the host you tried to connect to.\nDo you wish to override the security check and continue?")
onYes: {
certErrors.shift().ignoreCertificateError();
presentError();
}
onNo: reject()
onRejected: reject()
function reject(){
certErrors.shift().rejectCertificate();
presentError();
}
function enqueue(error){
certErrors.push(error);
presentError();
}
function presentError(){
visible = certErrors.length > 0
}
}
Menu {
id: historyMenu
Instantiator {
model: _internal.currentWebView && _internal.currentWebView.navigationHistory.items
MenuItem {
text: model.title
onTriggered: _internal.currentWebView.goBackOrForward(model.offset)
checkable: !enabled
checked: !enabled
enabled: model.offset
}
onObjectAdded: function(index, object) {
historyMenu.insertItem(index, object)
}
onObjectRemoved: function(index, object) {
historyMenu.removeItem(object)
}
}
}
Component {
id: favoritesBar
FavoritesBar {
bookmarkModel: BookmarksStore.bookmarksModel
favoritesMenu: favoriteMenu
setAsCurrentWebUrl: function(url) {
_internal.currentWebView.url = _internal.determineRealURL(url)
}
addFavModal: function() {
Global.openPopup(addFavoriteModal, {toolbarMode: true,
ogUrl: browserHeader.currentFavorite ? browserHeader.currentFavorite.url : _internal.currentWebView.url,
ogName: browserHeader.currentFavorite ? browserHeader.currentFavorite.name : _internal.currentWebView.title})
}
}
}
Component {
id: webEngineView
BrowserWebEngineView {
anchors.top: parent.top
anchors.topMargin: browserHeader.height
currentWebView: _internal.currentWebView
webChannel: channel
findBarComp: findBar
favMenu: favoriteMenu
addFavModal: addFavoriteModal
downloadsMenu: downloadMenu
determineRealURLFn: function(url) {
return _internal.determineRealURL(url)
}
onLinkHovered: function(hoveredUrl) {
if (hoveredUrl === "")
hideStatusText.start();
else {
statusText.text = hoveredUrl;
statusBubble.visible = true;
hideStatusText.stop();
}
}
onSetCurrentWebUrl: {
_internal.currentWebView.url = url
}
onWindowCloseRequested: tabs.removeView(tabs.indexOfView(webEngineView))
onNewViewRequested: function(request) {
if (!request.userInitiated) {
print("Warning: Blocked a popup window.");
} else if (request.destination === WebEngineView.NewViewInTab) {
var tab = tabs.createEmptyTab(_internal.currentWebView.profile);
tabs.currentIndex = tabs.count - 1;
request.openIn(tab.item);
} else if (request.destination === WebEngineView.NewViewInBackgroundTab) {
var backgroundTab = tabs.createEmptyTab(_internal.currentWebView.profile);
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);*/
} else {
// Instead of opening a new window, we open a new tab
// TODO: remove "open in new window" from context menu
var tab = tabs.createEmptyTab(_internal.currentWebView.profile);
tabs.currentIndex = tabs.count - 1;
request.openIn(tab.item);
}
}
onCertificateError: function(error) {
error.defer();
sslDialog.enqueue(error);
}
onJavaScriptDialogRequested: function(request) {
request.accepted = true;
var dialog = _internal.jsDialogComponent.createObject(root, {"request": request});
dialog.open();
}
}
}
Connections {
target: _internal.currentWebView
function onUrlChanged() {
browserHeader.addressBar.text = Web3ProviderStore.obtainAddress(_internal.currentWebView.url)
RootStore.currentTabConnected = Web3ProviderStore.hasWalletConnected(Utils.getHostname(_internal.currentWebView.url))
}
}
Connections {
target: BookmarksStore.bookmarksModel
function onModelChanged() {
browserHeader.currentFavorite = Qt.binding(function () {return BookmarksStore.getCurrentFavorite(_internal.currentWebView.url)})
}
}
Connections {
target: browserSection
function onOpenUrl(url: string) {
root.openUrlInNewTab(url);
}
}
}

View File

@ -1,76 +0,0 @@
import QtQuick 2.13
import StatusQ.Components 0.1 as StatusQ
import StatusQ.Core.Theme 0.1
import shared 1.0
import shared.panels 1.0
import shared.status 1.0
import utils 1.0
Item {
property url webUrl
property url source
property string text
signal clicked(mouse: var)
signal rightClicked(mouse: var)
id: root
width: 74
height: 48 + Style.current.halfPadding
SVGImage {
id: bookmarkImage
width: 48
height: 48
anchors.horizontalCenter: parent.horizontalCenter
source: !!root.source && !!root.source.toString() ? root.source : Style.svg("compassActive")
visible: root.source && root.source.toString()
}
StatusQ.StatusRoundIcon {
id: addButton
anchors.horizontalCenter: parent.horizontalCenter
asset.name: "add"
asset.color: Theme.palette.baseColor1
color: Theme.palette.baseColor2
visible: !webUrl.toString()
}
StatusQ.StatusLetterIdenticon {
id: identicon
anchors.horizontalCenter: parent.horizontalCenter
letterIdenticonColor: Theme.palette.baseColor2
identiconText.text: text.charAt(0)
identiconText.color: Theme.palette.baseColor1
visible: !bookmarkImage.visible && !addButton.visible
}
StyledText {
id: bookmarkName
text: root.text
width: 67
anchors.top: bookmarkImage.bottom
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Style.current.additionalTextSize
wrapMode: Text.WordWrap
anchors.topMargin: Style.current.halfPadding
maximumLineCount: 2
elide: Text.ElideRight
textFormat: Text.PlainText
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton) {
root.rightClicked(mouse)
} else {
root.clicked(mouse)
}
}
}
}

View File

@ -1,117 +0,0 @@
import QtQuick 2.1
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import utils 1.0
import shared.panels 1.0
Rectangle {
property bool downloadComplete: false
property bool isCanceled: false
property bool isPaused: false
property bool hovered: false
// use this to place the newest downloads first
property int reversedIndex: listView.count - 1 - index
property string primaryText: ""
property string downloadText: ""
signal optionsButtonClicked(var xVal)
signal itemClicked()
id: root
width: 272
height: 40
border.width: 0
color: hovered ? Style.current.backgroundHover : Style.current.transparent
radius: Style.current.radius
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: {
root.hovered = true
}
onExited: {
root.hovered = false
}
onClicked: {
itemClicked()
}
}
Loader {
id: iconLoader
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Style.current.smallPadding
active: root.visible
sourceComponent: {
if (downloadComplete || isPaused || isCanceled) {
return fileImageComponent
}
return loadingImageComponent
}
Component {
id: loadingImageComponent
StatusLoadingIndicator {}
}
Component {
id: fileImageComponent
SVGImage {
source: Style.svg("browser/file")
width: 24
height: 24
ColorOverlay {
anchors.fill: parent
source: parent
color: downloadComplete ? Style.current.transparent : Style.current.darkGrey
}
}
}
}
StyledText {
id: filenameText
text: primaryText
elide: Text.ElideRight
anchors.left: iconLoader.right
anchors.right: optionsBtn.left
anchors.top: downloadComplete ? undefined : parent.top
anchors.verticalCenter: downloadComplete ? parent.verticalCenter : undefined
minimumPixelSize: 13
anchors.leftMargin: Style.current.smallPadding
anchors.topMargin: 2
}
StyledText {
id: progressText
visible: !downloadComplete
color: Style.current.secondaryText
text: downloadText
elide: Text.ElideRight
anchors.left: iconLoader.right
anchors.right: optionsBtn.left
anchors.bottom: parent.bottom
minimumPixelSize: 13
anchors.leftMargin: Style.current.smallPadding
anchors.bottomMargin: 2
}
StatusFlatRoundButton {
width: 32
height: 32
id: optionsBtn
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
icon.name: "more"
type: StatusFlatRoundButton.Type.Tertiary
onClicked: optionsButtonClicked(optionsBtn.x)
}
}

View File

@ -1,16 +0,0 @@
import QtQuick 2.13
import shared 1.0
import utils 1.0
Image {
id: faviconImage
property var currentTab
width: 24
height: 24
sourceSize: Qt.size(width, height)
// TODO find a better default favicon
source: faviconImage.currentTab && !!faviconImage.currentTab.icon.toString() ? faviconImage.currentTab.icon : Style.svg("compassActive")
}

View File

@ -1,104 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls.Styles 1.0
import shared 1.0
import shared.panels 1.0
import shared.status 1.0
import "../"
import utils 1.0
import StatusQ.Controls 0.1
TabViewStyle {
id: tabViewStyle
property color fillColor: Style.current.background
property color nonSelectedColor: Qt.darker(Style.current.background, 1.2)
frameOverlap: 1
tabsMovable: true
frame: Rectangle {
color: Style.current.transparent
border.width: 0
}
tab: Item {
implicitWidth: tabRectangle.implicitWidth + 5 + (newTabloader.active ? newTabloader.width + Style.current.halfPadding : 0)
implicitHeight: tabRectangle.implicitHeight
Rectangle {
id: tabRectangle
color: styleData.selected ? fillColor : nonSelectedColor
border.width: 0
implicitWidth: 240
implicitHeight: control.tabHeight
radius: Style.current.radius
// This rectangle is to hide the bottom radius
Rectangle {
width: parent.implicitWidth
height: 5
color: parent.color
border.width: 0
anchors.bottom: parent.bottom
}
FaviconImage {
id: faviconImage
currentTab: control.getTab(styleData.index) && control.getTab(styleData.index).item
anchors.verticalCenter: parent.verticalCenter;
anchors.left: parent.left
anchors.leftMargin: Style.current.halfPadding
}
StyledText {
id: text
anchors.verticalCenter: parent.verticalCenter
anchors.left: faviconImage.right
anchors.leftMargin: Style.current.halfPadding
anchors.right: closeTabBtn.left
anchors.rightMargin: Style.current.halfPadding
text: styleData.title
// TODO the elide probably doesn't work. Set a Max width
elide: Text.ElideRight
color: Style.current.textColor
}
StatusFlatRoundButton {
id: closeTabBtn
width: 16
height: 16
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: Style.current.halfPadding
icon.name: "close"
type: StatusFlatRoundButton.Type.Quaternary
visible: control.count > 1 || styleData.title !== qsTr("Start Page")
enabled: visible
onClicked: control.closeButtonClicked(styleData.index)
}
}
Loader {
id: newTabloader
active: styleData.index === control.count - 1
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
sourceComponent: Component {
StatusFlatRoundButton {
id: addButton
width: 16
height: 16
icon.name: "close"
icon.rotation: 45
color: "transparent"
type: StatusFlatRoundButton.Type.Quaternary
onClicked: control.openNewTabClicked()
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,218 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import Qt.labs.settings 1.0
import QtQuick.Controls.Styles 1.0
import QtWebEngine 1.10
import StatusQ.Controls 0.1
import shared.controls 1.0
import utils 1.0
import "../popups"
import "../controls"
Rectangle {
id: root
property alias favoriteComponent: favoritesBarLoader.sourceComponent
property alias addressBar: addressBar
property var currentUrl
property bool isLoading: false
property bool canGoBack: false
property bool canGoForward: false
property var currentFavorite
property bool currentTabConnected: false
property string dappBrowserAccName: ""
property string dappBrowserAccIcon: ""
property var settingMenu
signal addNewFavoritelClicked(var xPos)
signal launchInBrowser(var url)
signal openHistoryPopup(var xPos, var yPos)
signal goForward()
signal goBack()
signal reload()
signal stopLoading()
signal openWalletMenu()
QtObject {
id: _internal
readonly property int innerMargin: 12
}
width: parent.width
height: barRow.height + (favoritesBarLoader.active ? favoritesBarLoader.height : 0)
color: Style.current.background
border.width: 0
RowLayout {
id: barRow
width: parent.width
height: 45
spacing: _internal.innerMargin
StatusFlatRoundButton {
id: backButton
Layout.preferredWidth: 32
Layout.preferredHeight: 32
icon.height: 20
icon.width: 20
icon.name: "arrow-left"
icon.disabledColor: Style.current.lightGrey
type: StatusFlatRoundButton.Type.Tertiary
enabled: canGoBack
Layout.leftMargin: _internal.innerMargin
onClicked: goBack()
onPressAndHold: {
if (canGoBack || canGoForward) {
openHistoryPopup(backButton.x, backButton.y + backButton.height)
}
}
}
StatusFlatRoundButton {
id: forwardButton
Layout.preferredWidth: 32
Layout.preferredHeight: 32
icon.width: 20
icon.height: 20
icon.name: "arrow-right"
icon.disabledColor: Style.current.lightGrey
type: StatusFlatRoundButton.Type.Tertiary
enabled: canGoForward
Layout.leftMargin: -_internal.innerMargin/2
onClicked: goForward()
onPressAndHold: {
if (canGoBack || canGoForward) {
openHistoryPopup(backButton.x, backButton.y + backButton.height)
}
}
}
StyledTextField {
id: addressBar
Layout.preferredHeight: 40
Layout.fillWidth: true
background: Rectangle {
color: Style.current.inputBackground
border.color: Style.current.inputBorderFocus
border.width: activeFocus ? 1 : 0
radius: 20
}
leftPadding: Style.current.padding
rightPadding: addFavoriteBtn.width + reloadBtn.width + Style.current.bigPadding
placeholderText: qsTr("Enter URL")
focus: true
text: ""
color: Style.current.textColor
onActiveFocusChanged: {
if (activeFocus) {
addressBar.selectAll()
}
}
Keys.onPressed: {
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
launchInBrowser(text)
}
}
StatusFlatRoundButton {
id: addFavoriteBtn
width: 24
height: 24
anchors.verticalCenter: parent.verticalCenter
anchors.right: reloadBtn.left
anchors.rightMargin: Style.current.halfPadding
visible: !!currentUrl
icon.source: !!root.currentFavorite ? Style.svg("browser/favoriteActive") : Style.svg("browser/favorite")
color: "transparent"
type: StatusFlatRoundButton.Type.Tertiary
onClicked: addNewFavoritelClicked(addFavoriteBtn.x)
}
StatusFlatRoundButton {
id: reloadBtn
width: 24
height: 24
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: Style.current.halfPadding
icon.name: isLoading ? "close-circle" : "refresh"
color: "transparent"
type: StatusFlatRoundButton.Type.Tertiary
onClicked: isLoading ? stopLoading(): reload()
}
}
Loader {
Layout.preferredWidth: 44
Layout.preferredHeight: 44
active: true
sourceComponent: currentTabConnected ? connectedBtnComponent : notConnectedBtnCompoent
}
Component {
id: notConnectedBtnCompoent
StatusFlatRoundButton {
id: accountBtn
width: 24
height: 24
icon.width: 24
icon.height: 24
icon.name: "filled-account"
type: StatusFlatRoundButton.Type.Tertiary
onPressed: {
root.openWalletMenu()
}
}
}
Component {
id: connectedBtnComponent
StatusFlatButton {
id: accountBtnConnected
icon.name: "wallet"
icon.width: 18
icon.height: 18
icon.color: dappBrowserAccIcon
text: dappBrowserAccName
onPressed: {
root.openWalletMenu();
}
}
}
StatusFlatRoundButton {
id: settingsMenuButton
Layout.preferredHeight: 32
Layout.preferredWidth: 32
icon.width: 24
icon.height: 24
icon.name: "more"
type: StatusFlatRoundButton.Type.Tertiary
Layout.rightMargin: _internal.innerMargin
onClicked: {
if (settingMenu.opened) {
settingMenu.close()
} else {
settingMenu.open()
}
}
}
}
Loader {
id: favoritesBarLoader
active: localAccountSensitiveSettings.shouldShowFavoritesBar
anchors.top: barRow.bottom
anchors.left: parent.left
anchors.leftMargin: Style.current.smallPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
}
}

View File

@ -1,81 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 1.0 as QQC1
import utils 1.0
import StatusQ.Core.Utils 0.1 as SQUtils
import "../controls/styles"
QQC1.TabView {
id: tabs
property var currentWebEngineProfile
property var tabComponent
property var determineRealURL: function(url) {}
readonly property int tabHeight: 40
signal openNewTabTriggered()
function createEmptyTab(profile, createAsStartPage) {
var tab = addTab("", tabComponent);
// We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately.
tab.active = true;
createAsStartPage = createAsStartPage || tabs.count === 1
tab.title = Qt.binding(function() {
var tabTitle = ""
if (tab.item.title) {
tabTitle = tab.item.title
}
else if (createAsStartPage) {
tabTitle = qsTr("Start Page")
}
else {
tabTitle = qsTr("New Tab")
}
return SQUtils.StringUtils.escapeHtml(tabTitle);
})
if (createAsStartPage) {
tab.item.url = "https://dap.ps"
}
tab.item.profile = profile;
if (localAccountSensitiveSettings.browserHomepage !== "") {
tab.item.url = determineRealURL(localAccountSensitiveSettings.browserHomepage)
}
return tab;
}
function createDownloadTab(profile) {
var tab = addTab("", tabComponent);
tab.active = true;
tab.title = qsTr("Downloads Page")
tab.item.profile = profile
tab.item.url = "status://downloads";
}
function indexOfView(view) {
for (let i = 0; i < tabs.count; ++i)
if (tabs.getTab(i).item === view)
return i
return -1
}
function openNewTabClicked() {
openNewTabTriggered()
}
function removeView(index) {
if (tabs.count === 1) {
tabs.createEmptyTab(currentWebEngineProfile, true)
}
tabs.removeTab(index)
}
function closeButtonClicked(index) {
removeView(index)
}
style: BrowserTabStyle {}
}

View File

@ -1,119 +0,0 @@
import QtQuick 2.1
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import utils 1.0
import "../controls"
Rectangle {
id: downloadBar
property bool isVisible: false
property var downloadsModel
property var downloadsMenu
signal openDownloadClicked(bool downloadComplete, int index)
signal addNewDownloadTab()
visible: isVisible && !!listView.count
color: Style.current.background
width: parent.width
height: 56
border.width: 1
border.color: Style.current.border
// This container is to contain the downloaded elements between the parent buttons and hide the overflow
Item {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Style.current.smallPadding
anchors.right: showAllBtn.left
anchors.rightMargin: Style.current.smallPadding
height: listView.height
clip: true
StatusListView {
id: listView
orientation: ListView.Horizontal
model: downloadsModel
height: currentItem ? currentItem.height : 0
// This makes it show the newest on the right
layoutDirection: Qt.RightToLeft
spacing: Style.current.smallPadding
anchors.left: parent.left
width: {
// Children rect shows a warning but this works ¯\_()_/¯
let w = 0
for (let i = 0; i < count; i++) {
w += this.itemAtIndex(i).width + this.spacing
}
return w
}
interactive: false
delegate: DownloadElement {
id: downloadElement
isPaused: downloadsModel.downloads[index] && downloadsModel.downloads[index].isPaused
primaryText: downloadFileName
downloadText: {
if (isCanceled) {
return qsTr("Cancelled")
}
if (isPaused) {
return qsTr("Paused")
}
return `${downloadsModel.downloads[index] ? (downloadsModel.downloads[index].receivedBytes / 1000000).toFixed(2) : 0}/${downloadsModel.downloads[index] ? (downloadsModel.downloads[index].totalBytes / 1000000).toFixed(2) : 0} MB` //"14.4/109 MB, 26 sec left"
}
downloadComplete: {
// listView.count ensures a value is returned even when index is undefined
return listView.count > 0 && !!downloadsModel.downloads && !!downloadsModel.downloads[index] &&
downloadsModel.downloads[index].receivedBytes >= downloadsModel.downloads[index].totalBytes
}
onItemClicked: {
openDownloadClicked(downloadComplete, index)
}
onOptionsButtonClicked: {
downloadsMenu.index = index
downloadsMenu.downloadComplete = Qt.binding(function() {return downloadElement.downloadComplete})
downloadsMenu.parent = downloadElement
downloadsMenu.x = xVal + 20
downloadsMenu.y = -downloadsMenu.height
downloadsMenu.open()
}
Connections {
target: downloadsMenu
function onCancelClicked() {
isCanceled = true
}
}
}
}
}
StatusButton {
id: showAllBtn
size: StatusBaseButton.Size.Small
text: qsTr("Show All")
anchors.verticalCenter: parent.verticalCenter
anchors.right: closeBtn.left
anchors.rightMargin: Style.current.padding
onClicked: {
addNewDownloadTab()
}
}
StatusFlatRoundButton {
id: closeBtn
width: 32
height: 32
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
icon.name: "close"
type: StatusFlatRoundButton.Type.Quaternary
onClicked: downloadBar.isVisible = false
}
}

View File

@ -1,79 +0,0 @@
import QtQuick 2.1
import StatusQ.Core 0.1
import utils 1.0
import "../controls"
Rectangle {
id: downloadView
property alias downloadsModel: listView.model
property var downloadsMenu
signal openDownloadClicked(bool downloadComplete, int index)
color: Style.current.background
StatusListView {
id: listView
anchors {
topMargin: Style.current.bigPadding
top: parent.top
bottom: parent.bottom
bottomMargin: Style.current.bigPadding * 2
horizontalCenter: parent.horizontalCenter
}
width: 624
spacing: Style.current.padding
delegate: DownloadElement {
id: downloadElement
width: parent.width
isPaused: downloadsModel.downloads[index] && downloadsModel.downloads[index].isPaused
primaryText: downloadFileName
downloadText: {
if (isCanceled) {
return qsTr("Cancelled")
}
if (isPaused) {
return qsTr("Paused")
}
return `${downloadsModel.downloads[index] ? (downloadsModel.downloads[index].receivedBytes / 1000000).toFixed(2) : 0}/${downloadsModel.downloads[index] ? (downloadsModel.downloads[index].totalBytes / 1000000).toFixed(2) : 0} MB` //"14.4/109 MB, 26 sec left"
}
downloadComplete: {
// listView.count ensures a value is returned even when index is undefined
return listView.count > 0 && !!downloadsModel.downloads && !!downloadsModel.downloads[index] &&
downloadsModel.downloads[index].receivedBytes >= downloadsModel.downloads[index].totalBytes
}
onItemClicked: {
openDownloadClicked(downloadComplete, index)
}
onOptionsButtonClicked: {
downloadsMenu.index = index
downloadsMenu.downloadComplete = Qt.binding(function() {return downloadElement.downloadComplete})
downloadsMenu.parent = downloadElement
downloadsMenu.x = xVal
downloadsMenu.y = downloadView.y - downloadsMenu.height
downloadsMenu.open()
}
Connections {
target: downloadsMenu
function onCancelClicked() {
isCanceled = true
}
}
}
}
Text {
visible: !listView.count
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
text: qsTr("Downloaded files will appear here.")
color: Style.current.secondaryText
}
}

View File

@ -1,66 +0,0 @@
import QtQuick 2.13
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Controls 0.1
import utils 1.0
RowLayout {
id: favoritesBar
property alias bookmarkModel: bookmarkList.model
property var favoritesMenu
property var setAsCurrentWebUrl: function(url){}
property var addFavModal: function(){}
spacing: 0
height: 38
StatusListView {
id: bookmarkList
spacing: Style.current.halfPadding
orientation : ListView.Horizontal
Layout.fillWidth: true
Layout.fillHeight: true
delegate: StatusFlatButton {
id: favoriteBtn
height: 32
icon.source: imageUrl
icon.width: 24
icon.height: 24
// Limit long named tabs. StatusFlatButton is not well-behaved control
// implicitWidth doesn't work. Also avoid breaking visualization by escaping HTML
text: SQUtils.StringUtils.escapeHtml(Utils.elideIfTooLong(name, 40))
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
z: 51
onClicked: function (mouse) {
const isAddBookmarkButton = url === Constants.newBookmark
if (mouse.button === Qt.RightButton && isAddBookmarkButton) {
return
}
if (mouse.button === Qt.RightButton) {
favoritesMenu.url = url
favoritesMenu.x = favoriteBtn.x + mouse.x
favoritesMenu.y = Qt.binding(function () {return mouse.y + favoritesMenu.height})
favoritesMenu.open()
return
}
if (isAddBookmarkButton) {
addFavModal()
return
}
setAsCurrentWebUrl(url)
}
}
}
}
}

View File

@ -1,39 +0,0 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import utils 1.0
import "../controls"
StatusGridView {
id: bookmarkGrid
property var determineRealURLFn: function(url){}
property var setAsCurrentWebUrl: function(url){}
property var favMenu
property var addFavModal
cellWidth: 100
cellHeight: 100
delegate: BookmarkButton {
id: bookmarkBtn
text: name
source: imageUrl
webUrl: determineRealURLFn(url)
onClicked: {
if (!webUrl.toString()) {
Global.openPopup(addFavModal)
} else {
setAsCurrentWebUrl(webUrl)
}
}
onRightClicked: {
favMenu.url = url
favMenu.x = bookmarkGrid.x + bookmarkBtn.x + mouse.x
favMenu.y = Qt.binding(function () {return bookmarkGrid.y + mouse.y + favMenu.height})
favMenu.open()
}
}
}

View File

@ -1,181 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import QtQuick.Layouts 1.0
import StatusQ.Controls 0.1
import shared.controls 1.0
import utils 1.0
Rectangle {
id: root
property int numberOfMatches: 0
property int activeMatch: 0
property alias text: findTextField.text
function reset() {
numberOfMatches = 0;
activeMatch = 0;
visible = false;
}
signal findNext()
signal findPrevious()
width: 300
height: 40
radius: Style.current.radius
border.width: 0
color: Style.current.background
layer.enabled: true
layer.effect: DropShadow{
width: root.width
height: root.height
x: root.x
y: root.y + 10
visible: root.visible
source: root
horizontalOffset: 0
verticalOffset: 2
radius: 10
samples: 15
color: "#22000000"
}
function forceActiveFocus() {
findTextField.forceActiveFocus();
}
onVisibleChanged: {
if (visible)
forceActiveFocus()
}
RowLayout {
anchors.fill: parent
anchors.topMargin: 5
anchors.bottomMargin: 5
anchors.leftMargin: 10
anchors.rightMargin: 10
spacing: 5
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
StyledTextField {
id: findTextField
anchors.fill: parent
background: Rectangle {
color: "transparent"
border.width: 0
}
onAccepted: root.findNext()
onTextChanged: root.findNext()
onActiveFocusChanged: activeFocus ? selectAll() : deselect()
}
}
Label {
text: activeMatch + "/" + numberOfMatches
visible: findTextField.text !== ""
}
Rectangle {
border.width: 1
border.color: Style.current.border
width: 2
height: parent.height
anchors.topMargin: 5
anchors.bottomMargin: 5
}
StatusFlatRoundButton {
id: prevBtn
implicitWidth: 32
implicitHeight: 32
icon.name: "previous"
enabled: numberOfMatches > 0
type: StatusFlatRoundButton.Type.Tertiary
onClicked: root.findPrevious()
}
StatusFlatRoundButton {
id: nextBtn
implicitWidth: 32
implicitHeight: 32
icon.name: "next"
enabled: numberOfMatches > 0
type: StatusFlatRoundButton.Type.Tertiary
onClicked: root.findNext()
}
StatusFlatRoundButton {
id: closeBtn
implicitWidth: 32
implicitHeight: 32
icon.name: "close-circle"
type: StatusFlatRoundButton.Type.Tertiary
onClicked: root.visible = false
}
}
}

View File

@ -1,161 +0,0 @@
import QtQuick 2.13
import QtGraphicalEffects 1.13
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
import shared.popups 1.0
import utils 1.0
import "../stores"
// TODO: replace with StatusModal
ModalPopup {
property string ogUrl: ""
property string ogName: ""
property bool modifiyModal: false
property bool toolbarMode: false
id: popup
width: toolbarMode ? 345 : 480
height: toolbarMode ? 400 : 480
modal: !toolbarMode
background: Rectangle {
id: bgPopup
color: Style.current.background
radius: Style.current.radius
layer.enabled: true
layer.effect: DropShadow{
width: bgPopup.width
height: bgPopup.height
x: bgPopup.x
y: bgPopup.y + 10
visible: bgPopup.visible
source: bgPopup
horizontalOffset: 0
verticalOffset: 5
radius: 10
samples: 15
color: Style.current.dropShadow
}
}
onOpened: {
urlInput.input.text = ogUrl
nameInput.input.text = ogName
urlInput.input.forceActiveFocus(Qt.MouseFocusReason)
}
onClosed: {
reset()
}
function reset() {
modifiyModal = false
toolbarMode = false
urlInput.reset()
nameInput.reset()
ogUrl = ""
ogName = ""
x = Math.round(((parent ? parent.width : 0) - width) / 2)
y = Math.round(((parent ? parent.height : 0) - height) / 2)
}
title: modifiyModal ?
toolbarMode ?
qsTr("Favorite added") :
qsTr("Edit")
: qsTr("Add favorite")
Column {
width: parent.width
spacing: Style.current.padding
StatusInput {
id: urlInput
anchors.left: parent.left
anchors.right: parent.right
label: qsTr("URL")
input.text: ogUrl
placeholderText: qsTr("Paste URL")
input.rightComponent: StatusButton {
anchors.verticalCenter: parent.verticalCenter
borderColor: Theme.palette.primaryColor1
size: StatusBaseButton.Size.Tiny
text: qsTr("Paste")
onClicked: {
text = qsTr("Pasted")
urlInput.input.edit.paste()
}
}
validators: [
StatusUrlValidator {
errorMessage: qsTr("Please enter a valid URL")
}
]
}
StatusInput {
id: nameInput
anchors.left: parent.left
anchors.right: parent.right
leftPadding: 0
rightPadding: 0
label: qsTr("Name")
input.text: ogName
placeholderText: qsTr("Name of the website")
validators: [
StatusMinLengthValidator {
errorMessage: qsTr("Please enter a name")
minLength: 1
}
]
}
}
footer: Item {
width: parent.width
height: removeBtn.height
StatusButton {
id: removeBtn
anchors.right: addBtn.left
anchors.rightMargin: Style.current.padding
visible: popup.modifiyModal
text: qsTr("Remove")
anchors.bottom: parent.bottom
type: StatusBaseButton.Type.Danger
onClicked: {
BookmarksStore.deleteBookmark(popup.ogUrl)
popup.close()
}
}
StatusButton {
id: addBtn
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
text: popup.modifiyModal ?
qsTr("Done") :
qsTr("Add")
anchors.bottom: parent.bottom
enabled: nameInput.valid && !!nameInput.text && urlInput.valid && !!urlInput.text
onClicked: {
if (!popup.modifiyModal) {
// remove "add favorite" button at the end, add new bookmark, add "add favorite" button back
BookmarksStore.deleteBookmark(Constants.newBookmark)
BookmarksStore.addBookmark(urlInput.input.text, nameInput.input.text)
BookmarksStore.addBookmark(Constants.newBookmark, qsTr("Add Favorite"))
} else if (popup.ogName !== nameInput.input.text || popup.ogUrl !== urlInput.input.text) {
BookmarksStore.updateBookmark(popup.ogUrl, urlInput.input.text, nameInput.input.text)
}
popup.close()
}
}
}
}

View File

@ -1,183 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import utils 1.0
import shared.panels 1.0
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import "../controls"
import "../stores"
StatusModal {
id: browserConnectionModal
property var currentTab
property var request: ({"hostname": "", "address": "", "title": "", "permission": ""})
property string currentAddress: ""
property bool interactedWith: false
property var web3Response: function(){}
width: 360
height: 480
showHeader: false
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
topPadding: 0
bottomPadding: 0
function postMessage(isAllowed){
console.log(isAllowed)
interactedWith = true
RootStore.currentTabConnected = isAllowed
if(isAllowed){
Web3ProviderStore.addPermission(request.hostname, request.address, request.permission)
}
Web3ProviderStore.web3ProviderInst.postMessage("", Constants.api_request, JSON.stringify(request))
}
onClosed: {
if(!interactedWith){
RootStore.currentTabConnected = false
postMessage(false);
}
}
contentItem: Item {
width: parent.width
height: parent.height
ColumnLayout {
spacing: Style.current.bigPadding
anchors.centerIn: parent
RowLayout {
property int imgSize: 40
id: logoHeader
spacing: Style.current.halfPadding
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
FaviconImage {
id: siteImg
}
SVGImage {
id: dots1
source: Style.svg("dots-icon")
}
RoundedIcon {
source: Style.svg("check")
iconColor: Style.current.primary
color: Style.current.secondaryBackground
}
SVGImage {
id: dots2
source: Style.svg("dots-icon")
}
RoundedIcon {
source: Style.svg("walletIcon")
iconHeight: 18
iconWidth: 18
iconColor: accountSelector.selectedAccount.iconColor || Style.current.primary
color: Style.current.background
border.width: 1
border.color: Style.current.border
}
}
StatusBaseText {
id: titleText
text: qsTr("'%1' would like to connect to").arg(request.title)
wrapMode: Text.WordWrap
font.weight: Font.Bold
font.pixelSize: 17
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
Layout.maximumWidth: browserConnectionModal.width - Style.current.padding
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
color: Theme.palette.directColor1
}
StatusAccountSelector {
id: accountSelector
label: ""
implicitWidth: 300
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
showAccountDetails: false
accounts: WalletStore.accounts
selectedAccount: WalletStore.dappBrowserAccount
currency: WalletStore.defaultCurrency
onSelectedAccountChanged: {
if (!browserConnectionModal.currentAddress) {
// We just set the account for the first time. Nothing to do here
browserConnectionModal.currentAddress = selectedAccount.address
return
}
if (browserConnectionModal.currentAddress === selectedAccount.address) {
return
}
browserConnectionModal.currentAddress = selectedAccount.address
Web3ProviderStore.web3ProviderInst.dappsAddress = selectedAccount.address;
if (selectedAccount.address) {
Web3ProviderStore.web3ProviderInst.dappsAddress = selectedAccount.address;
WalletStore.switchAccountByAddress(selectedAccount.address)
}
}
}
StatusBaseText {
id: infoText
text: {
switch(request.permission){
case Constants.permission_web3: return qsTr("Allowing authorizes this DApp to retrieve your wallet address and enable Web3");
case Constants.permission_contactCode: return qsTr("Granting access authorizes this DApp to retrieve your chat key");
default: return qsTr("Unknown permission: " + request.permission);
}
}
wrapMode: Text.WordWrap
font.pixelSize: 15
horizontalAlignment: Text.AlignHCenter
color: Theme.palette.baseColor1
Layout.maximumWidth: browserConnectionModal.width - Style.current.padding
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
}
Row {
spacing: Style.current.padding
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
StatusButton {
type: StatusBaseButton.Type.Danger
width: 151
text: qsTr("Deny")
onClicked: {
postMessage(false);
browserConnectionModal.close();
}
}
StatusButton {
normalColor: Utils.setColorAlpha(Style.current.success, 0.1)
textColor: Style.current.success
width: 151
text: qsTr("Allow")
onClicked: {
postMessage(true);
browserConnectionModal.close();
}
}
}
}
}
}

View File

@ -1,96 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.3
import QtWebEngine 1.9
import shared 1.0
import shared.panels 1.0
import shared.status 1.0
import shared.popups 1.0
import utils 1.0
// TODO: replace with StatusMenu
PopupMenu {
id: browserSettingsMenu
property bool isIncognito: false
signal addNewTab()
signal goIncognito(bool checked)
signal zoomIn()
signal zoomOut()
signal changeZoomFactor()
signal launchFindBar()
signal toggleCompatibilityMode(bool checked)
signal launchBrowserSettings()
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
Action {
text: qsTr("New Tab")
shortcut: StandardKey.AddTab
onTriggered: addNewTab()
}
Action {
id: offTheRecordEnabled
// TODO show an indicator on the browser or tab?
text: checked ?
qsTr("Exit Incognito mode") :
qsTr("Go Incognito")
checkable: true
checked: isIncognito
onToggled: goIncognito(checked)
}
Separator {}
// TODO find a way to put both in one button
Action {
text: qsTr("Zoom In")
shortcut: StandardKey.ZoomIn
onTriggered: zoomIn()
}
Action {
text: qsTr("Zoom Out")
shortcut: StandardKey.ZoomOut
onTriggered: zoomOut()
}
Action {
shortcut: "Ctrl+0"
onTriggered: changeZoomFactor()
}
Separator {}
Action {
text: qsTr("Find")
shortcut: StandardKey.Find
onTriggered: launchFindBar()
}
Action {
text: qsTr("Compatibility mode")
checkable: true
checked: true
onToggled: toggleCompatibilityMode(checked)
}
Action {
text: qsTr("Developer Tools")
shortcut: "F12"
onTriggered: {
localAccountSensitiveSettings.devToolsEnabled = !localAccountSensitiveSettings.devToolsEnabled
}
}
Separator {}
Action {
text: qsTr("Settings")
shortcut: "Ctrl+,"
onTriggered: launchBrowserSettings()
}
}

View File

@ -1,226 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtGraphicalEffects 1.13
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import shared.controls 1.0
import shared.views 1.0
import utils 1.0
import "../stores"
// TODO: replace with StatusMenu
Dialog {
id: popup
required property var assetsStore
required property var currencyStore
required property var tokensStore
signal sendTriggered(var selectedAccount)
signal disconnect()
signal reload()
modal: false
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
parent: Overlay.overlay
width: 360
height: 480
background: Rectangle {
id: bgPopup
color: Style.current.background
radius: Style.current.radius
layer.enabled: true
layer.effect: DropShadow {
width: bgPopup.width
height: bgPopup.height
x: bgPopup.x
y: bgPopup.y + 10
visible: bgPopup.visible
source: bgPopup
horizontalOffset: 0
verticalOffset: 5
radius: 10
samples: 15
color: Style.current.dropShadow
}
}
padding: Style.current.padding
Item {
id: walletHeader
width: parent.width
height: networkText.height
Rectangle {
id: networkColorCircle
width: 8
height: 8
radius: width / 2
color: {
switch (Web3ProviderStore.chainName) {
case Constants.networkMainnet: return Style.current.green;
case Constants.networkRopsten: return Style.current.turquoise;
default: return Style.current.red
}
}
anchors.verticalCenter: parent.verticalCenter
}
StatusBaseText {
id: networkText
text: {
switch (Web3ProviderStore.chainName) {
case Constants.networkMainnet: return qsTr("Mainnet");
case Constants.networkRopsten: return qsTr("Ropsten");
default: return qsTr("Unknown")
}
}
font.pixelSize: 15
anchors.verticalCenter: parent.verticalCenter
anchors.left: networkColorCircle.right
anchors.leftMargin: Style.current.halfPadding
}
StatusBaseText {
id: disconectBtn
text: qsTr("Disconnect")
font.pixelSize: 15
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
color: Style.current.danger
visible: RootStore.currentTabConnected
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: disconnect()
}
}
}
Connections {
target: WalletStore.dappBrowserAccount
function onConnectedAccountDeleted() {
popup.reload()
// This is done because when an account is deleted and the account is updated to default one,
// only the properties are updated and we need to listen to those events and update the selected account
accountSelectorRow.currentAddress = ""
accountSelector.selectedAccount = Qt.binding(function () {return WalletStore.dappBrowserAccount})
}
}
Item {
property string currentAddress: ""
id: accountSelectorRow
width: parent.width
height: accountSelector.height
anchors.top: walletHeader.bottom
anchors.topMargin: Style.current.bigPadding
StatusAccountSelector {
id: accountSelector
label: ""
anchors.left: parent.left
anchors.right: copyBtn.left
anchors.rightMargin: Style.current.padding
accounts: WalletStore.accounts
selectedAccount: WalletStore.dappBrowserAccount
currency: WalletStore.defaultCurrency
onSelectedAccountChanged: {
if (!accountSelectorRow.currentAddress) {
// We just set the account for the first time. Nothing to do here
accountSelectorRow.currentAddress = selectedAccount.address
return
}
if (accountSelectorRow.currentAddress === selectedAccount.address) {
return
}
accountSelectorRow.currentAddress = selectedAccount.address
Web3ProviderStore.web3ProviderInst.dappsAddress = selectedAccount.address;
WalletStore.switchAccountByAddress(selectedAccount.address)
reload()
}
}
CopyToClipBoardButton {
id: copyBtn
width: 20
height: 20
anchors.right: sendBtn.left
anchors.rightMargin: Style.current.padding
anchors.top: parent.top
anchors.topMargin: Style.current.padding
color: Style.current.transparent
textToCopy: accountSelector.selectedAccount.address
onCopyClicked: RootStore.copyToClipboard(textToCopy)
}
StatusFlatRoundButton {
id: sendBtn
width: 40
height: 40
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: Style.current.halfPadding
icon.name: "send"
onClicked: sendTriggered(accountSelector.selectedAccount)
}
}
Item {
id: walletInfoContent
width: parent.width
anchors.top: accountSelectorRow.bottom
anchors.topMargin: Style.current.bigPadding
anchors.bottom: parent.bottom
StatusTabBar {
id: walletTabBar
width: parent.width
anchors.top: parent.top
StatusTabButton {
id: assetBtn
width: implicitWidth
text: qsTr("Assets")
}
StatusTabButton {
id: historyBtn
width: implicitWidth
text: qsTr("History")
}
}
StackLayout {
id: stackLayout
width: parent.width
anchors.top: walletTabBar.bottom
anchors.topMargin: Style.current.bigPadding
anchors.bottom: parent.bottom
currentIndex: walletTabBar.currentIndex
// Disable because the refactored version of AssetView requires specific
// integration but the old version was not working properly neither.
//AssetsView {
// id: assetsTab
// controller: popup.assetsStore.assetsController
// currencyStore: popup.currencyStore
// tokensStore: popup.tokensStore
//}
HistoryView {
id: historyTab
overview: WalletStore.dappBrowserAccount
}
}
}
onClosed: {
popup.destroy();
}
}

View File

@ -1,71 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.3
import shared.panels 1.0
import shared.popups 1.0
import utils 1.0
import "../stores"
// TODO: replace with StatusMenu
PopupMenu {
id: downloadMenu
property int index: -1
property bool downloadComplete: false
property var download: DownloadsStore.getDownload(index)
signal cancelClicked()
Action {
enabled: downloadComplete
icon.source: Style.svg("browser/file")
icon.width: 16
icon.height: 16
text: qsTr("Open")
onTriggered: DownloadsStore.openFile(index)
}
Action {
icon.source: Style.svg("add_watch_only")
icon.width: 13
icon.height: 9
text: qsTr("Show in folder")
onTriggered: DownloadsStore.openDirectory(index)
}
Action {
enabled: !downloadComplete && !!download && !download.isPaused
icon.source: Style.svg("browser/pause")
icon.width: 16
icon.height: 16
text: qsTr("Pause")
onTriggered: {
download.pause()
}
}
Action {
enabled: !downloadComplete && !!download && download.isPaused
icon.source: Style.svg("browser/play")
icon.width: 16
icon.height: 16
text: qsTr("Resume")
onTriggered: {
download.resume()
}
}
Separator {
visible: !downloadComplete
}
Action {
enabled: !downloadComplete
icon.source: Style.svg("block-icon")
icon.width: 13
icon.height: 13
text: qsTr("Cancel")
onTriggered: {
download.cancel()
cancelClicked()
}
icon.color: Style.current.red
}
}

View File

@ -1,57 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.3
import shared.panels 1.0
import shared.popups 1.0
import utils 1.0
import "../stores"
// TODO: replace with StatusMenu
PopupMenu {
id: favoritePopupMenu
property var openInNewTab: function () {}
property string url
property var currentFavorite: BookmarksStore.getCurrentFavorite(url)
signal editFavoriteTriggered()
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
Action {
text: qsTr("Open in new Tab")
icon.source: Style.svg("generate_account")
icon.width: 16
icon.height: 16
onTriggered: {
openInNewTab(favoritePopupMenu.url)
}
}
Separator {}
Action {
text: qsTr("Edit")
icon.source: Style.svg("edit")
icon.width: 16
icon.height: 16
onTriggered: {
// Force reloading current favorite as it could have been modified when edited:
favoritePopupMenu.currentFavorite = BookmarksStore.getCurrentFavorite(url)
editFavoriteTriggered()
}
}
Action {
text: qsTr("Remove")
icon.source: Style.svg("remove")
icon.color: Style.current.danger
icon.width: 16
icon.height: 16
onTriggered: {
BookmarksStore.deleteBookmark(favoritePopupMenu.url)
}
}
}

View File

@ -1,88 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtWebEngine 1.10
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import shared.controls 1.0
import shared.popups 1.0
import utils 1.0
// TODO: replace with StatusModal
ModalPopup {
id: root
property QtObject request
height: 286
closePolicy: Popup.NoAutoClose
onClosed: {
request.dialogReject();
root.destroy();
}
Component.onCompleted: {
root.title = request.securityOrigin;
message.text = request.message;
if(request.type === JavaScriptDialogRequest.DialogTypeAlert){
cancelButton.visible = false;
}
if(request.type === JavaScriptDialogRequest.DialogTypePrompt){
prompt.text = request.defaultText;
prompt.visible = true;
svMessage.height = 75;
}
}
StatusScrollView {
id: svMessage
width: parent.width
height: 100
TextArea {
id: message
wrapMode: TextEdit.Wrap
readOnly: true
text: ""
}
}
Input {
id: prompt
text: ""
visible: false
anchors.top: svMessage.bottom
anchors.right: parent.right
anchors.left: parent.left
}
footer: Item {
width: parent.width
height: okButton.height
StatusButton {
id: okButton
anchors.right: parent.right
text: qsTr("Ok")
anchors.bottom: parent.bottom
onClicked: {
request.dialogAccept(prompt.text);
close();
}
}
StatusFlatButton {
id: cancelButton
anchors.right: okButton.left
anchors.rightMargin: Style.current.smallPadding
text: qsTr("Cancel")
anchors.bottom: parent.bottom
onClicked: {
request.dialogReject();
close();
}
}
}
}

View File

@ -1,236 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQuick.Dialogs 1.3
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import utils 1.0
import shared 1.0
import shared.views 1.0
import shared.panels 1.0
import shared.popups 1.0
import "../stores"
StatusModal {
property var request
property var selectedAccount
readonly property int bytes32Length: 66
property bool interactedWith: false
property bool showSigningPhrase: false
property alias transactionSigner: transactionSigner
property var signMessage: function(enteredPassword) {}
property var web3Response
anchors.centerIn: parent
id: root
headerSettings.title: qsTr("Signature request")
height: 504
onClosed: {
if(!interactedWith){
web3Response(JSON.stringify({
"type": "web3-send-async-callback",
"messageId": request.messageId,
"error": {
"code": 4100
}
}));
}
}
onOpened: {
showSigningPhrase = false;
}
function displayValue(input){
if(Utils.isHex(input) && Utils.startsWith0x(input)){
if (input.length === bytes32Length){
return input;
}
return RootStore.getHex2Ascii(input)
}
return input;
}
function messageToSign(){
switch(request.payload.method){
case Constants.personal_sign:
return displayValue(request.payload.params[0]);
case Constants.eth_sign:
return displayValue(request.payload.params[1]);
case Constants.eth_signTypedData:
case Constants.eth_signTypedData_v3:
return JSON.stringify(request.payload.params[1]); // TODO: requires design
default:
return JSON.stringify(request.payload.params); // support for any unhandled sign method
}
}
contentItem: Item {
width: root.width
TransactionSigner {
id: transactionSigner
width: parent.width
signingPhrase: WalletStore.signingPhrase
visible: showSigningPhrase
}
Column {
id: content
visible: !showSigningPhrase
width: root.width - Style.current.padding * 2
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
LabelValueRow {
label: qsTr("From")
value: Item {
id: itmFromValue
anchors.fill: parent
anchors.verticalCenter: parent.verticalCenter
Row {
spacing: Style.current.halfPadding
rightPadding: 0
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
StyledText {
font.pixelSize: 15
height: 22
text: selectedAccount.name
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
}
SVGImage {
id: imgFromWallet
sourceSize.height: 18
sourceSize.width: 18
visible: true
horizontalAlignment: Image.AlignLeft
width: undefined
anchors.verticalCenter: parent.verticalCenter
fillMode: Image.PreserveAspectFit
source: Style.svg("walletIcon")
ColorOverlay {
visible: parent.visible
anchors.fill: parent
source: parent
color: selectedAccount.iconColor
}
}
}
}
}
LabelValueRow {
label: qsTr("Data")
value: Item {
anchors.fill: parent
anchors.verticalCenter: parent.verticalCenter
// TODO; replace with StatusModal
ModalPopup {
id: messagePopup
title: qsTr("Message")
height: 286
width: 400
Item {
anchors.fill: parent
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
StatusScrollView {
width: parent.width
height: 150
TextArea {
wrapMode: TextEdit.Wrap
readOnly: true
text: messageToSign()
}
}
}
}
Row {
spacing: Style.current.halfPadding
rightPadding: 0
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
StyledText {
width: 250
font.pixelSize: 15
height: 22
text: messageToSign()
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
color: Style.current.secondaryText
}
SVGImage {
width: 13
anchors.verticalCenter: parent.verticalCenter
fillMode: Image.PreserveAspectFit
source: Style.svg("caret")
rotation: 270
ColorOverlay {
anchors.fill: parent
source: parent
color: Style.current.secondaryText
}
}
}
MouseArea {
anchors.fill: parent
visible: true
cursorShape: Qt.PointingHandCursor
onClicked: messagePopup.open()
}
}
}
}
}
leftButtons: [
StatusFlatButton {
id: btnReject
text: qsTr("Reject")
type: StatusBaseButton.Type.Danger
onClicked: close()
}
]
rightButtons: [
StatusButton {
id: btnNext
text: showSigningPhrase ?
qsTr("Sign") :
qsTr("Sign with password")
onClicked: {
if(!showSigningPhrase){
showSigningPhrase = true;
transactionSigner.forceActiveFocus(Qt.MouseFocusReason)
} else {
root.signMessage(transactionSigner.enteredPassword)
}
}
}
]
}

View File

@ -1 +0,0 @@
BrowserLayout 1.0 BrowserLayout.qml

View File

@ -1,49 +0,0 @@
pragma Singleton
import QtQuick 2.15
import StatusQ.Core.Utils 0.1 as SQUtils
QtObject {
id: root
property var bookmarksModel: bookmarkModule.model
function addBookmark(url, name)
{
bookmarkModule.addBookmark(url, name)
}
function deleteBookmark(url)
{
bookmarkModule.deleteBookmark(url)
}
function updateBookmark(originalUrl, newUrl, newName)
{
bookmarkModule.updateBookmark(originalUrl, newUrl, newName)
}
function getBookmarkIndexByUrl(url)
{
return bookmarkModule.model.getBookmarkIndexByUrl(url)
}
function getCurrentFavorite(url) {
if (!url) {
return null
}
const index = bookmarkModule.model.getBookmarkIndexByUrl(url)
if (index === -1) {
return null
}
const item = SQUtils.ModelUtils.get(bookmarkModule.model, index)
return {
url: url,
name: item.name,
image: item.imageUrl
}
}
}

View File

@ -1,36 +0,0 @@
pragma Singleton
import QtQuick 2.13
QtObject {
id: root
property ListModel downloadModel : ListModel {
property var downloads: []
}
function getDownload(index) {
return downloadModel.downloads[index]
}
function removeDownloadFromModel(index) {
downloadModel.downloads = downloadModel.downloads.filter(function (el) {
return el.id !== downloadModel.downloads[index].id;
});
downloadModel.remove(index);
}
function addDownload(download) {
downloadModel.append(download);
downloadModel.downloads.push(download);
}
function openFile(index) {
Qt.openUrlExternally(`file://${downloadModel.downloads[index].downloadDirectory}/${downloadModel.downloads[index].downloadFileName}`)
root.removeDownloadFromModel(index)
}
// TODO check if this works in Windows and Mac
function openDirectory(index) {
Qt.openUrlExternally("file://" + downloadModel.downloads[index].downloadDirectory)
}
}

View File

@ -1,82 +0,0 @@
pragma Singleton
import QtQuick 2.13
import utils 1.0
QtObject {
id: root
// Not Refactored Yet
// property string activeChannelName: chatsModel.channelView.activeChannel.name
property bool currentTabConnected: false
function getUrlFromUserInput(input) {
return globalUtils.urlFromUserInput(input)
}
function getAscii2Hex(input) {
return globalUtils.ascii2Hex(input)
}
function getHex2Ascii(input) {
return globalUtils.hex2Ascii(input)
}
function getWei2Eth(wei,decimals) {
return globalUtils.wei2Eth(wei,decimals)
}
function getEth2Hex(eth) {
return globalUtils.eth2Hex(eth)
}
function getGwei2Hex(gwei){
return globalUtils.gwei2Hex(gwei)
}
function generateAlias(pk) {
return globalUtils.generateAlias(pk)
}
function get0xFormedUrl(browserExplorer, url) {
var tempUrl = ""
switch (browserExplorer) {
case Constants.browserEthereumExplorerEtherscan:
if (url.length > 42) {
tempUrl = "https://etherscan.io/tx/" + url; break;
} else {
tempUrl = "https://etherscan.io/address/" + url; break;
}
case Constants.browserEthereumExplorerEthplorer:
if (url.length > 42) {
tempUrl = "https://ethplorer.io/tx/" + url; break;
} else {
tempUrl = "https://ethplorer.io/address/" + url; break;
}
case Constants.browserEthereumExplorerBlockchair:
if (url.length > 42) {
tempUrl = "https://blockchair.com/ethereum/transaction/" + url; break;
} else {
tempUrl = "https://blockchair.com/ethereum/address/" + url; break;
}
}
return tempUrl
}
function getFormedUrl(shouldShowBrowserSearchEngine, url) {
var tempUrl = ""
switch (localAccountSensitiveSettings.shouldShowBrowserSearchEngine) {
case Constants.browserSearchEngineGoogle: tempUrl = "https://www.google.com/search?q=" + url; break;
case Constants.browserSearchEngineYahoo: tempUrl = "https://search.yahoo.com/search?p=" + url; break;
case Constants.browserSearchEngineDuckDuckGo: tempUrl = "https://duckduckgo.com/?q=" + url; break;
}
return tempUrl
}
function copyToClipboard(text) {
globalUtils.copyToClipboard(text)
}
}

View File

@ -1,21 +0,0 @@
pragma Singleton
import QtQuick 2.13
QtObject {
id: root
property var dappBrowserAccount: browserSectionCurrentAccount
property var accounts: walletSectionAccounts.model
property string defaultCurrency: walletSection.currentCurrency
property string signingPhrase: walletSection.signingPhrase
function getEtherscanLink(chainID) {
return networksModule.getBlockExplorerURL(chainID)
}
function switchAccountByAddress(address) {
browserSectionCurrentAccount.switchAccountByAddress(address)
}
}

View File

@ -1,57 +0,0 @@
pragma Singleton
import QtQuick 2.13
import utils 1.0
QtObject {
id: root
property var web3ProviderInst: providerModule
property var urlENSDictionary: ({})
property int chainId: providerModule.chainId
property string chainName: providerModule.chainName
function disconnectAddress(dappName, address){
dappPermissionsModule.disconnectAddress(dappName, address)
}
function disconnect(hostname) {
dappPermissionsModule.disconnect(hostname)
}
function addPermission(hostname, address, permission){
dappPermissionsModule.addPermission(hostname, address, permission)
}
function hasPermission(hostname, address, permission){
return dappPermissionsModule.hasPermission(hostname, address, permission)
}
function hasWalletConnected(hostname) {
return hasPermission(hostname, WalletStore.dappBrowserAccount.address, "web3")
}
function determineRealURL(text){
var url = RootStore.getUrlFromUserInput(text);
var host = providerModule.getHost(url);
if(host.endsWith(".eth")){
var ensResource = providerModule.ensResourceURL(host, url);
if(/^https\:\/\/swarm\-gateways\.net\/bzz:\/([0-9a-fA-F]{64}|.+\.eth)(\/?)/.test(ensResource)){
// TODO: populate urlENSDictionary for prettier url instead of swarm-gateway big URL
return ensResource;
} else {
urlENSDictionary[providerModule.getHost(ensResource)] = host;
}
url = ensResource;
}
return url;
}
function obtainAddress(url) {
var ensAddr = urlENSDictionary[providerModule.getHost(url)];
return ensAddr ? providerModule.replaceHostByENS( url, ensAddr) : url;
}
}

View File

@ -1,5 +0,0 @@
singleton RootStore 1.0 RootStore.qml
singleton Web3ProviderStore 1.0 Web3ProviderStore.qml
singleton BookmarksStore 1.0 BookmarksStore.qml
singleton DownloadsStore 1.0 DownloadsStore.qml
singleton WalletStore 1.0 WalletStore.qml

View File

@ -1,74 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.13
import QtQuick.Window 2.13
import QtWebEngine 1.9
Window {
id: window
property alias currentWebView: webView
flags: Qt.Dialog | Qt.WindowStaysOnTopHint
width: 800
height: 600
visible: true
onClosing: destroy()
WebEngineView {
id: webView
anchors.fill: parent
onGeometryChangeRequested: function(geometry) {
window.x = geometry.x
window.y = geometry.y
window.width = geometry.width
window.height = geometry.height
}
}
}

View File

@ -1,146 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.13
import QtQuick.Controls 2.14
import QtWebEngine 1.10
Item {
id: shortcutActions
property var currentWebView
property var findBarComponent
property var browserHeaderComponent
signal addNewDownloadTab()
signal removeView()
Action {
shortcut: "Ctrl+D"
onTriggered: {
addNewDownloadTab()
}
}
Action {
shortcut: "Ctrl+L"
onTriggered: {
browserHeaderComponent.addressBar.forceActiveFocus();
browserHeaderComponent.addressBar.selectAll();
}
}
Action {
shortcut: StandardKey.Refresh
onTriggered: {
if (currentWebView)
currentWebView.reload();
}
}
Action {
shortcut: "Ctrl+W"
onTriggered: removeView()
}
Action {
shortcut: StandardKey.Close
onTriggered: {
currentWebView.triggerWebAction(WebEngineView.RequestClose);
}
}
Action {
shortcut: "Escape"
onTriggered: {
if (findBarComponent.visible)
findBarComponent.visible = false;
}
}
Action {
shortcut: StandardKey.Copy
onTriggered: currentWebView.triggerWebAction(WebEngineView.Copy)
}
Action {
shortcut: StandardKey.Cut
onTriggered: currentWebView.triggerWebAction(WebEngineView.Cut)
}
Action {
shortcut: StandardKey.Paste
onTriggered: currentWebView.triggerWebAction(WebEngineView.Paste)
}
Action {
shortcut: "Shift+"+StandardKey.Paste
onTriggered: currentWebView.triggerWebAction(WebEngineView.PasteAndMatchStyle)
}
Action {
shortcut: StandardKey.SelectAll
onTriggered: currentWebView.triggerWebAction(WebEngineView.SelectAll)
}
Action {
shortcut: StandardKey.Undo
onTriggered: currentWebView.triggerWebAction(WebEngineView.Undo)
}
Action {
shortcut: StandardKey.Redo
onTriggered: currentWebView.triggerWebAction(WebEngineView.Redo)
}
Action {
shortcut: StandardKey.Back
onTriggered: currentWebView.triggerWebAction(WebEngineView.Back)
}
Action {
shortcut: StandardKey.Forward
onTriggered: currentWebView.triggerWebAction(WebEngineView.Forward)
}
Action {
shortcut: StandardKey.FindNext
onTriggered: findBarComponent.findNext()
}
Action {
shortcut: StandardKey.FindPrevious
onTriggered: findBarComponent.findPrevious()
}
}

View File

@ -1,172 +0,0 @@
import QtQuick 2.13
import QtWebEngine 1.10
import shared.controls 1.0
import utils 1.0
import "../panels"
import "../stores"
WebEngineView {
id: webEngineView
property var currentWebView
property var findBarComp
property var favMenu
property var addFavModal
property var downloadsMenu
property var determineRealURLFn: function(url){}
signal setCurrentWebUrl(var url)
focus: true
function changeZoomFactor(newFactor) {
// FIXME there seems to be a bug in the WebEngine where the zoomFactor only update 1/2 times
zoomFactor = newFactor
zoomFactor = newFactor
zoomFactor = newFactor
}
settings.autoLoadImages: localAccountSensitiveSettings.autoLoadImages
settings.javascriptEnabled: localAccountSensitiveSettings.javaScriptEnabled
settings.errorPageEnabled: localAccountSensitiveSettings.errorPageEnabled
settings.pluginsEnabled: localAccountSensitiveSettings.pluginsEnabled
settings.autoLoadIconsForPage: localAccountSensitiveSettings.autoLoadIconsForPage
settings.touchIconsEnabled: localAccountSensitiveSettings.touchIconsEnabled
settings.webRTCPublicInterfacesOnly: localAccountSensitiveSettings.webRTCPublicInterfacesOnly
settings.pdfViewerEnabled: localAccountSensitiveSettings.pdfViewerEnabled
settings.focusOnNavigationEnabled: true
onQuotaRequested: function(request) {
if (request.requestedSize <= 5 * 1024 * 1024)
request.accept();
else
request.reject();
}
onRegisterProtocolHandlerRequested: function(request) {
console.log("accepting registerProtocolHandler request for "
+ request.scheme + " from " + request.origin);
request.accept();
}
onRenderProcessTerminated: function(terminationStatus, exitCode) {
var status = "";
switch (terminationStatus) {
case WebEngineView.NormalTerminationStatus:
status = "(normal exit)";
break;
case WebEngineView.AbnormalTerminationStatus:
status = "(abnormal exit)";
break;
case WebEngineView.CrashedTerminationStatus:
status = "(crashed)";
break;
case WebEngineView.KilledTerminationStatus:
status = "(killed)";
break;
}
print("Render process exited with code " + exitCode + " " + status);
reloadTimer.running = true;
}
onSelectClientCertificate: function(selection) {
selection.certificates[0].select();
}
onFindTextFinished: function(result) {
if (!findBarComp.visible)
findBarComp.visible = true;
findBarComp.numberOfMatches = result.numberOfMatches;
findBarComp.activeMatch = result.activeMatch;
}
onLoadingChanged: function(loadRequest) {
if (loadRequest.status === WebEngineView.LoadStartedStatus)
findBarComp.reset();
}
onNavigationRequested: {
if(request.url.toString().startsWith("file://")){
console.log("Local file browsing is disabled" )
request.action = WebEngineNavigationRequest.IgnoreRequest;
}
}
Loader {
active: webEngineView.url.toString() === "status://downloads"
width: parent.width
height: parent.height
z: 54
sourceComponent: DownloadView {
id: downloadView
downloadsModel: DownloadsStore.downloadModel
downloadsMenu: webEngineView.downloadsMenu
onOpenDownloadClicked: {
if (downloadComplete) {
return DownloadsStore.openFile(index)
}
DownloadsStore.openDirectory(index)
}
}
}
Loader {
active: !webEngineView.url.toString()
width: parent.width
height: parent.height
z: 54
sourceComponent: Item {
width: parent.width
height: parent.height
Image {
id: emptyPageImage
source: Style.png("browser/compass")
width: 294
height: 294
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 60
cache: false
}
FavoritesList {
id: bookmarkListContainer
anchors.horizontalCenter: emptyPageImage.horizontalCenter
anchors.top: emptyPageImage.bottom
anchors.topMargin: 30
width: (parent.width < 700) ? (Math.floor(parent.width/cellWidth)*cellWidth) : 700
height: parent.height - emptyPageImage.height - 20
model: BookmarksStore.bookmarksModel
favMenu: webEngineView.favMenu
addFavModal: webEngineView.addFavModal
determineRealURLFn: function(url) {
return webEngineView.determineRealURLFn(url)
}
setAsCurrentWebUrl: function(url) {
webEngineView.setCurrentWebUrl(url)
}
Component.onCompleted: {
// Add fav button at the end of the grid
var index = BookmarksStore.getBookmarkIndexByUrl(Constants.newBookmark)
if (index !== -1) { BookmarksStore.deleteBookmark(Constants.newBookmark) }
BookmarksStore.addBookmark(Constants.newBookmark, qsTr("Add Favorite"))
}
}
}
}
Timer {
id: reloadTimer
interval: 0
running: false
repeat: false
onTriggered: currentWebView.reload()
}
}

View File

@ -1,144 +0,0 @@
import QtQuick 2.13
import QtWebChannel 1.13
import QtQuick.Dialogs 1.2
import utils 1.0
import shared.controls 1.0
import "../stores"
QtObject {
id: provider
property var createAccessDialogComponent: function(){}
property var createSendTransactionModalComponent: function(){}
property var createSignMessageModalComponent: function(){}
property var showSendingError: function(){}
property var showSigningError: function(){}
property var showToastMessage: function(){}
property int chainId: (Web3ProviderStore && Web3ProviderStore.chainId) || 1
signal web3Response(string data);
function signValue(input){
if(Utils.isHex(input) && Utils.startsWith0x(input)){
return input
}
return RootStore.getAscii2Hex(input)
}
property Connections conn: Connections {
target: Web3ProviderStore.web3ProviderInst
function onPostMessageResult(payloadMethod: string, result: string, chainId: string) {
web3Response(result)
const isSign = ["eth_sign", "personal_sign", "eth_signTypedData", "eth_signTypedData_v3"].indexOf(payloadMethod) > -1
const isTx = payloadMethod === "eth_sendTransaction"
try {
let responseObj = JSON.parse(result)
if (responseObj.error) {
throw new Error(responseObj.error)
}
if (isTx) {
showToastMessage(responseObj.result.result, chainId)
}
} catch (e) {
if (isTx) {
showSendingError(e.message)
} else if (isSign) {
showSigningError(e.message.message)
}
}
}
}
function postMessage(requestType, data) {
var request;
try {
request = JSON.parse(data)
} catch (e) {
console.error("Error parsing the message data", e)
return;
}
request.address = WalletStore.dappBrowserAccount.address
if (!request.payload) {
request.payload = {}
}
request.payload.chainId = provider.chainId
var ensAddr = Web3ProviderStore.urlENSDictionary[request.hostname];
if (ensAddr) {
request.hostname = ensAddr;
}
if (requestType === Constants.web3DisconnectAccount) {
RootStore.currentTabConnected = false
web3Response(JSON.stringify({type: Constants.web3DisconnectAccount}));
} else if (requestType === Constants.api_request) {
if (!Web3ProviderStore.hasPermission(request.hostname, request.address, request.permission)) {
RootStore.currentTabConnected = false
var dialog = createAccessDialogComponent()
dialog.request = request;
dialog.open();
} else {
RootStore.currentTabConnected = true
Web3ProviderStore.web3ProviderInst.postMessage("", requestType, JSON.stringify(request));
}
} else if (requestType === Constants.web3SendAsyncReadOnly &&
request.payload.method === "eth_sendTransaction") {
var acc = WalletStore.dappBrowserAccount
const value = RootStore.getWei2Eth(request.payload.params[0].value, 18);
const sendDialog = createSendTransactionModalComponent(request, requestType)
sendDialog.sendTransaction = function () {
if(sendDialog.bestRoutes.length === 1) {
let path = sendDialog.bestRoutes[0]
let eip1559Enabled = path.gasFees.eip1559Enabled
let maxFeePerGas = path.gasFees.maxFeePerGasM
let trx = request.payload.params[0]
// TODO: use bignumber instead of floats
trx.value = RootStore.getEth2Hex(parseFloat(value))
trx.gas = "0x" + parseInt(path.gasAmount, 10).toString(16)
trx.maxPriorityFeePerGas = RootStore.getGwei2Hex(parseFloat(eip1559Enabled ? path.gasFees.maxPriorityFeePerGas : "0"))
trx.maxFeePerGas = RootStore.getGwei2Hex(parseFloat(eip1559Enabled ? maxFeePerGas : path.gasFees.gasPrice))
request.payload.params[0] = trx
Web3ProviderStore.web3ProviderInst.authenticateToPostMessage(request.payload.method, requestType, JSON.stringify(request))
sendDialog.close()
}
}
sendDialog.open();
} else if (requestType === Constants.web3SendAsyncReadOnly && ["eth_sign", "personal_sign", "eth_signTypedData", "eth_signTypedData_v3"].indexOf(request.payload.method) > -1) {
const signDialog = createSignMessageModalComponent(request)
signDialog.web3Response = web3Response
signDialog.signMessage = function (enteredPassword) {
signDialog.interactedWith = true;
request.payload.password = enteredPassword;
request.payload.from = WalletStore.dappBrowserAccount.address;
switch(request.payload.method){
case Constants.personal_sign:
request.payload.params[0] = signValue(request.payload.params[0]);
case Constants.eth_sign:
request.payload.params[1] = signValue(request.payload.params[1]);
}
Web3ProviderStore.web3ProviderInst.postMessage(request.payload.method, requestType, JSON.stringify(request));
signDialog.close()
signDialog.destroy()
}
signDialog.open();
} else if (request.type === Constants.web3DisconnectAccount) {
web3Response(data);
} else {
Web3ProviderStore.web3ProviderInst.postMessage(request.payload.method, requestType, JSON.stringify(request));
}
}
WebChannel.id: "backend"
}

View File

@ -1,67 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import utils 1.0
import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1
StatusDialog {
id: root
property string link
title: qsTr("Choose browser")
width: 400
footer: null
contentItem: ColumnLayout {
spacing: 20
Image {
source: Style.png("browser/chooseBrowserImage@2x")
Layout.preferredWidth: 240
Layout.preferredHeight: 148
Layout.alignment: Qt.AlignHCenter
cache: false
}
StatusButton {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Open in Status")
font.weight: Font.Medium
onClicked: {
localAccountSensitiveSettings.showBrowserSelector = !rememberChoiceCheckBox.checked
if (rememberChoiceCheckBox.checked) {
localAccountSensitiveSettings.openLinksInStatus = true
}
Global.changeAppSectionBySectionType(Constants.appSection.browser)
Global.openLinkInBrowser(root.link)
root.close()
}
}
StatusFlatButton {
text: qsTr("Open in my default browser")
Layout.alignment: Qt.AlignHCenter
font.weight: Font.Medium
onClicked: {
localAccountSensitiveSettings.showBrowserSelector = !rememberChoiceCheckBox.checked
if (rememberChoiceCheckBox.checked) {
localAccountSensitiveSettings.openLinksInStatus = false
}
Qt.openUrlExternally(root.link)
root.close()
}
}
StatusCheckBox {
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Style.current.smallPadding
id: rememberChoiceCheckBox
font.pixelSize: 13
text: qsTr("Remember my choice. To override it, go to settings.")
}
}
}

View File

@ -1,2 +1 @@
PinnedMessagesPopup 1.0 PinnedMessagesPopup.qml
ChooseBrowserPopup 1.0 ChooseBrowserPopup.qml

View File

@ -71,7 +71,7 @@ Item {
StyledText {
id: txtDesc1
color: Style.current.secondaryText
text: qsTr("Your fully decentralized gateway to Ethereum and Web3. Crypto wallet, privacy first group chat, and dApp browser.")
text: qsTr("Your fully decentralized gateway to Ethereum and Web3. Crypto wallet, privacy first group chat, and communities.")
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
anchors.right: parent.right

View File

@ -316,20 +316,6 @@ StatusSectionLayout {
}
}
Loader {
active: false
asynchronous: true
sourceComponent: BrowserView {
implicitWidth: parent.width
implicitHeight: parent.height
store: root.store
accountSettings: localAccountSensitiveSettings
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.browserSettings)
contentWidth: d.contentWidth
}
}
Loader {
active: false
asynchronous: true

View File

@ -20,7 +20,6 @@ Column {
property alias extraMenuItems: extraMenuItems.model
property alias appsMenuItems: appsMenuItems.model
property bool browserMenuItemEnabled: false
property bool walletMenuItemEnabled: false
signal menuItemClicked(var menu_item)
@ -87,8 +86,7 @@ Column {
selected: Global.settingsSubsection === model.subsection
onClicked: root.menuItemClicked(model)
visible: {
(model.subsection !== Constants.settingsSubsection.browserSettings && model.subsection !== Constants.settingsSubsection.wallet) ||
(model.subsection === Constants.settingsSubsection.browserSettings && root.browserMenuItemEnabled) ||
(model.subsection !== Constants.settingsSubsection.wallet) ||
(model.subsection === Constants.settingsSubsection.communitiesSettings) ||
(model.subsection === Constants.settingsSubsection.wallet && root.walletMenuItemEnabled)
}
@ -118,7 +116,6 @@ Column {
asset.name: model.icon
selected: Global.settingsSubsection === model.subsection
onClicked: root.menuItemClicked(model)
visible: model.subsection !== Constants.settingsSubsection.browserSettings || root.browserMenuItemEnabled
}
}
@ -136,7 +133,6 @@ Column {
title: model.text
asset.name: model.icon
selected: Global.settingsSubsection === model.subsection
visible: model.subsection !== Constants.settingsSubsection.browserSettings || root.browserMenuItemEnabled
onClicked: root.menuItemClicked(model)
}
}

View File

@ -1,77 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import utils 1.0
import shared.popups 1.0
import shared.controls 1.0
// TODO: replace with StatusModal
ModalPopup {
id: popup
property var accountSettings
title: qsTr("Search engine")
onClosed: {
destroy()
}
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
ButtonGroup {
id: searchEnginGroup
}
RadioButtonSelector {
title: qsTr("None")
buttonGroup: searchEnginGroup
checked: accountSettings.shouldShowBrowserSearchEngine === Constants.browserSearchEngineNone
onCheckedChanged: {
if (checked) {
accountSettings.shouldShowBrowserSearchEngine = Constants.browserSearchEngineNone
}
}
}
RadioButtonSelector {
title: "Google"
buttonGroup: searchEnginGroup
checked: accountSettings.shouldShowBrowserSearchEngine === Constants.browserSearchEngineGoogle
onCheckedChanged: {
if (checked) {
accountSettings.shouldShowBrowserSearchEngine = Constants.browserSearchEngineGoogle
}
}
}
RadioButtonSelector {
title: "Yahoo!"
buttonGroup: searchEnginGroup
checked: accountSettings.shouldShowBrowserSearchEngine === Constants.browserSearchEngineYahoo
onCheckedChanged: {
if (checked) {
accountSettings.shouldShowBrowserSearchEngine = Constants.browserSearchEngineYahoo
}
}
}
RadioButtonSelector {
title: "DuckDuckGo"
buttonGroup: searchEnginGroup
checked: accountSettings.shouldShowBrowserSearchEngine === Constants.browserSearchEngineDuckDuckGo
onCheckedChanged: {
if (checked) {
accountSettings.shouldShowBrowserSearchEngine = Constants.browserSearchEngineDuckDuckGo
}
}
}
}
}

View File

@ -27,7 +27,6 @@ QtObject {
readonly property bool createCommunityEnabled: localAppSettings.createCommunityEnabled ?? false
property bool isManageCommunityOnTestModeEnabled: false
readonly property QtObject experimentalFeatures: QtObject {
readonly property string browser: "browser"
readonly property string communities: "communities"
readonly property string activityCenter: "activityCenter"
readonly property string nodeManagement: "nodeManagement"
@ -120,10 +119,7 @@ QtObject {
if(!root.advancedModule)
return
if (feature === experimentalFeatures.browser) {
advancedModule.toggleBrowserSection()
}
else if (feature === experimentalFeatures.communities) {
if (feature === experimentalFeatures.communities) {
advancedModule.toggleCommunitySection()
}
else if (feature === experimentalFeatures.communitiesPortal) {

View File

@ -77,7 +77,6 @@ QtObject {
stickersModule: stickersModuleInst
}
property bool browserMenuItemEnabled: Global.appIsReady? localAccountSensitiveSettings.isBrowserEnabled : false
property bool walletMenuItemEnabled: profileStore.isWalletEnabled
property var communitiesModuleInst: Global.appIsReady? communitiesModule : null
@ -128,9 +127,6 @@ QtObject {
append({subsection: Constants.settingsSubsection.wallet,
text: qsTr("Wallet"),
icon: "wallet"})
append({subsection: Constants.settingsSubsection.browserSettings,
text: qsTr("Browser"),
icon: "browser"})
append({subsection: Constants.settingsSubsection.communitiesSettings,
text: qsTr("Communities"),
icon: "communities"})

View File

@ -132,23 +132,6 @@ SettingsContentBase {
bottomPadding: Style.current.padding
}
// TODO: replace with StatusQ component
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
text: qsTr("Dapp Browser")
isSwitch: true
switchChecked: localAccountSensitiveSettings.isBrowserEnabled
onClicked: {
if (!localAccountSensitiveSettings.isBrowserEnabled) {
confirmationPopup.experimentalFeature = root.advancedStore.experimentalFeatures.browser
confirmationPopup.open()
} else {
root.advancedStore.toggleExperimentalFeature(root.advancedStore.experimentalFeatures.browser)
}
}
}
// TODO: replace with StatusQ component
StatusSettingsLineButton {
anchors.leftMargin: 0

View File

@ -1,153 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import utils 1.0
import shared 1.0
import shared.panels 1.0
import shared.status 1.0
import AppLayouts.Profile.stores 1.0
import "../popups"
import "browser"
import "wallet"
SettingsContentBase {
id: root
property ProfileSectionStore store
property var accountSettings
property Component searchEngineModal: SearchEngineModal {
accountSettings: root.accountSettings
}
Item {
id: rootItem
width: root.contentWidth
height: childrenRect.height
Column {
id: layout
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
spacing: 10
HomePageView {
id: homePageView
accountSettings: root.accountSettings
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
}
// TODO: Replace with StatusQ StatusListItem component
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
text: qsTr("Search engine used in the address bar")
currentValue: {
switch (accountSettings.shouldShowBrowserSearchEngine) {
case Constants.browserSearchEngineGoogle: return "Google"
case Constants.browserSearchEngineYahoo: return "Yahoo!"
case Constants.browserSearchEngineDuckDuckGo: return "DuckDuckGo"
case Constants.browserSearchEngineNone:
default: return qsTr("None")
}
}
onClicked: searchEngineModal.createObject(root).open()
}
DefaultDAppExplorerView {
id: dAppExplorerView
accountSettings: root.accountSettings
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
}
StatusListItem {
id: showFavouritesItem
width: parent.width
title: qsTr("Show Favorites Bar")
components: [
StatusSwitch {
checked: accountSettings.shouldShowFavoritesBar
onToggled: { accountSettings.shouldShowFavoritesBar = checked }
}
]
}
Separator {
id: separator1
width: parent.width
}
StatusBaseText {
text: qsTr("Connected DApps")
font.pixelSize: 15
color: Theme.palette.baseColor1
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
}
Rectangle {
width: parent.width
implicitHeight: col1.height + 2 * Style.current.padding
visible: root.store.walletStore.dappList.count === 0
radius: Constants.settingsSection.radius
color: Theme.palette.baseColor4
ColumnLayout {
id: col1
width: parent.width - 2 * (Style.current.padding + Style.current.xlPadding)
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
spacing: Constants.settingsSection.infoSpacing
StatusBaseText {
Layout.preferredWidth: parent.width
horizontalAlignment: Text.AlignHCenter
text: qsTr("No connected dApps")
font.pixelSize: 15
lineHeight: Constants.settingsSection.infoLineHeight
lineHeightMode: Text.FixedHeight
color: Theme.palette.baseColor1
}
StatusBaseText {
Layout.preferredWidth: parent.width
horizontalAlignment: Text.AlignHCenter
text: qsTr("Connecting a dApp grants it permission to view your address and balances,"+
" and to send you transaction requests")
lineHeight: Constants.settingsSection.infoLineHeight
lineHeightMode: Text.FixedHeight
color: Theme.palette.baseColor1
wrapMode: Text.WordWrap
}
}
}
PermissionsListView {
id: permissionListView
walletStore: root.store.walletStore
visible: root.store.walletStore.dappList.count > 0
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
}
} // Column
} // Item
} // ScrollView

View File

@ -47,7 +47,6 @@ Item {
settingsMenuItems: store.settingsMenuItems
extraMenuItems: store.extraMenuItems
appsMenuItems: store.appsMenuItems
browserMenuItemEnabled: store.browserMenuItemEnabled
walletMenuItemEnabled: store.walletMenuItemEnabled
objectName: "leftTabViewProfileMenu"

View File

@ -1,86 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import utils 1.0
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
ColumnLayout {
id: root
property var accountSettings
StatusBaseText {
text: qsTr("Default DApp explorer")
font.pixelSize: 15
color: Theme.palette.directColor1
}
ButtonGroup {
id: explorerGroup
buttons: [
noneRadioButton,
etherscanRadioButton,
ethplorerRadioButton,
blockchairRadioButton
]
exclusive: true
}
StatusRadioButton {
id: noneRadioButton
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
checked: accountSettings.useBrowserEthereumExplorer === Constants.browserEthereumExplorerNone
text: qsTr("None")
onCheckedChanged: {
if (checked) {
accountSettings.useBrowserEthereumExplorer = Constants.browserEthereumExplorerNone
}
}
}
StatusRadioButton {
id: etherscanRadioButton
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
checked: accountSettings.useBrowserEthereumExplorer === Constants.browserEthereumExplorerEtherscan
text: "etherscan.io"
onCheckedChanged: {
if (checked && accountSettings.useBrowserEthereumExplorer !== Constants.browserEthereumExplorerEtherscan) {
accountSettings.useBrowserEthereumExplorer = Constants.browserEthereumExplorerEtherscan
}
}
}
StatusRadioButton {
id: ethplorerRadioButton
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
checked: accountSettings.useBrowserEthereumExplorer === Constants.browserEthereumExplorerEthplorer
text: "ethplorer.io"
onCheckedChanged: {
if (checked) {
accountSettings.useBrowserEthereumExplorer = Constants.browserEthereumExplorerEthplorer
}
}
}
StatusRadioButton {
id: blockchairRadioButton
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
checked: accountSettings.useBrowserEthereumExplorer === Constants.browserEthereumExplorerBlockchair
text: "blockchair.com"
onCheckedChanged: {
if (checked) {
accountSettings.useBrowserEthereumExplorer = Constants.browserEthereumExplorerBlockchair
}
}
}
} // Column

View File

@ -1,57 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
ColumnLayout {
id: root
property var accountSettings
spacing: 0
StatusBaseText {
text: qsTr("Homepage")
font.pixelSize: 15
color: Theme.palette.directColor1
}
ButtonGroup {
id: homepageGroup
buttons: [defaultRadioButton, customRadioButton]
exclusive: true
}
StatusRadioButton {
id: defaultRadioButton
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
checked: root.accountSettings.browserHomepage === ""
text: qsTr("System default")
}
StatusRadioButton {
id: customRadioButton
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
checked: root.accountSettings.browserHomepage !== ""
text: qsTr("Other")
}
StatusInput {
id: customUrlInput
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
visible: customRadioButton.checked
placeholderText: qsTr("Example: duckduckgo.com")
text: root.accountSettings.browserHomepage
onTextChanged: {
root.accountSettings.browserHomepage = text
}
}
} // Column

View File

@ -1,6 +1,5 @@
AboutView 1.0 AboutView.qml
AppearanceView 1.0 AppearanceView.qml
BrowserView 1.0 BrowserView.qml
ChangePasswordView 1.0 ChangePasswordView.qml
CommunitiesView 1.0 CommunitiesView.qml
LanguageView 1.0 LanguageView.qml

View File

@ -1,52 +0,0 @@
import QtQuick 2.15
import StatusQ.Core.Utils 0.1 as SQUtils
/// Helper item to clone a model and alter its data without affecting the original model
/// \beware this is not a proxy model. It clones the initial state
/// and every time the instance changes and doesn't adapt when the data
/// in the source model \c allNetworksModel changes
/// \beware use it with small models and in temporary views (e.g. popups)
/// \note tried to use SortFilterProxyModel with but it complicates implementation too much
ListModel {
id: root
required property var sourceModel
/// Roles to clone
required property var roles
/// Roles to override or add of the form { role: "roleName", transform: function(modelData) { return newValue } }
property var rolesOverride: []
Component.onCompleted: cloneModel(sourceModel)
onSourceModelChanged: cloneModel(sourceModel)
function findIndexForRole(roleName, value) {
for (let i = 0; i < count; i++) {
if(get(i)[roleName] === value) {
return i
}
}
return -1
}
function cloneModel(model) {
clear()
if (!model) {
console.warn("Missing valid data model to clone. The CloneModel is useless")
return
}
for (let i = 0; i < model.count; i++) {
const clonedItem = new Object()
for (var propName of roles) {
clonedItem[propName] = SQUtils.ModelUtils.get(model, i, propName)
}
for (var newProp of rolesOverride) {
clonedItem[newProp.role] = newProp.transform(clonedItem)
}
append(clonedItem)
}
}
}

View File

@ -171,9 +171,6 @@ QtObject {
property var savedAddressesModel: walletSectionSavedAddresses.model
readonly property bool showBrowserSelector: localAccountSensitiveSettings.showBrowserSelector
readonly property bool openLinksInStatus: false
property var flatNetworks: networksModule.flatNetworks
function getEtherscanLink(chainID) {

View File

@ -1,2 +1 @@
RootStore 1.0 RootStore.qml
CloneModel 1.0 CloneModel.qml

View File

@ -9,7 +9,6 @@ import QtQml 2.15
import AppLayouts.Wallet 1.0
import AppLayouts.Node 1.0
import AppLayouts.Browser 1.0
import AppLayouts.Chat 1.0
import AppLayouts.Chat.views 1.0
import AppLayouts.Profile 1.0
@ -39,7 +38,6 @@ import StatusQ.Layout 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
import AppLayouts.Browser.stores 1.0 as BrowserStores
import AppLayouts.stores 1.0
import AppLayouts.Chat.stores 1.0 as ChatStores
import AppLayouts.Communities.stores 1.0
@ -413,11 +411,6 @@ Item {
id: globalConns
target: Global
function onOpenLinkInBrowser(link: string) {
changeAppSectionBySectionId(Constants.appSection.browser)
Qt.callLater(() => browserLayoutContainer.item.openUrlInNewTab(link));
}
function onOpenCreateChatView() {
createChatView.opened = true
}
@ -433,18 +426,8 @@ Item {
function onOpenLink(link: string) {
// Qt sometimes inserts random HTML tags; and this will break on invalid URL inside QDesktopServices::openUrl(link)
link = appMain.rootStore.plainText(link)
if (appMain.rootStore.showBrowserSelector) {
popups.openChooseBrowserPopup(link)
} else {
if (appMain.rootStore.openLinksInStatus) {
globalConns.onAppSectionBySectionTypeChanged(Constants.appSection.browser)
globalConns.onOpenLinkInBrowser(link)
} else {
Qt.openUrlExternally(link)
}
}
}
function onOpenLinkWithConfirmation(link: string, domain: string) {
if (appMainLocalSettings.whitelistedUnfurledDomains.includes(domain))
@ -1264,8 +1247,6 @@ Item {
return Constants.appViewStackIndex.communitiesPortal
if (activeSectionType === Constants.appSection.wallet)
return Constants.appViewStackIndex.wallet
if (activeSectionType === Constants.appSection.browser)
return Constants.appViewStackIndex.browser
if (activeSectionType === Constants.appSection.profile)
return Constants.appViewStackIndex.profile
if (activeSectionType === Constants.appSection.node)
@ -1404,29 +1385,6 @@ Item {
}
}
Loader {
id: browserLayoutContainer
active: appView.currentIndex === Constants.appViewStackIndex.browser
asynchronous: true
sourceComponent: BrowserLayout {
globalStore: appMain.rootStore
sendTransactionModal: sendModal
transactionStore: appMain.transactionStore
assetsStore: appMain.walletAssetsStore
currencyStore: appMain.currencyStore
tokensStore: appMain.tokensStore
}
// Loaders do not have access to the context, so props need to be set
// Adding a "_" to avoid a binding loop
// Not Refactored Yet
// property var _chatsModel: chatsModel.messageView
// Not Refactored Yet
// property var _walletModel: walletModel
// Not Refactored Yet
// property var _utilsModel: utilsModel
// property var _web3Provider: BrowserStores.Web3ProviderStore.web3ProviderInst
}
Loader {
active: appView.currentIndex === Constants.appViewStackIndex.profile
asynchronous: true

View File

@ -58,7 +58,6 @@ QtObject {
Global.openInviteFriendsToCommunityByIdPopup.connect(openInviteFriendsToCommunityByIdPopup)
Global.openContactRequestPopup.connect(openContactRequestPopup)
Global.openReviewContactRequestPopup.connect(openReviewContactRequestPopup)
Global.openChooseBrowserPopup.connect(openChooseBrowserPopup)
Global.openDownloadModalRequested.connect(openDownloadModal)
Global.openImagePopup.connect(openImagePopup)
Global.openVideoPopup.connect(openVideoPopup)
@ -122,10 +121,6 @@ QtObject {
root.currentPopup.close();
}
function openChooseBrowserPopup(link: string) {
openPopup(chooseBrowserPopupComponent, {link: link})
}
function openDownloadModal(available: bool, version: string, url: string) {
const popupProperties = {
newVersionAvailable: available,
@ -624,13 +619,6 @@ QtObject {
}
},
Component {
id: chooseBrowserPopupComponent
ChooseBrowserPopup {
onClosed: destroy()
}
},
Component {
id: communityProfilePopup

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

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