feat(@desktop/wallet): Create API to retrieve historical price for a token
fixes #7260
This commit is contained in:
parent
b1f8a476e8
commit
7e82b36509
|
@ -36,6 +36,10 @@ proc init*(self: Controller) =
|
||||||
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args):
|
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args):
|
||||||
self.delegate.refreshTokens()
|
self.delegate.refreshTokens()
|
||||||
|
|
||||||
|
self.events.on(SIGNAL_TOKEN_HISTORICAL_DATA_LOADED) do(e:Args):
|
||||||
|
let args = TokenHistoricalDataArgs(e)
|
||||||
|
self.delegate.tokenHistoricalDataResolved(args.result)
|
||||||
|
|
||||||
proc getTokens*(self: Controller): seq[token_service.TokenDto] =
|
proc getTokens*(self: Controller): seq[token_service.TokenDto] =
|
||||||
proc compare(x, y: token_service.TokenDto): int =
|
proc compare(x, y: token_service.TokenDto): int =
|
||||||
if x.name < y.name:
|
if x.name < y.name:
|
||||||
|
@ -65,3 +69,7 @@ proc getTokenDetails*(self: Controller, address: string) =
|
||||||
|
|
||||||
method findTokenSymbolByAddress*(self: Controller, address: string): string =
|
method findTokenSymbolByAddress*(self: Controller, address: string): string =
|
||||||
return self.walletAccountService.findTokenSymbolByAddress(address)
|
return self.walletAccountService.findTokenSymbolByAddress(address)
|
||||||
|
|
||||||
|
method getHistoricalDataForToken*(self: Controller, symbol: string, currency: string, range: int) =
|
||||||
|
self.tokenService.getHistoricalDataForToken(symbol, currency, range)
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,12 @@ method tokenDetailsWereResolved*(self: AccessInterface, tokenDetails: string) {.
|
||||||
method findTokenSymbolByAddress*(self: AccessInterface, address: string): string {.base.} =
|
method findTokenSymbolByAddress*(self: AccessInterface, address: string): string {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getHistoricalDataForToken*(self: AccessInterface, symbol: string, currency: string) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method tokenHistoricalDataResolved*(self: AccessInterface, tokenDetails: string) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
# View Delegate Interface
|
# View Delegate Interface
|
||||||
# Delegate for the view must be declared here due to use of QtObject and multi
|
# Delegate for the view must be declared here due to use of QtObject and multi
|
||||||
# inheritance, which is not well supported in Nim.
|
# inheritance, which is not well supported in Nim.
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ../../../../global/global_singleton
|
||||||
import ../../../../core/eventemitter
|
import ../../../../core/eventemitter
|
||||||
import ../../../../../app_service/service/token/service as token_service
|
import ../../../../../app_service/service/token/service as token_service
|
||||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||||
|
import ../../../../../app_service/service/token/dto
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
|
@ -91,3 +92,13 @@ method tokenDetailsWereResolved*(self: Module, tokenDetails: string) =
|
||||||
|
|
||||||
method findTokenSymbolByAddress*(self: Module, address: string): string =
|
method findTokenSymbolByAddress*(self: Module, address: string): string =
|
||||||
return self.controller.findTokenSymbolByAddress(address)
|
return self.controller.findTokenSymbolByAddress(address)
|
||||||
|
|
||||||
|
method getHistoricalDataForToken*(self: Module, symbol: string, currency: string) =
|
||||||
|
self.controller.getHistoricalDataForToken(symbol, currency, WEEKLY_TIME_RANGE)
|
||||||
|
self.controller.getHistoricalDataForToken(symbol, currency, MONTHLY_TIME_RANGE)
|
||||||
|
self.controller.getHistoricalDataForToken(symbol, currency, HALF_YEARLY_TIME_RANGE)
|
||||||
|
self.controller.getHistoricalDataForToken(symbol, currency, YEARLY_TIME_RANGE)
|
||||||
|
self.controller.getHistoricalDataForToken(symbol, currency, ALL_TIME_RANGE)
|
||||||
|
|
||||||
|
method tokenHistoricalDataResolved*(self: Module, tokenDetails: string) =
|
||||||
|
self.view.tokenHistoricalDataReady(tokenDetails)
|
||||||
|
|
|
@ -77,3 +77,8 @@ QtObject:
|
||||||
|
|
||||||
proc findTokenSymbolByAddress*(self: View, address: string): string {.slot.} =
|
proc findTokenSymbolByAddress*(self: View, address: string): string {.slot.} =
|
||||||
return self.delegate.findTokenSymbolByAddress(address)
|
return self.delegate.findTokenSymbolByAddress(address)
|
||||||
|
|
||||||
|
proc getHistoricalDataForToken*(self: View, symbol: string, currency: string) {.slot.} =
|
||||||
|
self.delegate.getHistoricalDataForToken(symbol, currency)
|
||||||
|
|
||||||
|
proc tokenHistoricalDataReady*(self: View, tokenDetails: string) {.signal.}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
# include strformat, json
|
import times
|
||||||
include ../../common/json_utils
|
include ../../common/json_utils
|
||||||
import ../eth/utils
|
import ../eth/utils
|
||||||
|
|
||||||
import ../../../backend/backend as backend
|
import ../../../backend/backend as backend
|
||||||
|
import ./dto
|
||||||
#################################################
|
#################################################
|
||||||
# Async load transactions
|
# Async load transactions
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
|
const DAYS_IN_WEEK = 7
|
||||||
|
const HOURS_IN_DAY = 24
|
||||||
|
|
||||||
type
|
type
|
||||||
GetTokenDetailsTaskArg = ref object of QObjectTaskArg
|
GetTokenDetailsTaskArg = ref object of QObjectTaskArg
|
||||||
chainIds: seq[int]
|
chainIds: seq[int]
|
||||||
|
@ -35,3 +39,49 @@ const getTokenDetailsTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.}
|
||||||
"error": "Is this an ERC-20 or ERC-721 contract?",
|
"error": "Is this an ERC-20 or ERC-721 contract?",
|
||||||
}
|
}
|
||||||
arg.finish(output)
|
arg.finish(output)
|
||||||
|
|
||||||
|
type
|
||||||
|
GetTokenHistoricalDataTaskArg = ref object of QObjectTaskArg
|
||||||
|
symbol: string
|
||||||
|
currency: string
|
||||||
|
range: int
|
||||||
|
|
||||||
|
const getTokenHistoricalDataTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[GetTokenHistoricalDataTaskArg](argEncoded)
|
||||||
|
var response = %*{}
|
||||||
|
try:
|
||||||
|
let td = now()
|
||||||
|
case arg.range:
|
||||||
|
of WEEKLY_TIME_RANGE:
|
||||||
|
response = backend.getHourlyMarketValues(arg.symbol, arg.currency, DAYS_IN_WEEK*HOURS_IN_DAY, 1).result
|
||||||
|
of MONTHLY_TIME_RANGE:
|
||||||
|
response = backend.getHourlyMarketValues(arg.symbol, arg.currency, getDaysInMonth(td.month, td.year)*HOURS_IN_DAY, 2).result
|
||||||
|
of HALF_YEARLY_TIME_RANGE:
|
||||||
|
response = backend.getDailyMarketValues(arg.symbol, arg.currency, int(getDaysInYear(td.year)/2), false, 1).result
|
||||||
|
of YEARLY_TIME_RANGE:
|
||||||
|
response = backend.getDailyMarketValues(arg.symbol, arg.currency, getDaysInYear(td.year), false, 1).result
|
||||||
|
of ALL_TIME_RANGE:
|
||||||
|
response = backend.getDailyMarketValues(arg.symbol, arg.currency, 1, true, 12).result
|
||||||
|
else:
|
||||||
|
let output = %* {
|
||||||
|
"symbol": arg.symbol,
|
||||||
|
"range": arg.range,
|
||||||
|
"error": "Range not defined",
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = %* {
|
||||||
|
"symbol": arg.symbol,
|
||||||
|
"range": arg.range,
|
||||||
|
"historicalData": response
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.finish(output)
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
let output = %* {
|
||||||
|
"symbol": arg.symbol,
|
||||||
|
"range": arg.range,
|
||||||
|
"error": "Historical market value not found",
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ import
|
||||||
web3/ethtypes, json_serialization
|
web3/ethtypes, json_serialization
|
||||||
from web3/conversions import `$`
|
from web3/conversions import `$`
|
||||||
|
|
||||||
|
const WEEKLY_TIME_RANGE* = 0
|
||||||
|
const MONTHLY_TIME_RANGE* = 1
|
||||||
|
const HALF_YEARLY_TIME_RANGE* = 2
|
||||||
|
const YEARLY_TIME_RANGE* = 3
|
||||||
|
const ALL_TIME_RANGE* = 4
|
||||||
|
|
||||||
type
|
type
|
||||||
TokenDto* = ref object of RootObj
|
TokenDto* = ref object of RootObj
|
||||||
name*: string
|
name*: string
|
||||||
|
|
|
@ -21,6 +21,7 @@ include async_tasks
|
||||||
# Signals which may be emitted by this service:
|
# Signals which may be emitted by this service:
|
||||||
const SIGNAL_TOKEN_DETAILS_LOADED* = "tokenDetailsLoaded"
|
const SIGNAL_TOKEN_DETAILS_LOADED* = "tokenDetailsLoaded"
|
||||||
const SIGNAL_TOKEN_LIST_RELOADED* = "tokenListReloaded"
|
const SIGNAL_TOKEN_LIST_RELOADED* = "tokenListReloaded"
|
||||||
|
const SIGNAL_TOKEN_HISTORICAL_DATA_LOADED* = "tokenHistoricalDataLoaded"
|
||||||
|
|
||||||
type
|
type
|
||||||
TokenDetailsLoadedArgs* = ref object of Args
|
TokenDetailsLoadedArgs* = ref object of Args
|
||||||
|
@ -38,6 +39,10 @@ type
|
||||||
VisibilityToggled* = ref object of Args
|
VisibilityToggled* = ref object of Args
|
||||||
token*: TokenDto
|
token*: TokenDto
|
||||||
|
|
||||||
|
type
|
||||||
|
TokenHistoricalDataArgs* = ref object of Args
|
||||||
|
result*: string
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type Service* = ref object of QObject
|
type Service* = ref object of QObject
|
||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
|
@ -192,3 +197,24 @@ QtObject:
|
||||||
address: address
|
address: address
|
||||||
)
|
)
|
||||||
self.threadpool.start(arg)
|
self.threadpool.start(arg)
|
||||||
|
|
||||||
|
proc tokenHistorticalDataResolved*(self: Service, response: string) {.slot.} =
|
||||||
|
let responseObj = response.parseJson
|
||||||
|
if (responseObj.kind != JObject):
|
||||||
|
info "prepared tokens are not a json object"
|
||||||
|
return
|
||||||
|
|
||||||
|
self.events.emit(SIGNAL_TOKEN_HISTORICAL_DATA_LOADED, TokenHistoricalDataArgs(
|
||||||
|
result: response
|
||||||
|
))
|
||||||
|
|
||||||
|
proc getHistoricalDataForToken*(self: Service, symbol: string, currency: string, range: int) =
|
||||||
|
let arg = GetTokenHistoricalDataTaskArg(
|
||||||
|
tptr: cast[ByteAddress](getTokenHistoricalDataTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "tokenHistorticalDataResolved",
|
||||||
|
symbol: symbol,
|
||||||
|
currency: currency,
|
||||||
|
range: range
|
||||||
|
)
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
|
|
@ -241,3 +241,16 @@ rpc(updateKeycardUID, "accounts"):
|
||||||
|
|
||||||
rpc(deleteKeycard, "accounts"):
|
rpc(deleteKeycard, "accounts"):
|
||||||
keycardUid: string
|
keycardUid: string
|
||||||
|
|
||||||
|
rpc(getHourlyMarketValues, "wallet"):
|
||||||
|
symbol: string
|
||||||
|
currency: string
|
||||||
|
limit: int
|
||||||
|
aggregate: int
|
||||||
|
|
||||||
|
rpc(getDailyMarketValues, "wallet"):
|
||||||
|
symbol: string
|
||||||
|
currency: string
|
||||||
|
limit: int
|
||||||
|
allDate: bool
|
||||||
|
aggregate: int
|
||||||
|
|
|
@ -84,6 +84,12 @@ Page {
|
||||||
*/
|
*/
|
||||||
property string selectedTimeRange: timeRangeTabBar.currentItem.text
|
property string selectedTimeRange: timeRangeTabBar.currentItem.text
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty string StatusChartPanel::defaultTimeRangeIndexShown
|
||||||
|
This property holds the index of the time range tabbar to be shown by default
|
||||||
|
*/
|
||||||
|
property int defaultTimeRangeIndexShown: 0
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlsignal
|
\qmlsignal
|
||||||
This signal is emitted when a header tab bar is clicked.
|
This signal is emitted when a header tab bar is clicked.
|
||||||
|
@ -108,6 +114,7 @@ Page {
|
||||||
enabled: timeRangeModel[i].enabled });
|
enabled: timeRangeModel[i].enabled });
|
||||||
timeRangeTabBar.addItem(timeTab);
|
timeRangeTabBar.addItem(timeTab);
|
||||||
}
|
}
|
||||||
|
timeRangeTabBar.currentIndex = defaultTimeRangeIndexShown
|
||||||
}
|
}
|
||||||
if (!!graphsModel) {
|
if (!!graphsModel) {
|
||||||
for (var j = 0; j < graphsModel.length; j++) {
|
for (var j = 0; j < graphsModel.length; j++) {
|
||||||
|
|
|
@ -24,6 +24,22 @@ Item {
|
||||||
stack.currentIndex = 0;
|
stack.currentIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
function getBackButtonText(index) {
|
||||||
|
switch(index) {
|
||||||
|
case 1:
|
||||||
|
return qsTr("Assets")
|
||||||
|
case 2:
|
||||||
|
return qsTr("Assets")
|
||||||
|
case 3:
|
||||||
|
return qsTr("Activity")
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
@ -32,7 +48,7 @@ Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: parent.height - footer.height
|
Layout.preferredHeight: parent.height - footer.height
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
RootStore.backButtonName = ((currentIndex === 1) || (currentIndex === 2)) ? qsTr("Assets") : "";
|
RootStore.backButtonName = d.getBackButtonText(currentIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
@ -112,7 +128,7 @@ Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
sendModal: root.sendModal
|
sendModal: root.sendModal
|
||||||
contactsStore: root.contactsStore
|
contactsStore: root.contactsStore
|
||||||
onGoBack: stack.currentIndex = 0
|
visible: (stack.currentIndex === 3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ QtObject {
|
||||||
property var tokens: walletSectionAllTokens.all
|
property var tokens: walletSectionAllTokens.all
|
||||||
property var accounts: walletSectionAccounts.model
|
property var accounts: walletSectionAccounts.model
|
||||||
|
|
||||||
|
property var marketValueStore: TokenMarketValuesStore{}
|
||||||
|
|
||||||
function getNetworkColor(chainId) {
|
function getNetworkColor(chainId) {
|
||||||
return networksModule.all.getChainColor(chainId)
|
return networksModule.all.getChainColor(chainId)
|
||||||
}
|
}
|
||||||
|
@ -199,4 +201,8 @@ QtObject {
|
||||||
function getGasEthValue(gweiValue, gasLimit) {
|
function getGasEthValue(gweiValue, gasLimit) {
|
||||||
return profileSectionModule.ensUsernamesModule.getGasEthValue(gweiValue, gasLimit)
|
return profileSectionModule.ensUsernamesModule.getGasEthValue(gweiValue, gasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getHistoricalDataForToken(symbol, currency) {
|
||||||
|
walletSectionAllTokens.getHistoricalDataForToken(symbol,currency)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
import QtQuick 2.13
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
|
||||||
|
enum TimeRange {
|
||||||
|
Weekly = 0,
|
||||||
|
Monthly,
|
||||||
|
HalfYearly,
|
||||||
|
Yearly,
|
||||||
|
All
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property int hoursInADay: 24
|
||||||
|
readonly property int avgLengthOfMonth: 30
|
||||||
|
|
||||||
|
readonly property var graphTabsModel: [{text: qsTr("Price"), enabled: true}, {text: qsTr("Balance"), enabled: false}]
|
||||||
|
readonly property var timeRangeTabsModel: [{text: qsTr("7D"), enabled: true},
|
||||||
|
{text: qsTr("1M"), enabled: true}, {text: qsTr("6M"), enabled: true},
|
||||||
|
{text: qsTr("1Y"), enabled: true}, {text: qsTr("ALL"), enabled: true}]
|
||||||
|
|
||||||
|
property var weeklyData
|
||||||
|
property var monthlyData
|
||||||
|
property var halfYearlyData
|
||||||
|
property var yearlyData
|
||||||
|
property var allData
|
||||||
|
|
||||||
|
property var weeklyTimeRange
|
||||||
|
property var monthlyTimeRange
|
||||||
|
property var halfYearlyTimeRange
|
||||||
|
property var yearlyTimeRange
|
||||||
|
property var allTimeRange
|
||||||
|
|
||||||
|
readonly property var timeRange: [
|
||||||
|
{'7D': weeklyTimeRange},
|
||||||
|
{'1M': monthlyTimeRange},
|
||||||
|
{'6M': halfYearlyTimeRange},
|
||||||
|
{'1Y': yearlyTimeRange},
|
||||||
|
{'ALL': allTimeRange}
|
||||||
|
]
|
||||||
|
|
||||||
|
readonly property var dataRange: [
|
||||||
|
{'7D': weeklyData},
|
||||||
|
{'1M': monthlyData},
|
||||||
|
{'6M': halfYearlyData},
|
||||||
|
{'1Y': yearlyData},
|
||||||
|
{'ALL': allData}
|
||||||
|
]
|
||||||
|
|
||||||
|
property int allTimeRangeTicks: 0
|
||||||
|
|
||||||
|
readonly property var maxTicks: [
|
||||||
|
{'7D': weeklyTimeRange.length/hoursInADay},
|
||||||
|
{'1M': monthlyTimeRange.length/hoursInADay},
|
||||||
|
{'6M': halfYearlyTimeRange.length/avgLengthOfMonth},
|
||||||
|
{'1Y': yearlyTimeRange.length/avgLengthOfMonth},
|
||||||
|
{'ALL': allTimeRangeTicks}
|
||||||
|
]
|
||||||
|
|
||||||
|
function setTimeAndValueData(data, range) {
|
||||||
|
var marketValues = []
|
||||||
|
var timeRanges = []
|
||||||
|
for (var i = 0; i < data.length; ++i) {
|
||||||
|
marketValues[i] = data[i].close;
|
||||||
|
|
||||||
|
timeRanges[i] = range === TokenMarketValuesStore.TimeRange.Weekly || range === TokenMarketValuesStore.TimeRange.Monthly ?
|
||||||
|
Utils.getDayMonth(data[i].time * 1000, RootStore.accountSensitiveSettings.is24hTimeFormat):
|
||||||
|
Utils.getMonthYear(data[i].time * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(range) {
|
||||||
|
case TokenMarketValuesStore.TimeRange.Weekly: {
|
||||||
|
weeklyData = marketValues
|
||||||
|
weeklyTimeRange = timeRanges
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case TokenMarketValuesStore.TimeRange.Monthly: {
|
||||||
|
monthlyData = marketValues
|
||||||
|
monthlyTimeRange = timeRanges
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case TokenMarketValuesStore.TimeRange.HalfYearly: {
|
||||||
|
halfYearlyData = marketValues
|
||||||
|
halfYearlyTimeRange = timeRanges
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case TokenMarketValuesStore.TimeRange.Yearly: {
|
||||||
|
yearlyData = marketValues
|
||||||
|
yearlyTimeRange = timeRanges
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case TokenMarketValuesStore.TimeRange.All: {
|
||||||
|
allData = marketValues
|
||||||
|
allTimeRange = timeRanges
|
||||||
|
if(data.length > 0)
|
||||||
|
allTimeRangeTicks = Math.abs(Qt.formatDate(new Date(data[0].time*1000), 'yyyy') - Qt.formatDate(new Date(data[data.length-1].time*1000), 'yyyy'))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,72 +21,21 @@ Item {
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
//dummy data
|
property var marketValueStore : RootStore.marketValueStore
|
||||||
property real stepSize: 1000
|
}
|
||||||
property real minStep: 12000
|
|
||||||
property real maxStep: 22000
|
|
||||||
|
|
||||||
property var graphTabsModel: [{text: qsTr("Price"), enabled: true}, {text: qsTr("Balance"), enabled: false}]
|
Connections {
|
||||||
property var timeRangeTabsModel: [{text: qsTr("1H"), enabled: true},
|
target: walletSectionAllTokens
|
||||||
{text: qsTr("1D"), enabled: true},{text: qsTr("7D"), enabled: true},
|
onTokenHistoricalDataReady: {
|
||||||
{text: qsTr("1M"), enabled: true}, {text: qsTr("6M"), enabled: true},
|
let response = JSON.parse(tokenDetails)
|
||||||
{text: qsTr("1Y"), enabled: true}, {text: qsTr("ALL"), enabled: true}]
|
if (response === null) {
|
||||||
|
console.debug("error parsing message for tokenHistoricalDataReady: error: ", response.error)
|
||||||
property var simTimer: Timer {
|
return
|
||||||
running: root.visible
|
|
||||||
interval: 3000
|
|
||||||
repeat: true
|
|
||||||
onTriggered: {
|
|
||||||
d.generateData();
|
|
||||||
}
|
}
|
||||||
}
|
if(response.historicalData === null || response.historicalData <= 0)
|
||||||
|
return
|
||||||
|
|
||||||
function minutes(minutes = 0) {
|
d.marketValueStore.setTimeAndValueData(response.historicalData, response.range)
|
||||||
var newMinute = new Date(new Date().getTime() - (minutes * 60 * 1000)).toString();
|
|
||||||
if (newMinute.slice(10,12) === "00") {
|
|
||||||
var dateToday = new Date(Date.now()).toString();
|
|
||||||
return dateToday.slice(4,7) + " " + dateToday.slice(8,10);
|
|
||||||
}
|
|
||||||
return newMinute.slice(10,16);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hour(hours = 0) {
|
|
||||||
var newHour = new Date(new Date().getTime() - (hours * 60 * 60 * 1000)).toString();
|
|
||||||
if (newHour.slice(10,12) === "00") {
|
|
||||||
var dateToday = new Date(Date.now()).toString();
|
|
||||||
return dateToday.slice(4,7) + " " + dateToday.slice(8,10);
|
|
||||||
}
|
|
||||||
return newHour.slice(10,16);
|
|
||||||
}
|
|
||||||
|
|
||||||
function day(before = 0) {
|
|
||||||
var newDay = new Date(Date.now() - before * 24 * 60 * 60 * 1000).toString();
|
|
||||||
return newDay.slice(4,7) + " " + newDay.slice(8,10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function month(before = 0) {
|
|
||||||
var newMonth = new Date(Date.now() - before * 24 * 60 * 60 * 1000).toString();
|
|
||||||
return newMonth.slice(4,7) + " '" + newMonth.slice(newMonth.indexOf("G")-3, newMonth.indexOf("G")-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
property var timeRange: [
|
|
||||||
{'1H': [minutes(60), minutes(55), minutes(50), minutes(45), minutes(40), minutes(35), minutes(30), minutes(25), minutes(20), minutes(15), minutes(10), minutes(5), minutes()]},
|
|
||||||
{'1D': [hour(24), hour(23), hour(22), hour(21), hour(20), hour(19), hour(18), hour(17), hour(16), hour(15), hour(14), hour(13),
|
|
||||||
hour(12), hour(11), hour(10), hour(9), hour(8), hour(7), hour(6), hour(5), hour(4), hour(3), hour(2), hour(1), hour()]},
|
|
||||||
{'7D': [day(6), day(5), day(4), day(3), day(2), day(1), day()]},
|
|
||||||
{'1M': [day(30), day(28), day(26), day(24), day(22), day(20), day(18), day(16), day(14), day(12), day(10), day(8), day(6), day(4), day()]},
|
|
||||||
{'6M': [month(150), month(120), month(90), month(60), month(30), month()]},
|
|
||||||
{'1Y': [month(330), month(300), month(270), month(240), month(210), month(180), month(150), month(120), month(90), month(60), month(30), month()]},
|
|
||||||
{'ALL': ['2016', '2017', '2018', '2019', '2020', '2021', '2022']}
|
|
||||||
]
|
|
||||||
|
|
||||||
function generateData() {
|
|
||||||
var result = [];
|
|
||||||
for (var i = 0; i < timeRange[graphDetailLoader.item.timeRangeTabBarIndex][graphDetailLoader.item.selectedTimeRange].length; ++i) {
|
|
||||||
result[i] = Math.random() * (maxStep - minStep) + minStep;
|
|
||||||
}
|
|
||||||
graphDetailLoader.item.chart.chartData.datasets[0].data = result;
|
|
||||||
graphDetailLoader.item.chart.animateToNewData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,28 +68,23 @@ Item {
|
||||||
active: root.visible
|
active: root.visible
|
||||||
sourceComponent: StatusChartPanel {
|
sourceComponent: StatusChartPanel {
|
||||||
id: graphDetail
|
id: graphDetail
|
||||||
graphsModel: d.graphTabsModel
|
graphsModel: d.marketValueStore.graphTabsModel
|
||||||
timeRangeModel: d.timeRangeTabsModel
|
defaultTimeRangeIndexShown: TokenMarketValuesStore.TimeRange.All
|
||||||
onHeaderTabClicked: {
|
timeRangeModel: d.marketValueStore.timeRangeTabsModel
|
||||||
//TODO
|
onHeaderTabClicked: chart.animateToNewData()
|
||||||
//if time range tab
|
|
||||||
d.generateData();
|
|
||||||
//if graph bar
|
|
||||||
//switch graph
|
|
||||||
}
|
|
||||||
chart.chartType: 'line'
|
chart.chartType: 'line'
|
||||||
chart.chartData: {
|
chart.chartData: {
|
||||||
return {
|
return {
|
||||||
labels: d.timeRange[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange],
|
labels: d.marketValueStore.timeRange[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange],
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Price',
|
|
||||||
xAxisId: 'x-axis-1',
|
xAxisId: 'x-axis-1',
|
||||||
yAxisId: 'y-axis-1',
|
yAxisId: 'y-axis-1',
|
||||||
backgroundColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 0.2)' : 'rgba(67, 96, 223, 0.2)',
|
backgroundColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 0.2)' : 'rgba(67, 96, 223, 0.2)',
|
||||||
borderColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 1)' : 'rgba(67, 96, 223, 1)',
|
borderColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 1)' : 'rgba(67, 96, 223, 1)',
|
||||||
borderWidth: 3,
|
borderWidth: 3,
|
||||||
pointRadius: 0,
|
pointRadius: 0,
|
||||||
//data: d.generateData()
|
data: d.marketValueStore.dataRange[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange],
|
||||||
|
parsing: false,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,14 +108,13 @@ Item {
|
||||||
intersect: false,
|
intersect: false,
|
||||||
displayColors: false,
|
displayColors: false,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
footer: function(tooltipItem, data) { return 'Vol: $43,042,678,876'; },
|
|
||||||
label: function(tooltipItem, data) {
|
label: function(tooltipItem, data) {
|
||||||
let label = data.datasets[tooltipItem.datasetIndex].label || '';
|
let label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||||
if (label) {
|
if (label) {
|
||||||
label += ': ';
|
label += ': ';
|
||||||
}
|
}
|
||||||
label += tooltipItem.yLabel.toFixed(2);
|
label += tooltipItem.yLabel.toFixed(2);
|
||||||
return label.slice(0,label.indexOf(":")+1)+ " $"+label.slice(label.indexOf(":")+2, label.length);
|
return label.slice(0,label.indexOf(":")+1) + " %1".arg(RootStore.currencyStore.currentCurrencySymbol) + label.slice(label.indexOf(":") + 2, label.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -188,7 +131,10 @@ Item {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
|
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
|
||||||
padding: 16,
|
padding: 16,
|
||||||
}
|
maxRotation: 0,
|
||||||
|
minRotation: 0,
|
||||||
|
maxTicksLimit: d.marketValueStore.maxTicks[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange],
|
||||||
|
},
|
||||||
}],
|
}],
|
||||||
yAxes: [{
|
yAxes: [{
|
||||||
position: 'left',
|
position: 'left',
|
||||||
|
@ -207,11 +153,8 @@ Item {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
|
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
|
||||||
padding: 8,
|
padding: 8,
|
||||||
min: d.minStep,
|
|
||||||
max: d.maxStep,
|
|
||||||
stepSize: d.stepSize,
|
|
||||||
callback: function(value, index, ticks) {
|
callback: function(value, index, ticks) {
|
||||||
return '$' + value;
|
return LocaleUtils.numberToLocaleString(value)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|
|
@ -86,6 +86,7 @@ Item {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
RootStore.getHistoricalDataForToken(symbol, RootStore.currencyStore.currentCurrency)
|
||||||
d.selectedAssetIndex = index
|
d.selectedAssetIndex = index
|
||||||
assetClicked(model)
|
assetClicked(model)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ Item {
|
||||||
property var transaction
|
property var transaction
|
||||||
property var sendModal
|
property var sendModal
|
||||||
|
|
||||||
signal goBack()
|
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
@ -38,23 +37,9 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusFlatButton {
|
|
||||||
id: backButton
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
anchors.topMargin: -Style.current.xlPadding
|
|
||||||
anchors.leftMargin: -Style.current.xlPadding
|
|
||||||
icon.name: "arrow-left"
|
|
||||||
icon.width: 20
|
|
||||||
icon.height: 20
|
|
||||||
text: qsTr("Activity")
|
|
||||||
size: StatusBaseButton.Size.Large
|
|
||||||
onClicked: root.goBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusScrollView {
|
StatusScrollView {
|
||||||
anchors.top: backButton.bottom
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
|
@ -295,6 +295,22 @@ QtObject {
|
||||||
return qsTr("%1D").arg(diffDay)
|
return qsTr("%1D").arg(diffDay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDayMonth(value, isDDMMYYDateFormat) {
|
||||||
|
const formatDDMMYY = "d MMMM"
|
||||||
|
const formatMMDDYY = "MMMM d"
|
||||||
|
const currentFormat = isDDMMYYDateFormat ? formatDDMMYY : formatMMDDYY
|
||||||
|
var timeStamp = checkTimestamp(value, "formatLongDate") ? Qt.formatDate(new Date(value), currentFormat) :
|
||||||
|
Qt.formatDate(new Date(), currentFormat)
|
||||||
|
return formatShortDateStr(timeStamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMonthYear(value) {
|
||||||
|
const formatDDMMYY = "MMMM yyyy"
|
||||||
|
var timeStamp = checkTimestamp(value, "formatLongDate") ? Qt.formatDate(new Date(value), formatDDMMYY) :
|
||||||
|
Qt.formatDate(new Date(), formatDDMMYY)
|
||||||
|
return formatShortDateStr(timeStamp)
|
||||||
|
}
|
||||||
|
|
||||||
function formatShortDate(value, isDDMMYYDateFormat) {
|
function formatShortDate(value, isDDMMYYDateFormat) {
|
||||||
const formatDDMMYY = "d MMMM yyyy"
|
const formatDDMMYY = "d MMMM yyyy"
|
||||||
const formatMMDDYY = "MMMM d yyyy"
|
const formatMMDDYY = "MMMM d yyyy"
|
||||||
|
|
Loading…
Reference in New Issue