408 lines
14 KiB
QML
408 lines
14 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
|
|
|
|
// Calendario delle consegne (il tab *Calendar* della Home dell'originale):
|
|
// griglia del mese con un puntino sui giorni che hanno ordini e, sotto,
|
|
// l'elenco degli ordini del giorno scelto.
|
|
// Nomi di mesi e giorni nella lingua del TELEFONO (Qt.locale()), come faceva
|
|
// TableCalendar nell'app Flutter: non sono nelle 126 chiavi dell'app.
|
|
// Tutto sta dentro la lista (griglia compresa): su questa Silica e' il layout
|
|
// che si comporta bene con i menu a tendina.
|
|
Page {
|
|
id: page
|
|
allowedOrientations: Orientation.All
|
|
|
|
property string lang: "en"
|
|
property var reservations: []
|
|
property var orders: []
|
|
property string selectedIso: ""
|
|
property int viewYear: 0
|
|
property int viewMonth: 1
|
|
property string todayIso: ""
|
|
property string monthTitle: ""
|
|
property var weekdayNames: []
|
|
property bool ready: false
|
|
|
|
// Larghezza di una cella del calendario: 7 colonne piene.
|
|
readonly property real cellWidth: width / 7
|
|
readonly property real cellHeight: Theme.itemSizeSmall
|
|
|
|
function tr(key, arg) { return I18N.t(key, arg, page.lang) }
|
|
|
|
ListModel { id: gridModel }
|
|
ListModel { id: ordersModel }
|
|
|
|
function isoOf(y, m, d) {
|
|
return HF.isoDay(new Date(y, m - 1, d))
|
|
}
|
|
|
|
function countFor(iso) {
|
|
var n = 0
|
|
for (var i = 0; i < page.reservations.length; i++) {
|
|
var d = HF.parseIso(page.reservations[i].deliveryDate)
|
|
if (d && HF.isoDay(d) === iso)
|
|
n++
|
|
}
|
|
return n
|
|
}
|
|
|
|
function buildWeekdays() {
|
|
var names = []
|
|
for (var i = 1; i <= 7; i++)
|
|
names.push(Qt.locale().dayName(i, Locale.ShortFormat))
|
|
page.weekdayNames = names
|
|
}
|
|
|
|
function updateTitle() {
|
|
page.monthTitle = Qt.locale().monthName(page.viewMonth, Locale.LongFormat)
|
|
+ " " + page.viewYear
|
|
}
|
|
|
|
function reload() {
|
|
page.lang = I18N.langFor(appSettings.language, Qt.locale().name)
|
|
page.reservations = appData.reservations()
|
|
|
|
var today = HF.todayMidnight()
|
|
page.todayIso = HF.isoDay(today)
|
|
if (page.viewYear === 0) {
|
|
page.viewYear = today.getFullYear()
|
|
page.viewMonth = today.getMonth() + 1
|
|
}
|
|
if (page.selectedIso.length === 0)
|
|
page.selectedIso = page.todayIso
|
|
|
|
page.buildWeekdays()
|
|
page.updateTitle()
|
|
page.buildGrid()
|
|
page.buildOrders()
|
|
}
|
|
|
|
function buildGrid() {
|
|
gridModel.clear()
|
|
|
|
var first = new Date(page.viewYear, page.viewMonth - 1, 1)
|
|
// settimana che inizia di lunedi: getDay() da' 0 = domenica
|
|
var offset = (first.getDay() + 6) % 7
|
|
var daysInMonth = new Date(page.viewYear, page.viewMonth, 0).getDate()
|
|
|
|
for (var i = 0; i < offset; i++)
|
|
gridModel.append({ "day": 0, "iso": "", "count": 0, "today": false, "selected": false })
|
|
|
|
for (var d = 1; d <= daysInMonth; d++) {
|
|
var iso = page.isoOf(page.viewYear, page.viewMonth, d)
|
|
gridModel.append({
|
|
"day": d,
|
|
"iso": iso,
|
|
"count": page.countFor(iso),
|
|
"today": iso === page.todayIso,
|
|
"selected": iso === page.selectedIso
|
|
})
|
|
}
|
|
|
|
while (gridModel.count % 7 !== 0)
|
|
gridModel.append({ "day": 0, "iso": "", "count": 0, "today": false, "selected": false })
|
|
}
|
|
|
|
function buildOrders() {
|
|
ordersModel.clear()
|
|
var today = HF.todayMidnight()
|
|
for (var i = 0; i < page.reservations.length; i++) {
|
|
var r = page.reservations[i]
|
|
var d = HF.parseIso(r.deliveryDate)
|
|
if (!d || HF.isoDay(d) !== page.selectedIso)
|
|
continue
|
|
|
|
var days = HF.dayDiff(today, d)
|
|
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)
|
|
|
|
var breed = Catalog.breedFromId(r.breedId)
|
|
ordersModel.append({
|
|
"id": r.id,
|
|
"customer": r.customerName,
|
|
"breed": breed ? page.tr(breed.name) : r.breedId,
|
|
"eggs": r.eggsRequested,
|
|
"note": r.clientNote ? r.clientNote : "",
|
|
"status": status,
|
|
"late": (!r.isDelivered && days < 0),
|
|
"delivered": r.isDelivered
|
|
})
|
|
}
|
|
}
|
|
|
|
function shiftMonth(delta) {
|
|
var m = page.viewMonth + delta
|
|
var y = page.viewYear
|
|
if (m < 1) {
|
|
m = 12
|
|
y--
|
|
} else if (m > 12) {
|
|
m = 1
|
|
y++
|
|
}
|
|
page.viewMonth = m
|
|
page.viewYear = y
|
|
page.updateTitle()
|
|
page.buildGrid()
|
|
}
|
|
|
|
function selectDay(iso) {
|
|
if (iso.length === 0)
|
|
return
|
|
page.selectedIso = iso
|
|
page.buildGrid()
|
|
page.buildOrders()
|
|
}
|
|
|
|
function goToday() {
|
|
var today = HF.todayMidnight()
|
|
page.viewYear = today.getFullYear()
|
|
page.viewMonth = today.getMonth() + 1
|
|
page.selectedIso = page.todayIso
|
|
page.updateTitle()
|
|
page.buildGrid()
|
|
page.buildOrders()
|
|
}
|
|
|
|
function openOrder(index) {
|
|
var id = page.orders[index].id
|
|
var list = appData.reservations()
|
|
var reservation = null
|
|
for (var i = 0; i < list.length; i++) {
|
|
if (list[i].id === id)
|
|
reservation = list[i]
|
|
}
|
|
pageStack.push(Qt.resolvedUrl("OrderPage.qml"),
|
|
{ "reservation": reservation,
|
|
"onSaved": function () { page.reload() } })
|
|
}
|
|
|
|
// Consegnato: come l'originale, segnare la consegna SCALA le uova dal
|
|
// magazzino (e annullarla le rimette).
|
|
function toggleDelivered(index) {
|
|
var id = page.orders[index].id
|
|
var list = appData.reservations().slice()
|
|
for (var i = 0; i < list.length; i++) {
|
|
if (list[i].id === id) {
|
|
list[i].isDelivered = !list[i].isDelivered
|
|
appData.saveWarehouseStock(
|
|
HF.applyDelivery(appData.warehouseStock(), list[i], list[i].isDelivered))
|
|
}
|
|
}
|
|
appData.saveReservations(list)
|
|
page.reload()
|
|
}
|
|
|
|
Component.onCompleted: page.reload()
|
|
|
|
onStatusChanged: {
|
|
if (status !== PageStatus.Active)
|
|
return
|
|
if (page.ready)
|
|
page.reload()
|
|
page.ready = true
|
|
}
|
|
|
|
SilicaListView {
|
|
id: dayList
|
|
anchors.fill: parent
|
|
model: ordersModel
|
|
|
|
header: Column {
|
|
width: dayList.width
|
|
|
|
PageHeader { title: page.tr("calendar") }
|
|
|
|
// navigazione fra i mesi
|
|
Row {
|
|
x: Theme.horizontalPageMargin
|
|
width: dayList.width - 2 * Theme.horizontalPageMargin
|
|
spacing: Theme.paddingSmall
|
|
|
|
IconButton {
|
|
id: prevButton
|
|
icon.source: "image://theme/icon-m-left"
|
|
onClicked: page.shiftMonth(-1)
|
|
}
|
|
|
|
Label {
|
|
anchors.verticalCenter: prevButton.verticalCenter
|
|
width: parent.width - 2 * (prevButton.width + parent.spacing)
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: page.monthTitle
|
|
color: Theme.highlightColor
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
truncationMode: TruncationMode.Fade
|
|
}
|
|
|
|
IconButton {
|
|
icon.source: "image://theme/icon-m-right"
|
|
onClicked: page.shiftMonth(1)
|
|
}
|
|
}
|
|
|
|
// intestazione dei giorni della settimana
|
|
Row {
|
|
x: Theme.horizontalPageMargin
|
|
width: dayList.width - 2 * Theme.horizontalPageMargin
|
|
|
|
Repeater {
|
|
model: page.weekdayNames.length
|
|
delegate: Label {
|
|
width: page.cellWidth
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: page.weekdayNames[index]
|
|
color: Theme.secondaryColor
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
truncationMode: TruncationMode.Fade
|
|
}
|
|
}
|
|
}
|
|
|
|
// griglia del mese
|
|
Grid {
|
|
x: Theme.horizontalPageMargin
|
|
width: dayList.width - 2 * Theme.horizontalPageMargin
|
|
height: (gridModel.count / 7) * page.cellHeight
|
|
columns: 7
|
|
|
|
Repeater {
|
|
model: gridModel
|
|
|
|
delegate: BackgroundItem {
|
|
id: cell
|
|
width: page.cellWidth
|
|
height: page.cellHeight
|
|
|
|
onClicked: page.selectDay(model.iso)
|
|
|
|
Rectangle {
|
|
anchors.centerIn: parent
|
|
width: Math.min(parent.width, parent.height) - Theme.paddingMedium
|
|
height: width
|
|
radius: width / 2
|
|
color: model.selected ? Theme.highlightBackgroundColor
|
|
: (model.today ? Theme.rgba(Theme.highlightBackgroundColor, 0.35)
|
|
: "transparent")
|
|
|
|
Label {
|
|
anchors.centerIn: parent
|
|
text: model.day > 0 ? String(model.day) : ""
|
|
color: model.selected ? Theme.highlightColor
|
|
: (model.day > 0 ? Theme.primaryColor : Theme.secondaryColor)
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
}
|
|
}
|
|
|
|
// puntino: quel giorno ha ordini
|
|
Rectangle {
|
|
visible: model.count > 0
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
bottom: parent.bottom
|
|
bottomMargin: Theme.paddingSmall
|
|
}
|
|
width: Theme.paddingSmall
|
|
height: width
|
|
radius: width / 2
|
|
color: Theme.highlightColor
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item { width: parent.width; height: Theme.paddingMedium }
|
|
|
|
SectionHeader {
|
|
text: HF.formatDay(page.selectedIso) + " (" + ordersModel.count + ")"
|
|
}
|
|
}
|
|
|
|
delegate: ListItem {
|
|
id: orderItem
|
|
contentHeight: orderText.height + Theme.paddingMedium
|
|
|
|
Column {
|
|
id: orderText
|
|
x: Theme.horizontalPageMargin
|
|
y: Theme.paddingMedium
|
|
width: parent.width - 2 * Theme.horizontalPageMargin - deliveredSwitch.width
|
|
- Theme.paddingMedium
|
|
spacing: Theme.paddingSmall
|
|
|
|
Label {
|
|
width: parent.width
|
|
text: model.customer
|
|
color: orderItem.highlighted ? Theme.highlightColor : Theme.primaryColor
|
|
truncationMode: TruncationMode.Fade
|
|
}
|
|
|
|
Label {
|
|
width: parent.width
|
|
text: page.tr("breed") + ": " + model.breed + " · " + page.tr("eggs_req") + ": " + model.eggs
|
|
color: Theme.secondaryColor
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
truncationMode: TruncationMode.Fade
|
|
}
|
|
|
|
Label {
|
|
width: parent.width
|
|
text: model.status
|
|
color: model.late ? Theme.errorColor : Theme.secondaryColor
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
truncationMode: TruncationMode.Fade
|
|
}
|
|
|
|
Label {
|
|
width: parent.width
|
|
visible: model.note.length > 0
|
|
text: page.tr("client_note") + ": " + model.note
|
|
color: Theme.secondaryColor
|
|
font.pixelSize: Theme.fontSizeExtraSmall
|
|
wrapMode: Text.Wrap
|
|
}
|
|
}
|
|
|
|
Switch {
|
|
id: deliveredSwitch
|
|
anchors {
|
|
right: parent.right
|
|
rightMargin: Theme.horizontalPageMargin
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
checked: model.delivered
|
|
onClicked: page.toggleDelivered(index)
|
|
}
|
|
|
|
onClicked: page.openOrder(index)
|
|
}
|
|
|
|
ViewPlaceholder {
|
|
enabled: ordersModel.count === 0
|
|
text: page.tr("no_reservations")
|
|
}
|
|
|
|
PullDownMenu {
|
|
MenuItem {
|
|
text: page.tr("today")
|
|
onClicked: page.goToday()
|
|
}
|
|
MenuItem {
|
|
text: page.tr("new_order")
|
|
onClicked: pageStack.push(Qt.resolvedUrl("OrderPage.qml"),
|
|
{ "reservation": null,
|
|
"onSaved": function () { page.reload() } })
|
|
}
|
|
}
|
|
|
|
VerticalScrollDecorator {}
|
|
}
|
|
}
|