Skip to content

Commit

Permalink
Merge pull request #96 from EPNW/attach_pvid
Browse files Browse the repository at this point in the history
Option to attach the last pvId automatically
  • Loading branch information
TesteurManiak authored May 25, 2023
2 parents 785520b + eb188a3 commit 4bab27d
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 91 deletions.
11 changes: 1 addition & 10 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,12 @@ class MyHomePageState extends State<MyHomePage> with TraceableClientMixin {

void _incrementCounter() {
// Send an event to Matomo on tap.
// To signal that this event happend on this page, we use the
// pvId of the page.
MatomoTracker.instance.trackEvent(
eventInfo: EventInfo(
category: 'Main',
action: 'Click',
name: 'IncrementCounter',
),
pvId: pvId,
);
setState(() {
_counter++;
Expand All @@ -77,9 +74,7 @@ class MyHomePageState extends State<MyHomePage> with TraceableClientMixin {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ContentWidget(
pvId: pvId,
),
const ContentWidget(),
const Text(
'You have pushed the button this many times:',
),
Expand Down Expand Up @@ -190,10 +185,8 @@ class OtherPage2 extends StatelessWidget {
}

class ContentWidget extends StatefulWidget {
final String? pvId;
const ContentWidget({
super.key,
this.pvId,
});

@override
Expand All @@ -213,7 +206,6 @@ class _ContentWidgetState extends State<ContentWidget> {
_closed = false;
MatomoTracker.instance.trackContentImpression(
content: _exampleContent,
pvId: widget.pvId,
);
}

Expand Down Expand Up @@ -253,7 +245,6 @@ class _ContentWidgetState extends State<ContentWidget> {
MatomoTracker.instance.trackContentInteraction(
interaction: 'close',
content: _exampleContent,
pvId: widget.pvId,
);
}
}
2 changes: 2 additions & 0 deletions lib/matomo_tracker.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// A fully cross-platform wrap of the Matomo [Tracking HTTP API](https://developer.matomo.org/api-reference/tracking-api)
/// for Flutter.
library matomo_tracker;

export 'src/campaign.dart';
Expand Down
10 changes: 8 additions & 2 deletions lib/src/assert.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
/// only.
///
/// If the passed [value] is null, it won't do anything.
void assertStringIsFilled({required String? value, required String name}) {
void assertStringIsFilled({
required String? value,
required String name,
}) {
if (value != null && value.trim().isEmpty) {
throw ArgumentError.value(
value,
Expand All @@ -15,7 +18,10 @@ void assertStringIsFilled({required String? value, required String name}) {
/// Method used to assert that a duration is not negative.
///
/// If the passed [value] is null, it won't do anything.
void assertDurationNotNegative({required Duration? value, required String name}) {
void assertDurationNotNegative({
required Duration? value,
required String name,
}) {
if (value != null && value.isNegative) {
throw ArgumentError.value(
value,
Expand Down
86 changes: 62 additions & 24 deletions lib/src/matomo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ class MatomoTracker {
);
}

/// Whether to attach the last `pvId` to actions that can be associated with
/// page views.
///
/// There are some actions like [trackEvent] and [trackContentImpression]
/// that can be associated with page views by setting a `pvId` (what is the
/// abbreviation of page view id). If [attachLastPvId] is `true` and there is
/// a last page view tracked by [trackScreenWithName] (or a method/class that
/// uses it like [trackScreen], [TraceableClientMixin], [TraceableWidget]) the
/// last recored `pvId` is automatically used unless it is overwritten in that
/// action.
late final bool attachLastPvId;

/// The user agent is used to detect the operating system and browser used.
late final String? userAgent;

Expand Down Expand Up @@ -109,7 +121,7 @@ class MatomoTracker {
late final LocalStorage _localStorage;

@visibleForTesting
final queue = Queue<MatomoAction>();
final queue = Queue<Map<String, String>>();

@visibleForTesting
late Timer dequeueTimer;
Expand All @@ -121,7 +133,7 @@ class MatomoTracker {

String? _tokenAuth;

String? get getAuthToken => _tokenAuth;
String? get authToken => _tokenAuth;

late final Duration _dequeueInterval;

Expand All @@ -145,7 +157,9 @@ class MatomoTracker {
///
/// The [visitorId] should have a length of 16 characters otherwise an
/// [ArgumentError] will be thrown. This parameter corresponds with the
/// `_id` and should not be confused with the user id `uid`.
/// `_id` and should not be confused with the user id `uid`. See the
/// [Visitor] class for additional remarks. It is recommended to leave this
/// to `null` to use an automatically generated id.
///
/// If [cookieless] is set to true, a [CookielessStorage] instance will be
/// used. This means that the first_visit and the user_id will be stored in
Expand All @@ -155,6 +169,9 @@ class MatomoTracker {
/// send to Matomo to circumvent the [last page viewtime issue](https://github.com/Floating-Dartists/matomo-tracker/issues/78).
/// To deactivate pings, set this to `null`. The default value is a good
/// compromise between accuracy and network traffic.
///
/// It is recommended to leave [userAgent] to `null` so it will be detected
/// automatically.
Future<void> initialize({
required int siteId,
required String url,
Expand All @@ -171,6 +188,8 @@ class MatomoTracker {
bool cookieless = false,
Level verbosityLevel = Level.off,
Map<String, String> customHeaders = const {},
String? userAgent,
bool attachLastPvId = true,
}) async {
if (_initialized) {
throw const AlreadyInitializedMatomoInstanceException();
Expand Down Expand Up @@ -198,8 +217,8 @@ class MatomoTracker {
_platformInfo = platformInfo ?? PlatformInfo.instance;
_cookieless = cookieless;
_tokenAuth = tokenAuth;
_dispatcher = MatomoDispatcher(url, tokenAuth);
_newVisit = newVisit;
this.attachLastPvId = attachLastPvId;

final effectiveLocalStorage = localStorage ?? SharedPrefsStorage();
_localStorage = cookieless
Expand All @@ -210,7 +229,14 @@ class MatomoTracker {
_visitor = Visitor(id: localVisitorId, uid: uid);

// User agent
userAgent = await getUserAgent();
this.userAgent = userAgent ?? await getUserAgent();

_dispatcher = MatomoDispatcher(
baseUrl: url,
tokenAuth: tokenAuth,
userAgent: this.userAgent,
log: log,
);

// Screen Resolution
final physicalSize = PlatformDispatcher.instance.views.first.physicalSize;
Expand Down Expand Up @@ -258,7 +284,7 @@ class MatomoTracker {
unawaited(_localStorage.setOptOut(optOut: _optOut));

log.fine(
'Matomo Initialized: firstVisit=$firstVisit; lastVisit=$now; visitCount=$visitCount; visitorId=$visitorId; contentBase=$contentBase; resolution=${screenResolution.width}x${screenResolution.height}; userAgent=$userAgent',
'Matomo Initialized: firstVisit=$firstVisit; lastVisit=$now; visitCount=$visitCount; visitorId=$visitorId; contentBase=$contentBase; resolution=${screenResolution.width}x${screenResolution.height}; userAgent=${this.userAgent}',
);
_initialized = true;

Expand Down Expand Up @@ -372,9 +398,9 @@ class MatomoTracker {
/// This will register a page view with [trackScreenWithName] by using the
/// `context.widget.toStringShort()` as `actionName` value.
///
/// - `pvId`: A 6 character unique ID that identifies which actions
/// were performed on a specific page view. If `null`, a random id will be
/// generated.
/// - `pvId`: A 6 character unique ID that can later be used to associate
/// other actions (like [trackEvent]) with this page view. If `null`,
/// a random id will be generated (recommended). Also see [attachLastPvId].
///
/// - `path`: A string that identifies the path of the screen. If not
/// `null`, it will be combined to [contentBase] to create a URL. This combination
Expand Down Expand Up @@ -408,9 +434,9 @@ class MatomoTracker {
/// - `actionName`: Equivalent to the page name, here used to identify the
/// screen with a proper name.
///
/// - `pvId`: A 6 character unique ID that identifies which actions
/// were performed on a specific page view. If `null`, a random ID will be
/// generated.
/// - `pvId`: A 6 character unique ID that can later be used to associate
/// other actions (like [trackEvent]) with this page view. If `null`,
/// a random id will be generated (recommended). Also see [attachLastPvId].
///
/// - `path`: A string that identifies the path of the screen. If not
/// `null`, it will be combined to [contentBase] to create a URL. This
Expand Down Expand Up @@ -474,8 +500,10 @@ class MatomoTracker {

/// Tracks an event.
///
/// To associate this event with a page view, set [pvId]
/// to the [pvId] of that page, e.g. [TraceableClientMixin.pvId].
/// To associate this event with a page view, enable [attachLastPvId] and
/// leave [pvId] to `null` here or set [pvId] to the [pvId] of that page view
/// manually, e.g. [TraceableClientMixin.pvId]. Setting [pvId] manually will
/// take precedance over [attachLastPvId].
///
/// For remarks on [dimensions] see [trackDimensions].
void trackEvent({
Expand All @@ -487,7 +515,7 @@ class MatomoTracker {
return _track(
MatomoAction(
eventInfo: eventInfo,
screenId: pvId,
screenId: _inferPvId(pvId),
dimensions: dimensions,
),
);
Expand Down Expand Up @@ -618,8 +646,10 @@ class MatomoTracker {
/// Later, if the user interacts with the content (e.g. taps on it),
/// call [trackContentInteraction].
///
/// To associate this impression with a page view, set [pvId]
/// to the [pvId] of that page, e.g. [TraceableClientMixin.pvId].
/// To associate this impression with a page view, enable [attachLastPvId] and
/// leave [pvId] to `null` here or set [pvId] to the [pvId] of that page view
/// manually, e.g. [TraceableClientMixin.pvId]. Setting [pvId] manually will
/// take precedance over [attachLastPvId].
///
/// For remarks on [dimensions] see [trackDimensions].
void trackContentImpression({
Expand All @@ -630,7 +660,7 @@ class MatomoTracker {
return _track(
MatomoAction(
content: content,
screenId: pvId,
screenId: _inferPvId(pvId),
dimensions: dimensions,
),
);
Expand All @@ -644,8 +674,10 @@ class MatomoTracker {
/// The [interaction] corresponds with `c_i` and should
/// describe the type of interaction, e.g. `tap` or `swipe`.
///
/// To associate this interaction with a page view, set [pvId]
/// to the [pvId] of that page, e.g. [TraceableClientMixin.pvId].
/// To associate this interaction with a page view, enable [attachLastPvId]
/// and leave [pvId] to `null` here or set [pvId] to the [pvId] of that page
/// view manually, e.g. [TraceableClientMixin.pvId]. Setting [pvId] manually
/// will take precedance over [attachLastPvId].
///
/// For remarks on [dimensions] see [trackDimensions].
void trackContentInteraction({
Expand All @@ -658,7 +690,7 @@ class MatomoTracker {
MatomoAction(
content: content,
contentInteraction: interaction,
screenId: pvId,
screenId: _inferPvId(pvId),
dimensions: dimensions,
),
);
Expand All @@ -670,7 +702,7 @@ class MatomoTracker {
ac = ac.copyWith(newVisit: true);
_newVisit = false;
}
queue.add(ac);
queue.add(ac.toMap(this));
}

void _ping() {
Expand All @@ -693,9 +725,12 @@ class MatomoTracker {

if (!_lock.locked) {
return _lock.synchronized(() async {
final actions = List<MatomoAction>.from(queue);
final actions = List<Map<String, String>>.of(queue);
if (!_optOut) {
final hasSucceeded = await _dispatcher.sendBatch(actions, this);
final hasSucceeded = await _dispatcher.sendBatch(
actions: actions,
customHeaders: customHeaders,
);
if (hasSucceeded) {
// As the operation is asynchronous we need to be sure to remove
// only the actions that were sent in the batch.
Expand Down Expand Up @@ -750,4 +785,7 @@ class MatomoTracker {
}
}
}

String? _inferPvId(String? pvId) =>
pvId ?? (attachLastPvId ? _lastPageView?.screenId : null);
}
2 changes: 1 addition & 1 deletion lib/src/matomo_action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class MatomoAction {
'cookie': '1',
if (ua != null) 'ua': ua,
'lang': locale.toString(),
if (country != null && tracker.getAuthToken != null) 'country': country,
if (country != null && tracker.authToken != null) 'country': country,

if (uid != null) 'uid': uid,

Expand Down
Loading

0 comments on commit 4bab27d

Please sign in to comment.