Line data Source code
1 : import 'package:flutter/material.dart'; 2 : import 'package:pal/src/database/entity/helper/helper_entity.dart'; 3 : import 'package:pal/src/database/entity/helper/helper_group_entity.dart'; 4 : import 'package:pal/src/database/entity/in_app_user_entity.dart'; 5 : import 'package:pal/src/pal_navigator_observer.dart'; 6 : import 'package:pal/src/services/client/helper_client_service.dart'; 7 : import 'package:pal/src/services/client/in_app_user/in_app_user_client_service.dart'; 8 : import 'package:pal/src/theme.dart'; 9 : import 'package:pal/src/ui/client/helper_factory.dart'; 10 : 11 : import 'helpers_synchronizer.dart'; 12 : 13 : /// this class is the main intelligence wether or not we are gonna show an helper to user. 14 : /// On each page visited we check if we have to show a new helper to user 15 : /// There is a variety of Helper types. 16 : class HelperOrchestrator { 17 : 18 : static HelperOrchestrator _instance; 19 : 20 : final PalRouteObserver routeObserver; 21 : 22 : final HelperClientService helperClientService; 23 : 24 : final InAppUserClientService inAppUserClientService; 25 : 26 : final GlobalKey<NavigatorState> navigatorKey; 27 : 28 : final HelpersSynchronizer helpersSynchronizer; 29 : 30 : OverlayEntry overlay; 31 : 32 : bool hasSync; 33 : 34 : 35 2 : factory HelperOrchestrator.getInstance({ 36 : GlobalKey<NavigatorState> navigatorKey, 37 : PalRouteObserver routeObserver, 38 : HelperClientService helperClientService, 39 : InAppUserClientService inAppUserClientService, 40 : HelpersSynchronizer helpersSynchronizer 41 : }) { 42 : if (_instance == null) { 43 2 : _instance = HelperOrchestrator._(routeObserver, helperClientService, inAppUserClientService, navigatorKey, helpersSynchronizer); 44 : } 45 : return _instance; 46 : } 47 : 48 : @visibleForTesting 49 1 : factory HelperOrchestrator.create({ 50 : GlobalKey<NavigatorState> navigatorKey, 51 : PalRouteObserver routeObserver, 52 : HelperClientService helperClientService, 53 : InAppUserClientService inAppUserClientService, 54 : HelpersSynchronizer helpersSynchronizer 55 : }) { 56 1 : _instance = HelperOrchestrator._(routeObserver, helperClientService, inAppUserClientService, navigatorKey, helpersSynchronizer); 57 : return _instance; 58 : } 59 : 60 2 : HelperOrchestrator._(this.routeObserver, this.helperClientService, this.inAppUserClientService, this.navigatorKey, this.helpersSynchronizer) 61 0 : : assert(routeObserver != null), 62 0 : assert(helperClientService != null), 63 0 : assert(inAppUserClientService != null) { 64 2 : this.hasSync = false; 65 8 : this.routeObserver.routeSettings.listen((RouteSettings newRoute) async { 66 2 : if (newRoute == null || newRoute.name == null) { 67 : return; 68 : } 69 3 : await onChangePage(newRoute.name); 70 : }); 71 : } 72 : 73 : @visibleForTesting 74 2 : onChangePage(final String route) async { 75 2 : if (overlay != null) { 76 1 : popHelper(); 77 : } 78 : try { 79 6 : final InAppUserEntity inAppUser = await this.inAppUserClientService.getOrCreate(); 80 1 : if(!hasSync) { 81 4 : await this.helpersSynchronizer.sync(inAppUser.id); 82 1 : this.hasSync = true; 83 : } 84 4 : final helperGroupToShow = await helperClientService.getPageNextHelper(route, inAppUser.id); 85 2 : if (helperGroupToShow != null && helperGroupToShow.helpers.isNotEmpty) { 86 4 : showHelper(helperGroupToShow, inAppUser.id, helperGroupToShow.page.id); 87 : } 88 : } catch (e) { 89 : // TODO log error to our server or crashlitycs... 90 0 : print("on change page error $e"); 91 : } 92 : } 93 : 94 1 : bool popHelper() { 95 1 : if (overlay != null) { 96 2 : overlay.remove(); 97 1 : overlay = null; 98 : return true; 99 : } 100 : return false; 101 : } 102 : 103 1 : @visibleForTesting 104 : // for now we show only one helper from the group / next version will allow to show a group 105 : showHelper(final HelperGroupEntity helperGroup, final String inAppUserId, final String pageId) { 106 1 : OverlayEntry entry = OverlayEntry( 107 : opaque: false, 108 0 : builder: (context) => PalTheme( 109 0 : theme: PalThemeData.light(), 110 0 : child: HelperFactory.build(helperGroup.helpers[0], onTrigger: (res) async { 111 0 : await helperClientService.onHelperTrigger(pageId, helperGroup, inAppUserId, res); 112 0 : this.popHelper(); 113 : }), 114 : )); 115 3 : var overlay = navigatorKey.currentState.overlay; 116 : // If there is already an helper, remove it and show the next one (useful when we change page fastly) 117 1 : if (this.overlay != null) { 118 0 : this.overlay.remove(); 119 : } 120 1 : overlay.insert(entry); 121 1 : this.overlay = entry; 122 : } 123 : 124 : }