feat(@desktop/wallet): Create API to retrieve historical price for a token

fixes #7260
This commit is contained in:
Khushboo Mehta 2022-09-27 10:30:18 +02:00 committed by Khushboo-dev-cpp
parent b1f8a476e8
commit 7e82b36509
16 changed files with 305 additions and 102 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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)

View File

@ -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.}

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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++) {

View File

@ -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)
} }
} }

View File

@ -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)
}
} }

View File

@ -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
}
}
}
}

View File

@ -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)
}, },
} }
}] }]

View File

@ -86,6 +86,7 @@ Item {
} }
] ]
onClicked: { onClicked: {
RootStore.getHistoricalDataForToken(symbol, RootStore.currencyStore.currentCurrency)
d.selectedAssetIndex = index d.selectedAssetIndex = index
assetClicked(model) assetClicked(model)
} }

View File

@ -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

View File

@ -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"