status-desktop/ui/imports/shared/views/AssetsDetailView.qml

361 lines
16 KiB
QML
Raw Normal View History

import QtQuick 2.13
import QtQuick.Layouts 1.13
import QtQuick.Controls 2.14
import QtQuick.Window 2.12
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import utils 1.0
import shared.views 1.0
import shared.controls 1.0
import "../stores"
Item {
id: root
property var token
QtObject {
id: d
//dummy data
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}]
property var timeRangeTabsModel: [{text: qsTr("1H"), enabled: true},
{text: qsTr("1D"), enabled: true},{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 simTimer: Timer {
2022-09-19 14:50:25 +00:00
running: root.visible
interval: 3000
repeat: true
onTriggered: {
d.generateData();
}
}
function minutes(minutes = 0) {
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();
}
}
AssetsDetailsHeader {
id: tokenDetailsHeader
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
width: parent.width
asset.name: token && token.symbol ? Style.png("tokens/%1".arg(token.symbol)) : ""
asset.isImage: true
primaryText: token ? token.name : ""
secondaryText: token ? `${token.enabledNetworkBalance} ${token.symbol}` : ""
tertiaryText: token ? "%1 %2".arg(Utils.toLocaleString(token.enabledNetworkCurrencyBalance.toFixed(2), RootStore.locale, {"currency": true})).arg(RootStore.currencyStore.currentCurrency.toUpperCase()) : ""
balances: token && token.balances ? token.balances : null
getNetworkColor: function(chainId){
return RootStore.getNetworkColor(chainId)
}
getNetworkIcon: function(chainId){
return RootStore.getNetworkIcon(chainId)
}
}
Loader {
id: graphDetailLoader
width: parent.width
height: 290
anchors.top: tokenDetailsHeader.bottom
anchors.topMargin: 24
active: root.visible
sourceComponent: StatusChartPanel {
id: graphDetail
graphsModel: d.graphTabsModel
timeRangeModel: d.timeRangeTabsModel
onHeaderTabClicked: {
//TODO
//if time range tab
d.generateData();
//if graph bar
//switch graph
}
chart.chartType: 'line'
chart.chartData: {
return {
labels: d.timeRange[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange],
datasets: [{
label: 'Price',
xAxisId: 'x-axis-1',
yAxisId: 'y-axis-1',
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)',
borderWidth: 3,
pointRadius: 0,
//data: d.generateData()
}]
}
}
chart.chartOptions: {
return {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false
},
//TODO enable zoom
//zoom: {
// enabled: true,
// drag: true,
// speed: 0.1,
// threshold: 2
//},
//pan:{enabled:true,mode:'x'},
tooltips: {
intersect: false,
displayColors: false,
callbacks: {
footer: function(tooltipItem, data) { return 'Vol: $43,042,678,876'; },
label: function(tooltipItem, data) {
let label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += tooltipItem.yLabel.toFixed(2);
return label.slice(0,label.indexOf(":")+1)+ " $"+label.slice(label.indexOf(":")+2, label.length);
}
}
},
scales: {
xAxes: [{
id: 'x-axis-1',
position: 'bottom',
gridLines: {
drawOnChartArea: false,
drawBorder: false,
drawTicks: false,
},
ticks: {
fontSize: 10,
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
padding: 16,
}
}],
yAxes: [{
position: 'left',
id: 'y-axis-1',
gridLines: {
borderDash: [8, 4],
drawBorder: false,
drawTicks: false,
color: (Theme.palette.name === "dark") ? '#909090' : '#939BA1'
},
beforeDataLimits: (axis) => {
axis.paddingTop = 25;
axis.paddingBottom = 0;
},
ticks: {
fontSize: 10,
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
padding: 8,
min: d.minStep,
max: d.maxStep,
stepSize: d.stepSize,
callback: function(value, index, ticks) {
return '$' + value;
},
}
}]
}
}
}
}
}
ColumnLayout {
anchors.top: graphDetailLoader.bottom
anchors.topMargin: 24
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
width: parent.width
spacing: Style.current.padding
RowLayout {
Layout.fillWidth: true
InformationTile {
maxWidth: parent.width
primaryText: qsTr("Market Cap")
secondaryText: token && token.marketCap !== "" ? token.marketCap : "---"
}
InformationTile {
maxWidth: parent.width
primaryText: qsTr("Day Low")
secondaryText: token && token.lowDay !== "" ? token.lowDay : "---"
}
InformationTile {
maxWidth: parent.width
primaryText: qsTr("Day High")
secondaryText: token && token.highDay ? token.highDay : "---"
}
Item {
Layout.fillWidth: true
}
InformationTile {
readonly property string changePctHour: token ? token.changePctHour : ""
maxWidth: parent.width
primaryText: qsTr("Hour")
secondaryText: changePctHour ? "%1%".arg(changePctHour) : "---"
secondaryLabel.color: Math.sign(Number(changePctHour)) === 0 ? Theme.palette.directColor1 :
Math.sign(Number(changePctHour)) === -1 ? Theme.palette.dangerColor1 :
Theme.palette.successColor1
}
InformationTile {
readonly property string changePctDay: token ? token.changePctDay : ""
maxWidth: parent.width
primaryText: qsTr("Day")
secondaryText: changePctDay ? "%1%".arg(changePctDay) : "---"
secondaryLabel.color: Math.sign(Number(changePctDay)) === 0 ? Theme.palette.directColor1 :
Math.sign(Number(changePctDay)) === -1 ? Theme.palette.dangerColor1 :
Theme.palette.successColor1
}
InformationTile {
readonly property string changePct24hour: token ? token.changePct24hour : ""
maxWidth: parent.width
primaryText: qsTr("24 Hours")
secondaryText: changePct24hour ? "%1%".arg(changePct24hour) : "---"
secondaryLabel.color: Math.sign(Number(changePct24hour)) === 0 ? Theme.palette.directColor1 :
Math.sign(Number(changePct24hour)) === -1 ? Theme.palette.dangerColor1 :
Theme.palette.successColor1
}
}
StatusTabBar {
Layout.fillWidth: true
Layout.topMargin: Style.current.xlPadding
StatusTabButton {
leftPadding: 0
width: implicitWidth
text: qsTr("Overview")
}
}
StackLayout {
id: stack
Layout.fillWidth: true
Layout.fillHeight: true
StatusScrollView {
id: scrollView
Layout.preferredWidth: parent.width
Layout.preferredHeight: parent.height
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
topPadding: 8
bottomPadding: 8
Flow {
id: detailsFlow
readonly property bool isOverflowing: detailsFlow.width - tagsLayout.width - tokenDescriptionText.width < 24
spacing: 24
width: scrollView.availableWidth
StatusBaseText {
id: tokenDescriptionText
width: Math.max(536 , scrollView.availableWidth - tagsLayout.width - 24)
font.pixelSize: 15
lineHeight: 22
lineHeightMode: Text.FixedHeight
text: token ? token.description : ""
color: Theme.palette.directColor1
elide: Text.ElideRight
wrapMode: Text.Wrap
textFormat: Qt.RichText
}
ColumnLayout {
id: tagsLayout
spacing: 10
InformationTag {
id: website
Layout.alignment: detailsFlow.isOverflowing ? Qt.AlignLeft : Qt.AlignRight
iconAsset.icon: "browser"
tagPrimaryLabel.text: qsTr("Website")
controlBackground.color: Theme.palette.baseColor2
controlBackground.border.color: "transparent"
visible: token && token.assetWebsiteUrl !== ""
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Global.openLink(token.assetWebsiteUrl)
}
}
InformationTag {
id: smartContractAddress
Layout.alignment: detailsFlow.isOverflowing ? Qt.AlignLeft : Qt.AlignRight
image.source: token && token.builtOn !== "" ? Style.svg("tiny/" + RootStore.getNetworkIconUrl(token.builtOn)) : ""
tagPrimaryLabel.text: token && token.builtOn !== "" ? RootStore.getNetworkName(token.builtOn) : "---"
tagSecondaryLabel.text: token && token.smartContractAddress !== "" ? token.smartContractAddress : "---"
controlBackground.color: Theme.palette.baseColor2
controlBackground.border.color: "transparent"
visible: token && token.builtOn !== "" && token.smartContractAddress !== ""
}
}
}
}
}
}
}