Notifications added to the app -> updated version to V1.1.0
This commit is contained in:
@@ -5,6 +5,7 @@ import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import '../services/google_calendar_service.dart';
|
||||
import '../services/notification_service.dart';
|
||||
import '../utils/translations.dart';
|
||||
import '../utils/target_colors.dart';
|
||||
|
||||
@@ -234,6 +235,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
_events = filteredEvents;
|
||||
});
|
||||
}
|
||||
NotificationService().scheduleEventNotifications(filteredEvents);
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
|
||||
@@ -133,7 +133,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
padding: const EdgeInsets.only(right: 16.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'V1.0.3',
|
||||
'V1.1',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[400],
|
||||
fontSize: 12,
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user