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() }