From f689fceda8073374bd130a267abc9ccf863be2ef Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 16:23:55 -0700 Subject: [PATCH 01/40] Restart project with code snippets by Ask Brave. --- android/app/src/main/AndroidManifest.xml | 5 + lib/main.dart | 386 +++++++++++++++++++++-- pubspec.yaml | 5 + 3 files changed, 369 insertions(+), 27 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e0d0521..9b017ee 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -42,4 +42,9 @@ + + + + + diff --git a/lib/main.dart b/lib/main.dart index fb005f2..7044f24 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,45 +1,377 @@ +import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:timezone/data/latest_all.dart' as tz; +import 'package:timezone/timezone.dart' as tz; +import 'package:http/http.dart' as http; +import 'dart:convert'; -void main() { - runApp(const MainApp()); +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + tz.initializeTimeZones(); + runApp(const SunsetAlarmApp()); } -class MainApp extends StatelessWidget { - const MainApp({super.key}); +class SunsetAlarmApp extends StatelessWidget { + const SunsetAlarmApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( - home: Scaffold( - body: Column( + title: 'Sunset Alarm', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange), + useMaterial3: true, + ), + home: const HomeScreen(), + ); + } +} + +class HomeScreen extends StatefulWidget { + const HomeScreen({super.key}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + final _latController = TextEditingController(); + final _lngController = TextEditingController(); + final _sunsetController = TextEditingController(); + + final FlutterLocalNotificationsPlugin _notifications = + FlutterLocalNotificationsPlugin(); + + bool _alarmEnabled = false; + int _minutesBefore = 30; + bool _loading = false; + + static const _alarmId = 1001; + + @override + void initState() { + super.initState(); + _initNotifications(); + _loadPrefs(); + } + + Future _initNotifications() async { + const androidInit = + AndroidInitializationSettings('@mipmap/ic_launcher'); + const linuxInit = DarwinInitializationSettings(); + await _notifications.initialize( + const InitializationSettings( + android: androidInit, + iOS: linuxInit, + ), + ); + } + + Future _loadPrefs() async { + final prefs = await SharedPreferences.getInstance(); + setState(() { + final lat = prefs.getDouble('lat'); + final lng = prefs.getDouble('lng'); + final sunset = prefs.getString('sunset_time'); + _alarmEnabled = prefs.getBool('alarm_enabled') ?? false; + _minutesBefore = prefs.getInt('minutes_before') ?? 30; + if (lat != null) _latController.text = lat.toString(); + if (lng != null) _lngController.text = lng.toString(); + if (sunset != null) _sunsetController.text = sunset; + }); + if (_alarmEnabled && _sunsetController.text.isNotEmpty) { + _scheduleAlarm(); + } + } + + Future _savePrefs() async { + final prefs = await SharedPreferences.getInstance(); + final lat = double.tryParse(_latController.text); + final lng = double.tryParse(_lngController.text); + if (lat != null) await prefs.setDouble('lat', lat); + if (lng != null) await prefs.setDouble('lng', lng); + if (_sunsetController.text.isNotEmpty) { + await prefs.setString('sunset_time', _sunsetController.text); + } + await prefs.setBool('alarm_enabled', _alarmEnabled); + await prefs.setInt('minutes_before', _minutesBefore); + } + + Future _getGpsLocation() async { + try { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + _showSnack('Location services are disabled.'); + return; + } + LocationPermission permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + _showSnack('Location permission denied.'); + return; + } + } + final position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high, + ); + setState(() { + _latController.text = position.latitude.toString(); + _lngController.text = position.longitude.toString(); + }); + await _savePrefs(); + _showSnack('Location updated.'); + } catch (e) { + _showSnack('GPS error: $e'); + } + } + + Future _fetchSunset() async { + final lat = double.tryParse(_latController.text); + final lng = double.tryParse(_lngController.text); + if (lat == null || lng == null) { + _showSnack('Enter valid latitude and longitude first.'); + return; + } + + setState(() => _loading = true); + try { + final url = Uri.parse( + 'https://api.open-meteo.com/v1/forecast' + '?latitude=$lat&longitude=$lng' + '&daily=sunset&timezone=auto&forecast_days=1', + ); + final response = await http.get(url); + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + final sunsetStr = data['daily']['sunset'][0] as String; + // "2026-09-12T19:42" -> "19:42" + final timePart = sunsetStr.split('T')[1]; + setState(() => _sunsetController.text = timePart); + await _savePrefs(); + _showSnack('Sunset: $timePart'); + } else { + _showSnack('API error: ${response.statusCode}'); + } + } catch (e) { + _showSnack('Network error: $e'); + } finally { + setState(() => _loading = false); + } + } + + Future _scheduleAlarm() async { + final sunsetText = _sunsetController.text.trim(); + if (sunsetText.isEmpty) return; + + final now = DateTime.now(); + final parts = sunsetText.split(':'); + if (parts.length < 2) return; + + final h = int.parse(parts[0]); + final m = int.parse(parts[1]); + var alarmTime = DateTime(now.year, now.month, now.day, h, m); + + // If the alarm time has already passed today, schedule for tomorrow + if (alarmTime.isBefore(now)) { + alarmTime = alarmTime.add(const Duration(days: 1)); + } + + // Subtract the "minutes before" offset + alarmTime = alarmTime.subtract(Duration(minutes: _minutesBefore)); + + if (alarmTime.isBefore(now)) { + _showSnack('Alarm time is in the past. Will fire tomorrow.'); + alarmTime = alarmTime.add(const Duration(days: 1)); + } + + final tzAlarm = tz.TZDateTime.from(alarmTime, tz.local); + + const androidDetails = AndroidNotificationDetails( + 'sunset_alarm', + 'Sunset Alarm', + channelDescription: 'Alarm X minutes before sunset', + importance: Importance.max, + priority: Priority.high, + fullScreenIntent: true, + category: AndroidNotificationCategory.alarm, + ); + const linuxDetails = DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + + await _notifications.zonedSchedule( + _alarmId, + 'Sunset in ${_minutesBefore} min', + 'The sun sets at $sunsetText. Time to get ready!', + tzAlarm, + NotificationDetails(android: androidDetails, iOS: linuxDetails), + androidScheduleMode: AndroidScheduleMode.alarmClock, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + ); + } + + Future _toggleAlarm(bool value) async { + setState(() => _alarmEnabled = value); + await _savePrefs(); + if (value) { + await _scheduleAlarm(); + _showSnack('Alarm scheduled.'); + } else { + await _notifications.cancel(_alarmId); + _showSnack('Alarm cancelled.'); + } + } + + void _showSnack(String msg) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); + } + + @override + void dispose() { + _latController.dispose(); + _lngController.dispose(); + _sunsetController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Sunset Alarm')), + body: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Sunset Coordinates"), // TODO: Text Field - Text( - "Hours before Sunset", - ), // TODO: Text Field. Add Spanish translation "Horas antes Noche" - TextButton( - child: Text("Set Alarm"), - onPressed: () { - null; - }, - ), - // If enabled, this section controls "Pythagorian theorum" (spelling) - // type math to check if the user has exited the distance from the - // sunset location. - Text("Enable Proximity Detector / Geofencing"), // TODO: Checkbox - Text( - "Current Coordinates", - ), // TODO: Read Only View with current location + // --- Location section --- + const Text('Location', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 8), Row( - mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("Distance"), // TODO: Text Field - Text("* Miles, * Kilometers"), // TODO: Radio Button Group + Expanded( + child: TextField( + controller: _latController, + keyboardType: + const TextInputType.numberWithOptions(signed: true, decimal: true), + decoration: const InputDecoration( + labelText: 'Latitude', + border: OutlineInputBorder(), + ), + onChanged: (_) => _savePrefs(), + ), + ), + const SizedBox(width: 8), + Expanded( + child: TextField( + controller: _lngController, + keyboardType: + const TextInputType.numberWithOptions(signed: true, decimal: true), + decoration: const InputDecoration( + labelText: 'Longitude', + border: OutlineInputBorder(), + ), + onChanged: (_) => _savePrefs(), + ), + ), + const SizedBox(width: 8), + IconButton.filledTonal( + icon: const Icon(Icons.my_location), + tooltip: 'Get GPS location', + onPressed: _getGpsLocation, + ), ], ), + const SizedBox(height: 16), + + // --- Sunset time section --- + const Text('Sunset', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 8), + Row( + children: [ + Expanded( + child: TextField( + controller: _sunsetController, + decoration: const InputDecoration( + labelText: 'Sunset time (HH:MM)', + border: OutlineInputBorder(), + ), + onChanged: (_) => _savePrefs(), + ), + ), + const SizedBox(width: 8), + IconButton.filledTonal( + icon: _loading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.cloud_done_outlined), + tooltip: 'Fetch sunset from Open-Meteo', + onPressed: _loading ? null : _fetchSunset, + ), + ], + ), + const SizedBox(height: 16), + + // --- Minutes before --- + const Text('Alert Before Sunset', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 8), + Row( + children: [ + const Text('Minutes before: '), + SizedBox( + width: 80, + child: TextField( + controller: TextEditingController(text: '$_minutesBefore'), + keyboardType: TextInputType.number, + decoration: + const InputDecoration(border: OutlineInputBorder()), + onEditingComplete: () async { + final val = int.tryParse( + (findContextController() as TextEditingController?)?.text ?? ''); + if (val != null && val > 0) { + setState(() => _minutesBefore = val); + await _savePrefs(); + } + }, + ), + ), + ], + ), + const SizedBox(height: 24), + + // --- Toggle --- + SwitchListTile( + title: const Text('Enable Sunset Alarm'), + subtitle: Text( + _alarmEnabled + ? 'Will alert ${_minutesBefore} min before sunset' + : 'Alarm is off', + ), + value: _alarmEnabled, + onChanged: _toggleAlarm, + ), ], ), ), ); } -} + + // Helper to avoid recreating TextEditingController on each build + TextEditingController? _minutesController; + TextEditingController? findContextController() { + _minutesController ??= TextEditingController(text: '$_minutesBefore'); + return _minutesController; + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 3b99060..bd45dcb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,6 +9,11 @@ environment: dependencies: flutter: sdk: flutter + geolocator: ^13.0.0 + shared_preferences: ^2.3.0 + flutter_local_notifications: ^18.0.0 + timezone: ^0.9.0 + http: ^1.2.0 dev_dependencies: flutter_test: From 810788e30ef0da2a16cf2acda82cf71d58adba76 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 16:24:22 -0700 Subject: [PATCH 02/40] Update app details. --- pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index bd45dcb..22f1037 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ -name: flutter_sunset_alarm -description: "A new Flutter project." +name: sunset_alarm +description: "Set an alarm to go off a specified time before sunset." publish_to: 'none' -version: 0.1.0 +version: 0.1.1 environment: sdk: ^3.7.2 From dc15af60dd11d4cd12c942d029920a9decfc48c5 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 16:52:56 -0700 Subject: [PATCH 03/40] Fix the minutes field to be persistent. (via Ask Brave) --- lib/main.dart | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 7044f24..378c23f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,6 +41,7 @@ class _HomeScreenState extends State { final _latController = TextEditingController(); final _lngController = TextEditingController(); final _sunsetController = TextEditingController(); + final _minutesController = TextEditingController(text: '30'); final FlutterLocalNotificationsPlugin _notifications = FlutterLocalNotificationsPlugin(); @@ -61,11 +62,11 @@ class _HomeScreenState extends State { Future _initNotifications() async { const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher'); - const linuxInit = DarwinInitializationSettings(); + const iosInit = DarwinInitializationSettings(); await _notifications.initialize( const InitializationSettings( android: androidInit, - iOS: linuxInit, + iOS: iosInit, ), ); } @@ -81,6 +82,7 @@ class _HomeScreenState extends State { if (lat != null) _latController.text = lat.toString(); if (lng != null) _lngController.text = lng.toString(); if (sunset != null) _sunsetController.text = sunset; + _minutesController.text = '$_minutesBefore'; }); if (_alarmEnabled && _sunsetController.text.isNotEmpty) { _scheduleAlarm(); @@ -148,7 +150,6 @@ class _HomeScreenState extends State { if (response.statusCode == 200) { final data = jsonDecode(response.body); final sunsetStr = data['daily']['sunset'][0] as String; - // "2026-09-12T19:42" -> "19:42" final timePart = sunsetStr.split('T')[1]; setState(() => _sunsetController.text = timePart); await _savePrefs(); @@ -175,12 +176,10 @@ class _HomeScreenState extends State { final m = int.parse(parts[1]); var alarmTime = DateTime(now.year, now.month, now.day, h, m); - // If the alarm time has already passed today, schedule for tomorrow if (alarmTime.isBefore(now)) { alarmTime = alarmTime.add(const Duration(days: 1)); } - // Subtract the "minutes before" offset alarmTime = alarmTime.subtract(Duration(minutes: _minutesBefore)); if (alarmTime.isBefore(now)) { @@ -199,7 +198,7 @@ class _HomeScreenState extends State { fullScreenIntent: true, category: AndroidNotificationCategory.alarm, ); - const linuxDetails = DarwinNotificationDetails( + const iosDetails = DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, @@ -210,7 +209,7 @@ class _HomeScreenState extends State { 'Sunset in ${_minutesBefore} min', 'The sun sets at $sunsetText. Time to get ready!', tzAlarm, - NotificationDetails(android: androidDetails, iOS: linuxDetails), + NotificationDetails(android: androidDetails, iOS: iosDetails), androidScheduleMode: AndroidScheduleMode.alarmClock, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, @@ -238,6 +237,7 @@ class _HomeScreenState extends State { _latController.dispose(); _lngController.dispose(); _sunsetController.dispose(); + _minutesController.dispose(); super.dispose(); } @@ -333,16 +333,14 @@ class _HomeScreenState extends State { SizedBox( width: 80, child: TextField( - controller: TextEditingController(text: '$_minutesBefore'), + controller: _minutesController, keyboardType: TextInputType.number, decoration: const InputDecoration(border: OutlineInputBorder()), - onEditingComplete: () async { - final val = int.tryParse( - (findContextController() as TextEditingController?)?.text ?? ''); + onChanged: (v) { + final val = int.tryParse(v); if (val != null && val > 0) { - setState(() => _minutesBefore = val); - await _savePrefs(); + _minutesBefore = val; } }, ), @@ -367,11 +365,4 @@ class _HomeScreenState extends State { ), ); } - - // Helper to avoid recreating TextEditingController on each build - TextEditingController? _minutesController; - TextEditingController? findContextController() { - _minutesController ??= TextEditingController(text: '$_minutesBefore'); - return _minutesController; - } } \ No newline at end of file From 0e463078152647b16fc737c72592d76cb987b833 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 17:06:43 -0700 Subject: [PATCH 04/40] Automatic refactor after changing Code OSS settings. --- lib/main.dart | 60 +++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 378c23f..84cc402 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -60,14 +60,10 @@ class _HomeScreenState extends State { } Future _initNotifications() async { - const androidInit = - AndroidInitializationSettings('@mipmap/ic_launcher'); + const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher'); const iosInit = DarwinInitializationSettings(); await _notifications.initialize( - const InitializationSettings( - android: androidInit, - iOS: iosInit, - ), + const InitializationSettings(android: androidInit, iOS: iosInit), ); } @@ -251,16 +247,20 @@ class _HomeScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ // --- Location section --- - const Text('Location', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + const Text( + 'Location', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), const SizedBox(height: 8), Row( children: [ Expanded( child: TextField( controller: _latController, - keyboardType: - const TextInputType.numberWithOptions(signed: true, decimal: true), + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), decoration: const InputDecoration( labelText: 'Latitude', border: OutlineInputBorder(), @@ -272,8 +272,10 @@ class _HomeScreenState extends State { Expanded( child: TextField( controller: _lngController, - keyboardType: - const TextInputType.numberWithOptions(signed: true, decimal: true), + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), decoration: const InputDecoration( labelText: 'Longitude', border: OutlineInputBorder(), @@ -292,8 +294,10 @@ class _HomeScreenState extends State { const SizedBox(height: 16), // --- Sunset time section --- - const Text('Sunset', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + const Text( + 'Sunset', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), const SizedBox(height: 8), Row( children: [ @@ -309,13 +313,14 @@ class _HomeScreenState extends State { ), const SizedBox(width: 8), IconButton.filledTonal( - icon: _loading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ) - : const Icon(Icons.cloud_done_outlined), + icon: + _loading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.cloud_done_outlined), tooltip: 'Fetch sunset from Open-Meteo', onPressed: _loading ? null : _fetchSunset, ), @@ -324,8 +329,10 @@ class _HomeScreenState extends State { const SizedBox(height: 16), // --- Minutes before --- - const Text('Alert Before Sunset', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + const Text( + 'Alert Before Sunset', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), const SizedBox(height: 8), Row( children: [ @@ -335,8 +342,9 @@ class _HomeScreenState extends State { child: TextField( controller: _minutesController, keyboardType: TextInputType.number, - decoration: - const InputDecoration(border: OutlineInputBorder()), + decoration: const InputDecoration( + border: OutlineInputBorder(), + ), onChanged: (v) { final val = int.tryParse(v); if (val != null && val > 0) { @@ -365,4 +373,4 @@ class _HomeScreenState extends State { ), ); } -} \ No newline at end of file +} From 71e6f4e13df682c0c19c9cc1a26a88160ce3575b Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 17:17:40 -0700 Subject: [PATCH 05/40] Alter message to show when the alarm is set for. Try fixing the alarm for Linux. --- lib/main.dart | 124 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 84cc402..8767fc3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,8 @@ import 'package:timezone/timezone.dart' as tz; import 'package:http/http.dart' as http; import 'dart:convert'; +import 'dart:io'; + void main() async { WidgetsFlutterBinding.ensureInitialized(); tz.initializeTimeZones(); @@ -160,6 +162,8 @@ class _HomeScreenState extends State { } } + Timer? _alarmTimer; + Future _scheduleAlarm() async { final sunsetText = _sunsetController.text.trim(); if (sunsetText.isEmpty) return; @@ -175,7 +179,6 @@ class _HomeScreenState extends State { if (alarmTime.isBefore(now)) { alarmTime = alarmTime.add(const Duration(days: 1)); } - alarmTime = alarmTime.subtract(Duration(minutes: _minutesBefore)); if (alarmTime.isBefore(now)) { @@ -183,33 +186,50 @@ class _HomeScreenState extends State { alarmTime = alarmTime.add(const Duration(days: 1)); } - final tzAlarm = tz.TZDateTime.from(alarmTime, tz.local); - - const androidDetails = AndroidNotificationDetails( - 'sunset_alarm', - 'Sunset Alarm', - channelDescription: 'Alarm X minutes before sunset', - importance: Importance.max, - priority: Priority.high, - fullScreenIntent: true, - category: AndroidNotificationCategory.alarm, - ); - const iosDetails = DarwinNotificationDetails( - presentAlert: true, - presentBadge: true, - presentSound: true, - ); - - await _notifications.zonedSchedule( - _alarmId, - 'Sunset in ${_minutesBefore} min', - 'The sun sets at $sunsetText. Time to get ready!', - tzAlarm, - NotificationDetails(android: androidDetails, iOS: iosDetails), - androidScheduleMode: AndroidScheduleMode.alarmClock, - uiLocalNotificationDateInterpretation: - UILocalNotificationDateInterpretation.absoluteTime, - ); + if (Platform.isLinux) { + // Linux: use a Timer (app must stay open) + _alarmTimer?.cancel(); + final delay = alarmTime.difference(now); + _alarmTimer = Timer(delay, () { + const linuxDetails = LinuxNotificationDetails( + urgency: LinuxNotificationUrgency.critical, + resident: true, + timeout: LinuxNotificationTimeout.expiresNever(), + ); + _notifications.show( + _alarmId, + 'Sunset in ${_minutesBefore} min', + 'The sun sets at $sunsetText. Time to get ready!', + const NotificationDetails(linux: linuxDetails), + ); + }); + _showSnack( + 'Alarm set for ${alarmTime.hour.toString().padLeft(2, '0')}:${alarmTime.minute.toString().padLeft(2, '0')} (app must stay open)', + ); + } else { + // Android: use zonedSchedule (works in background) + final tzAlarm = tz.TZDateTime.from(alarmTime, tz.local); + const androidDetails = AndroidNotificationDetails( + 'sunset_alarm', + 'Sunset Alarm', + channelDescription: 'Alarm X minutes before sunset', + importance: Importance.max, + priority: Priority.high, + fullScreenIntent: true, + category: AndroidNotificationCategory.alarm, + ); + await _notifications.zonedSchedule( + _alarmId, + 'Sunset in ${_minutesBefore} min', + 'The sun sets at $sunsetText. Time to get ready!', + tzAlarm, + const NotificationDetails(android: androidDetails), + androidScheduleMode: AndroidScheduleMode.alarmClock, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + ); + _showSnack('Alarm scheduled.'); + } } Future _toggleAlarm(bool value) async { @@ -217,9 +237,11 @@ class _HomeScreenState extends State { await _savePrefs(); if (value) { await _scheduleAlarm(); - _showSnack('Alarm scheduled.'); } else { - await _notifications.cancel(_alarmId); + _alarmTimer?.cancel(); + if (!Platform.isLinux) { + await _notifications.cancel(_alarmId); + } _showSnack('Alarm cancelled.'); } } @@ -353,24 +375,40 @@ class _HomeScreenState extends State { }, ), ), - ], - ), - const SizedBox(height: 24), - // --- Toggle --- - SwitchListTile( - title: const Text('Enable Sunset Alarm'), - subtitle: Text( - _alarmEnabled - ? 'Will alert ${_minutesBefore} min before sunset' - : 'Alarm is off', - ), - value: _alarmEnabled, - onChanged: _toggleAlarm, + const SizedBox(height: 24), + + // --- Toggle --- + SwitchListTile( + title: const Text('Enable Sunset Alarm'), + subtitle: Text( + _alarmEnabled + ? 'Will alert ${_minutesBefore} min before sunset. ($_alarmDisplayTime)' + : 'Alarm is off', + ), + value: _alarmEnabled, + onChanged: _toggleAlarm, + ), + ], ), ], ), ), ); } + + String get _alarmDisplayTime { + final sunsetText = _sunsetController.text.trim(); + if (sunsetText.isEmpty) return '—'; + final parts = sunsetText.split(':'); + if (parts.length < 2) return '—'; + final h = int.tryParse(parts[0]); + final m = int.tryParse(parts[1]); + if (h == null || m == null) return '—'; + final alarmMinutes = h * 60 + m - _minutesBefore; + final displayMin = alarmMinutes % (24 * 60); + final dh = (displayMin ~/ 60) % 24; + final dm = displayMin % 60; + return '${dh.toString().padLeft(2, '0')}:${dm.toString().padLeft(2, '0')}'; + } } From e47c85b3d97782b786285ecf661b6c1be0a8416a Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 17:22:35 -0700 Subject: [PATCH 06/40] Continue trying to fix Linux alarm. Android untested. --- lib/main.dart | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 8767fc3..992aa4a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -64,8 +64,15 @@ class _HomeScreenState extends State { Future _initNotifications() async { const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher'); const iosInit = DarwinInitializationSettings(); + const linuxInit = LinuxInitializationSettings( + defaultActionName: 'Sunset Alarm', + ); await _notifications.initialize( - const InitializationSettings(android: androidInit, iOS: iosInit), + const InitializationSettings( + android: androidInit, + iOS: iosInit, + linux: linuxInit, + ), ); } @@ -375,22 +382,21 @@ class _HomeScreenState extends State { }, ), ), - - const SizedBox(height: 24), - - // --- Toggle --- - SwitchListTile( - title: const Text('Enable Sunset Alarm'), - subtitle: Text( - _alarmEnabled - ? 'Will alert ${_minutesBefore} min before sunset. ($_alarmDisplayTime)' - : 'Alarm is off', - ), - value: _alarmEnabled, - onChanged: _toggleAlarm, - ), ], ), + const SizedBox(height: 24), + + // --- Toggle --- + SwitchListTile( + title: const Text('Enable Sunset Alarm'), + subtitle: Text( + _alarmEnabled + ? 'Will alert ${_minutesBefore} min before sunset. ($_alarmDisplayTime)' + : 'Alarm is off', + ), + value: _alarmEnabled, + onChanged: _toggleAlarm, + ), ], ), ), From 50cb05f3c924607ec47ee090ba92349a84b12639 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 17:24:00 -0700 Subject: [PATCH 07/40] Refactor library order. --- lib/main.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 992aa4a..4bc0cb1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'dart:async'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; @@ -8,8 +9,6 @@ import 'package:timezone/timezone.dart' as tz; import 'package:http/http.dart' as http; import 'dart:convert'; -import 'dart:io'; - void main() async { WidgetsFlutterBinding.ensureInitialized(); tz.initializeTimeZones(); From bb396abe2054ae5b453e79823bbb1b2b4e40565a Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 18:42:57 -0700 Subject: [PATCH 08/40] Remove the `flutter_` from app ID. --- README.md | 2 +- android/app/build.gradle.kts | 4 ++-- .../sunset_alarm}/MainActivity.kt | 2 +- linux/CMakeLists.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename android/app/src/main/kotlin/com/{example/flutter_sunset_alarm => hyperling/sunset_alarm}/MainActivity.kt (69%) diff --git a/README.md b/README.md index 7c50514..1a775c4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# flutter_sunset_alarm +# sunset_alarm Android app to set off an alarm a set number of hours before sunset if enabled manually or if the user has wandered a set distance away from the sunset diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 79fd38f..6e433af 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.flutter_sunset_alarm" + namespace = "com.hyperling.sunset_alarm" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.flutter_sunset_alarm" + applicationId = "com.hyperling.sunset_alarm" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/android/app/src/main/kotlin/com/example/flutter_sunset_alarm/MainActivity.kt b/android/app/src/main/kotlin/com/hyperling/sunset_alarm/MainActivity.kt similarity index 69% rename from android/app/src/main/kotlin/com/example/flutter_sunset_alarm/MainActivity.kt rename to android/app/src/main/kotlin/com/hyperling/sunset_alarm/MainActivity.kt index 11cd4fd..c9c868d 100644 --- a/android/app/src/main/kotlin/com/example/flutter_sunset_alarm/MainActivity.kt +++ b/android/app/src/main/kotlin/com/hyperling/sunset_alarm/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.flutter_sunset_alarm +package com.hyperling.sunset_alarm import io.flutter.embedding.android.FlutterActivity diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 195e8cf..01a76f1 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "flutter_sunset_alarm") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.flutter_sunset_alarm") +set(APPLICATION_ID "com.hyperling.sunset_alarm") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. From 718992eb425f11753e735ee77a5414e57097828e Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 19:27:05 -0700 Subject: [PATCH 09/40] Change flutter_sunset_alarm to just sunset_alarm. --- android/app/src/main/AndroidManifest.xml | 4 ++-- ios/Runner/Info.plist | 2 +- linux/runner/my_application.cc | 4 ++-- macos/Runner.xcodeproj/project.pbxproj | 12 ++++++------ .../xcshareddata/xcschemes/Runner.xcscheme | 8 ++++---- macos/Runner/Configs/AppInfo.xcconfig | 2 +- web/index.html | 4 ++-- web/manifest.json | 4 ++-- windows/CMakeLists.txt | 4 ++-- windows/runner/Runner.rc | 8 ++++---- windows/runner/main.cpp | 2 +- 11 files changed, 27 insertions(+), 27 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9b017ee..2973385 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ - + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index a8cf432..d653fc1 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -13,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - flutter_sunset_alarm + sunset_alarm CFBundlePackageType APPL CFBundleShortVersionString diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index e469171..e48b3fb 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) { if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "flutter_sunset_alarm"); + gtk_header_bar_set_title(header_bar, "sunset_alarm"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { - gtk_window_set_title(window, "flutter_sunset_alarm"); + gtk_window_set_title(window, "sunset_alarm"); } gtk_window_set_default_size(window, 1280, 720); diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 04e1b33..5a17973 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -64,7 +64,7 @@ 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flutter_sunset_alarm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "flutter_sunset_alarm.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* sunset_alarm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sunset_alarm.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -131,7 +131,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* flutter_sunset_alarm.app */, + 33CC10ED2044A3C60003C045 /* sunset_alarm.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; @@ -217,7 +217,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* flutter_sunset_alarm.app */; + productReference = 33CC10ED2044A3C60003C045 /* sunset_alarm.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -388,7 +388,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterSunsetAlarm.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_sunset_alarm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_sunset_alarm"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sunset_alarm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sunset_alarm"; }; name = Debug; }; @@ -402,7 +402,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterSunsetAlarm.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_sunset_alarm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_sunset_alarm"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sunset_alarm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sunset_alarm"; }; name = Release; }; @@ -416,7 +416,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterSunsetAlarm.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flutter_sunset_alarm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flutter_sunset_alarm"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sunset_alarm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sunset_alarm"; }; name = Profile; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 93690b4..3e79b97 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,7 +31,7 @@ @@ -66,7 +66,7 @@ @@ -83,7 +83,7 @@ diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index 307dea9..d907902 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -5,7 +5,7 @@ // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = flutter_sunset_alarm +PRODUCT_NAME = sunset_alarm // The application's bundle identifier PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterSunsetAlarm diff --git a/web/index.html b/web/index.html index 49fc9f1..93a2a19 100644 --- a/web/index.html +++ b/web/index.html @@ -23,13 +23,13 @@ - + - flutter_sunset_alarm + sunset_alarm diff --git a/web/manifest.json b/web/manifest.json index 593da7b..effe87b 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1,6 +1,6 @@ { - "name": "flutter_sunset_alarm", - "short_name": "flutter_sunset_alarm", + "name": "sunset_alarm", + "short_name": "sunset_alarm", "start_url": ".", "display": "standalone", "background_color": "#0175C2", diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 203261d..17d95a6 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -1,10 +1,10 @@ # Project-level configuration. cmake_minimum_required(VERSION 3.14) -project(flutter_sunset_alarm LANGUAGES CXX) +project(sunset_alarm LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. -set(BINARY_NAME "flutter_sunset_alarm") +set(BINARY_NAME "sunset_alarm") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index e86faf0..0a8985e 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -90,12 +90,12 @@ BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "flutter_sunset_alarm" "\0" + VALUE "FileDescription", "sunset_alarm" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "flutter_sunset_alarm" "\0" + VALUE "InternalName", "sunset_alarm" "\0" VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "flutter_sunset_alarm.exe" "\0" - VALUE "ProductName", "flutter_sunset_alarm" "\0" + VALUE "OriginalFilename", "sunset_alarm.exe" "\0" + VALUE "ProductName", "sunset_alarm" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index ee9fc4c..9059525 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.Create(L"flutter_sunset_alarm", origin, size)) { + if (!window.Create(L"sunset_alarm", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); From 1064a0b33fab3d3f785718cb9b622b5e4c8bf910 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 20:27:55 -0700 Subject: [PATCH 10/40] Successful settings to build on Android!! Finally! --- android/app/build.gradle.kts | 18 +++++++++++++----- .../gradle/wrapper/gradle-wrapper.properties | 4 +++- android/settings.gradle.kts | 8 ++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 6e433af..a6dde87 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,22 +1,30 @@ plugins { id("com.android.application") - id("kotlin-android") + + // This will need removed in Gradle/AGP 9. + id("org.jetbrains.kotlin.android") // id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") } +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + android { namespace = "com.hyperling.sunset_alarm" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + // This will need removed in Gradle/AGP 9. + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } } defaultConfig { diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..342eb8c 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ +#Sat Sep 12 19:36:23 MST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.5-bin.zip +#distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index a439442..80fcf29 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -18,8 +18,12 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + + id("com.android.application") version "8.13.0" apply false + //id("com.android.application") version "9.0.1" apply false + + // This will need removed in Gradle/AGP 9. + id("org.jetbrains.kotlin.android") version "2.4.20" apply false } include(":app") From 4ba8777ca9fc18671ea806e279eee9457cc30bd8 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 20:30:29 -0700 Subject: [PATCH 11/40] Missed a flutter_. --- linux/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 01a76f1..88f744a 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -4,7 +4,7 @@ project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. -set(BINARY_NAME "flutter_sunset_alarm") +set(BINARY_NAME "sunset_alarm") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "com.hyperling.sunset_alarm") From 0f979d3d3134a11e39c58bf1b76ebb99241a9321 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 20:42:41 -0700 Subject: [PATCH 12/40] Enable "core library deguaring" for android. --- android/app/build.gradle.kts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index a6dde87..a0b433c 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -16,6 +16,7 @@ android { ndkVersion = flutter.ndkVersion compileOptions { + isCoreLibraryDesugaringEnabled = true targetCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17 } @@ -36,6 +37,8 @@ android { targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName + + isMultiDexEnabled = true } buildTypes { @@ -47,6 +50,10 @@ android { } } +dependencies { + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") +} + flutter { source = "../.." } From 4b2f295fe7db34adab17fd5a068f0d4e38bee902 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 12 Sep 2026 20:43:07 -0700 Subject: [PATCH 13/40] Auto changes from Flutter and Android Studio. --- analysis_options.yaml | 9 +++++++++ android/gradle.properties | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index f9b3034..743e05a 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,10 @@ +analyzer: + exclude: + - build/** + - android/** + - ios/** + - web/** + - windows/** + - macos/** + - linux/** include: package:flutter_lints/flutter.yaml diff --git a/android/gradle.properties b/android/gradle.properties index f018a61..475a628 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,7 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false From 952c0449d5115c21d8e9edae0fcf1d1fd279edce Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sun, 13 Sep 2026 18:18:43 -0700 Subject: [PATCH 14/40] android, successfully upgraded gradle and AGP to 9. --- android/app/build.gradle.kts | 2 -- android/gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle.kts | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index a0b433c..cbbad29 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -37,8 +37,6 @@ android { targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName - - isMultiDexEnabled = true } buildTypes { diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 342eb8c..cd9b381 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ #Sat Sep 12 19:36:23 MST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip #distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 80fcf29..9085f1b 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.13.0" apply false + id("com.android.application") version "9.4.0" apply false //id("com.android.application") version "9.0.1" apply false // This will need removed in Gradle/AGP 9. From d6c0c79f8a698f18ec36b62ec19f3bedfa98da3d Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sun, 13 Sep 2026 18:36:16 -0700 Subject: [PATCH 15/40] android, upgraded all components to the latest versions and it builds successfully!! --- android/app/build.gradle.kts | 10 +++++----- android/gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle.kts | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index cbbad29..aafc64c 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,15 +1,15 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("com.android.application") - // This will need removed in Gradle/AGP 9. + // This supposedly needs removed in Gradle/AGP 9 but works fine. id("org.jetbrains.kotlin.android") // id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") } -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - android { namespace = "com.hyperling.sunset_alarm" compileSdk = flutter.compileSdkVersion @@ -21,7 +21,7 @@ android { sourceCompatibility = JavaVersion.VERSION_17 } - // This will need removed in Gradle/AGP 9. + // This supposedly needs removed in Gradle/AGP 9, but then uses 21 and fails to build. kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) @@ -49,7 +49,7 @@ android { } dependencies { - coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") } flutter { diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index cd9b381..90f15b6 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ #Sat Sep 12 19:36:23 MST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip #distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 9085f1b..4d19a0f 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -22,7 +22,8 @@ plugins { id("com.android.application") version "9.4.0" apply false //id("com.android.application") version "9.0.1" apply false - // This will need removed in Gradle/AGP 9. + // This will need removed in Gradle/AGP 9. JK - needs to exist otherwiese: + // "Error: Your project's Kotlin version (2.2.10) is lower than Flutter's minimum supported version of 2.2.20." id("org.jetbrains.kotlin.android") version "2.4.20" apply false } From 657b41d63c16a70008ef04b1e0236906b1749fd6 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sun, 13 Sep 2026 18:46:03 -0700 Subject: [PATCH 16/40] Increment version now that exports have been done. --- pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 22f1037..1eaf527 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: sunset_alarm description: "Set an alarm to go off a specified time before sunset." publish_to: 'none' -version: 0.1.1 +version: 0.1.2 environment: sdk: ^3.7.2 @@ -13,7 +13,7 @@ dependencies: shared_preferences: ^2.3.0 flutter_local_notifications: ^18.0.0 timezone: ^0.9.0 - http: ^1.2.0 + http: ^1.2.0 dev_dependencies: flutter_test: From 46eeaca422bb8a04947b97d650ae6cbd2a642388 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sun, 13 Sep 2026 18:46:54 -0700 Subject: [PATCH 17/40] Ignore linux bundles. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f4c3b0c..6e4f705 100644 --- a/.gitignore +++ b/.gitignore @@ -153,3 +153,4 @@ google-services.json # Android Profiling *.hprof +linux-bundle.zip From 6586398db614b7c9f4ecb037054550133d49be66 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sun, 13 Sep 2026 18:53:06 -0700 Subject: [PATCH 18/40] Add an initial build program, still needs work. --- compile.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 compile.sh diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..858f5df --- /dev/null +++ b/compile.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# 20260913 - Hyperling +# Build the project and add them to a releases folder. + +flutter clean + +flutter build linux +zip -r release/linux-bundle.zip build/linux/x64/release/bundle/* + +flutter clean + +flutter build apk +cp build/app/outputs/flutter-apk/app-release.apk release/ + +flutter clean From 09fdcea0f92779082e23290a07e40cb4ff700636 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sun, 13 Sep 2026 18:54:36 -0700 Subject: [PATCH 19/40] Fix the build vs compile scrips to be compile. --- compile.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) mode change 100755 => 100644 compile.sh diff --git a/compile.sh b/compile.sh old mode 100755 new mode 100644 index 858f5df..9d6a644 --- a/compile.sh +++ b/compile.sh @@ -2,14 +2,22 @@ # 20260913 - Hyperling # Build the project and add them to a releases folder. +# TODO +# create dir name release-${version} to store these in, + +echo -e "\nCleaning..." flutter clean +echo -e "\nBuilding Linux..." flutter build linux zip -r release/linux-bundle.zip build/linux/x64/release/bundle/* +echo -e "\nCleaning..." flutter clean +echo -e "\nBuilding APK..." flutter build apk -cp build/app/outputs/flutter-apk/app-release.apk release/ +cp -v build/app/outputs/flutter-apk/app-release.apk release/ +echo -e "\nCleaning..." flutter clean From 7fe2af80585b2c3a82b961fd56ec5c3c216e2317 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Thu, 24 Sep 2026 09:36:07 -0700 Subject: [PATCH 20/40] Create a basic icon with GIMP. --- media/icons/sunrise01.png | Bin 0 -> 3648 bytes media/icons/sunrise01.xcf | Bin 0 -> 18526 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 media/icons/sunrise01.png create mode 100644 media/icons/sunrise01.xcf diff --git a/media/icons/sunrise01.png b/media/icons/sunrise01.png new file mode 100644 index 0000000000000000000000000000000000000000..9be2ccd2eddfa4b78fd9f23d610bdea4cf01fd17 GIT binary patch literal 3648 zcmeHJc~nzp7QgQik`RIfjSirahoa&_K|Cr7ng=dGTL|JViU=a3B0@!B6nL*HivtBZ z>R81A98hXilu|5ABSZnwB8!JAE)_!ARb*8bLozqeIi5LZ#!mfvPEO9d@4oMDzwh_m z`yKOecQz213IM>s)n&OS0Er?Ad@erv!hagV2eHr7*@<|3cMgLuoB&5RM}V9pebqKy ze5d?eJly~eP6uF*0%+H>Z23AmFy}8yz(NMe7 z>F*ksZ?0W7J?(1rib~$HDbrE3%anX3mOYgz-Ih8Rtz1_ZlYL^#xsaJhOMYwxY`{uza2dm7j7p_o#N};XES}}n<{nXqb~0RgDYXLJ16ho6%xAm z(3{pH$M4$NnI*-=or=x4|3q@E^-%Hs4U%sMJc38Ku#tPGe|piHJ*7VlbU$vXE5DF> zvNoq{@mO!O#M_M>CLsuNTUhSZd-M0@-rs5=G_6>)3RQM{i;I@#Zpp7GJZ1T4&strA z57!#9bzAUv(UFghy8e@%XZaw+O#^NuY8r_ol7mM4yIlARrktAM6dF%=8hc5RKB|Lw}F=rb!vt~o4;Ni z-&v?}C@hffoht(6MM)NsY_^QG2*|5Tlxo!V-R*f-t+k><8U@Ig>FxV_$ zHy<3{SYNMxZl5BJ?(TN}VXpmfMip;0AKBTHKUlwUXNj+Waf{4cMoyR=ph=0Gt=$@C zIW)zZz-Rs!pL{!b+=CNX;+f}<$ON0|Fqy^#SI1~172MMl=@g{Ew7gAw%Q~X1Ql#hO z*r)nlOD84()W69JR2@K`q!eK?K4^a8lk*RcHJ4^BU_PEql*h|5JYQ@Oa-cZ``SoD% z?S#Xgmn!R%>}MP3e-7!BUe!H4R{CR1G#j_!a$xv8An2h_RmGa#9YC_4f$A8w(k+HG z0*mr$iQJwP>P`WdO3%FUwE@?yIAFRaf0MA{p#w;y~wn`G_*+$HqJsfW96NO zH+my6@936DrY)^ghXTt?JgFxOE*xUoY93V|T+?zU8}Sy$XE6D8>+#SC{E-TSm#XG) zgbLMzfI0yU$;<`ywrle7EToGfx_I0w-eD0moiS9?3nC~!L1#acci*}%-M&5OpjA*^ z_%?I=+Sy*Olx#1jDU#hhcYt>)OyEO_2s+4Eb)?*HL`qdhb{l?_WX+iZU44e`1P#h| z$yt&GMUB)>7YH_s2^JuzGL2G<6{MdDKUpC-KY;@|o5 z*q6ik3l8nV;M>cr)sE_c^E3xe_rx>FTcc)T=p8$z%X|aFtDNXDUl??j-fKD*O@qyb z7!B1*_!#4Y3GyM{VCzY=(pfk^>Sen`5G=5n9~Fomg)t3M%Q3|)AGo)>B;q!)!UhX- zv{CVN^c$e+KK+$Ey3)J4h_{4`!&fle5Dm<_iH>NT5t&V-5Zu# zh+ss#H7w06o&+SDU7(3QN-DHs5Q?EACiBtSW7OIJMYDYfSlwN;HXgB-$G>G~z+<8XR#AV5w)d(U*-1WZF!G7*xy^w@=1 z1!NqhJ#sL!lXs9!a(&?~U^>ZJ`gH=v#^I0U3ExU)(j! z1jEw>4)qfgj~sW^C-m&?PAA~BnLv&t<+=N^Vd>58{Al)s3=+#Sa+Yo%wX$52rV|r7 zD75*t)H0T87zYxL0c&^SZ&!hPVO9Cf+11=90>)=Y&q zFTY4j9F?`;@m-e2-3rBi4U(?a6a>bQh>mlIa=@LyKEVfU7+Dw?8-`3n0XB?OwIg7|a2TEn zika9aoPk}94JHX7OWR-wz^lfeE3W7k8G*^}>o0N&^0Zny3fsk<)U7JN>g;9t6h*Q&w%mCLF?#r{Cd=CE;q@gQy literal 0 HcmV?d00001 diff --git a/media/icons/sunrise01.xcf b/media/icons/sunrise01.xcf new file mode 100644 index 0000000000000000000000000000000000000000..9ab043b36a8db254475a2bfeb195eff24f79efe8 GIT binary patch literal 18526 zcmeHOYiwM{c^y%t#Fs?sElaYrq9i^fl1ow)MNxdLB{`B)yE0O)lMH&=^W5j`5q=pe>jV1_;qKJ#MD1tW47A+72K~NWM5Ezcg z={YlJb}uQeExJML8eU@VnVCB?clORV-}&yj%ZbTrv#A@GuB4vm>FqVfR4D08n|C>x&KdUh^5KA*ju z`sC#N)ztZW?z^97nqAY$YvU8yu8FzH%dBJT7u&DTKRK06U7wknyxdXWer4j)%+$+CUe<;wN!e9E;?U zPE1aZPra8h+{EwAPEX8VZ5ch$+xIThbX_*<-vX1ur%jzcjqUc%3faE{arrDds`zv z#zklB-b%W9P7d|-RJ<)KJ0#}5#-8N~uk1*(=eEqIX6Le3CU1j=7{lqZ$E34Od^R@uLjBh~9{;$

HG_ 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 Date: Thu, 24 Sep 2026 09:36:27 -0700 Subject: [PATCH 21/40] Add the basic icon via Android Studio. --- .../app/src/main/ic_launcher-playstore.png | Bin 0 -> 15264 bytes .../res/drawable/ic_launcher_background.xml | 74 ++++++++++++++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1218 bytes .../mipmap-hdpi/ic_launcher_foreground.webp | Bin 0 -> 910 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2566 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 818 bytes .../mipmap-mdpi/ic_launcher_foreground.webp | Bin 0 -> 602 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1732 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1474 bytes .../mipmap-xhdpi/ic_launcher_foreground.webp | Bin 0 -> 1246 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3612 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2250 bytes .../mipmap-xxhdpi/ic_launcher_foreground.webp | Bin 0 -> 2132 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5792 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3052 bytes .../ic_launcher_foreground.webp | Bin 0 -> 3062 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 8230 bytes 24 files changed, 86 insertions(+) create mode 100644 android/app/src/main/ic_launcher-playstore.png create mode 100644 android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..52aac65b6284d6bc8e6659655b56c32a3531c19e GIT binary patch literal 15264 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 Pc+d?E{c9y^4p06U-gqFP literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..82cd4a2 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..82cd4a2 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..35a92796279ea39e386f1b597b524fd2437607e6 GIT binary patch literal 1218 zcmV;z1U>swNk&Gx1ONb6MM6+kP&iDk1ONapN5Byf;!x1G4U_PP-CYI|F#(PN0_0c= zf8o})ty&rHyWsBb?h%n&(|J|USsh~4jdo5g9h zZOd|g!QHizd;^OdBALz#RFX?_m-PS4U<2qnzuXf*bMNpM&?i~QPa2?4A_;n_>XHbr zs3S@jna9XHM3j-C_n$5;5?!jeBxDXF${iV)h`{(Jp5=}_hv`z$Cn7|Cn8>dtq>1bE z1w{I!CA6y#6C^9$Ce84#2`;Ci1U0ztmw`2*|Y z?m-!lalR}>`Nvos_O=R~u1oFoc+i&q<-~b);XgR@9v#{57Rrwn3yH%b9n|1-S!tsu z0B(Y(B=@+yQtq2Orw`Oi7n0R$?#dN^@k}C*;uRi%Cwe%A{(t8aC zf^!!2OeXxP9|^ zf1?{NrdRS~4GjhYkT6h&zpnuB{xjQ4{0!j8`dGV?Gh{=%sKbF|5*p5nwq=Z?H@dI% zfy|cvJ+p6O(2_z$rHV1{&%OyL3rBi8#ut%o8z+gxJp^3Gv&VO+@3#SSP)(1_jZF&BS z#aTR+JF-7$qD=dVO5h-*5b>G z@UDNf9g`$089}xin$D`H?b6eBwYSb6VVD;r0`eY${dL~kcD1gyOL@~d+W(ccvKoRR zv_~O_(FUNJ<3gntmf}=%P}9arlxJ2gM>Wk%Mfqiwuu@Y*>+#nhh;aX_3o>cjO<0tS zA^-^_>UdkfgtRL8f%MLb5=uh?{uIj9{5qf?EaP`VIsaH{?;Oaa+#fqgf>K6Zce1z^ zaLYx>M`h+bRAwoeB}-;0nI$u`WR{XyvSgN$S+dMWd2;sRV%-}DsRV*2P7ntfkOeuz gzdi;rH(W2(5G7%W#~(^Kh^XP8eLE#hUkXTbsY4E9(f|Me literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..7a4636d02fc8bf838e7ecf553830ed4cb6a69813 GIT binary patch literal 910 zcmV;919ALPNk&G70{{S5MM6+kP&iC_0{{Rop+G1A7Y8enZP&`IP0k<=lZe6r#qSH} ztRa|y9Z8a7rFsr6y}=aB#{>S=P8aM*l3Ybqy=Vg>Z>{a*MSDBFwFJd!a*($xNakW=Nj)mhMrvX$KVu0<{b2GDUt+xxNlRaluX-t3{)9+X=hk zHWi8xJB8DL6dPbCz&VScDufvfPzsa)fhs^D1Z1e95`ZRH1*#O30u)f85Fi8slmH=k zd;7V%ojg4ZOqrCKaxo=S-al_{pZ+|)|GT`s3*CI|-96pSOg_J^)(J@5w(a&xc=)wjl@gklj~_jl)mqz*s2uZj-2i zE&eu>VFh?sUW(nlm(%4BR<@JyXt>QmVt+LxA1$Gk5C-i-i*iAbju~LF4TRBW6Ihfp zghXUuWwa2=fc;q8y)a~`K{Ze~tKNXR91J2$q1HH&^nw~8q}5}PGMl4#K1VuT5=AXQ z+Te~Ny^$6RYok=6K`_CWfO6Zy_&x?oZV2PK4d_8l7}wQ6*DJy}%m%tz97bk*mt8AC zGZW}$Eg09eK(X~<+&2PcwS@6|24r@HDRqHp3{349qGir3olN4V0W4#YlIx&2Z$&cu zpj5udG*6MdFqj^_B3WcI=d=eY_5{jY;=mDMP~EA4;j+r4zCRkH-d!y7R3(Tv^G$AJ k6hz(IVCI=n1h=`S#Xnm7?R&y^A3j>V$bbL;_x~UK0kWX5Y5)KL literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..1d8178820160cebd336f56de595866b0cc4029f0 GIT binary patch literal 2566 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 c&(H25mWi*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@U8TiBO z6O}&un19G6_r-)-;d{J8!7efG!8yW??l-#x4!;*JJYNJ52AX_BxhK>qO- zLYgGB5W~vq@p$9;a!w&zl5Eqq=CN(eb!_Zo+qP}nwtcQ`TYtDU#=3glW37n(PXPN{ zJ{>`qG#e%+!eP>2n9H)d09nM$B8yKf%aST62rVWk#9t5 zao;Z9V0JjyP>9VxLz-?#;97bo4WUfegmCQ@?Fciq!5mW21=ktHVUtgx4l_8gPvH(w zb0`$W55VkYa&Vy(raumj(vCnH0}!HnK}tAcU<*hthENTXg+Y}dIT%6}ND+pAGf2H3 zLS#2cZwx}pF~~tWoKP?WLUlo4ik?}G9@3*bx9<|sgP%X3f88Uxd+YvV_E6~=Ilg)M zk@0U%&c@EXgmv*)S(1ayIbz@ZzNonRM^n4V{@P weKXhZpTB%Y{qp&%o2kAUk_}BPt*wxC7AA(yq+T{RGDatJnQ83gi7wIK5-tLT?f?J) literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..4694c1fd6e5143334c5376404a0ed109370a0631 GIT binary patch literal 602 zcmV-g0;T;@Nk&Fe0ssJ4MM6+kP&iCQ0ssInYrq-+m*h5*WLKFd3Qyw_0!83thJ~l! z-lPG!jU-1>R0I1K-?c$Ird-#%chwngBT15!>Ym-bi$Fuee{0Zjf100j&LApxNs$ZBg8W0{>66I7`Pn0)DkO(G!1Mm1D?e@%klUjv0KejOU4 z7MUdxV_=zoja4O758qN;n`TBvWxzRBk#+bhU zwhY^1LCn#O@x$Wkb>E_j5itFuz69x}SF^fl*h*9YMMI}V1kFaR64X=%TE(DXtQew% zicVN0DxxAl5kQ~_6e3jXlcI2~?P2V5bbR(DhmH-l(JS&rvToN7FqmjmL3W@iq*GOVB zhBzwa8Yvtl5l^K-BZ0dt;_A_hr>!KuL5pysUW_R14(vLPShs?;5%2JQsPiahR1MWm z+`|un?i1KiC(x89zl>*`D&p_62BXOYpgx#`AcP{AX$2wi6{VXHBQ8*CA$&|Ir4U{V zDESaH`4cLJ@R&oXf$&~O>3|46Lm7sMeL&grL&!6rKE)$+!5B&ayykI66n?R{IG54< o8V$g8?EE*7wnMlT>X7sm%zRf3f^CBBP8Vy3)h1Z=@BiN~04{eH*Z=?k literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..f533ca78fff879bd4a72f39fba0bf47b0d5f7a47 GIT binary patch literal 1732 zcmV;#20QsuNk&Gz1^@t8MM6+kP&iDm1^@srFTe{B+E9?T0kh7(>}Me&CO{eB@GQ%< zZPkhK2GX>^A)gH&oZiHLgwoT_} z-+M7ic6RauuZr!~wv*1bea;weZQC}T6Wg{^WxOi3%cQkk+NxAN<8ukJZTvxg%cTn2 zwr!ZCd;9^(+P34(yMuNK8uoOoMOf3!YumPM2AjyztgkD0>;CBJpW62K2X(`rQ6x!< zqZut>;dKl~m_Z{+ildc770T~XzzJ@Ng-W>cMj?<)PJY|ibitlsaSl)$%dp>7STBy zZ35iy*+6L^R0H{J`_-LumFF#xC5RN%n>_=iAQRVaBnhY(nX z1isr*P@iQ-x4DNh$vn;?#3<@J0lqP00)Usr7_&`OK2pk7q)tX%`YQl9H?F=zh^1F) z9V(4Ipwwr;O|hmuU6qdnA+Q;#qfxK<0KjLc6vkkhbyX%2LIn8U?+h2k>9_2qP6o<$ z+>AmJ;vc~8_Hfk$m6a?)DYVJ$#(3-7Q5Yexul5&MNz`foe8dcxdKHy1Icj#J{cqOO zL%_qJDqpE~&4X^6Wq$A`em5@l0{M5%#YBI%qYy&CimhCcpF^vy00F$mKfPU8xe%+m z0u}N7lJr{jC&u%AuxOCK*#@AW(RbSjF^VkK&2sYQht(X#BSB!oF&1wR1WdvWgqT^s z@LuP^;PDG@8z&~UUn&U9EW1L8BQcmu(AQ(I{^22aQ{j4E`tS2l+FFkfeK-9QAlF^yrhQsvt>N4mHsW{Ja1o z=qWH_+W4=kPgVEeeu|JBA;vk@`Wb#%-^%4$Ts{aw z*%+i^9He9jq?M`SKSHd9hT&*tI4OaG2VDUKI>I>wJsu#U8V10rr78z1h!R3BAF~7s zX?Y|>Ljn|I9F;)Hom>vu$19-5ROo0x0@yO*3tY*YgePB5I(n0?H<4%Rt4G$fWb%8kYPjho&3=Ou*2}>ensjLDKu%$Qm$; zt7r}tbQUl*Fkb|2hXP`qoDTQJ8(?N@VE`2Ke6WDNAZaqgg)-I@oDPOgbID7ZzFKs| zg9uoB0)<|Vi$GtHd}cpe(wAO)IL1-pFIUkrTrDg>3OI6;xq2YcTmTo40k&8| znMsWXmOX4oI8X96&G+%%Q7_w@t2@9RcyrZ4Ljn%eFhoEU0Q9yX+>v;q@b3CPZLfhN aQ93|ExQ|*`g7^mT0pauZn<%(GEN_B)13WPR literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d4391482be68e9e4a07fab769b5de337d16eb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!iOI#yLg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+5i=O3-AeX1=1l$e`s#|#^}+&7(N@w0CIr{$Oe+Uk^K-ZP~83C zcc@hG6rikF&NPT(23>y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..5fa19b16afeea938c0097ba44cfaaff9a85d021d GIT binary patch literal 1474 zcmV;z1wHywNk&Gx1pok7MM6+kP&iDj1pojqU%(d--cZoC4U_Pv-CYC`F#$HAfsq*a zt(D(VN!qp@|6<#=ZQHhOGut+P_`Ye{DZl&q9nIfat>8cU=Nj8B!8L4X<5@rl^xC#f zXRV}xbf9i*+qRv2wvAu5ZO67x#(*FIVA*K4ZQHhOduQ9WZKQi{|0h7MY;DK(>=XEH zbw+HfQfs@n)!Mdopn0B|_l|YPNoCu1Dkrs__pf57v!3||a%|hGqJ@kphSX1i2;6<< zE^YTxodu!8t!-;rw2>Y(g})BE(1-%u$ux4t-#401m5{V;JC^l**|u#P!;Us!tfr%3 z^Tv&8HMU0l&CF*4bUtf7Ta?2;R=~$fIHw{yXN}Jmr%EO~e_t~G-!=SwsXhMu#%ysRE5C2R^;ofRSy>H; zM6_4%7x(i*-a60y)Th~`>17kA91d#oCVh)KBS6^9ZA9!O;d$LN z==oom0m^z}7lp@lN2?pSZU$Hu1E(nG=(Iw+WRbQq>_wLS}Oxf%(#<6e5`qIaZbc_YS}sm_pUY2|i;9ko&9Dsq4T83+k^xFIBrJY(C3<#D$$#{2ria(o{b;2gk`+AEAP*d*yySNmi8=A#dUkUQ ztgH<1ElEjcWZj4eNcpR8SALizK(OM6o216|wmIdG&c#68&CaZt5w$(kz(K*3{7)v_ zc)hR8XG}45k-bkONO!#}FJx3PuwO8v{E=`IKX3TcGVYuDmHu-AR`lP=%jgv#KGdM3 z2e&W6{V$uDQg^Tny(y;jls>`vtM7JXMT{*0qGzXMLiz_YA%UTzi~!>UHF})$7%a+i zexS-=_?hd7IprV9hyabBr3BugIyK&T4CSYM+*@Wbz8E>q7~n=oO>2D#kOX*7iQ^@E z0Wu?lP5(xwsO@4(rxt($R8Q|o@XU4WB2K~RvbKk!u`?^NrvKp#ALRv&g;2vC%=ryJ zR;H=#qVtB=U@WNrdrJZ$R~pxPFz&+7!%Z3yF?O7X@l(F2J47NpcN>KX(%ou%NGi)- z9On%FswYhcPi66a2*y+Vp=wfzh>6oI%>4cehlmV_w(S;-F%jAlGZ1-GJh23GYw9u~ zXsFt_Xxk-D4eZ zrG@D3kRmOY2kR6Hiys1CkW5Kn>64d$x=qNAY~Dh;l^)!Ainr?BZp-|^`nBlZ2d8Qi zat79KDKrD@t~&LavulyYKTZ$M~aXQS9z>3~a=m5m77Xo+PSUy=;xyB1!vZlJr8 z;ZJ7ZPvb7d0lz=fM5Mc_f;G`*;DOnf>QrDl*J(Uuco7&6w5PUq4PeZGRv6z9mInee zxV;l_I=8@qo~-i|0(w;lW`LB12GS~I`>-Ad_}>Kd#{=EjRHXR31oRhX3b=T9pvzS) z##>VF!D2AK!#E6Q|H9KdUku^zbaNW%)nejyEc}0J5fC6IA-N5Xuxc?{yi!P3s1$N# zD}}7b%T@}xS7Fs+3>>!)ZFyls0R>Vt!VuJ;2QyeafAILNJ3p?g-4}odY7pEgM3IOi ck$C*wx>rEWd7;){0QO&w=l|_`q4Spl0L#enAOHXW literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..371f1b14a5524f52f6aea8e0bd46cc54762e1a92 GIT binary patch literal 1246 zcmV<41R?uUNk&H21ONb6MM6+kP&iD=1ONap*T6LZ70J=I?bsaKwr$(CJ+W=u=HSD> zg)Ef+d%v;M&NjX-?EkdZbEHl=)BZb{Hf~cTZ922d3al|*{~z-IA!XZCR6tut*tk$E{e&{C?nlqj z#2cG@eZ9StZg9*T4DXu(`Y8uZr1gT@+%ZG=&(P@(6_i@4Lv*)rdNypFus*V#RcEvH z@;M3i-n0>mr+p0fGg{6)JwE7OF0bi1$G$_;s4}46ma9&(7j1vpE~~3-XkX<+#AyQb zoyB2>n-SWu5xQE}+0wbuj{df>lgDc}zI99{m9I4R6`GeKi?c(tC+(cFomNy`Mbf*a z*E4={=-@h1tnC8T+0stDc@p~(-80>Eoy$kI6t2~Fh6swH*b*lDTK>H3u2>uj^lLE#}{@PF)?nWb0=1Qo5Lk9dho=T;qh~p z*!gW%to8AOfiwFP>jkm&+x0$PIMEnXFNm$Ook!xOmlN_KA*>&<_J2zd@j-~p)^!1~ zw__tysH=Oq9N?5eE3=tcyrFVJXo1gY(}&>yHIr1fpU!pjPDH24l7e6#VzYeqb)MXnMr>bIweIqUmHkx2^<$iLZuLR`4AhnRnjqG%&RXXT1Qkt4 zr$d-`FCS8vPK=C?f6SvfT=)dZy}UMbHnG3U!QqKS^r-4_N%jCBpTm$qdkX0HoLD7< z%hhey;eY~R*FMP*Zl*n5Kv_`z2H|)kC^UFRy>G%eFBU(-xwTk*AU1Taivr+ym+R(9 z0wLNrmH;?KpR{-$AgJF*0jGr|uTf0K2^!N$o)PPWa#?otfU%mGWgLL9p^7}x3ykfA zukTzKog3m;4q!sVvVG!Ui0hT{>3~Uo#$6i*<6gxl1m=%ue;Be|8iD~#4izMO!}!(= zN-)LALpTTJ$6k8*67PX=ydSZ_WK&79FAVvdn?M65HS~oIfg#zg>hXbzec+Cbh9TOs z@Lvv$TY7KmBpAZ_L=XYSW+GQ-BaF?Hb_a~b#LvexjMZ7!4d&TUemz7nOYsI?usTYCjGTqu!g|<=}}TOxREe zlD!Hbso?#)LLCs+cY!aR0X-Y`p~&X|Ky|j$uw&LqfRsod8TP6#HI11!BV{Cwzf){*13^UflzQis{oJ6wk#WpAA`+Qvn@ZsL;gSH|3m&i Ipgc6B4Prp)mviC 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..b130ad86a284936de990544f04edfab6ceca0e21 GIT binary patch literal 2250 zcmV;*2sQUoNk&G(2mk=I)kUp7+B#lLW4|ZHJs|=GV-| zwr$%y1UpqK>j<1GIhR~1w+~C(>HUAR|2qM^i(2@%(4N^i{bQPMOSYh7v}fGLB--4` z7UE`RJp4L%e@j90nSs}jbd5i6`^e00iwLqCshL1(_7Uk8k-iW~BhtUd+xH#_g}XUu z0YOG;+7Rg+ksu`^K%tc1(R{RXP*{+WK8B@41R*{MDFR4g2+Z;OB~k$Qk7FDZweB*Mc3 zaCkhU-ittcW&?&M4y2!!BWT`$(+fY~IGtt!k`<n3*lJdd-K0Gw#RkZqX5H(1ek=z9US`)%h{JE(8F9t&NiF z1YvBvAx6L%ps>1DP7y{%n$BTpT8hBRN(Dt29&X;D0uD{O#>il~3WaDebYr1lrTn(j zzB?H19ZgqX9ZffOx;Ja}mzm^Gi>0bkZFxM~y2;^~I^DEX{6t1i3dg2~>@|+RDxCYC z*qM*%sf6>eM~VU_MG*%=yNXc@zv3s~Wsf|rshaIiZrgFxzv^;SMIzlw$>XV!KnV|D zR?ZHNzbfv?M@do0de2pYGoCVAHrkTgc5IZt%4A0d!?!jsl}NkBY56NN@~ZJ7Q@09X(kq{XNNoT zkpdgI9Po}lsqwNs$rC8Jhb@1%Fy*d*hcO$_!or`}oW50EwgIj9&og@dEn&%jHv~4& zIp7<*({3RX&fzi^Xl)x^9OPvLc?3op811`0_P29bR4Go?^b`+cMqHSDQ)(`epzP1+-0v!dG4ecu2XFQ0uuLTG=8w7W znG9f0IV7`d`!^14hBfl2=^_F)|1;$#jB{Dtdp*F%AW9K5e7{|bZlkc2Dt8&k7YUgY z84Sm8vUzEeM=%Ou)^mX|&&1%Y6+7~=45kG3p+-@kPn&iL~>Erv}? zo$3tR>tJvf|0dfg|7n?u)VZ$(csLLe6~3qCZu;md#Nd&lFn?h4B&q1wjRXq8!!rIC38-RXS%JVvSxCi&UzvE0 z#HTJqQrb*w51y_r)YS@ozi-8 zj@Yj;M{Q_2{u5nve;NTJ5x-uq*;|N4mGMRAR zB*0kmALpVI!~urkUZGbQ8L6mqbfD`T9iqE4y6`KI$@(naH-tN%y z^r6?a5BJT(8k?I`rgyLzI2h`Y<{OOAhgMa^+Pcl$n8+8hY`>Z-uzCb*>;pj=n$ z-P`*s>*^W{J6+VZESvS7ND-r`FrtmXh;fl>z?i^ls3*;P7BZGf6GYD%s1Ge7I>PlK zl$rRZXC*(KY1Eq_%-0j9HzIKxPc8!iT5??rd80VhD3vu{!Fh1POp;+r#E|kmZ2B(4-#WU01kr7k_>W3Mx z>bxvNzdYYLSeBG@zW{y;oV}&U0!4lDe13YCy{-hCfh(KB)Ky?|mc4b$^OgUhz4}uY zsAAGVdzn6$Wy`WLJUSsg zMv363K!I?ORE`2rT%fAT3shBQrLyd7SrmP3ieji$Q4DGPsg_02|Fb|IGRP=IUO@_qQ>^)~3z2*4 z-;3+IRk3Jg1rqqK?**|5Ai;h~)9v2s)Xr=_gO#{dF$J YsuWwKQcs^+34HogDYjrmAn&Xc0Ix_~h5!Hn literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..a42936fa83ab63fa2e72adf0e5c684be347fa5b5 GIT binary patch literal 2132 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..9ed198024675b6155b9d283990afee8fa6bb6dd0 GIT binary patch literal 3052 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 YH#;^jTD1_d2QntW*aHS~pHTK30EO}xxBvhE literal 0 HcmV?d00001 From 00566d9cc059b1dbf56cfe0090893681103606a0 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Thu, 24 Sep 2026 09:40:09 -0700 Subject: [PATCH 22/40] Add descriptions of the new folders. --- media/README.md | 1 + media/icons/README.md | 1 + media/screenshots/README.md | 1 + 3 files changed, 3 insertions(+) create mode 100644 media/README.md create mode 100644 media/icons/README.md create mode 100644 media/screenshots/README.md diff --git a/media/README.md b/media/README.md new file mode 100644 index 0000000..8db2995 --- /dev/null +++ b/media/README.md @@ -0,0 +1 @@ +Images, audio, and anything else used to support the app. diff --git a/media/icons/README.md b/media/icons/README.md new file mode 100644 index 0000000..6eb8743 --- /dev/null +++ b/media/icons/README.md @@ -0,0 +1 @@ +Images for use as app icons. diff --git a/media/screenshots/README.md b/media/screenshots/README.md new file mode 100644 index 0000000..f34f6b8 --- /dev/null +++ b/media/screenshots/README.md @@ -0,0 +1 @@ +Images for use in app stores. From 0ef88ba97823d63d2c20d6c79dfc4d411e6b4a59 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Thu, 24 Sep 2026 09:44:53 -0700 Subject: [PATCH 23/40] compile, fix permissions. --- compile.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 compile.sh diff --git a/compile.sh b/compile.sh old mode 100644 new mode 100755 From a19447b8a0371ad5d7a45f91b076fda15300e41b Mon Sep 17 00:00:00 2001 From: Hyperling Date: Fri, 25 Sep 2026 11:55:27 -0700 Subject: [PATCH 24/40] compile, overhaul the script to have the name and version in the filenames as well as reuse more code. --- compile.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/compile.sh b/compile.sh index 9d6a644..e041847 100755 --- a/compile.sh +++ b/compile.sh @@ -1,23 +1,70 @@ #!/usr/bin/env bash # 20260913 - Hyperling -# Build the project and add them to a releases folder. +# Build the project and add the output to a releases folder. -# TODO -# create dir name release-${version} to store these in, +## Setup ## -echo -e "\nCleaning..." -flutter clean +DIR="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" -echo -e "\nBuilding Linux..." +## Functions ## + +function log { + echo -e "\n $@ \n" +} + +function clean_flutter { + log "Cleaning..." + flutter clean +} + +## Variables ## + +app_details="$DIR/pubspec.yaml" + +name="" +for i in `grep name $app_details`; do + name="$i" +done +name="${name// /_}" + +version="" +for i in `grep version $app_details`; do + version="$i" +done +version="v${version// /_}" + +if [[ -z $name || -z $version ]]; then + echo "ERROR: Could not retrieve name or version. name='$name' version='$version'" + exit 1 +fi + +RELEASE="release/$name-$version" +echo "Running for '$RELEASE'." + +## Main ## + +clean_flutter + +log "Building Linux Bundle..." flutter build linux -zip -r release/linux-bundle.zip build/linux/x64/release/bundle/* -echo -e "\nCleaning..." -flutter clean +log "Saving Linux Bundle..." +filename=$RELEASE.linux-bundle.zip +if [[ -e $filename ]]; then + rm -v $filename +fi +zip -r $filename build/linux/x64/release/bundle/* +ls -sh $filename -echo -e "\nBuilding APK..." +clean_flutter + +log "Building APK..." flutter build apk -cp -v build/app/outputs/flutter-apk/app-release.apk release/ -echo -e "\nCleaning..." -flutter clean +log "Saving APK..." +filename=$RELEASE.apk +if [[ -e $filename ]]; then + rm -v $filename +fi +cp -v build/app/outputs/flutter-apk/app-release.apk $filename +ls -sh $filename From 280e748bb7ac890969805b5837a9f86a5d105c6e Mon Sep 17 00:00:00 2001 From: Hyperling Date: Fri, 25 Sep 2026 11:55:46 -0700 Subject: [PATCH 25/40] android, AGP Upgrade Assistant. --- android/settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 4d19a0f..2a9c2f5 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "9.4.0" apply false + id("com.android.application") version "9.4.1" apply false //id("com.android.application") version "9.0.1" apply false // This will need removed in Gradle/AGP 9. JK - needs to exist otherwiese: From e643e797c970fcb54288efd4eafb69d7af998550 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Fri, 25 Sep 2026 11:56:14 -0700 Subject: [PATCH 26/40] Begin changes to ask for Android permissions rather than silrently failing. --- lib/main.dart | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index 4bc0cb1..a88c43d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -7,6 +8,7 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/timezone.dart' as tz; import 'package:http/http.dart' as http; + import 'dart:convert'; void main() async { @@ -171,6 +173,12 @@ class _HomeScreenState extends State { Timer? _alarmTimer; Future _scheduleAlarm() async { + final canSchedule = await android?.canScheduleExactNotifications(); + if (canSchedule != true) { + _showSnack('Permissions not yet granted, requesting...'); + await android?.requestExactAlarmsPermission(); + } + final sunsetText = _sunsetController.text.trim(); if (sunsetText.isEmpty) return; @@ -417,3 +425,27 @@ class _HomeScreenState extends State { return '${dh.toString().padLeft(2, '0')}:${dm.toString().padLeft(2, '0')}'; } } + +final _plugin = FlutterLocalNotificationsPlugin(); + +Future requestPermissions() async { + if (Platform.isAndroid) { + final android = + _plugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin + >(); + + // Android 13+ — standard notification permission (shows a dialog) + await android?.requestNotificationsPermission(); + + // Android 12+ — exact alarm special access (opens system settings page) + await android?.requestExactAlarmsPermission(); + } +} + +final android = + _plugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin + >(); From dfca094c95423155b4eed0ab53fbf24e290fb9f3 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Fri, 25 Sep 2026 11:58:32 -0700 Subject: [PATCH 27/40] gitignore, add anything in the release directory. --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6e4f705..a82d757 100644 --- a/.gitignore +++ b/.gitignore @@ -153,4 +153,6 @@ google-services.json # Android Profiling *.hprof -linux-bundle.zip +# Staged build files for distribution. +*.linux-bundle.zip +release/* From aade4fd7f207a3e83ce8f659d1bb291bf1183f45 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Fri, 25 Sep 2026 12:07:11 -0700 Subject: [PATCH 28/40] Change alarm display code to ensure we're hitting the Android section. --- lib/main.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index a88c43d..badec0e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -173,6 +173,7 @@ class _HomeScreenState extends State { Timer? _alarmTimer; Future _scheduleAlarm() async { + // Ensure that Android has the correct permissions enabled. final canSchedule = await android?.canScheduleExactNotifications(); if (canSchedule != true) { _showSnack('Permissions not yet granted, requesting...'); @@ -220,7 +221,7 @@ class _HomeScreenState extends State { _showSnack( 'Alarm set for ${alarmTime.hour.toString().padLeft(2, '0')}:${alarmTime.minute.toString().padLeft(2, '0')} (app must stay open)', ); - } else { + } else if (Platform.isAndroid) { // Android: use zonedSchedule (works in background) final tzAlarm = tz.TZDateTime.from(alarmTime, tz.local); const androidDetails = AndroidNotificationDetails( @@ -243,6 +244,8 @@ class _HomeScreenState extends State { UILocalNotificationDateInterpretation.absoluteTime, ); _showSnack('Alarm scheduled.'); + } else { + _showSnack('Platform not detected, unsure how to show alarm.'); } } From 5f14dbbc5b7cabffef0c2b83e8abfd0302c6e38b Mon Sep 17 00:00:00 2001 From: Hyperling Date: Fri, 25 Sep 2026 12:07:30 -0700 Subject: [PATCH 29/40] Add an additional permission in case that's why Android is not alarming. --- android/app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 2973385..169c10c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -47,4 +47,5 @@ + From 9ac5fdd4f6e6c81d353f2788a075d6c455bbbb33 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Mon, 28 Sep 2026 03:06:18 -0700 Subject: [PATCH 30/40] android, move permissions to beginning of manifest file based on studio suggestion. --- android/app/src/main/AndroidManifest.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 169c10c..a9f34d9 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,11 @@ + + + + + + + - - - - - - From 6de5fbe99167a5210211041b293f4d54584b6c71 Mon Sep 17 00:00:00 2001 From: Hyperling Date: Mon, 28 Sep 2026 03:43:27 -0700 Subject: [PATCH 31/40] main, ensure the notifications permission is requested. --- lib/main.dart | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index badec0e..1bf930f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -173,7 +173,15 @@ class _HomeScreenState extends State { Timer? _alarmTimer; Future _scheduleAlarm() async { - // Ensure that Android has the correct permissions enabled. + // Get the Notifications permission: + final android = + _notifications + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin + >(); + await android?.requestNotificationsPermission(); + + // Ensure that Android has the correct alarm permissions. final canSchedule = await android?.canScheduleExactNotifications(); if (canSchedule != true) { _showSnack('Permissions not yet granted, requesting...'); @@ -243,7 +251,12 @@ class _HomeScreenState extends State { uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, ); - _showSnack('Alarm scheduled.'); + _showSnack('Alarm scheduled!'); + debugPrint('DEBUG: Alarm time: ${tzAlarm.toString()}'); + debugPrint('DEBUG: Current time: ${DateTime.now().toUtc().toString()}'); + debugPrint('DEBUG: ${_notifications.toString()}'); + + debugPrint('alarm: $tzAlarm, now: ${tz.TZDateTime.now(tz.local)}'); } else { _showSnack('Platform not detected, unsure how to show alarm.'); } From 3d89661b375f9dc2766de990fc62cdfc7e3e2a3c Mon Sep 17 00:00:00 2001 From: Hyperling Date: Mon, 28 Sep 2026 03:44:10 -0700 Subject: [PATCH 32/40] android, add receiver block to the manifest, seems to be the last piece of the puzzle for getting a notification to go off, but was not a true alarm. --- android/app/src/main/AndroidManifest.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a9f34d9..4064286 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -37,6 +37,21 @@ + + + + + + + + + + + + +