Add multi calendar support and protected web app
This commit is contained in:
+102
-6
@@ -11,6 +11,7 @@ class _OtthonAppState extends State<OtthonApp> {
|
||||
final store = AppJsonStore();
|
||||
final weatherService = WeatherService();
|
||||
List<Person> people = defaultPeople();
|
||||
List<AppCalendar> appCalendars = defaultAppCalendars();
|
||||
List<GoogleCalendarConnection> googleConnections = defaultGoogleConnections();
|
||||
List<CalendarEvent> syncedEvents = [];
|
||||
List<String> todoSuggestions = [];
|
||||
@@ -38,6 +39,7 @@ class _OtthonAppState extends State<OtthonApp> {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
people = settings.people;
|
||||
appCalendars = settings.appCalendars;
|
||||
googleConnections = settings.googleConnections;
|
||||
syncedEvents = settings.syncedEvents;
|
||||
todoSuggestions = settings.todoSuggestions;
|
||||
@@ -54,6 +56,7 @@ class _OtthonAppState extends State<OtthonApp> {
|
||||
await store.save(
|
||||
AppSettings(
|
||||
people: people,
|
||||
appCalendars: appCalendars,
|
||||
themeId: themeId,
|
||||
languageCode: languageCode,
|
||||
googleConnections: googleConnections,
|
||||
@@ -98,6 +101,11 @@ class _OtthonAppState extends State<OtthonApp> {
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void _updateAppCalendars(List<AppCalendar> nextCalendars) {
|
||||
setState(() => appCalendars = nextCalendars);
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void _updateTheme(String nextThemeId) {
|
||||
setState(() => themeId = nextThemeId);
|
||||
_saveSettings();
|
||||
@@ -177,6 +185,7 @@ class _OtthonAppState extends State<OtthonApp> {
|
||||
),
|
||||
home: HomeShell(
|
||||
people: people,
|
||||
appCalendars: appCalendars,
|
||||
googleConnections: googleConnections,
|
||||
syncedEvents: syncedEvents,
|
||||
todoSuggestions: todoSuggestions,
|
||||
@@ -187,6 +196,7 @@ class _OtthonAppState extends State<OtthonApp> {
|
||||
languageCode: languageCode,
|
||||
loaded: loaded,
|
||||
onPeopleChanged: _updatePeople,
|
||||
onAppCalendarsChanged: _updateAppCalendars,
|
||||
onThemeChanged: _updateTheme,
|
||||
onLanguageChanged: _updateLanguage,
|
||||
onGoogleConnectionsChanged: _updateGoogleConnections,
|
||||
@@ -202,6 +212,7 @@ class HomeShell extends StatefulWidget {
|
||||
const HomeShell({
|
||||
super.key,
|
||||
required this.people,
|
||||
required this.appCalendars,
|
||||
required this.googleConnections,
|
||||
required this.syncedEvents,
|
||||
required this.todoSuggestions,
|
||||
@@ -212,6 +223,7 @@ class HomeShell extends StatefulWidget {
|
||||
required this.languageCode,
|
||||
required this.loaded,
|
||||
required this.onPeopleChanged,
|
||||
required this.onAppCalendarsChanged,
|
||||
required this.onThemeChanged,
|
||||
required this.onLanguageChanged,
|
||||
required this.onGoogleConnectionsChanged,
|
||||
@@ -221,6 +233,7 @@ class HomeShell extends StatefulWidget {
|
||||
});
|
||||
|
||||
final List<Person> people;
|
||||
final List<AppCalendar> appCalendars;
|
||||
final List<GoogleCalendarConnection> googleConnections;
|
||||
final List<CalendarEvent> syncedEvents;
|
||||
final List<String> todoSuggestions;
|
||||
@@ -231,6 +244,7 @@ class HomeShell extends StatefulWidget {
|
||||
final String languageCode;
|
||||
final bool loaded;
|
||||
final ValueChanged<List<Person>> onPeopleChanged;
|
||||
final ValueChanged<List<AppCalendar>> onAppCalendarsChanged;
|
||||
final ValueChanged<String> onThemeChanged;
|
||||
final ValueChanged<String> onLanguageChanged;
|
||||
final ValueChanged<List<GoogleCalendarConnection>> onGoogleConnectionsChanged;
|
||||
@@ -363,25 +377,51 @@ class _HomeShellState extends State<HomeShell> {
|
||||
Widget build(BuildContext context) {
|
||||
final wide = MediaQuery.sizeOf(context).width >= 850;
|
||||
final text = AppText.of(widget.languageCode);
|
||||
final mainCalendarEvents = allEvents
|
||||
.where((event) => event.appCalendarId == null)
|
||||
.toList();
|
||||
final secondaryCalendarEvents = allEvents
|
||||
.where((event) => event.appCalendarId != null)
|
||||
.toList();
|
||||
final labels = [
|
||||
text.calendar,
|
||||
...widget.appCalendars.map((calendar) => calendar.name),
|
||||
text.shopping,
|
||||
text.stock,
|
||||
text.familyMembers,
|
||||
text.style,
|
||||
text.accounts,
|
||||
];
|
||||
final navIcons = [
|
||||
icons.first,
|
||||
...List.filled(widget.appCalendars.length, Icons.event_note_outlined),
|
||||
...icons.skip(1),
|
||||
];
|
||||
final body = IndexedStack(
|
||||
index: selected,
|
||||
children: [
|
||||
CalendarPage(
|
||||
events: allEvents,
|
||||
events: mainCalendarEvents,
|
||||
people: widget.people,
|
||||
weather: widget.weather,
|
||||
onAdd: _addEvent,
|
||||
secondaryEvents: secondaryCalendarEvents,
|
||||
appCalendars: widget.appCalendars,
|
||||
onAdd: () => _addEvent(),
|
||||
onEdit: _editEvent,
|
||||
onAssignPerson: _assignSyncedEventToPerson,
|
||||
),
|
||||
...widget.appCalendars.map(
|
||||
(calendar) => CalendarPage(
|
||||
title: calendar.name,
|
||||
events: allEvents
|
||||
.where((event) => event.appCalendarId == calendar.id)
|
||||
.toList(),
|
||||
people: widget.people,
|
||||
weather: widget.weather,
|
||||
onAdd: () => _addEvent(appCalendarId: calendar.id),
|
||||
onEdit: _editEvent,
|
||||
),
|
||||
),
|
||||
ShoppingPage(
|
||||
items: shopping,
|
||||
languageCode: widget.languageCode,
|
||||
@@ -413,6 +453,7 @@ class _HomeShellState extends State<HomeShell> {
|
||||
connections: widget.googleConnections,
|
||||
cachedEvents: widget.syncedEvents,
|
||||
people: widget.people,
|
||||
appCalendars: widget.appCalendars,
|
||||
jarvisSettings: widget.jarvisSettings,
|
||||
serverClientId: widget.googleServerClientId,
|
||||
languageCode: widget.languageCode,
|
||||
@@ -517,6 +558,23 @@ class _HomeShellState extends State<HomeShell> {
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: '\u00daj napt\u00e1r',
|
||||
onPressed: _addAppCalendar,
|
||||
icon: const Icon(
|
||||
Icons.add_circle_outline,
|
||||
size: 19,
|
||||
),
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: sage,
|
||||
minimumSize: const Size(30, 30),
|
||||
tapTargetSize:
|
||||
MaterialTapTargetSize.shrinkWrap,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
IconButton(
|
||||
tooltip: text.jarvisSettings,
|
||||
onPressed: _openJarvisSettings,
|
||||
@@ -540,8 +598,8 @@ class _HomeShellState extends State<HomeShell> {
|
||||
destinations: List.generate(
|
||||
labels.length,
|
||||
(i) => NavigationRailDestination(
|
||||
icon: Icon(icons[i]),
|
||||
selectedIcon: Icon(icons[i]),
|
||||
icon: Icon(navIcons[i]),
|
||||
selectedIcon: Icon(navIcons[i]),
|
||||
label: Text(labels[i]),
|
||||
),
|
||||
),
|
||||
@@ -728,7 +786,8 @@ class _HomeShellState extends State<HomeShell> {
|
||||
destinations: List.generate(
|
||||
labels.length,
|
||||
(i) => NavigationDestination(
|
||||
icon: Icon(icons[i]),
|
||||
icon: Icon(navIcons[i]),
|
||||
selectedIcon: Icon(navIcons[i]),
|
||||
label: labels[i],
|
||||
),
|
||||
),
|
||||
@@ -756,6 +815,30 @@ class _HomeShellState extends State<HomeShell> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _addAppCalendar() async {
|
||||
final data = await showDialog<List<String>>(
|
||||
context: context,
|
||||
builder: (_) => const QuickAddDialog(
|
||||
title: 'Napt\u00e1r hozz\u00e1ad\u00e1sa',
|
||||
firstLabel: 'Napt\u00e1r neve',
|
||||
secondLabel: 'Le\u00edr\u00e1s (opcion\u00e1lis)',
|
||||
),
|
||||
);
|
||||
final name = data == null ? '' : data.first.trim();
|
||||
if (name.isEmpty) return;
|
||||
|
||||
final color =
|
||||
appCalendarColors[widget.appCalendars.length %
|
||||
appCalendarColors.length];
|
||||
final nextCalendar = AppCalendar(
|
||||
id: uniqueId(),
|
||||
name: name,
|
||||
colorValue: color.toARGB32(),
|
||||
);
|
||||
widget.onAppCalendarsChanged([...widget.appCalendars, nextCalendar]);
|
||||
setState(() => selected = widget.appCalendars.length + 1);
|
||||
}
|
||||
|
||||
Future<void> _openJarvisSettings() async {
|
||||
final result = await showDialog<JarvisSettings>(
|
||||
context: context,
|
||||
@@ -963,11 +1046,12 @@ class _HomeShellState extends State<HomeShell> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _addEvent() async {
|
||||
Future<void> _addEvent({String? appCalendarId}) async {
|
||||
final data = await showDialog<EventInput>(
|
||||
context: context,
|
||||
builder: (_) => EventAddDialog(
|
||||
people: widget.people,
|
||||
appCalendars: widget.appCalendars,
|
||||
todoSuggestions: widget.todoSuggestions,
|
||||
),
|
||||
);
|
||||
@@ -986,6 +1070,7 @@ class _HomeShellState extends State<HomeShell> {
|
||||
.color,
|
||||
personId: assignedPersonId,
|
||||
date: data.date,
|
||||
appCalendarId: data.appCalendarId ?? appCalendarId,
|
||||
note: data.note,
|
||||
hasTodos: data.hasTodos,
|
||||
todos: data.todos,
|
||||
@@ -1001,6 +1086,7 @@ class _HomeShellState extends State<HomeShell> {
|
||||
context: context,
|
||||
builder: (_) => EventAddDialog(
|
||||
people: widget.people,
|
||||
appCalendars: widget.appCalendars,
|
||||
event: event,
|
||||
todoSuggestions: widget.todoSuggestions,
|
||||
),
|
||||
@@ -1017,6 +1103,8 @@ class _HomeShellState extends State<HomeShell> {
|
||||
date: data.date,
|
||||
color: color,
|
||||
personId: assignedPersonId,
|
||||
appCalendarId: data.appCalendarId,
|
||||
clearAppCalendar: data.appCalendarId == null,
|
||||
note: data.note,
|
||||
hasTodos: data.hasTodos,
|
||||
todos: data.todos,
|
||||
@@ -1032,6 +1120,14 @@ class _HomeShellState extends State<HomeShell> {
|
||||
});
|
||||
|
||||
if (event.isSynced) {
|
||||
if (widget.googleConnections.isNotEmpty) {
|
||||
final currentConnection = widget.googleConnections.first;
|
||||
final nextEventPersonIds = {...currentConnection.eventPersonIds};
|
||||
nextEventPersonIds[importedEventKey(event)] = assignedPersonId;
|
||||
widget.onGoogleConnectionsChanged([
|
||||
currentConnection.copyWith(eventPersonIds: nextEventPersonIds),
|
||||
]);
|
||||
}
|
||||
final nextSyncedEvents = [
|
||||
for (final syncedEvent in widget.syncedEvents)
|
||||
if (identical(syncedEvent, event)) updated else syncedEvent,
|
||||
|
||||
Reference in New Issue
Block a user