From 35dc47fd62b890cb655ced2d4e679679e8496d1f Mon Sep 17 00:00:00 2001 From: Kima Date: Sun, 11 Feb 2024 19:39:33 +0100 Subject: [PATCH] first google calendar timetable sync demo done --- filcnaplo/android/app/build.gradle | 11 ++ filcnaplo/lib/app.dart | 6 + filcnaplo/lib/main.dart | 9 ++ .../lib/providers/third_party_provider.dart | 133 ++++++++++++++++++ filcnaplo/pubspec.yaml | 4 + .../lib/pages/timetable/timetable_page.dart | 52 ++++--- .../lib/screens/settings/settings_screen.dart | 25 ++++ refilc_plus | 2 +- 8 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 filcnaplo/lib/providers/third_party_provider.dart diff --git a/filcnaplo/android/app/build.gradle b/filcnaplo/android/app/build.gradle index 49825fb..e1fddd7 100644 --- a/filcnaplo/android/app/build.gradle +++ b/filcnaplo/android/app/build.gradle @@ -62,6 +62,13 @@ android { } signingConfigs { + debug { + keyAlias "androiddebugkey" + keyPassword "Jelszo123" + storeFile file("C:/Users/kima/debugkeystore.jks") + storePassword "Jelszo123" + } + release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] @@ -71,6 +78,10 @@ android { } buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { signingConfig signingConfigs.release shrinkResources false diff --git a/filcnaplo/lib/app.dart b/filcnaplo/lib/app.dart index 18135e1..c5383a8 100644 --- a/filcnaplo/lib/app.dart +++ b/filcnaplo/lib/app.dart @@ -12,6 +12,7 @@ import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/self_note_provider.dart'; import 'package:filcnaplo/api/providers/status_provider.dart'; import 'package:filcnaplo/models/config.dart'; +import 'package:filcnaplo/providers/third_party_provider.dart'; import 'package:filcnaplo/theme/observer.dart'; import 'package:filcnaplo/theme/theme.dart'; import 'package:filcnaplo_kreta_api/client/client.dart'; @@ -178,6 +179,11 @@ class App extends StatelessWidget { ChangeNotifierProvider( create: (context) => SelfNoteProvider(context: context), ), + + // third party providers + ChangeNotifierProvider( + create: (context) => ThirdPartyProvider(context: context), + ), ], child: Consumer( builder: (context, themeMode, child) { diff --git a/filcnaplo/lib/main.dart b/filcnaplo/lib/main.dart index c3ae0e0..42748de 100644 --- a/filcnaplo/lib/main.dart +++ b/filcnaplo/lib/main.dart @@ -13,6 +13,9 @@ import 'package:flutter/services.dart'; import 'package:filcnaplo_mobile_ui/screens/error_screen.dart'; import 'package:filcnaplo_mobile_ui/screens/error_report_screen.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +// import 'package:firebase_core/firebase_core.dart'; + +// import 'firebase_options.dart'; void main() async { // Initalize @@ -112,6 +115,12 @@ class Startup { initializationSettings, ); } + + // if (Platform.isAndroid || Platform.isIOS) { + // await Firebase.initializeApp( + // options: DefaultFirebaseOptions.currentPlatform, + // ); + // } } } diff --git a/filcnaplo/lib/providers/third_party_provider.dart b/filcnaplo/lib/providers/third_party_provider.dart new file mode 100644 index 0000000..a0f0fc6 --- /dev/null +++ b/filcnaplo/lib/providers/third_party_provider.dart @@ -0,0 +1,133 @@ +import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; +import 'package:filcnaplo_kreta_api/controllers/timetable_controller.dart'; +import 'package:filcnaplo_kreta_api/models/lesson.dart'; +import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:googleapis/calendar/v3.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:provider/provider.dart'; + +class ThirdPartyProvider with ChangeNotifier { + late List? _googleEvents; + // late BuildContext _context; + + static final _googleSignIn = GoogleSignIn(scopes: [ + CalendarApi.calendarScope, + CalendarApi.calendarEventsScope, + ]); + + List get googleEvents => _googleEvents ?? []; + + ThirdPartyProvider({ + required BuildContext context, + }) { + // _context = context; + } + + Future googleSignIn() async { + if (!await _googleSignIn.isSignedIn()) { + return _googleSignIn.signIn(); + } + return null; + } + + // Future fetchGoogle() async { + // try { + // var httpClient = (await _googleSignIn.authenticatedClient())!; + // var calendarApi = CalendarApi(httpClient); + + // var calendarList = await calendarApi.calendarList.list(); + + // if (calendarList.items == null) return; + // if (calendarList.items!.isEmpty) return; + + // _googleEvents = (await calendarApi.events.list( + // '13342d17fe1e68680c43c0c44dcb7e30cb0171cc4e4ee9ee13c9ff3082d3279c@group.calendar.google.com')) + // .items; + + // print(calendarList.items! + // .map((e) => (e.id ?? 'noid') + '-' + (e.description ?? 'nodesc'))); + // print(_googleEvents!.map((e) => e.toJson())); + // } catch (e) { + // print(e); + // await _googleSignIn.signOut(); + // } + // } + + Future pushEvent({ + required String title, + required String calendarId, + required DateTime start, + required DateTime end, + }) async { + try { + var httpClient = (await _googleSignIn.authenticatedClient())!; + var calendarApi = CalendarApi(httpClient); + + Event event = Event( + created: DateTime.now(), + creator: EventCreator(self: true), + start: EventDateTime(dateTime: start), + end: EventDateTime(dateTime: end), + summary: title, + ); + + return await calendarApi.events.insert(event, calendarId); + } catch (e) { + if (kDebugMode) print(e); + await _googleSignIn.signOut(); + } + + return null; + } + + Future createCalendar({ + required String name, + required String description, + }) async { + try { + var httpClient = (await _googleSignIn.authenticatedClient())!; + var calendarApi = CalendarApi(httpClient); + + Calendar calendar = Calendar( + summary: name, + description: description, + timeZone: 'Europe/Budapest', + ); + + return await calendarApi.calendars.insert(calendar); + } catch (e) { + if (kDebugMode) print(e); + await _googleSignIn.signOut(); + } + + return null; + } + + Future pushTimetable( + BuildContext context, TimetableController controller) async { + Calendar? calendar = await createCalendar( + name: 'reFilc - Órarend', + description: + 'Ez egy automatikusan generált naptár, melyet a reFilc hozott létre az órarend számára.', + ); + + if (calendar == null) return; + + final days = controller.days!; + final everyLesson = days.expand((x) => x).toList(); + everyLesson.sort((a, b) => a.start.compareTo(b.start)); + + for (Lesson l in everyLesson) { + Event? event = await pushEvent( + title: l.name, + calendarId: calendar.id!, + start: l.start, + end: l.end, + ); + } + + print('finished'); + } +} diff --git a/filcnaplo/pubspec.yaml b/filcnaplo/pubspec.yaml index a976869..b5f2fae 100644 --- a/filcnaplo/pubspec.yaml +++ b/filcnaplo/pubspec.yaml @@ -72,6 +72,10 @@ dependencies: image_crop: git: url: https://github.com/kimaah/image_crop.git + googleapis: ^12.0.0 + google_sign_in: ^6.2.1 + extension_google_sign_in_as_googleapis_auth: ^2.0.12 + firebase_core: ^2.25.4 dev_dependencies: flutter_lints: ^3.0.1 diff --git a/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart b/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart index 529e48a..e71298e 100755 --- a/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart +++ b/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:animations/animations.dart'; import 'package:filcnaplo/api/providers/update_provider.dart'; import 'package:filcnaplo/models/settings.dart'; +import 'package:filcnaplo/providers/third_party_provider.dart'; import 'package:filcnaplo/utils/format.dart'; import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/models/week.dart'; @@ -210,30 +211,37 @@ class TimetablePageState extends State padding: const EdgeInsets.all(8.0), child: IconButton( splashRadius: 24.0, - onPressed: () { - // If timetable empty, show empty - if (_tabController.length == 0) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text("empty_timetable".i18n), - duration: const Duration(seconds: 2), - )); - return; - } + onPressed: () async { + ThirdPartyProvider tpp = + Provider.of(context, + listen: false); - Navigator.of(context, rootNavigator: true) - .push(PageRouteBuilder( - pageBuilder: - (context, animation, secondaryAnimation) => - FSTimetable( - controller: _controller, - ), - )) - .then((_) { - SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp]); - setSystemChrome(context); - }); + await tpp.pushTimetable(context, _controller); }, + // onPressed: () { + // // If timetable empty, show empty + // if (_tabController.length == 0) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text("empty_timetable".i18n), + // duration: const Duration(seconds: 2), + // )); + // return; + // } + + // Navigator.of(context, rootNavigator: true) + // .push(PageRouteBuilder( + // pageBuilder: + // (context, animation, secondaryAnimation) => + // FSTimetable( + // controller: _controller, + // ), + // )) + // .then((_) { + // SystemChrome.setPreferredOrientations( + // [DeviceOrientation.portraitUp]); + // setSystemChrome(context); + // }); + // }, icon: Icon(FeatherIcons.trello, color: AppColors.of(context).text), ), diff --git a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart index 990132d..2c21cbd 100755 --- a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart +++ b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart @@ -1,6 +1,7 @@ // ignore_for_file: no_leading_underscores_for_local_identifiers, use_build_context_synchronously, deprecated_member_use import 'package:filcnaplo/api/providers/update_provider.dart'; +import 'package:filcnaplo/providers/third_party_provider.dart'; import 'package:filcnaplo/theme/colors/accent.dart'; import 'package:filcnaplo/theme/observer.dart'; import 'package:filcnaplo_kreta_api/providers/absence_provider.dart'; @@ -1095,6 +1096,30 @@ class SettingsScreenState extends State ], ), + if (kDebugMode) + SplittedPanel( + title: const Text("debug_settings"), + cardPadding: const EdgeInsets.all(4.0), + children: [ + PanelButton( + title: const Text('loginToGoogle'), + onPressed: () async { + ThirdPartyProvider tpp = Provider.of( + context, + listen: false); + + await tpp.googleSignIn(); + }, + ), + PanelButton( + title: const Text('pushTimetableToCalendar'), + onPressed: () async { + + }, + ), + ], + ), + // developer options if (settings.developerMode) SplittedPanel( diff --git a/refilc_plus b/refilc_plus index 5d73a83..534f4a6 160000 --- a/refilc_plus +++ b/refilc_plus @@ -1 +1 @@ -Subproject commit 5d73a83c7d1f8925ef20d919ed31f583d1303d23 +Subproject commit 534f4a66216a84af13d4a0b28e745e5ec8c335d0