From 10cb1152a2cb76609e6f65a0e7a2690013d3de16 Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Tue, 12 Apr 2022 00:24:14 -0500 Subject: Initial version of custom reports in iOS --- .../iosApp/Details/Reports/UnitReportsView.swift | 130 ++++++++++----------- .../Details/Reports/UnitReportsViewModel.swift | 50 +++++++- iosApp/iosApp/en.lproj/Localizable.strings | 3 + iosApp/iosApp/es-419.lproj/Localizable.strings | 3 + .../mx/trackermap/TrackerMap/utils/ReportDates.kt | 11 ++ .../mx/trackermap/TrackerMap/utils/DateUtils.kt | 22 ++++ 6 files changed, 150 insertions(+), 69 deletions(-) create mode 100644 shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/DateUtils.kt diff --git a/iosApp/iosApp/Details/Reports/UnitReportsView.swift b/iosApp/iosApp/Details/Reports/UnitReportsView.swift index e189835..4f4378f 100644 --- a/iosApp/iosApp/Details/Reports/UnitReportsView.swift +++ b/iosApp/iosApp/Details/Reports/UnitReportsView.swift @@ -31,6 +31,9 @@ struct UnitReportsView: View { self.unit = unit self._unitReportsViewModel = StateObject( wrappedValue: UnitReportsViewModel(deviceId: unit.device.id)) + // Source: https://stackoverflow.com/a/63607411 + UITableView.appearance().contentInset.top = -35 + UITableView.appearance().contentInset.bottom = -25 } private var eventsConfig: TablerListConfig { @@ -111,76 +114,71 @@ struct UnitReportsView: View { isReport: true) } - VStack { - HStack { - Text("report-period") - Spacer() - Picker(selection: $unitReportsViewModel.reportPeriod) { - Text("period-today").tag(ReportDates.ReportPeriod.today) - Text("period-last-24").tag(ReportDates.ReportPeriod.last24) - Text("period-yesterday").tag(ReportDates.ReportPeriod.yesterday) - Text("period-this-week").tag(ReportDates.ReportPeriod.thisWeek) - Text("period-last-7").tag(ReportDates.ReportPeriod.last7) - Text("period-this-month").tag(ReportDates.ReportPeriod.thisMonth) - Text("period-last-30").tag(ReportDates.ReportPeriod.last30) - } label: { - switch unitReportsViewModel.reportPeriod { - case .today: - Text("period-today") - case .last24: - Text("period-last-24") - case .yesterday: - Text("period-yesterday") - case .thisWeek: - Text("period-this-week") - case .last7: - Text("period-last-7") - case .thisMonth: - Text("period-this-month") - case .last30: - Text("period-last-30") - default: - Text("period-today") - } + // MARK: - Report type + Picker(selection: $unitReportsViewModel.reportType) { + Text("report-positions").tag(ReportController.ReportType.positions) + Text("report-events").tag(ReportController.ReportType.events) + Text("report-stops").tag(ReportController.ReportType.stops) + } label: { + EmptyView() + } + .pickerStyle(SegmentedPickerStyle()) + .padding() + + Form { + // MARK: - Report period + Section { + Picker(selection: $unitReportsViewModel.periodType, label: Text("report-period")) { + Text("period-today").tag(ReportDates.PeriodTypes.today) + Text("period-last-24").tag(ReportDates.PeriodTypes.last24) + Text("period-yesterday").tag(ReportDates.PeriodTypes.yesterday) + Text("period-this-week").tag(ReportDates.PeriodTypes.thisWeek) + Text("period-last-7").tag(ReportDates.PeriodTypes.last7) + Text("period-this-month").tag(ReportDates.PeriodTypes.thisMonth) + Text("period-last-30").tag(ReportDates.PeriodTypes.last30) + Text("period-custom").tag(ReportDates.PeriodTypes.custom) } - }.padding() - Picker(selection: $unitReportsViewModel.reportType) { - Text("report-positions").tag(ReportController.ReportType.positions) - Text("report-events").tag(ReportController.ReportType.events) - Text("report-stops").tag(ReportController.ReportType.stops) - } label: { - EmptyView() - }.pickerStyle(SegmentedPickerStyle()) - - HStack { - Group { - Button { - unitReportsViewModel.saveXlsxReport() - } label: { - Text("report-save") + + if unitReportsViewModel.periodType == .custom { + DatePicker(selection: $unitReportsViewModel.fromDate) { + Text("period-from") } - - Button { - unitReportsViewModel.shareXlsxReport() - } label: { - Text("report-share") - } - }.frame(maxWidth: .infinity) - }.padding() - .sheet(isPresented: $unitReportsViewModel.showShareDialog) { - ShareView(activityItems: $unitReportsViewModel.activityItems) - } - .fileExporter(isPresented: $unitReportsViewModel.showExportDialog, - documents: [unitReportsViewModel.saveDocument], - contentType: .xlsx) { result in - switch result { - case .success (let url): - print ("Saved to \(url)") - case .failure (let error): - print (error.localizedDescription) + + DatePicker(selection: $unitReportsViewModel.toDate) { + Text("period-to") } } - }.padding() + } + + // MARK: - Report actions + Section { + Button { + unitReportsViewModel.saveXlsxReport() + } label: { + Text("report-save") + }.frame(maxWidth: .infinity) + + Button { + unitReportsViewModel.shareXlsxReport() + } label: { + Text("report-share") + }.frame(maxWidth: .infinity) + } + } + .frame(maxHeight: 150) + .sheet(isPresented: $unitReportsViewModel.showShareDialog) { + ShareView(activityItems: $unitReportsViewModel.activityItems) + } + .fileExporter(isPresented: $unitReportsViewModel.showExportDialog, + documents: [unitReportsViewModel.saveDocument], + contentType: .xlsx) { result in + switch result { + case .success (let url): + print ("Saved to \(url)") + case .failure (let error): + print (error.localizedDescription) + } + } }.onAppear { unitReportsViewModel.fetchReport() } diff --git a/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift b/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift index e5b3e4b..450bfa7 100644 --- a/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift +++ b/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift @@ -29,12 +29,38 @@ class UnitReportsViewModel: ObservableObject { } @Published var deviceId: Int32? = nil + + // MARK: - Report settings @Published var reportType: ReportController.ReportType = .positions { didSet { fetchReport() } } - @Published var reportPeriod: ReportDates.ReportPeriod = .today { + @Published var periodType: ReportDates.PeriodTypes = .today { + didSet { + switch periodType { + case .today: + reportPeriod = ReportDates.ReportPeriodToday() + case .last24: + reportPeriod = ReportDates.ReportPeriodLast24() + case .yesterday: + reportPeriod = ReportDates.ReportPeriodYesterday() + case .thisWeek: + reportPeriod = ReportDates.ReportPeriodThisWeek() + case .last7: + reportPeriod = ReportDates.ReportPeriodLast7() + case .thisMonth: + reportPeriod = ReportDates.ReportPeriodThisMonth() + case .last30: + reportPeriod = ReportDates.ReportPeriodLast30() + case .custom: + reportPeriod = ReportDates.ReportPeriodCustom(from: nil, to: nil) + default: + reportPeriod = ReportDates.ReportPeriodToday() + } + } + } + @Published var reportPeriod: ReportDates.ReportPeriod = ReportDates.ReportPeriodToday() { didSet { fetchReport() } @@ -67,7 +93,25 @@ class UnitReportsViewModel: ObservableObject { @Published var markers = [Marker]() @Published var selectedMarker: Marker? = nil - // Geofences + @Published var fromDate: Date = Date() { + didSet { + if let custom = reportPeriod as? ReportDates.ReportPeriodCustom { + reportPeriod = custom.withFrom( + from: DateUtils.companion.iosDateToKotlin(date: fromDate)) + } + } + } + + @Published var toDate: Date = Calendar.current.startOfDay(for: Date()) { + didSet { + if let custom = reportPeriod as? ReportDates.ReportPeriodCustom { + reportPeriod = custom.withTo( + to: DateUtils.companion.iosDateToKotlin(date: toDate)) + } + } + } + + // MARK: - Geofences @Published var geofences: [Int: Geofence] = [:] { didSet { flatGeofences = Array(geofences.values) @@ -75,7 +119,7 @@ class UnitReportsViewModel: ObservableObject { } @Published var flatGeofences: [Geofence] = [] - // Save and share + // MARK: - Save and share var xlsxAction: XlsxAction = .save var saveDocument = XlsxFile() @Published var showExportDialog: Bool = false diff --git a/iosApp/iosApp/en.lproj/Localizable.strings b/iosApp/iosApp/en.lproj/Localizable.strings index fee132b..ca1c3b8 100644 --- a/iosApp/iosApp/en.lproj/Localizable.strings +++ b/iosApp/iosApp/en.lproj/Localizable.strings @@ -67,6 +67,9 @@ "period-last-7" = "Last 7d"; "period-this-month" = "Month"; "period-last-30" = "Last 30d"; +"period-custom" = "Custom"; +"period-from" = "Start"; +"period-to" = "End"; "events-table-event" = "Event"; "events-table-datetime" = "Datetime"; diff --git a/iosApp/iosApp/es-419.lproj/Localizable.strings b/iosApp/iosApp/es-419.lproj/Localizable.strings index 0105e5d..146da98 100644 --- a/iosApp/iosApp/es-419.lproj/Localizable.strings +++ b/iosApp/iosApp/es-419.lproj/Localizable.strings @@ -67,6 +67,9 @@ "period-last-7" = "Últimos 7d"; "period-this-month" = "Mes"; "period-last-30" = "Últimos 30d"; +"period-custom" = "Personalizado"; +"period-from" = "Inicio"; +"period-to" = "Fin"; "events-table-event" = "Evento"; "events-table-datetime" = "Fecha y hora"; diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/ReportDates.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/ReportDates.kt index 6c86d27..5298df3 100644 --- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/ReportDates.kt +++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/ReportDates.kt @@ -22,6 +22,17 @@ import kotlinx.datetime.* @DelicateCoroutinesApi class ReportDates { + enum class PeriodTypes { + TODAY, + LAST_24, + YESTERDAY, + THIS_WEEK, + LAST_7, + THIS_MONTH, + LAST_30, + CUSTOM + } + sealed class ReportPeriod { val timezone = TimeZone.currentSystemDefault() val clock = Clock.System diff --git a/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/DateUtils.kt b/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/DateUtils.kt new file mode 100644 index 0000000..7286ea5 --- /dev/null +++ b/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/DateUtils.kt @@ -0,0 +1,22 @@ +package mx.trackermap.TrackerMap.utils + +import kotlinx.datetime.* +import platform.Foundation.NSDate +import platform.Foundation.NSDateFormatter + +actual class DateUtils { + actual companion object { + fun iosDateToKotlin(date: NSDate): LocalDateTime { + val timezone = TimeZone.currentSystemDefault() + return date.toKotlinInstant().toLocalDateTime(timezone) + } + + actual fun formatDate(date: LocalDateTime): String { + val timezone = TimeZone.currentSystemDefault() + val iosDate = date.toInstant(timezone).toNSDate() + val formatter = NSDateFormatter() + formatter.setDateFormat("yyyy-MM-dd HH:mm") + return formatter.stringFromDate(iosDate) + } + } +} \ No newline at end of file -- cgit v1.2.3