From 055b402c81c6c9ad1529bba599567023926e79e7 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Mon, 21 Apr 2025 20:19:22 +0200 Subject: [PATCH 1/6] feat: add swipe action to refresh report screen --- lib/screens/report_screen.dart | 138 +++++---------------------------- 1 file changed, 21 insertions(+), 117 deletions(-) diff --git a/lib/screens/report_screen.dart b/lib/screens/report_screen.dart index 1c56861..b24c37e 100644 --- a/lib/screens/report_screen.dart +++ b/lib/screens/report_screen.dart @@ -1,7 +1,6 @@ import 'dart:developer'; import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; @@ -16,14 +15,12 @@ DateTime unixSecondsToDateTime(int ts) => DateTime.fromMillisecondsSinceEpoch(ts * 1000, isUtc: true).toLocal(); extension TimeEntryFormatting on TimeEntry { - /// Konvertiert den startTime (Unix Timestamp) in ein lokales DateTime Objekt. DateTime get startDateTime => DateTime.fromMillisecondsSinceEpoch( startTime.toInt() * 1000, isUtc: true, ).toLocal(); - /// Konvertiert den optionalen endTime (Unix Timestamp) in ein lokales DateTime Objekt. DateTime? get endDateTime => endTime == null ? null @@ -32,7 +29,6 @@ extension TimeEntryFormatting on TimeEntry { isUtc: true, ).toLocal(); - /// Formatiert die Dauer (durationSecs) als HH:MM:SS String. String get durationFormatted { final durationInSeconds = durationSecs?.toInt(); if (durationInSeconds == null || durationInSeconds < 0) return '--:--:--'; @@ -47,7 +43,6 @@ extension TimeEntryFormatting on TimeEntry { } extension ReportDataFormatting on ReportData { - /// Formatiert die Gesamtdauer als HH:MM:SS String. String get totalDurationFormatted { final durationInSeconds = totalDurationSecs.toInt(); if (durationInSeconds < 0) return '--:--:--'; @@ -99,8 +94,9 @@ class _ReportScreenState extends State { final Map> dailyTagDurations = {}; for (final entry in entries) { - if (entry.durationSecs == null || entry.durationSecs!.toInt() <= 0) + if (entry.durationSecs == null || entry.durationSecs!.toInt() <= 0) { continue; + } final entryDay = DateTime( entry.startDateTime.year, @@ -393,14 +389,24 @@ class _ReportScreenState extends State { children: [ _buildFilterControls(tagOptions), Expanded( - child: - _isLoadingReport - ? Center(child: PlatformCircularProgressIndicator()) - : _reportData == null - ? const Center( - child: Text('Keine Reportdaten gefunden oder Fehler.'), - ) - : _buildReportView(), + child: RefreshIndicator.adaptive( + onRefresh: _generateReport, + child: + _isLoadingReport + ? Center(child: PlatformCircularProgressIndicator()) + : _reportData == null + ? ListView( + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.5, + child: Text( + 'Keine Reportdaten gefunden oder Fehler.', + ), + ), + ], + ) + : _buildReportView(), + ), ), ], ), @@ -487,8 +493,6 @@ class _ReportScreenState extends State { ), ), ), - // SizedBox(height: 250, child: _buildPieChart(_reportData!)), - // const Divider(), SizedBox( height: 250, child: _buildBarChart(_reportData!, startDate, endDate), @@ -512,103 +516,6 @@ class _ReportScreenState extends State { ); } - Widget _buildPieChart(ReportData data) { - Map durationPerTag = {}; - for (var entry in data.entries) { - final tagName = entry.tagName ?? 'Ohne Tag'; - final duration = (entry.durationSecs?.toInt() ?? 0).toDouble(); - durationPerTag[tagName] = (durationPerTag[tagName] ?? 0) + duration; - } - - if (durationPerTag.isEmpty) { - return const Center(child: Text("Keine Daten für Chart")); - } - - List colors = Colors.primaries.take(durationPerTag.length).toList(); - if (durationPerTag.length > Colors.primaries.length) { - colors.addAll( - Colors.accents.take(durationPerTag.length - Colors.primaries.length), - ); - } - - int colorIndex = 0; - List sections = - durationPerTag.entries.map((entry) { - final isTouched = false; - final fontSize = isTouched ? 18.0 : 14.0; - final radius = isTouched ? 60.0 : 50.0; - final color = colors[colorIndex % colors.length]; - colorIndex++; - - final hours = (entry.value / 3600).toStringAsFixed(1); - - return PieChartSectionData( - color: color, - value: entry.value, - title: '${entry.key}\n${hours}h', - radius: radius, - titleStyle: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.bold, - color: Colors.white, - shadows: [ - Shadow(color: Colors.black.withOpacity(0.7), blurRadius: 2), - ], - ), - titlePositionPercentageOffset: 0.6, - ); - }).toList(); - - return Padding( - padding: const EdgeInsets.all(8.0), - child: PieChart( - PieChartData( - sections: sections, - centerSpaceRadius: 40, - sectionsSpace: 2, - ), - duration: const Duration(milliseconds: 150), - curve: Curves.linear, - ), - ); - } - - // Widget _buildDataTable(List entries) { - // final DateFormat timeFormatter = DateFormat('HH:mm:ss'); - // final DateFormat dateFormatter = DateFormat('dd.MM.yy'); - - // return DataTable( - // columnSpacing: 10, - // columns: [ - // DataColumn(label: PlatformText('Tag')), - // DataColumn(label: PlatformText('Start')), - // DataColumn(label: PlatformText('Ende')), - // DataColumn(label: PlatformText('Dauer'), numeric: true), - // ], - // rows: - // entries.map((entry) { - // return DataRow( - // cells: [ - // DataCell(PlatformText(entry.tagName ?? '-')), - // DataCell( - // PlatformText( - // '${dateFormatter.format(unixSecondsToDateTime(entry.startTime))}\n${timeFormatter.format(unixSecondsToDateTime(entry.startTime))}', - // ), - // ), - // DataCell( - // entry.endTime != null - // ? PlatformText( - // '${dateFormatter.format(unixSecondsToDateTime(entry.endTime!))}\n${timeFormatter.format(unixSecondsToDateTime(entry.endTime!))}', - // ) - // : PlatformText('-'), - // ), - // DataCell(Text(entry.durationFormatted)), - // ], - // ); - // }).toList(), - // ); - // } - void _confirmAndDeleteEntry(TimeEntry entry, BuildContext context) { showPlatformDialog( context: context, @@ -855,10 +762,7 @@ class _ReportScreenState extends State { actions: [ PlatformDialogAction( child: PlatformText('OK'), - onPressed: - () => Navigator.pop( - dialogContext, - ), // Pop using dialog's context + onPressed: () => Navigator.pop(dialogContext), ), ], ), From 4eed56f155b0583fc46fd3354ce7c1658b50cf75 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Mon, 21 Apr 2025 20:20:21 +0200 Subject: [PATCH 2/6] docs: update changelog --- changelog.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 changelog.md diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..d7bfb8d --- /dev/null +++ b/changelog.md @@ -0,0 +1,24 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [unreleased] + +### 🚀 Features + +- Add swipe action to refresh report screen + +## [0.2.0] - 2025-04-16 + +### 🚀 Features + +- Add update and delete functionality to tags and improve report screen + +## [0.1.0] - 2025-04-09 + +### 🚜 Refactor + +- Clean up +- Perform some clean up + + From 9fe11e4796a1c4ec1a6bf8935e65c43fc91467a6 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Mon, 21 Apr 2025 20:31:56 +0200 Subject: [PATCH 3/6] docs: update README --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 23fad13..a4d4d74 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,51 @@ # timetracker -A new Flutter project. +A cross-platform time tracker built with Flutter for the frontend and Rust for the backend logic. Communication is handled via `flutter_rust_bridge`, and data is stored locally on the device using SQLite. The user interface adapts to the native look-and-feel of Android and iOS thanks to `flutter_platform_widgets`. -## Getting Started +## Features -This project is a starting point for a Flutter application. +* **Time Tracking:** Start and stop time tracking entries. +* **Tag Management:** + * Create new tags. + * List all tags. + * Edit tag names (via swipe gesture). + * Delete tags (via swipe gesture, includes confirmation). Associated time entries will have their tag set to NULL. +* **Local Storage:** All data is securely stored in a local SQLite database on the device (managed by Rust). +* **Reporting:** + * Display time entries filtered by period (Day, Week, Month, Year) and optionally by tag. + * Total duration display for the filtered period. + * Visualization using charts (`fl_chart`): + * **Bar chart:** Distribution of daily time spent per tag for the selected period. + * List view for report entries. + * **Pull-to-Refresh:** Manually refresh report data. + * **Swipe-to-Delete:** Delete individual time entries directly from the report list via swipe gesture (with confirmation). +* **Platform-Adaptive UI:** Uses `flutter_platform_widgets` to provide a native appearance on Android (Material Design) and iOS (Cupertino). -A few resources to get you started if this is your first Flutter project: +## Technologies -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +* **Frontend:** Flutter / Dart + * State Management: `provider` + * UI Adaptation: `flutter_platform_widgets` + * Charts: `fl_chart` + * Swipe Actions: `flutter_slidable` + * Intl: `intl` +* **Backend:** Rust + * Database: SQLite (via `rusqlite`) + * Error Handling: `anyhow` + * Logging: `log` +* **Bridge:** `flutter_rust_bridge` +* **Build:** Cargo, Flutter Build Tools, Gradle (Android), Xcode (iOS) -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Architecture + +The app follows a clear separation between UI and logic: + +`Flutter UI (Widgets)` <-> `Dart Service Layer (TimeTrackingService)` <-> `flutter_rust_bridge (Generated Bindings)` <-> `Rust API (api.rs)` <-> `Rust DB Logic (database.rs)` <-> `SQLite Database` + +## Contributing + +Contributions are welcome! Please create an issue to report bugs or suggest new features. Pull requests are also welcome. + +## License + +[MIT License] From 169669315c6dc08d468f808ce9caa6b808146cdc Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Tue, 29 Apr 2025 20:18:36 +0200 Subject: [PATCH 4/6] feat: add pickable daterange to report screen --- lib/main.dart | 7 + lib/screens/report_screen.dart | 272 +++++++++++++++++++++++++++++---- pubspec.lock | 9 +- pubspec.yaml | 5 +- 4 files changed, 258 insertions(+), 35 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index f5c288c..7743e0e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:path_provider/path_provider.dart'; import 'package:timetracker/screens/main_screen.dart'; import 'package:timetracker/src/rust/api.dart'; @@ -68,6 +69,12 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Rust Time Tracker', + supportedLocales: const [Locale('de', 'DE'), Locale('en', '')], + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true), home: const InitializerWidget(), ); diff --git a/lib/screens/report_screen.dart b/lib/screens/report_screen.dart index b24c37e..dcae7ae 100644 --- a/lib/screens/report_screen.dart +++ b/lib/screens/report_screen.dart @@ -1,9 +1,11 @@ import 'dart:developer'; import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:timetracker/src/rust/api.dart'; @@ -56,7 +58,7 @@ extension ReportDataFormatting on ReportData { } } -enum ReportPeriod { day, week, month, year } +enum ReportPeriod { day, week, month, year, custom } class ReportScreen extends StatefulWidget { const ReportScreen({super.key}); @@ -68,6 +70,8 @@ class ReportScreen extends StatefulWidget { class _ReportScreenState extends State { final DateTime _selectedDate = DateTime.now(); ReportPeriod _selectedPeriod = ReportPeriod.day; + DateTime _customStartDate = DateTime.now(); + DateTime _customEndDate = DateTime.now(); Tag? _selectedTag; ReportData? _reportData; bool _isLoadingReport = false; @@ -85,6 +89,9 @@ class _ReportScreenState extends State { @override void initState() { super.initState(); + final now = DateTime.now(); + _customStartDate = DateTime(now.year, now.month, now.day); + _customEndDate = DateTime(now.year, now.month, now.day); _generateReport(); } @@ -330,7 +337,7 @@ class _ReportScreenState extends State { ); } - (DateTime, DateTime) _calculateDateRange() { + (DateTime, DateTime) _calculateDateRange(ReportPeriod period) { final nowLocal = DateTime.now().toLocal(); final startOfDay = DateTime(nowLocal.year, nowLocal.month, nowLocal.day); @@ -352,6 +359,13 @@ class _ReportScreenState extends State { final startOfYear = DateTime(nowLocal.year, 1, 1); final endOfYear = DateTime(nowLocal.year + 1, 1, 1); return (startOfYear, endOfYear); + case ReportPeriod.custom: + final endExclusive = DateTime( + _customEndDate.year, + _customEndDate.month, + _customEndDate.day, + ).add(const Duration(days: 1)); + return (_customStartDate, endExclusive); } } @@ -363,12 +377,33 @@ class _ReportScreenState extends State { }); final timeService = context.read(); - final (start, end) = _calculateDateRange(); final tagId = _selectedTag?.id; - log("Generating report for TagID: $tagId, Start: $start, End: $end"); + late DateTime reportStartDate; + late DateTime reportEndDateExclusive; - final data = await timeService.flGetReport(tagId, start, end); + if (_selectedPeriod == ReportPeriod.custom) { + reportStartDate = _customStartDate; + reportEndDateExclusive = DateTime( + _customEndDate.year, + _customEndDate.month, + _customEndDate.day, + ).add(const Duration(days: 1)); + } else { + final (start, end) = _calculateDateRange(_selectedPeriod); + reportStartDate = start; + reportEndDateExclusive = end; + } + + log( + "Generating report for Period: $_selectedPeriod, TagID: $tagId, Start: $reportStartDate, End (Exclusive): $reportEndDateExclusive", + ); + + final data = await timeService.flGetReport( + tagId, + reportStartDate, + reportEndDateExclusive, + ); if (mounted) { setState(() { @@ -378,6 +413,29 @@ class _ReportScreenState extends State { } } + // Future _generateReport() async { + // if (!mounted) return; + // setState(() { + // _isLoadingReport = true; + // _reportData = null; + // }); + + // final timeService = context.read(); + // final (start, end) = _calculateDateRange(); + // final tagId = _selectedTag?.id; + + // log("Generating report for TagID: $tagId, Start: $start, End: $end"); + + // final data = await timeService.flGetReport(tagId, start, end); + + // if (mounted) { + // setState(() { + // _reportData = data; + // _isLoadingReport = false; + // }); + // } + // } + @override Widget build(BuildContext context) { final tags = context.watch().tags; @@ -405,7 +463,7 @@ class _ReportScreenState extends State { ), ], ) - : _buildReportView(), + : _buildReportView(_reportData!), ), ), ], @@ -415,33 +473,71 @@ class _ReportScreenState extends State { Widget _buildFilterControls(List tagOptions) { final DateFormat formatter = DateFormat('dd.MM.yyyy'); - final (start, end) = _calculateDateRange(); + final String dateRangeButtonText = + '${formatter.format(_customStartDate)} - ${formatter.format(_customEndDate)}'; return Padding( padding: const EdgeInsets.all(8.0), child: Wrap( spacing: 8.0, runSpacing: 4.0, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, children: [ - DropdownButton( - value: _selectedPeriod, - onChanged: (ReportPeriod? newValue) { - if (newValue != null) { - setState(() { - _selectedPeriod = newValue; - }); - _generateReport(); - } - }, - items: - ReportPeriod.values.map((ReportPeriod period) { - return DropdownMenuItem( - value: period, - child: PlatformText( - period.toString().split('.').last.toUpperCase(), - ), - ); - }).toList(), + PlatformWidget( + material: + (_, __) => DropdownButton( + value: _selectedPeriod, + items: [ + ...ReportPeriod.values.map((period) { + String text; + switch (period) { + case ReportPeriod.day: + text = 'Tag'; + break; + case ReportPeriod.week: + text = 'Woche'; + break; + case ReportPeriod.month: + text = 'Monat'; + break; + case ReportPeriod.year: + text = 'Jahr'; + break; + case ReportPeriod.custom: + text = 'Benutzerdefiniert'; + break; + } + return DropdownMenuItem( + value: period, + child: PlatformText(text), + ); + }), + ], + onChanged: (ReportPeriod? newValue) { + if (newValue != null && newValue != _selectedPeriod) { + setState(() { + _selectedPeriod = newValue; + if (_selectedPeriod != ReportPeriod.custom) { + _generateReport(); + } else { + // Optional: Direkt den Picker öffnen, wenn "Custom" gewählt wird? + // WidgetsBinding.instance.addPostFrameCallback((_) => _selectDateRange()); + } + }); + } + }, + ), + // TODO: Cupertino Dropdown Alternative (komplexer, oft wird Button+Picker genutzt) + // Fürs Erste verwenden wir auch auf iOS das Material Dropdown + cupertino: + (_, __) => CupertinoButton( + padding: EdgeInsets.zero, + child: Text(_selectedPeriod.toString().split('.').last), + onPressed: () { + /* Hier müsste ein Picker geöffnet werden */ + }, + ), ), DropdownButton( @@ -462,23 +558,135 @@ class _ReportScreenState extends State { }).toList(), ), - Chip( - label: PlatformText( - '${formatter.format(start)} - ${formatter.format(end.subtract(const Duration(seconds: 1)))}', + if (_selectedPeriod == ReportPeriod.custom) + PlatformElevatedButton( + onPressed: _selectDateRange, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(FontAwesomeIcons.calendar), // PlatformIcons(context)), + const SizedBox(width: 8), + PlatformText(dateRangeButtonText), + ], + ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), - ), ], ), ); } - Widget _buildReportView() { + // Widget _buildFilterControls(List tagOptions) { + // final DateFormat formatter = DateFormat('dd.MM.yyyy'); + // final (start, end) = _calculateDateRange(); + + // return Padding( + // padding: const EdgeInsets.all(8.0), + // child: Wrap( + // spacing: 8.0, + // runSpacing: 4.0, + // alignment: WrapAlignment.center, + // children: [ + // DropdownButton( + // value: _selectedPeriod, + // onChanged: (ReportPeriod? newValue) { + // if (newValue != null) { + // setState(() { + // _selectedPeriod = newValue; + // }); + // _generateReport(); + // } + // }, + // items: + // ReportPeriod.values.map((ReportPeriod period) { + // return DropdownMenuItem( + // value: period, + // child: PlatformText( + // period.toString().split('.').last.toUpperCase(), + // ), + // ); + // }).toList(), + // ), + + // DropdownButton( + // value: _selectedTag, + // hint: PlatformText("Alle Tags"), + // onChanged: (Tag? newValue) { + // setState(() { + // _selectedTag = newValue; + // }); + // _generateReport(); + // }, + // items: + // tagOptions.map((Tag? tag) { + // return DropdownMenuItem( + // value: tag, + // child: PlatformText(tag?.name ?? "Alle Tags"), + // ); + // }).toList(), + // ), + + // Chip( + // label: PlatformText( + // '${formatter.format(start)} - ${formatter.format(end.subtract(const Duration(seconds: 1)))}', + // ), + // ), + // ], + // ), + // ); + // } + + Future _selectDateRange() async { + final DateTimeRange initialRange = DateTimeRange( + start: _customStartDate, + end: _customEndDate, + ); + + final DateTimeRange? picked = await showDateRangePicker( + context: context, + locale: const Locale('de', 'DE'), + initialDateRange: initialRange, + firstDate: DateTime(2020), + lastDate: DateTime.now().add(const Duration(days: 365)), + helpText: 'Zeitraum auswählen', + cancelText: 'Abbrechen', + confirmText: 'Ok', + saveText: 'Speichern', + ); + + if (picked != null) { + if (picked.start != _customStartDate || + picked.end != _customEndDate || + _selectedPeriod != ReportPeriod.custom) { + setState(() { + _customStartDate = DateTime( + picked.start.year, + picked.start.month, + picked.start.day, + ); + _customEndDate = DateTime( + picked.end.year, + picked.end.month, + picked.end.day, + ); + _selectedPeriod = ReportPeriod.custom; + }); + _generateReport(); + } + } + } + + Widget _buildReportView(ReportData reportData) { if (_reportData == null) { return Center( child: PlatformText('Keine Reportdaten geladen oder Fehler.'), ); } - final (startDate, endDate) = _calculateDateRange(); + final (startDate, endDate) = _calculateDateRange( + _selectedPeriod == ReportPeriod.custom + ? ReportPeriod.custom + : _selectedPeriod, + ); return ListView( children: [ diff --git a/pubspec.lock b/pubspec.lock index eb05bdd..77a96e6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -123,6 +123,11 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_platform_widgets: dependency: "direct main" description: @@ -174,10 +179,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.20.2" + version: "0.19.0" leak_tracker: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b4bb4df..b081108 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter cupertino_icons: ^1.0.8 rust_lib_timetracker: @@ -17,7 +19,8 @@ dependencies: flutter_rust_bridge: 2.9.0 ffi: ^2.1.0 path_provider: ^2.1.1 - intl: ^0.20.2 + # intl: ^0.20.2 + intl: ^0.19.0 provider: ^6.1.1 fl_chart: ^0.70.2 flutter_platform_widgets: ^8.0.0 From e73e178d08b6a5bc00b654a3cb408bc2ab40ed86 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 4 Jun 2025 14:56:28 +0000 Subject: [PATCH 5/6] Add renovate.json --- renovate.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..7190a60 --- /dev/null +++ b/renovate.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json" +} From d41cedb5f05632b645999dd19e9a35d1f01f52a5 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Sun, 22 Jun 2025 13:25:31 +0200 Subject: [PATCH 6/6] deps: update dependencies --- pubspec.lock | 24 ++++++++++++------------ pubspec.yaml | 10 ++++------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 77a96e6..8f22e82 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" boolean_selector: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: "direct main" description: @@ -179,18 +179,18 @@ packages: dependency: "direct main" description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -415,10 +415,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" web: dependency: transitive description: @@ -431,10 +431,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.1.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b081108..e250767 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: timetracker description: "A simple timetracking app" -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter flutter_localizations: - sdk: flutter + sdk: flutter cupertino_icons: ^1.0.8 rust_lib_timetracker: @@ -19,8 +19,8 @@ dependencies: flutter_rust_bridge: 2.9.0 ffi: ^2.1.0 path_provider: ^2.1.1 - # intl: ^0.20.2 - intl: ^0.19.0 + intl: ^0.20.2 + # intl: ^0.19.0 provider: ^6.1.1 fl_chart: ^0.70.2 flutter_platform_widgets: ^8.0.0 @@ -36,6 +36,4 @@ dev_dependencies: sdk: flutter flutter: - uses-material-design: true -