harbour-expenditure/qml/pages/BannerAddProject.qml
2023-11-13 19:04:58 +01:00

502 lines
23 KiB
QML

import QtQuick 2.6
import Sailfish.Silica 1.0
MouseArea {
id: popup
z: 10
width: parent.width
height: parent.height
visible: opacity > 0
opacity: 0.0
onClicked: {
hide()
}
onOpacityChanged: {
//if needed
}
// UI variables
property var hideBackColor : Theme.rgba(Theme.overlayBackgroundColor, 0.9)
property int amountBeneficiaries : listModel_activeProjectMembersTEMP.count
property string modeEdit : "new"
property real editItemIndex : -1 // -1=new, otherwise gives index of list
property int tempProjectListIndex
property bool showTextfieldMemberName : false
property string timeStamp : ((new Date).getTime()).toString() // creates unix timestamp
property string backupFilePath : ""
// suppress blend to main window on this overlay, e.g. for context menu ...
// BUG: creates problems with _selectOrientation for context menus larger than 5 entries
property alias __silica_applicationwindow_instance: fakeApplicationWindow
Item {
id: fakeApplicationWindow
// suppresses warnings by context menu
property var _dimScreen
property var _undim
function _undim() {}
function _dimScreen() {}
}
Behavior on opacity {
FadeAnimator {}
}
ListModel {
id: listModel_activeProjectMembersTEMP
}
RemorsePopup {
z: 10
id: remorse_deleteProject
}
Rectangle {
anchors.fill: parent
color: hideBackColor
onColorChanged: opacity = 4
Rectangle {
id: idBackgroundRectProject
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
width: parent.width
height: parent.height - anchors.topMargin - Theme.paddingLarge
radius: Theme.paddingLarge
SilicaFlickable {
anchors.fill: parent
contentHeight: addExpenseColumn.height
clip: true
Column {
id: addExpenseColumn
width: parent.width
Row {
x: Theme.paddingLarge
width: parent.width - 2*x
topPadding: Theme.paddingLarge
bottomPadding: Theme.paddingLarge
Column {
id: idColumnAddProject
width: parent.width /3*2 - Theme.paddingLarge /2
Label {
width: parent.width
text: qsTr("Project")
}
Label {
width: parent.width
font.pixelSize: Theme.fontSizeTiny
text: (modeEdit === "new") ? (qsTr("create")) : (qsTr("edit"))
}
}
Item {
width: Theme.paddingLarge
height: 1
}
Button {
id: idLabelHeaderAdd2
enabled: (idTextfieldProjectname.length > 0) && (amountBeneficiaries > 0)
width: parent.width /3 - Theme.paddingLarge /2
height: idColumnAddProject.height
text: (modeEdit === "new") ? qsTr("Add") : qsTr("Save")
onClicked: {
addProjectDB()
}
}
}
Row {
width: parent.width
topPadding: Theme.paddingLarge
bottomPadding: Theme.paddingLarge
TextField {
id: idTextfieldProjectname
width: parent.width /3 * 2 - Theme.paddingLarge
acceptableInput: text.length < 255
font.pixelSize: Theme.fontSizeMedium
EnterKey.onClicked: {
focus = false
}
Label {
anchors.top: parent.bottom
anchors.topMargin: Theme.paddingSmall
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: qsTr("name")
}
}
Item {
width: Theme.paddingLarge
height: 1
}
TextField {
id: idTextfieldCurrencyProject
width: parent.width /3
textLeftMargin: 0
horizontalAlignment: TextInput.AlignRight
acceptableInput: text.length > 0
EnterKey.enabled: text.length >= 0
EnterKey.onClicked: {
focus = false
}
onFocusChanged: {
if (text.length === 0) {
text = recentlyUsedCurrency
}
if (focus) {
selectAll()
}
}
Label {
anchors.right: parent.right
anchors.top: parent.bottom
anchors.topMargin: Theme.paddingSmall
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: qsTr("base currency")
}
}
}
Row {
x: Theme.paddingLarge
width: parent.width - 2*x
topPadding: Theme.paddingLarge
Label {
x: Theme.paddingLarge
width: parent.width/ 3*2 - Theme.paddingLarge / 2
height: idAddMemberButton.height
verticalAlignment: Text.AlignVCenter
font.pixelSize: Theme.fontSizeMedium
text: qsTr("Members")
}
Item {
width: Theme.paddingLarge
height: 1
}
Item {
id: idAddMemberButton
width: parent.width / 3 - Theme.paddingLarge/2
height: Theme.iconSizeMedium
Icon {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
height: parent.height
width: height
source: !showTextfieldMemberName ? "image://theme/icon-m-add?" : "image://theme/icon-m-clear?"
}
MouseArea {
anchors.fill: parent
onClicked: {
showTextfieldMemberName ? showTextfieldMemberName=false : showTextfieldMemberName=true
if (showTextfieldMemberName) {
// clear field and set for new member
editItemIndex = -1 // -1=add new member
idTextfieldAddMember.text = ""
idTextfieldAddMember.forceActiveFocus()
} else {
idTextfieldAddMember.text = ""
idTextfieldAddMember.focus = false
}
}
}
}
}
Column {
visible: !showTextfieldMemberName
width: parent.width
Repeater {
model: listModel_activeProjectMembersTEMP
delegate: ListItem {
contentHeight: Theme.itemSizeExtraSmall
menu: ContextMenu {
MenuItem {
text: qsTr("rename")
onClicked: {
showTextfieldMemberName ? showTextfieldMemberName=false : showTextfieldMemberName=true
editItemIndex = index
idTextfieldAddMember.text = member_name
idTextfieldAddMember.forceActiveFocus()
}
}
MenuItem {
text: qsTr("remove")
onClicked: {
listModel_activeProjectMembersTEMP.remove(index)
}
}
}
Row {
x: Theme.paddingLarge
width: parent.width - 2*x
height: parent.height
Label {
width: parent.width
height: parent.height
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
font.pixelSize: Theme.fontSizeSmall
color: Theme.highlightColor
text: member_name
}
}
}
}
}
Row {
width: parent.width
visible: showTextfieldMemberName
topPadding: Theme.paddingMedium
TextField {
id: idTextfieldAddMember
width: parent.width // 3*2 - Theme.paddingLarge
acceptableInput: text.length < 255
font.pixelSize: Theme.fontSizeSmall
onActiveFocusChanged: {
if (!focus) {
showTextfieldMemberName = false
idTextfieldAddMember.text = ""
}
}
EnterKey.onClicked: {
if (text.length > 0) {
if (editItemIndex === -1) { // -1=add new member
listModel_activeProjectMembersTEMP.append({ member_name : idTextfieldAddMember.text,
member_isBeneficiary : true,
member_isPayer : false,
})
} else { // "edit" existing member name by index in listmodel
listModel_activeProjectMembersTEMP.setProperty(editItemIndex, "member_name", idTextfieldAddMember.text)
}
}
focus = false
showTextfieldMemberName = false
}
Label {
anchors.top: parent.bottom
anchors.topMargin: Theme.paddingSmall
font.pixelSize: Theme.fontSizeExtraSmall
text: qsTr("name")
}
}
}
Item {
width: parent.width
height: Theme.itemSizeSmall
}
Row {
width: parent.width
visible: (modeEdit === "edit") && (listModel_allProjects.count > 0) // make sure there is always one project left once created
spacing: Theme.paddingLarge
leftPadding: Theme.paddingLarge
Button {
id: idLabelDeleteProject
width: parent.width /3 - parent.spacing * 1.5
height: idColumnAddProject.height
color: Theme.errorColor
text: (Number(activeProjectID_unixtime) != Number(timeStamp)) ? qsTr("Delete") : qsTr("Reset")
onClicked: {
if (Number(activeProjectID_unixtime) != Number(timeStamp)) { // if it is not the active project, delete it
remorse_deleteProject.execute(qsTr("Delete this project?"), function() {
deleteProject()
})
} else { // if active project
remorse_deleteProject.execute(qsTr("Clear all transactions?"), function() {
clearProject()
})
}
}
}
Button {
id: idLabelBackupProject
width: parent.width /3 - parent.spacing * 1.5
height: idColumnAddProject.height
text: qsTr("Backup")
onClicked: {
// hide() // ToDo: maybe close this popup?
pageStack.push(idFolderPickerPage)
}
}
Button {
id: idLabelRestoreProject
width: parent.width /3 - parent.spacing
height: idColumnAddProject.height
text: qsTr("Restore")
onClicked: {
// hide() // ToDo: maybe close this popup?
pageStack.push(idFilePickerPage)
}
}
}
Item {
width: parent.width
height: Theme.itemSizeSmall / 2
}
}
}
}
}
Icon {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: idBackgroundRectProject.anchors.topMargin / 2 - height/2
source: "image://theme/icon-splus-cancel?"
opacity: 1
}
function notify( color, upperMargin, modeEditNew, indexCurrentProject ) {
// color settings
if (color && (typeof(color) != "undefined")) {
idBackgroundRectProject.color = color
}
else {
idBackgroundRectProject.color = Theme.rgba(Theme.highlightBackgroundColor, 0.9)
}
// position settings
if (upperMargin && (typeof(upperMargin) != "undefined")) {
idBackgroundRectProject.anchors.topMargin = upperMargin
}
else {
idBackgroundRectProject.anchors.topMargin = 0
}
// adjust input fields
tempProjectListIndex = indexCurrentProject
listModel_activeProjectMembersTEMP.clear()
if (modeEditNew === "new") {
modeEdit = "new"
timeStamp = ((new Date).getTime()).toString()
idTextfieldCurrencyProject.text = recentlyUsedCurrency
idTextfieldProjectname.text = ""
idTextfieldProjectname.forceActiveFocus()
} else { // edit project mode
modeEdit = "edit"
var tempProjectMembersArray = []
tempProjectMembersArray = (listModel_allProjects.get(idComboboxProject.currentIndex).project_members).split(" ||| ")
for (var i = 0; i < tempProjectMembersArray.length ; i++) {
listModel_activeProjectMembersTEMP.append({ member_name : tempProjectMembersArray[i],
})
}
timeStamp = (listModel_allProjects.get(idComboboxProject.currentIndex).project_id_timestamp).toString()
idTextfieldProjectname.text = listModel_allProjects.get(idComboboxProject.currentIndex).project_name
idTextfieldCurrencyProject.text = listModel_allProjects.get(idComboboxProject.currentIndex).project_base_currency
}
// all members are beneficiaries
// show banner overlay
popup.opacity = 1.0
}
function hide() {
idTextfieldProjectname.focus = false
idTextfieldCurrencyProject.focus = false
// clear all fields
idTextfieldProjectname.text = ""
idTextfieldCurrencyProject.text = recentlyUsedCurrency
// make invisible
popup.opacity = 0.0
}
function addProjectDB () {
var project_id_timestamp = timeStamp
var project_name = idTextfieldProjectname.text
var project_members = ""
var project_recent_payer_boolarray = ""
var project_recent_beneficiaries_boolarray = ""
var project_base_currency = idTextfieldCurrencyProject.text
for (var i = 0; i < listModel_activeProjectMembersTEMP.count ; i++) {
project_members += " ||| " + listModel_activeProjectMembersTEMP.get(i).member_name
project_recent_beneficiaries_boolarray += " ||| " + "true"
// recent_payer can only be one person, initially this will be the first entry of the list
if (i===0) {
project_recent_payer_boolarray += " ||| " + "true"
} else {
project_recent_payer_boolarray += " ||| " + "false"
}
}
// remove first occurance of " ||| " to later be able to split that string
project_members = project_members.replace(" ||| ", "")
project_recent_payer_boolarray = project_recent_payer_boolarray.replace(" ||| ", "")
project_recent_beneficiaries_boolarray = project_recent_beneficiaries_boolarray.replace(" ||| ", "")
if (modeEdit === "new") {
// store in DB and list for new project
storageItem.setProject( project_id_timestamp, project_name, project_members, project_recent_payer_boolarray, project_recent_beneficiaries_boolarray, project_base_currency )
listModel_allProjects.append({ project_id_timestamp : Number(project_id_timestamp),
project_name : project_name,
project_members : project_members,
project_recent_payer_boolarray : project_recent_payer_boolarray,
project_recent_beneficiaries_boolarray : project_recent_beneficiaries_boolarray,
project_base_currency : project_base_currency,
})
// if this is the first project, auto set it as active project
if (listModel_allProjects.count === 1) { // auto-sets as currently active project, if this project is very first one
storageItem.setSettings("activeProjectID_unixtime", Number(project_id_timestamp) )
activeProjectID_unixtime = Number(project_id_timestamp)
loadActiveProjectInfos_FromDB( Number(project_id_timestamp) )
//console.log("auto set as active project ID = " + activeProjectID_unixtime)
}
} else { // modeEdit === "edit
// update DB and list for existing project
storageItem.updateProject( project_id_timestamp, project_name, project_members, project_recent_payer_boolarray, project_recent_beneficiaries_boolarray, project_base_currency )
for (var j = 0; j < listModel_allProjects.count ; j++) {
if (listModel_allProjects.get(j).project_id_timestamp === Number(project_id_timestamp)) {
//console.log("updated entry at: id_" + project_id_timestamp)
listModel_allProjects.set(j, { "project_name" : project_name,
"project_members" : project_members,
"project_recent_payer_boolarray" : project_recent_payer_boolarray,
"project_recent_beneficiaries_boolarray" : project_recent_beneficiaries_boolarray,
"project_base_currency" : project_base_currency
})
}
}
}
updateEvenWhenCanceled = true
hide()
}
function deleteProject() {
updateEvenWhenCanceled = true
storageItem.deleteProject(timeStamp)
listModel_allProjects.remove(tempProjectListIndex)
// set active project to reasonable one
if (idComboboxProject.currentIndex != 0) {
idComboboxProject.currentIndex = idComboboxProject.currentIndex -1
}
//console.log("auto set after deleting ID = " + Number(listModel_allProjects.get(idComboboxProject.currentIndex).project_id_timestamp))
loadActiveProjectInfos_FromDB(Number(listModel_allProjects.get(idComboboxProject.currentIndex).project_id_timestamp)) // needed to make sure there is no expense or member list still active
hide()
}
function clearProject() {
updateEvenWhenCanceled = true
listModel_activeProjectExpenses.clear()
storageItem.removeFullTable( "table_" + activeProjectID_unixtime.toString() )
loadActiveProjectInfos_FromDB(Number(listModel_allProjects.get(idComboboxProject.currentIndex).project_id_timestamp)) // needed to make sure there is no expense or member list still active
hide()
}
}