diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..7e7e7f6 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/lib/extensions/dateOfTimeExtensions.dart b/lib/extensions/dateOfTimeExtensions.dart new file mode 100644 index 0000000..7999ed4 --- /dev/null +++ b/lib/extensions/dateOfTimeExtensions.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +extension TimeExtensions on DateTime { + DateTime forwardTo(TimeOfDay timeOfDay) { + final now = DateTime.now(); + final today = DateTime(now.year, now.month, now.day); + DateTime result; + + final targetTime = DateTime(now.year, now.month, now.day, timeOfDay.hour, timeOfDay.minute); + if (targetTime.isBefore(now) || targetTime.isAtSameMomentAs(now)) { + result = today.add(Duration(days: 1)); + } else { + result = today; + } + + return result.add(Duration(hours: timeOfDay.hour, minutes: timeOfDay.minute)); + } + + bool isBetweenTimeOfDay(TimeOfDay start, TimeOfDay end) { + final now = this; + final today = DateTime(now.year, now.month, now.day); + + final startTime = today.add(Duration(hours: start.hour, minutes: start.minute)); + final endTime = today.add(Duration(hours: end.hour, minutes: end.minute)); + + return now.isAfter(startTime) && now.isBefore(endTime); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 18614f9..fbb3799 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,4 @@ -import 'package:app/state/legalStatusState.dart'; +import 'package:app/state/timeStatusState.dart'; import 'package:app/state/mapState.dart'; import 'package:app/view/home.dart'; import 'package:flutter/material.dart'; @@ -8,7 +8,7 @@ void main() { runApp( MultiProvider( providers: [ - ChangeNotifierProvider(create: (context) => LegalStatusState()), + ChangeNotifierProvider(create: (context) => TimeStatusState()), ChangeNotifierProvider(create: (context) => MapState()), ], builder: (context, child) => const MyApp(), diff --git a/lib/state/legalStatusState.dart b/lib/state/legalStatusState.dart deleted file mode 100644 index ebbcb8b..0000000 --- a/lib/state/legalStatusState.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:app/model/legelState.dart'; -import 'package:app/model/stateInfo.dart'; -import 'package:flutter/material.dart'; - -class LegalStatusState extends ChangeNotifier { - LegalState _legalState = LegalState.unknown; - - LegalState get getLegalState => _legalState; - - StateInfo get info { - switch(_legalState) { - case LegalState.allowed: - return StateInfo( - icon: Icons.check, - color: Colors.lightGreen, - title: "Passt", - subtitle: "Alle kriterien erfüllt", - description: "asd" - ); - - case LegalState.disallowedTime: - return StateInfo( - icon: Icons.timer_outlined, - color: Colors.amber, - title: "Zu früh", - subtitle: "Bubazen ist nur zwischn 20 und 6 uhr Abends/ Nachts erlaubt!", - description: "asd" - ); - - case LegalState.disallowedRegion: - return StateInfo( - icon: Icons.location_off_outlined, - color: Colors.red, - title: "Zu nah an einem geschützen Gebäude", - subtitle: "asd", - description: "asd" - ); - - case LegalState.unknown: - default: - return StateInfo( - icon: Icons.question_mark_outlined, - color: Colors.grey, - title: "Status nicht bekannt", - subtitle: "asd", - description: "asd" - ); - } - } - - - set setInSightOfDisallowedAreas(bool isInSight) { - _legalState = LegalState.disallowedRegion; - notifyListeners(); - } - - set setIsInDisallowedTimeRanges(bool isInDisallowedTime) { - _legalState = LegalState.disallowedTime; - notifyListeners(); - } -} \ No newline at end of file diff --git a/lib/state/mapState.dart b/lib/state/mapState.dart index 6383c63..9da94ee 100644 --- a/lib/state/mapState.dart +++ b/lib/state/mapState.dart @@ -1,11 +1,14 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter_map/flutter_map.dart'; class MapState extends ChangeNotifier { bool _isLocationLock = false; - bool _isCurrentlyFetchin = true; + bool _isCurrentlyFetchin = false; + final MapController _mapController = MapController(); bool get followLocation => _isLocationLock; bool get isCurrentlyFetching => _isCurrentlyFetchin; + MapController get getMapController => _mapController; toggleLocationLock() { _isLocationLock = !_isLocationLock; diff --git a/lib/state/timeStatusState.dart b/lib/state/timeStatusState.dart new file mode 100644 index 0000000..7518af7 --- /dev/null +++ b/lib/state/timeStatusState.dart @@ -0,0 +1,46 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class TimeStatusState extends ChangeNotifier { + final TimeOfDay legalStart = const TimeOfDay(hour: 20, minute: 00); + final TimeOfDay legalEnd = const TimeOfDay(hour: 07, minute: 00); + + late Timer _refreshTimer; + + TimeStatusState() { + _refreshTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + notifyListeners(); + }); + } + + bool get isCurrentlyLegal { + final now = TimeOfDay.now(); + final currentTime = DateTime.now(); + + final startDateTime = DateTime(currentTime.year, currentTime.month, currentTime.day, legalStart.hour, legalStart.minute); + final currentDateTime = currentTime.subtract(Duration(hours: now.hour, minutes: now.minute)); + + return currentDateTime.isBefore(startDateTime); + } + + Duration get remainingTimeUntilStart { + final now = DateTime.now(); + final today = DateTime(now.year, now.month, now.day); + final targetDateTime = today.add(Duration(hours: legalStart.hour, minutes: legalStart.minute)); + + if (now.isBefore(targetDateTime)) { + return targetDateTime.difference(now); + } else { + final nextDay = today.add(const Duration(days: 1)); + final nextTargetDateTime = nextDay.add(Duration(hours: legalStart.hour, minutes: legalStart.minute)); + return nextTargetDateTime.difference(now); + } + } + + @override + void dispose() { + _refreshTimer.cancel(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/view/home.dart b/lib/view/home.dart index 49e4da2..9bc7c9a 100644 --- a/lib/view/home.dart +++ b/lib/view/home.dart @@ -1,5 +1,7 @@ + import 'package:app/extensions/obtainProviderExtension.dart'; import 'package:app/state/mapState.dart'; +import 'package:app/state/timeStatusState.dart'; import 'package:app/util/loadingContainer.dart'; import 'package:app/util/watchState.dart'; import 'package:app/view/appInfo.dart'; @@ -46,10 +48,14 @@ class _HomePageState extends State { ), body: Column( children: [ - const SizedBox( - height: 100, - child: StatusView(), - ), + WatchState((context, state) { + if(state.isCurrentlyLegal) return const SizedBox.shrink(); + + return const SizedBox( + height: 100, + child: StatusView(), + ); + }), Expanded( child: Consumer( builder: (context, state, child) { diff --git a/lib/view/map.dart b/lib/view/map.dart index 9ccc0af..3bf59be 100644 --- a/lib/view/map.dart +++ b/lib/view/map.dart @@ -1,3 +1,5 @@ +import 'package:app/extensions/obtainProviderExtension.dart'; +import 'package:app/state/mapState.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:http/http.dart'; @@ -15,6 +17,7 @@ class _MapViewState extends State { @override Widget build(BuildContext context) { return FlutterMap( + mapController: context.obtainState().getMapController, options: const MapOptions( initialCenter: LatLng(50.354, 7.5845), initialZoom: 16, @@ -26,9 +29,9 @@ class _MapViewState extends State { TileLayer( urlTemplate: "https://bubatzkarte.de/tiles/radius/100/{z}/{x}/{y}.png", tileProvider: NetworkTileProvider( - httpClient: RetryClient( - Client(), - when: (response) => response.statusCode == 502) + httpClient: RetryClient( + Client(), + when: (response) => response.statusCode == 502) ), ) ], diff --git a/lib/view/status.dart b/lib/view/status.dart index 81c4a40..4f0679e 100644 --- a/lib/view/status.dart +++ b/lib/view/status.dart @@ -1,25 +1,26 @@ import 'package:app/util/watchState.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_timer_countdown/flutter_timer_countdown.dart'; -import '../state/legalStatusState.dart'; +import '../state/timeStatusState.dart'; class StatusView extends StatelessWidget { const StatusView({super.key}); @override Widget build(BuildContext context) { - return WatchState((context, state) { + return WatchState((context, state) { return Container( decoration: BoxDecoration( - color: state.info.color + color: Theme.of(context).colorScheme.surface ), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Center( + const Center( child: Icon( - state.info.icon, + Icons.timer_outlined, size: 40, ), ), @@ -28,7 +29,7 @@ class StatusView extends StatelessWidget { indent: 20, color: Colors.white, thickness: 3, - width: 30, + width: 40, ), Center( child: Column( @@ -36,21 +37,22 @@ class StatusView extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - state.info.title, - style: const TextStyle(fontSize: 20), + const Text( + "Ab 20 Uhr", + style: TextStyle(fontSize: 20), + ), + TimerCountdown( + format: CountDownTimerFormat.hoursMinutesSeconds, + enableDescriptions: false, + spacerWidth: 5, + endTime: DateTime.now().add(state.remainingTimeUntilStart), + onEnd: () { + print("Timer finished"); + }, ), - Text(state.info.subtitle), ], ), ), - const SizedBox(width: 20), - IconButton( - icon: const Icon(Icons.info_outline), - onPressed: () { - - }, - ) ], ) ); diff --git a/pubspec.lock b/pubspec.lock index 0c6de39..1a142e6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -163,6 +163,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_timer_countdown: + dependency: "direct main" + description: + name: flutter_timer_countdown + sha256: "0c73e1593ad7949c007752199a17e7ed50bb581568743dbc32f061f49873219e" + url: "https://pub.dev" + source: hosted + version: "1.0.7" flutter_web_plugins: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 87f7bf8..e373df3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: flutter_map: ^6.1.0 latlong2: ^0.9.0 http: ^1.2.1 + flutter_timer_countdown: ^1.0.7 dev_dependencies: flutter_test: