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 {} } }