Persist per-event Google calendar assignments
This commit is contained in:
@@ -26,7 +26,8 @@ class AccountsPage extends StatefulWidget {
|
||||
State<AccountsPage> createState() => _AccountsPageState();
|
||||
}
|
||||
|
||||
class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver {
|
||||
class _AccountsPageState extends State<AccountsPage>
|
||||
with WidgetsBindingObserver {
|
||||
List<GoogleCalendarInfo> googleCalendars = [];
|
||||
bool loadingCalendars = false;
|
||||
bool syncing = false;
|
||||
@@ -89,7 +90,10 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
|
||||
Uri _jarvisUri(String path, [Map<String, String?> query = const {}]) {
|
||||
final baseUri = Uri.parse(normalizeJarvisUrl(widget.jarvisSettings.apiUrl));
|
||||
return baseUri.replace(path: path, queryParameters: query.isEmpty ? null : query);
|
||||
return baseUri.replace(
|
||||
path: path,
|
||||
queryParameters: query.isEmpty ? null : query,
|
||||
);
|
||||
}
|
||||
|
||||
String? _jarvisConfigError() {
|
||||
@@ -121,7 +125,9 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
.get(_jarvisUri('/api/google/oauth/status'), headers: _jarvisHeaders)
|
||||
.timeout(const Duration(seconds: 10));
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('JARVIS status ${response.statusCode}: ${response.body}');
|
||||
throw Exception(
|
||||
'JARVIS status ${response.statusCode}: ${response.body}',
|
||||
);
|
||||
}
|
||||
final payload = jsonDecode(response.body);
|
||||
if (payload is! Map<String, dynamic>) {
|
||||
@@ -137,6 +143,7 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
accountEmail: email ?? current?.accountEmail ?? 'Google fi\u00f3k',
|
||||
enabledCalendarIds: current?.enabledCalendarIds ?? const [],
|
||||
calendarPersonIds: current?.calendarPersonIds ?? const {},
|
||||
eventPersonIds: current?.eventPersonIds ?? const {},
|
||||
lastSync: current?.lastSync,
|
||||
),
|
||||
]);
|
||||
@@ -152,7 +159,8 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
loadingCalendars = false;
|
||||
statusMessage = 'JARVIS Google kapcsolat nem el\u00e9rhet\u0151: $error';
|
||||
statusMessage =
|
||||
'JARVIS Google kapcsolat nem el\u00e9rhet\u0151: $error';
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -160,7 +168,8 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
Future<void> _startGoogleConnection() async {
|
||||
setState(() {
|
||||
loadingCalendars = true;
|
||||
statusMessage = 'Google \u00f6sszek\u00f6t\u00e9s ind\u00edt\u00e1sa JARVIS-on...';
|
||||
statusMessage =
|
||||
'Google \u00f6sszek\u00f6t\u00e9s ind\u00edt\u00e1sa JARVIS-on...';
|
||||
});
|
||||
|
||||
final configError = _jarvisConfigError();
|
||||
@@ -176,17 +185,27 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
.get(_jarvisUri('/api/google/oauth/start'), headers: _jarvisHeaders)
|
||||
.timeout(const Duration(seconds: 10));
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('JARVIS OAuth ${response.statusCode}: ${response.body}');
|
||||
throw Exception(
|
||||
'JARVIS OAuth ${response.statusCode}: ${response.body}',
|
||||
);
|
||||
}
|
||||
final payload = jsonDecode(response.body);
|
||||
if (payload is! Map<String, dynamic>) throw Exception('Hib\u00e1s JARVIS v\u00e1lasz.');
|
||||
if (payload is! Map<String, dynamic>) {
|
||||
throw Exception('Hib\u00e1s JARVIS v\u00e1lasz.');
|
||||
}
|
||||
final url = payload['authorizationUrl'] as String?;
|
||||
if (url == null || url.isEmpty) throw Exception('Hi\u00e1nyzik az OAuth URL.');
|
||||
if (url == null || url.isEmpty) {
|
||||
throw Exception('Hi\u00e1nyzik az OAuth URL.');
|
||||
}
|
||||
final launched = await launchUrl(
|
||||
Uri.parse(url),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
if (!launched) throw Exception('Nem siker\u00fclt megnyitni a b\u00f6ng\u00e9sz\u0151t.');
|
||||
if (!launched) {
|
||||
throw Exception(
|
||||
'Nem siker\u00fclt megnyitni a b\u00f6ng\u00e9sz\u0151t.',
|
||||
);
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
waitingForGoogleAuthReturn = true;
|
||||
@@ -198,7 +217,8 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
loadingCalendars = false;
|
||||
statusMessage = 'Google \u00f6sszek\u00f6t\u00e9s nem indult el: $error';
|
||||
statusMessage =
|
||||
'Google \u00f6sszek\u00f6t\u00e9s nem indult el: $error';
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -243,6 +263,7 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
accountEmail: 'Google Calendar',
|
||||
enabledCalendarIds: const [],
|
||||
calendarPersonIds: const {},
|
||||
eventPersonIds: const {},
|
||||
lastSync: null,
|
||||
),
|
||||
]);
|
||||
@@ -290,6 +311,17 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
.toList();
|
||||
final synced = <CalendarEvent>[];
|
||||
final syncDetails = <String>[];
|
||||
final eventPersonOverrides = {...current.eventPersonIds};
|
||||
for (final cachedEvent in widget.cachedEvents) {
|
||||
if (!cachedEvent.isSynced || cachedEvent.personId == null) continue;
|
||||
final defaultPersonId =
|
||||
current.calendarPersonIds[cachedEvent.calendarId];
|
||||
if (cachedEvent.personId == defaultPersonId) continue;
|
||||
eventPersonOverrides.putIfAbsent(
|
||||
importedEventKey(cachedEvent),
|
||||
() => cachedEvent.personId!,
|
||||
);
|
||||
}
|
||||
final now = DateTime.now();
|
||||
final start = DateTime(
|
||||
now.year,
|
||||
@@ -299,19 +331,18 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
final end = start.add(const Duration(days: 180));
|
||||
|
||||
for (final calendar in selectedCalendars) {
|
||||
final uri = _jarvisUri(
|
||||
'/api/google/events',
|
||||
{
|
||||
'calendarId': calendar.id,
|
||||
'timeMin': start.toUtc().toIso8601String(),
|
||||
'timeMax': end.toUtc().toIso8601String(),
|
||||
},
|
||||
);
|
||||
final uri = _jarvisUri('/api/google/events', {
|
||||
'calendarId': calendar.id,
|
||||
'timeMin': start.toUtc().toIso8601String(),
|
||||
'timeMax': end.toUtc().toIso8601String(),
|
||||
});
|
||||
final response = await http
|
||||
.get(uri, headers: _jarvisHeaders)
|
||||
.timeout(const Duration(seconds: 20));
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('${calendar.name}: Events API ${response.statusCode}');
|
||||
throw Exception(
|
||||
'${calendar.name}: Events API ${response.statusCode}',
|
||||
);
|
||||
}
|
||||
|
||||
final payload = jsonDecode(response.body);
|
||||
@@ -323,13 +354,12 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
syncDetails.add('${calendar.name}: ${events.length}');
|
||||
for (final event in events) {
|
||||
if (event['status'] == 'cancelled') continue;
|
||||
synced.add(
|
||||
CalendarEvent.fromGoogleEvent(
|
||||
event,
|
||||
calendar,
|
||||
personId: current.calendarPersonIds[calendar.id],
|
||||
),
|
||||
);
|
||||
final imported = CalendarEvent.fromGoogleEvent(event, calendar);
|
||||
final eventKey = importedEventKey(imported);
|
||||
final assignedPersonId =
|
||||
eventPersonOverrides[eventKey] ??
|
||||
current.calendarPersonIds[calendar.id];
|
||||
synced.add(imported.copyWith(personId: assignedPersonId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +369,12 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
});
|
||||
|
||||
widget.onSyncedEventsChanged(synced);
|
||||
widget.onChanged([current.copyWith(lastSync: DateTime.now())]);
|
||||
widget.onChanged([
|
||||
current.copyWith(
|
||||
eventPersonIds: eventPersonOverrides,
|
||||
lastSync: DateTime.now(),
|
||||
),
|
||||
]);
|
||||
setState(() {
|
||||
syncing = false;
|
||||
statusMessage =
|
||||
@@ -369,9 +404,7 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
action: FilledButton.icon(
|
||||
onPressed: loadingCalendars ? null : _startGoogleConnection,
|
||||
icon: const Icon(Icons.open_in_browser),
|
||||
label: Text(
|
||||
hasConnection ? text.googleReconnect : text.googleConnect,
|
||||
),
|
||||
label: Text(hasConnection ? text.googleReconnect : text.googleConnect),
|
||||
),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
@@ -457,9 +490,7 @@ class _AccountsPageState extends State<AccountsPage> with WidgetsBindingObserver
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
OutlinedButton.icon(
|
||||
onPressed: loadingCalendars
|
||||
? null
|
||||
: _loadGoogleConnectionStatus,
|
||||
onPressed: loadingCalendars ? null : _loadGoogleConnectionStatus,
|
||||
icon: const Icon(Icons.refresh),
|
||||
label: const Text('Google napt\u00e1rlista friss\u00edt\u00e9se'),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user