# Flutter

## Migrating from `v0.0.22` to `v6.9.x` of the Sentiance Flutter SDKs <a href="#migrating-from-v0022-to-v690-of-the-sentiance-flutter-sdks" id="migrating-from-v0022-to-v690-of-the-sentiance-flutter-sdks"></a>

### Changes regarding library imports <a href="#changes-regarding-library-imports" id="changes-regarding-library-imports"></a>

In version `0.0.22`, the imports you needed to specify to interact with the Sentiance SDKs were a little too much. That's why we're now offering the entirety of a package's functionality under 1 library file, ready for import.

For the example, in order to create a new Sentiance user, you needed to do something like this:

```dart
// import #1, brings in CreateUserResult and CreateUserOptions types among other types
import 'package:sentiance_core/api.g.dart'; 
// import #2, brings in SentianceCore and more
import 'package:sentiance_core/sentiance_core.dart';

void createNewSentianceUser() async {
    final sentianceCore = SentianceCore();
    CreateUserResult result = await sentianceCore.createUser(
        CreateUserOptions(...)
    );
}
```

Change your code to import everything it needs from the `sentiance_core` package's single public library instead:

```dart
// This brings in everything you previously needed in addition to all other public declarations of the package
import 'package:sentiance_core/sentiance_core.dart';
                                                     
void createNewSentianceUser() async {
    final sentianceCore = SentianceCore();
    CreateUserResult result = await sentianceCore.createUser(
        CreateUserOptions(...)
    );
}
```

If you don't want to pollute the global namespace, you can be specific about what you want to import:

```dart
import 'package:sentiance_core/sentiance_core.dart' 
    show SentianceCore, CreateUserResult, CreateUserOptions; // Import only these 3 types

void createNewSentianceUser() async {
    final sentianceCore = SentianceCore();
    CreateUserResult result = await sentianceCore.createUser(
        CreateUserOptions(...)
    );
}
```

This applies for every single Sentiance package out there. At the time of writing this, the following are the only public imports for all of our SDKs:

```dart
import 'package:sentiance_core/sentiance_core.dart';
import 'package:sentiance_crash_detection/sentiance_crash_detection.dart';
import 'package:sentiance_driving_insights/sentiance_driving_insights.dart';
import 'package:sentiance_event_timeline/sentiance_event_timeline.dart';
import 'package:sentiance_smart_geofences/sentiance_smart_geofences.dart';
import 'package:sentiance_user_context/sentiance_user_context.dart';
```

For more information on what types and functionality our packages provide, check out the API reference on pub.dev.

### Changes regarding duplicate type definitions across packages <a href="#changes-regarding-duplicate-type-definitions-across-packages" id="changes-regarding-duplicate-type-definitions-across-packages"></a>

In `v0.0.22`, several packages were re-defining the same type. For the example, `sentiance_crash_detection` was defining its own `Location` type, as well as `sentiance_smart_geofences`. These types shared the same fields as well, so it only made sense to get rid of the duplication here and to centralize the definition of commonly used types in one package and one package alone.

For more information on where to find what, check out the documentation on [pub.dev](https://pub.dev/packages?q=sentiance).

### Changes regarding the public signature of certain APIs <a href="#changes-regarding-the-public-signature-of-certain-apis" id="changes-regarding-the-public-signature-of-certain-apis"></a>

The signatures of several Sentiance APIs have changed. Make sure to update your code accordingly:

* `reset()` now returns `void` instead of `bool`. If the operation succeeds, execution terminates normally. If an error occurs, a `ResetError` will be thrown.
* `submitDetections()` now returns `void` instead of `bool`. If the operation succeeds, execution terminates normally. If an error occurs, a `SubmitDetectionsError` will be thrown.
* `enableDetections()` now returns `void` instead of `bool`. If the operation succeeds, execution terminates normally. If an error occurs, an `EnableDetectionsError` will be thrown.
* `enableDetectionsWithExpiryDate()` now returns `void` instead of `bool`. If the operation succeeds, execution terminates normally. If an error occurs, an `EnableDetectionsError` will be thrown.
* `disableDetections()` now returns `void` instead of `bool`. If the operation succeeds, execution terminates normally. If an error occurs, a `DisableDetectionsError` will be thrown.
* `createUser()` now throws a `UserCreationError` if the operation fails.
* `requestAccessToken()` now throws a `UserAccessTokenError` if the operation fails.
* `refreshGeofences()` now throws a `SmartGeofencesRefreshError` if the operation fails.
* `requestUserContext()` now throws a `RequestUserContextError` if the operation fails.
* `invokeDummyVehicleCrash()` now returns `void` instead of `bool`.
* The `getPhoneUsageEvents`, `getHarshDrivingEvents`, `getCallWhileMovingEvents`, `getSpeedingEvents`, `getTimelineUpdates` and `getTimelineEvents` APIs now return a list of non-nullable events instead of nullable ones. This change could be breaking for you if you're using a linter as part of your build process. If not, you may want to do something about those "unnecessary null-aware operator use" warnings that will pop.

### APIs that were removed <a href="#apis-that-were-removed" id="apis-that-were-removed"></a>

* `getLanguageName()` has been removed and is no longer supported.

### Changes concerning overall usage of background listeners <a href="#changes-concerning-overall-usage-of-background-listeners" id="changes-concerning-overall-usage-of-background-listeners"></a>

#### Setting a background listener <a href="#setting-a-background-listener" id="setting-a-background-listener"></a>

In order to set a listener to get notified of SDK events in the background - for the example, smart geofence events - you had to create a top level Dart handler function like this:

```dart
import 'package:sentiance_smart_geofences/api.g.dart';

@pragma('vm:entry-point')
void handleSmartGeofenceEvents() async {
  // Initialize required Flutter bindings
  WidgetsFlutterBinding.ensureInitialized();
  
  SentianceSmartGeofencesListenerApi.setUp(SmartGeofenceEventHandler());
}

class SmartGeofenceEventHandler extends SentianceSmartGeofencesListenerApi {
  @override
  void onSmartGeofenceEvent(SmartGeofenceEvent event) {
    // Do something with the event
  }
}
```

The `SentianceSmartGeofencesListenerApi` class is no longer directly accessible. Change your code to use the static `SentianceSmartGeofences.registerSmartGeofenceEventListener` function instead:

```dart
import 'package:sentiance_smart_geofences/sentiance_smart_geofences.dart';

@pragma('vm:entry-point')
void handleSmartGeofenceEvents() async {
  // Initialize required Flutter bindings
  WidgetsFlutterBinding.ensureInitialized();

  SentianceSmartGeofences.registerSmartGeofenceEventListener((smartGeofenceEvent) {
    // Do something with the event
  });
}
```

On that same note, here is a summary with all the changes that you need to make for any background listeners that you may be setting:

<table><thead><tr><th width="375">Before migrating</th><th>After migrating</th></tr></thead><tbody><tr><td><code>SentianceUserContextListenerApi.setUp(...)</code></td><td><code>SentianceUserContext.registerUserContextUpdateListener()</code></td></tr><tr><td><code>SentianceEventTimelineListenerApi.setUp(...)</code></td><td><code>SentianceEventTimeline.registerEventTimelineUpdateListener()</code></td></tr><tr><td><code>SentianceSmartGeofencesListenerApi.setUp(...)</code></td><td><code>SentianceSmartGeofences.registerSmartGeofenceEventListener()</code></td></tr><tr><td><code>SentianceCrashDetectionListenerApi.setUp(...)</code></td><td><code>SentianceCrashDetection.registerCrashListener()</code><br><code>SentianceCrashDetection.registerCrashDiagnosticListener()</code></td></tr><tr><td><code>SentianceDrivingInsightsListenerApi.setUp(...)</code></td><td><code>SentianceDrivingInsights.registerDrivingInsightsListener()</code></td></tr></tbody></table>

#### Setting crash detection background listeners <a href="#setting-crash-detection-background-listeners" id="setting-crash-detection-background-listeners"></a>

As you may have noticed in the table above, you now have the option to set a listener to vehicle crash events independently of setting another listener for crash diagnostic updates; make sure to update your code accordingly based on your needs and requirements.

#### Setting a user context updates' background listener <a href="#setting-a-user-context-updates-background-listener" id="setting-a-user-context-updates-background-listener"></a>

In version `0.0.22`, you set a background listener to get the most recent user context updates as follows:

```dart
import 'package:sentiance_user_context/api.g.dart';

@pragma('vm:entry-point')
void handleUserContextUpdates() async {
  // Initialize required Flutter bindings
  WidgetsFlutterBinding.ensureInitialized();

  SentianceUserContextListenerApi.setUp(UserContextUpdatesHandler());
}

class UserContextUpdatesHandler extends SentianceUserContextListenerApi {
  @override
  void didUpdate(UserContext userContext) {
    // Do something with the user context
  }
}
```

Change your code to take into account an additional list of user context update criteria that now gets delivered as well:

```dart
import 'package:sentiance_user_context/sentiance_user_context.dart' show SentianceUserContext;

@pragma('vm:entry-point')
void handleUserContextUpdates() async {
  // Initialize required Flutter bindings
  WidgetsFlutterBinding.ensureInitialized();

  SentianceUserContext.registerUserContextUpdateListener((criteria, userContext) {
    // Do something with the user context
    // Do something with the update criteria
  });
}
```

### Changes impacting users of event timeline features <a href="#changes-impacting-users-of-event-timeline-features" id="changes-impacting-users-of-event-timeline-features"></a>

All the event timeline APIs return objects of type `TimelineEvent` that had multiple nullable fields that only carry a value if the event is of a certain `type`.

The `type` field has been removed and the `TimelineEvent` class is now abstract. To process the timeline events based on their type, use inheritance checks as follows:

```dart
import 'package:sentiance_event_timeline/sentiance_event_timeline.dart';

final eventTimeline = SentianceEventTimeline();

/// A function that processes all events that occurred since the dawn of times.
void processTimelineEvents() async {
  final startEpochTimeMs = 0;
  final endEpochTimeMs = DateTime.now().millisecondsSinceEpoch;
  final events = await eventTimeline.getTimelineEvents(startEpochTimeMs, endEpochTimeMs);

  for (final timelineEvent in events) {
    if (timelineEvent is StationaryEvent) {
      // Process stationary
    } else if (timelineEvent is TransportEvent) {
      // Process transport
    } else if (timelineEvent is OffTheGridEvent) {
      // Process off the grid
    } else if (timelineEvent is UnknownEvent) {
      // Process unknown event
    }
  }
}
```

### Changes impacting users of user context features <a href="#changes-impacting-users-of-user-context-features" id="changes-impacting-users-of-user-context-features"></a>

#### Segment attributes <a href="#segment-attributes" id="segment-attributes"></a>

As of `v6.9.0`, segment attribute values are `double` instead of `int`. Please update your code accordingly.

### Changes impacting users of driving insights features <a href="#changes-impacting-users-of-driving-insights-features" id="changes-impacting-users-of-driving-insights-features"></a>

#### Call-while-moving events <a href="#call-while-moving-events" id="call-while-moving-events"></a>

* The `minTravelledSpeedInMps` and `maxTravelledSpeedInMps` fields have been renamed to `minTraveledSpeedInMps` and `maxTraveledSpeedInMps` respectively.

#### Transport events associated with a driving insights payload <a href="#transport-events-associated-with-a-driving-insights-payload" id="transport-events-associated-with-a-driving-insights-payload"></a>

Transport events previously had a `String type` field, which is no longer the case.

```dart
final sentianceDrivingInsights = SentianceDrivingInsights();
final drivingInsights = await sentianceDrivingInsights.getDrivingInsights("transport_id_here");

String type = drivingInsights.transportEvent.type; // no longer compiles
```

Moreover, with `v6.9.0`, the transport event associated with driving insights is now a type that is provided by the `sentiance_event_timeline` package:

```dart
import 'package:sentiance_driving_insights/sentiance_driving_insights.dart' show SentianceDrivingInsights;
import 'package:sentiance_event_timeline/sentiance_event_timeline.dart' show TransportEvent;

final sentianceDrivingInsights = SentianceDrivingInsights();
final drivingInsights = await sentianceDrivingInsights.getDrivingInsights("transport_id_here");

TransportEvent transportEvent = drivingInsights.transportEvent;
```

Make sure to change your code accordingly.
