Files

233 lines
7.7 KiB
QML
Raw Permalink Normal View History

2025-06-24 22:19:37 +02:00
/*
* This file is part of the Flowee project
2026-02-12 23:06:58 +01:00
* Copyright (C) 2023-2026 Tom Zander <tom@flowee.org>
2025-06-24 22:19:37 +02:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls.Basic as QQC2
import "../Flowee" as Flowee
import "../Utils.js" as Utils
2026-02-04 15:02:32 +01:00
import Flowee.org.pay
2025-06-24 22:19:37 +02:00
Item {
2026-02-04 15:02:32 +01:00
property string icon: "qrc:/homeButtonIcon" + (Pay.useDarkSkin ? "-light.svg" : ".svg")
2025-06-24 22:19:37 +02:00
property string title: qsTr("Home")
property bool showFilterIcon: tabBar.currentIndex === 0
property bool showAllWalletsOption: tabBar.currentIndex !== 0
required property bool allWalletsEntrySelected
2025-06-24 22:19:37 +02:00
property bool itIsChristmas: {
2026-02-04 15:02:32 +01:00
var today = new Date()
2025-06-24 22:19:37 +02:00
return today.getMonth() == 11 && today.getDate() >= 24 && today.getDate() <= 31
}
2025-06-25 00:17:25 +02:00
Rectangle {
2025-07-12 16:56:08 +02:00
id: headerBg
2025-06-25 00:17:25 +02:00
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: tabBar.bottom
2025-07-12 16:56:08 +02:00
anchors.bottomMargin: -6
2025-06-25 00:17:25 +02:00
color: palette.window
2025-07-12 16:56:08 +02:00
property var headerGradient: Gradient {
2025-08-03 14:01:38 +02:00
GradientStop { position: 0.93; color: headerBg.color }
2025-07-12 16:56:08 +02:00
GradientStop { position: 1; color: {
2026-02-04 15:02:32 +01:00
let c = headerBg.color
return Qt.rgba(c.r, c.g, c.b, 0)
2025-07-12 16:56:08 +02:00
}
}
}
2025-08-03 14:01:38 +02:00
gradient: tabBar.visible ? undefined : headerGradient
2025-06-25 00:17:25 +02:00
}
2025-06-24 22:19:37 +02:00
ListView {
id: tabBar
orientation: Qt.Horizontal
width: parent.width
height: {
2025-07-12 16:05:38 +02:00
if (!visible || count <= 1 || currentItem === null)
2026-02-04 15:02:32 +01:00
return 0
return currentItem.height
2025-06-24 22:19:37 +02:00
}
property bool havePlannedTab: Pay.haveRepeatPayments
property bool haveTokensTab: tokens.showTokenTab !== Wallet.AlwaysOff
2026-03-16 11:44:46 +01:00
visible: count > 1
2025-06-24 22:19:37 +02:00
function selectTab(index) {
// fast move
activityTabs.positionViewAtIndex(index, ListView.Beginning)
// slow scroll
2026-02-04 15:02:32 +01:00
currentIndex = index
}
2025-06-24 22:19:37 +02:00
clip: true
boundsBehavior: Flickable.StopAtBounds
model: ListModel {
id: tabsModel
2025-06-24 22:19:37 +02:00
ListElement {
2025-07-08 20:54:56 +02:00
title: qsTr("Activity")
2025-06-24 22:19:37 +02:00
qml: "AccountHistory.qml"
}
}
onHavePlannedTabChanged: {
2026-02-15 22:16:51 +01:00
if (!havePlannedTab)
return
2026-03-16 11:44:46 +01:00
tabBar.selectTab(0)
2026-02-15 22:16:51 +01:00
for (let i = 1; i < tabsModel.count; ++i) {
let tab = tabsModel.get(i)
if (tab.qml === "PlannedPayments.qml")
return
2025-06-24 22:19:37 +02:00
}
tabsModel.append({ title: qsTr("Planned"), qml: "PlannedPayments.qml" })
}
onHaveTokensTabChanged: {
2026-03-16 11:44:46 +01:00
tabBar.selectTab(0)
for (let i = 1; i < tabsModel.count; ++i) {
let tab = tabsModel.get(i)
if (tab.qml === "TokensTab.qml") {
if (!haveTokensTab)
tabsModel.remove(i)
return
}
}
if (haveTokensTab)
tabsModel.insert(1, { title: qsTr("Tokens"), qml: "TokensTab.qml" })
2025-06-24 22:19:37 +02:00
}
delegate: Item {
width: Math.max(tabName.width, 120)
height: tabName.height + 20
Rectangle {
x: 5
height: 4
width: parent.width - 10
color: palette.highlight
visible: index === tabBar.currentIndex
anchors.bottom: parent.bottom
}
Rectangle {
anchors.fill: parent
color: palette.highlight
visible: index === tabBar.currentIndex
opacity: 0.15
}
Text {
id: tabName
2025-06-25 00:17:25 +02:00
color: palette.windowText
2025-06-24 22:19:37 +02:00
text: model.title
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
2026-02-04 15:02:32 +01:00
onClicked: tabBar.selectTab(index)
2025-06-24 22:19:37 +02:00
}
}
}
2026-02-05 17:49:52 +01:00
Rectangle {
color: palette.base // background is dark.
anchors.fill: activityTabs
}
2025-06-24 22:19:37 +02:00
ListView {
id: activityTabs
anchors.top: tabBar.bottom
2025-07-12 16:56:08 +02:00
anchors.topMargin: tabBar.visible ? 0 : 6
2025-06-24 22:19:37 +02:00
anchors.bottom: parent.bottom
width: parent.width
model: tabBar.model
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem
2026-03-16 11:44:46 +01:00
onContentXChanged: tabBar.currentIndex = Math.round(contentX / width)
2025-06-24 22:19:37 +02:00
boundsBehavior: Flickable.StopAtBounds
2026-02-04 15:02:32 +01:00
onCurrentItemChanged: currentItem.makeActive()
2025-06-24 22:19:37 +02:00
delegate: Loader {
2025-06-25 00:17:25 +02:00
id: delegateRoot
2025-06-24 22:19:37 +02:00
width: activityTabs.width
height: activityTabs.height
2026-02-15 22:16:51 +01:00
clip: true
2025-06-24 22:19:37 +02:00
source: model.qml
2025-06-25 00:17:25 +02:00
function makeActive() {
2026-02-12 23:06:58 +01:00
if (item != null) {
2026-03-16 11:44:46 +01:00
if (typeof(item.active) != "undefined")
item.active = true
2026-02-12 23:06:58 +01:00
item.forceActiveFocus()
2025-06-25 00:17:25 +02:00
}
}
2026-02-12 23:06:58 +01:00
Connections {
2026-03-16 11:44:46 +01:00
target: tabBar
2026-02-12 23:06:58 +01:00
function onCurrentIndexChanged() {
// let a tab know if it is currently active.
// as the user can slide between them, we can't use visible and tabs have
// a right to know if they are actually visible.
if (item != null && typeof(item.active) != "undefined")
2026-03-16 11:44:46 +01:00
item.active = index == tabBar.currentIndex
2026-02-12 23:06:58 +01:00
}
}
2025-06-24 22:19:37 +02:00
}
}
Rectangle {
id: startQRButton
width: height
height: {
2026-03-16 11:44:46 +01:00
let i = activityTabs.itemAtIndex(tabBar.currentIndex)
2026-02-12 23:06:58 +01:00
if (i != null && i.item !== null) { // at creation this is the case.
2025-06-24 22:19:37 +02:00
let hide = i.item.hideQRScanButton
if (typeof(hide) === "boolean" && hide)
2026-02-04 15:02:32 +01:00
return 0
2025-06-24 22:19:37 +02:00
}
2026-02-04 15:02:32 +01:00
return 70
2025-06-24 22:19:37 +02:00
}
radius: 35
clip: true
x: parent.width - width - 30 - (70 / 2 - width / 2) // almost right, but keep this centered around the max width
y: parent.height - height - 15 - (70 / 2 - height / 2)
color: mainWindow.floweeBlue
Image {
source: "qrc:/qr-code-scan-light.svg"
anchors.centerIn: parent
2025-06-25 12:29:08 +02:00
width: 40
height: 40
2025-06-24 22:19:37 +02:00
}
MouseArea {
anchors.fill: parent
onClicked: thePile.push("ScanQRPage.qml")
}
Behavior on height { NumberAnimation { } }
}
2025-06-25 00:17:25 +02:00
Keys.onPressed: (event)=> {
if (event.key === Qt.Key_Escape || event.key === Qt.Key_Back) {
// when we are on another tab, we can go to 'main' on back.
2026-03-16 11:44:46 +01:00
if (tabBar.currentIndex !== 0) {
2026-02-04 15:02:32 +01:00
event.accepted = true
tabBar.selectTab(0)
2025-06-25 00:17:25 +02:00
}
}
}
// should the app be started with the intent to open the "Planned Payment" screen,
// we handle that here.
Connections {
target: intent
function onGenericIntentChanged() { // it only ever changes at most once
if (intent.genericIntent === Intent.OpenPlannedPaymentScreen)
2026-02-04 15:02:32 +01:00
tabBar.selectTab(1)
}
}
2025-06-24 22:19:37 +02:00
}