Notifications added to the app -> updated version to V1.1.0

This commit is contained in:
2026-05-30 18:00:30 +02:00
parent c58ca5cf15
commit cd3398df99
18 changed files with 559 additions and 13 deletions
+209
View File
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../utils/translations.dart';
import '../utils/target_colors.dart';
import '../services/notification_service.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@@ -43,6 +44,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
'Grey',
];
int _notificationHours = 1;
final List<int> _notificationHourOptions = [1, 2, 3, 6, 12, 24, 48];
bool _notifyDezuranje = true;
bool _notifySestanek = true;
bool _notifyTekma = true;
String _selectedLanguage = 'English';
final List<Map<String, String>> _languages = [
{'code': 'en', 'name': 'English', 'flag': '🇬🇧'},
@@ -96,6 +104,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
_loadBulletColor();
_loadLanguage();
_loadSelectedTarget();
_loadNotificationSettings();
}
@@ -205,6 +214,28 @@ String _getTargetDisplayName(String targetPath) {
return _t(targetName);
}
Future<void> _loadNotificationSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_notificationHours = prefs.getInt('notificationHours_single') ?? 1;
_notifyDezuranje = prefs.getBool('notifyDezuranje') ?? true;
_notifySestanek = prefs.getBool('notifySestanek') ?? true;
_notifyTekma = prefs.getBool('notifyTekma') ?? true;
});
}
Future<void> _saveNotificationHours(int hours) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('notificationHours_single', hours);
await prefs.setStringList('notificationHours', [hours.toString()]);
setState(() => _notificationHours = hours);
}
Future<void> _saveNotifyType(String key, bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(key, value);
}
Future<void> _loadCameraIPs() async {
final prefs = await SharedPreferences.getInstance();
@@ -388,6 +419,8 @@ String _getTargetDisplayName(String targetPath) {
_buildAppearanceSelector(),
const SizedBox(height: 16),
_buildNotificationSettings(),
const SizedBox(height: 16),
_buildCameraList(),
],
),
@@ -1096,4 +1129,180 @@ void _showLanguagePopup() {
);
}
Widget _buildNotifyToggle(String label, bool value, ValueChanged<bool> onChanged) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(color: Colors.black87, fontSize: 14)),
Switch(
value: value,
onChanged: onChanged,
activeThumbColor: _getColorFromName(_selectedBulletColor),
),
],
),
);
}
Widget _buildNotificationSettings() {
return Container(
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 0),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: Colors.grey[900],
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
child: Row(
children: [
Container(
width: 4,
height: 16,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
_t('Notifications'),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
GestureDetector(
onTap: () async {
await NotificationService().scheduleTestNotification();
},
child: const Icon(Icons.notifications_active_outlined, color: Colors.white, size: 20),
),
],
),
),
// Hours before picker
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 4),
Text(
_t('Event types'),
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 8),
_buildNotifyToggle(_t('Dežuranje'), _notifyDezuranje, (v) {
setState(() => _notifyDezuranje = v);
_saveNotifyType('notifyDezuranje', v);
}),
_buildNotifyToggle(_t('Sestanek'), _notifySestanek, (v) {
setState(() => _notifySestanek = v);
_saveNotifyType('notifySestanek', v);
}),
_buildNotifyToggle(_t('Tekma'), _notifyTekma, (v) {
setState(() => _notifyTekma = v);
_saveNotifyType('notifyTekma', v);
}),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_t('Notify before event'),
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.black87),
),
Text(
_notificationHours == 1
? '1 ${_t('hour')}'
: '$_notificationHours ${_t('hours')}',
style: TextStyle(
color: _getColorFromName(_selectedBulletColor),
fontWeight: FontWeight.bold,
fontSize: 13,
),
),
],
),
const SizedBox(height: 12),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Row(
children: _notificationHourOptions.asMap().entries.map((entry) {
final i = entry.key;
final hours = entry.value;
final isSelected = hours == _notificationHours;
final label = '${hours}h';
final isFirst = i == 0;
final isLast = i == _notificationHourOptions.length - 1;
return Expanded(
child: GestureDetector(
onTap: () => _saveNotificationHours(hours),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: isSelected
? _getColorFromName(_selectedBulletColor)
: Colors.grey[700],
border: Border(
right: isLast
? BorderSide.none
: BorderSide(color: Colors.grey[600]!, width: 1),
),
borderRadius: isFirst
? const BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10))
: isLast
? const BorderRadius.only(topRight: Radius.circular(10), bottomRight: Radius.circular(10))
: BorderRadius.zero,
),
child: Text(
label,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
),
),
);
}).toList(),
),
),
],
),
),
],
),
);
}
}