/* * This file is part of the Flowee project * Copyright (C) 2023-2026 Tom Zander * * 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 . */ import QtQuick import QtQuick.Controls.Basic as QQC2 import "../Flowee" as Flowee import "../Utils.js" as Utils import Flowee.org.pay Item { property string icon: "qrc:/homeButtonIcon" + (Pay.useDarkSkin ? "-light.svg" : ".svg") property string title: qsTr("Home") property bool showFilterIcon: tabBar.currentIndex === 0 property bool showAllWalletsOption: tabBar.currentIndex !== 0 required property bool allWalletsEntrySelected property bool itIsChristmas: { var today = new Date() return today.getMonth() == 11 && today.getDate() >= 24 && today.getDate() <= 31 } Rectangle { id: headerBg anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.bottom: tabBar.bottom anchors.bottomMargin: -6 color: palette.window property var headerGradient: Gradient { GradientStop { position: 0.93; color: headerBg.color } GradientStop { position: 1; color: { let c = headerBg.color return Qt.rgba(c.r, c.g, c.b, 0) } } } gradient: tabBar.visible ? undefined : headerGradient } ListView { id: tabBar orientation: Qt.Horizontal width: parent.width height: { if (!visible || count <= 1 || currentItem === null) return 0 return currentItem.height } property bool havePlannedTab: Pay.haveRepeatPayments property bool haveTokensTab: tokens.showTokenTab !== Wallet.AlwaysOff visible: count > 1 function selectTab(index) { // fast move activityTabs.positionViewAtIndex(index, ListView.Beginning) // slow scroll currentIndex = index } clip: true boundsBehavior: Flickable.StopAtBounds model: ListModel { id: tabsModel ListElement { title: qsTr("Activity") qml: "AccountHistory.qml" } } onHavePlannedTabChanged: { if (!havePlannedTab) return tabBar.selectTab(0) for (let i = 1; i < tabsModel.count; ++i) { let tab = tabsModel.get(i) if (tab.qml === "PlannedPayments.qml") return } tabsModel.append({ title: qsTr("Planned"), qml: "PlannedPayments.qml" }) } onHaveTokensTabChanged: { 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" }) } 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 color: palette.windowText text: model.title anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: tabBar.selectTab(index) } } } Rectangle { color: palette.base // background is dark. anchors.fill: activityTabs } ListView { id: activityTabs anchors.top: tabBar.bottom anchors.topMargin: tabBar.visible ? 0 : 6 anchors.bottom: parent.bottom width: parent.width model: tabBar.model orientation: ListView.Horizontal snapMode: ListView.SnapOneItem onContentXChanged: tabBar.currentIndex = Math.round(contentX / width) boundsBehavior: Flickable.StopAtBounds onCurrentItemChanged: currentItem.makeActive() delegate: Loader { id: delegateRoot width: activityTabs.width height: activityTabs.height clip: true source: model.qml function makeActive() { if (item != null) { if (typeof(item.active) != "undefined") item.active = true item.forceActiveFocus() } } Connections { target: tabBar 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") item.active = index == tabBar.currentIndex } } } } Rectangle { id: startQRButton width: height height: { let i = activityTabs.itemAtIndex(tabBar.currentIndex) if (i != null && i.item !== null) { // at creation this is the case. let hide = i.item.hideQRScanButton if (typeof(hide) === "boolean" && hide) return 0 } return 70 } 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 width: 40 height: 40 } MouseArea { anchors.fill: parent onClicked: thePile.push("ScanQRPage.qml") } Behavior on height { NumberAnimation { } } } 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. if (tabBar.currentIndex !== 0) { event.accepted = true tabBar.selectTab(0) } } } // 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) tabBar.selectTab(1) } } }