334 lines
12 KiB
QML
334 lines
12 KiB
QML
import QtQuick 2.2
|
|
import Sailfish.Silica 1.0
|
|
import "../js/henflow.js" as HF
|
|
import "../js/i18n.js" as I18N
|
|
import "../js/catalog.js" as Catalog
|
|
|
|
// Home: produzione stimata del giorno e coda degli ordini.
|
|
// Porting di HomePage + _buildOrdersListTab dell'app Flutter.
|
|
Page {
|
|
id: page
|
|
allowedOrientations: Orientation.All
|
|
|
|
property var breeds: []
|
|
property var reservations: []
|
|
property var stock: ({})
|
|
property var productionRows: []
|
|
property real totalProduction: 0
|
|
property string hintMsg: ""
|
|
property string banner: ""
|
|
property string lang: "en"
|
|
property bool ready: false
|
|
|
|
function tr(key, arg) { return I18N.t(key, arg, page.lang) }
|
|
|
|
function breedLabel(breedId) {
|
|
var c = Catalog.breedFromId(breedId)
|
|
return c ? page.tr(c.name) : breedId
|
|
}
|
|
|
|
function reload() {
|
|
page.lang = I18N.langFor(appSettings.language, Qt.locale().name)
|
|
page.breeds = appData.breedSettings()
|
|
page.reservations = appData.reservations()
|
|
page.stock = appData.warehouseStock()
|
|
page.accrue()
|
|
page.totalProduction = HF.totalDailyProduction(page.breeds, Catalog.HF_BREEDS)
|
|
page.productionRows = HF.productionDetail(page.breeds, Catalog.HF_BREEDS)
|
|
page.rebuildList()
|
|
page.ready = true
|
|
}
|
|
|
|
// Accrual del magazzino all'apertura (come _loadData in main.dart): i giorni
|
|
// passati dall'ultimo aggiornamento aggiungono la produzione giornaliera;
|
|
// poi le date di consegna vengono ricalcolate sulla coda FIFO.
|
|
function accrue() {
|
|
var today = HF.todayMidnight()
|
|
var last = appData.lastProductionUpdate()
|
|
var since = last ? HF.parseIso(last) : HF.addDays(today, -1)
|
|
var days = HF.dayDiff(since, today)
|
|
if (days > 0) {
|
|
page.stock = HF.accrueStock(page.stock, page.breeds, Catalog.HF_BREEDS, days)
|
|
appData.saveWarehouseStock(page.stock)
|
|
}
|
|
page.reservations = HF.refreshDeliveryDates(page.reservations, page.stock,
|
|
page.breeds, Catalog.HF_BREEDS, today)
|
|
appData.saveReservations(page.reservations)
|
|
appData.saveLastProductionUpdate(HF.isoDay(today))
|
|
}
|
|
|
|
function rebuildList() {
|
|
orderModel.clear()
|
|
var today = HF.todayMidnight()
|
|
for (var i = 0; i < page.reservations.length; i++) {
|
|
var r = page.reservations[i]
|
|
var days = HF.dayDiff(today, HF.parseIso(r.deliveryDate))
|
|
var status
|
|
if (r.isDelivered) status = page.tr("ready_delivery")
|
|
else if (days < 0) status = page.tr("expired")
|
|
else if (days === 0) status = page.tr("today")
|
|
else if (days === 1) status = page.tr("in_day")
|
|
else status = page.tr("in_days", days)
|
|
|
|
orderModel.append({
|
|
"customer": r.customerName,
|
|
"breed": page.breedLabel(r.breedId),
|
|
"eggs": r.eggsRequested,
|
|
"delivery": HF.formatDay(r.deliveryDate),
|
|
"status": status,
|
|
"late": (!r.isDelivered && days < 0),
|
|
"delivered": r.isDelivered
|
|
})
|
|
}
|
|
page.hintMsg = page.reservations.length === 0
|
|
? page.tr("no_reservations") + "\n" + page.tr("use_button")
|
|
: ""
|
|
}
|
|
|
|
function showBanner(text) {
|
|
page.banner = text
|
|
bannerTimer.restart()
|
|
}
|
|
|
|
function openOrder(index) {
|
|
if (page.breeds.length === 0) {
|
|
page.showBanner(page.tr("config_breed_first"))
|
|
return
|
|
}
|
|
var reservation = null
|
|
if (index >= 0 && index < page.reservations.length) {
|
|
reservation = page.reservations[index]
|
|
} else if (page.totalProduction <= 0) {
|
|
page.showBanner(page.tr("need_hen_error"))
|
|
return
|
|
}
|
|
pageStack.push(Qt.resolvedUrl("OrderPage.qml"),
|
|
{ "reservation": reservation,
|
|
"onSaved": function () { page.reload() } })
|
|
}
|
|
|
|
function toggleDelivered(index) {
|
|
var list = page.reservations.slice()
|
|
if (index < 0 || index >= list.length)
|
|
return
|
|
list[index].isDelivered = !list[index].isDelivered
|
|
page.reservations = list
|
|
appData.saveReservations(list)
|
|
page.rebuildList()
|
|
}
|
|
|
|
function deleteOrder(index, item) {
|
|
var list = page.reservations.slice()
|
|
if (index < 0 || index >= list.length)
|
|
return
|
|
list.splice(index, 1)
|
|
page.reservations = list
|
|
appData.saveReservations(list)
|
|
page.rebuildList()
|
|
remorse.execute(item, page.tr("delete"), function () {}, 3000)
|
|
}
|
|
|
|
ListModel { id: orderModel }
|
|
|
|
RemorseItem { id: remorse }
|
|
|
|
Timer {
|
|
id: bannerTimer
|
|
interval: 3000
|
|
onTriggered: page.banner = ""
|
|
}
|
|
|
|
SilicaListView {
|
|
id: listView
|
|
anchors.fill: parent
|
|
model: orderModel
|
|
|
|
header: Column {
|
|
width: listView.width
|
|
|
|
PageHeader {
|
|
title: page.tr("app_title")
|
|
}
|
|
|
|
// card della produzione stimata
|
|
Rectangle {
|
|
x: Theme.horizontalPageMargin
|
|
width: listView.width - 2 * Theme.horizontalPageMargin
|
|
height: productionColumn.height + 2 * Theme.paddingMedium
|
|
radius: Theme.paddingSmall
|
|
color: Theme.rgba(Theme.highlightBackgroundColor, 0.12)
|
|
|
|
Column {
|
|
id: productionColumn
|
|
x: Theme.paddingMedium
|
|
y: Theme.paddingMedium
|
|
width: parent.width - 2 * Theme.paddingMedium
|
|
spacing: Theme.paddingSmall
|
|
|
|
Label {
|
|
text: page.tr("daily_prod_est")
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryColor
|
|
}
|
|
|
|
Label {
|
|
text: page.totalProduction.toFixed(1) + " " + page.tr("eggs_per_day")
|
|
font.pixelSize: Theme.fontSizeHuge
|
|
color: Theme.highlightColor
|
|
}
|
|
|
|
Repeater {
|
|
model: page.productionRows.length
|
|
|
|
delegate: Label {
|
|
width: parent.width
|
|
truncationMode: TruncationMode.Fade
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryColor
|
|
text: page.breedLabel(page.productionRows[index].breedId)
|
|
+ " (" + page.productionRows[index].hens + " "
|
|
+ page.tr("hens") + ") "
|
|
+ page.productionRows[index].daily.toFixed(1) + " "
|
|
+ page.tr("eggs_per_g")
|
|
}
|
|
}
|
|
|
|
Label {
|
|
visible: page.productionRows.length === 0
|
|
width: parent.width
|
|
wrapMode: Text.WordWrap
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryColor
|
|
text: page.tr("no_breeds")
|
|
}
|
|
}
|
|
}
|
|
|
|
Label {
|
|
x: Theme.horizontalPageMargin
|
|
text: page.tr("reservations")
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.secondaryColor
|
|
}
|
|
}
|
|
|
|
delegate: ListItem {
|
|
id: orderItem
|
|
contentHeight: itemColumn.height + 2 * Theme.paddingMedium
|
|
|
|
menu: ContextMenu {
|
|
MenuItem {
|
|
text: orderItem.delivered ? page.tr("new_order") : page.tr("ready_delivery")
|
|
onClicked: page.toggleDelivered(index)
|
|
}
|
|
MenuItem {
|
|
text: page.tr("edit_order")
|
|
onClicked: page.openOrder(index)
|
|
}
|
|
MenuItem {
|
|
text: page.tr("delete")
|
|
onClicked: page.deleteOrder(index, orderItem)
|
|
}
|
|
}
|
|
|
|
Column {
|
|
id: itemColumn
|
|
x: Theme.horizontalPageMargin
|
|
y: Theme.paddingMedium
|
|
width: parent.width - 2 * Theme.horizontalPageMargin - statusLabel.width
|
|
|
|
Label {
|
|
width: parent.width
|
|
text: model.customer
|
|
truncationMode: TruncationMode.Fade
|
|
color: orderItem.highlighted ? Theme.highlightColor : Theme.primaryColor
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
}
|
|
|
|
Label {
|
|
width: parent.width
|
|
truncationMode: TruncationMode.Fade
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryColor
|
|
text: page.tr("breed") + ": " + model.breed
|
|
+ " " + page.tr("eggs_req") + ": " + model.eggs
|
|
}
|
|
|
|
Label {
|
|
width: parent.width
|
|
truncationMode: TruncationMode.Fade
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryColor
|
|
text: page.tr("delivery") + ": " + model.delivery
|
|
}
|
|
}
|
|
|
|
Label {
|
|
id: statusLabel
|
|
anchors {
|
|
right: parent.right
|
|
rightMargin: Theme.horizontalPageMargin
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
text: model.status
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: model.late ? Theme.errorColor
|
|
: (model.delivered ? Theme.secondaryColor : Theme.highlightColor)
|
|
}
|
|
}
|
|
|
|
PullDownMenu {
|
|
MenuItem {
|
|
text: page.tr("new_order")
|
|
onClicked: page.openOrder(-1)
|
|
}
|
|
}
|
|
|
|
footer: Item {
|
|
width: listView.width
|
|
height: footerLabel.height + 3 * Theme.paddingLarge
|
|
|
|
Label {
|
|
id: footerLabel
|
|
x: Theme.horizontalPageMargin
|
|
y: Theme.paddingMedium
|
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
|
visible: page.hintMsg.length > 0
|
|
text: page.hintMsg
|
|
wrapMode: Text.WordWrap
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.secondaryHighlightColor
|
|
}
|
|
}
|
|
|
|
VerticalScrollDecorator {}
|
|
}
|
|
|
|
// banner in basso: Label + Timer (in Silica non esiste un Toast)
|
|
Rectangle {
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
height: bannerLabel.height + 2 * Theme.paddingMedium
|
|
color: Theme.rgba(Theme.highlightBackgroundColor, 0.9)
|
|
visible: page.banner.length > 0
|
|
|
|
Label {
|
|
id: bannerLabel
|
|
x: Theme.horizontalPageMargin
|
|
y: Theme.paddingMedium
|
|
width: parent.width - 2 * Theme.horizontalPageMargin
|
|
text: page.banner
|
|
wrapMode: Text.WordWrap
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
color: Theme.highlightColor
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: page.reload()
|
|
}
|