Skip to content

Commit

Permalink
Event-less background limiting & other improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
stasgora committed Apr 29, 2021
1 parent 9b3f562 commit 0e17e7f
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import '../models/scrolling_status.dart';
import '../models/session.dart';
import '../utils/utils.dart';

/// Produces an image from widgets surrounded by a [RepaintBoundary]
class ScreenshotProvider {
final _logger = Logger('RoundSpot.ScreenshotProvider');
/// Creates backgrounds for sessions
class BackgroundManager {
final _logger = Logger('RoundSpot.BackgroundManager');

/// Controls when to take screenshot depending on the scroll amount
void onScroll(Session session, GlobalKey areaKey) {
Expand All @@ -24,7 +24,7 @@ class ScreenshotProvider {
bool _scrollOutsideBounds(Session session) {
var status = session.scrollStatus!;
var diff = status.lastScreenshotPosition - status.position;
return (diff).abs() > status.viewportDimension * 0.5;
return (diff).abs() > status.viewportDimension * 0.8;
}

/// Determines if its necessary to take a screenshot when event is recorded
Expand Down Expand Up @@ -63,27 +63,29 @@ class ScreenshotProvider {
var status = session.scrollStatus!;
var queue = status.screenshotQueue;
while (queue.isNotEmpty) {
var image = await queue.first.image;
if (image == null) return;
var offset = queue.first.offset;
if (session.background == null) {
session.background = image;
status.backgroundPosition = offset;
status.viewportDimension = image.size.alongAxis(status.axis);
return;
}
// Decrease the drawn image by 1 pixel in the main axis direction
// to account for the scroll position being rounded to the nearest pixel
var imageSize = image.size.modifiedSize(status.axis, -1);
session.background = await image.drawOnto(
session.background!,
Offsets.fromAxis(status.axis, offset - status.backgroundPosition),
imageSize,
);
status.backgroundPosition = min(
offset,
status.backgroundPosition,
);
await Future.sync(() async {
var image = await queue.first.image;
if (image == null) return;
var offset = queue.first.offset;
if (session.background == null) {
session.background = image;
status.backgroundPosition = offset;
status.viewportDimension = image.size.alongAxis(status.axis);
return;
}
// Decrease the drawn image by 1 pixel in the main axis direction
// to account for the scroll position being rounded to the nearest pixel
var imageSize = image.size.modifiedSize(status.axis, -1);
session.background = await image.drawOnto(
session.background!,
Offsets.fromAxis(status.axis, offset - status.backgroundPosition),
imageSize,
);
status.backgroundPosition = min(
offset,
status.backgroundPosition,
);
});
queue.removeAt(0);
}
}
Expand Down
21 changes: 15 additions & 6 deletions lib/src/components/processors/graphical_processor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/painting.dart';
import 'package:logging/logging.dart';

import '../../models/config/heat_map_style.dart';
import '../../models/event.dart';
import '../../models/session.dart';
import '../../utils/utils.dart';
import '../heat_map.dart';
Expand Down Expand Up @@ -46,16 +47,24 @@ class GraphicalProcessor extends SessionProcessor {
var size = image.size;
if (session.scrolling) {
var status = session.scrollStatus!;
var diff = status.backgroundPosition - status.extent.dx;
getPosition(Event e) => e.location.alongAxis(status.axis);
var eventPositions = session.events.map(getPosition);
final cutMargin = status.viewportDimension;
var extent = Offset(
max(status.extent.dx, eventPositions.reduce(min) - cutMargin),
min(
status.extent.dy + status.viewportDimension,
eventPositions.reduce(max) + cutMargin,
),
);
var diff = status.backgroundPosition - extent.dx;
if (diff < 0) {
offset = Offsets.fromAxis(status.axis, -diff);
size = size.modifiedSize(status.axis, diff);
status.backgroundPosition = status.extent.dx;
status.backgroundPosition = extent.dx;
}
diff = status.extent.dy +
status.viewportDimension -
status.backgroundPosition -
size.alongAxis(status.axis);
diff =
extent.dy - status.backgroundPosition - size.alongAxis(status.axis);
if (diff < 0) size = size.modifiedSize(status.axis, diff);
}
return offset & size;
Expand Down
8 changes: 4 additions & 4 deletions lib/src/components/session_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import '../models/detector_status.dart';
import '../models/event.dart';
import '../models/session.dart';
import '../utils/components.dart';
import 'background_manager.dart';
import 'processors/graphical_processor.dart';
import 'processors/raw_data_processor.dart';
import 'processors/session_processor.dart';
import 'screenshot_provider.dart';

/// Coordinates and manages data gathering, processing and reporting.
class SessionManager {
final _logger = Logger('RoundSpot.SessionManager');

final _config = S.get<Config>();
final _screenshotProvider = S.get<ScreenshotProvider>();
final _backgroundManager = S.get<BackgroundManager>();

final Map<String, Session> _sessions = {};
final Set<int> _processedEventIDs = {};
Expand Down Expand Up @@ -75,12 +75,12 @@ class SessionManager {
if (_currentPageDisabled && !status.hasGlobalScope) return;

var session = _recordEvent(event: event, status: status);
_screenshotProvider.onEvent(event.location, session, status.areaKey);
_backgroundManager.onEvent(event.location, session, status.areaKey);
}

/// Handles the scroll event of a [Session]
void onSessionScroll(DetectorStatus status) =>
_screenshotProvider.onScroll(_getSession(status), status.areaKey);
_backgroundManager.onScroll(_getSession(status), status.areaKey);

Session _recordEvent({required Event event, required DetectorStatus status}) {
var session = _getSession(status);
Expand Down
11 changes: 10 additions & 1 deletion lib/src/entry_point.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,16 @@ void _initializeLogger(LogLevel level) {
Logger('RoundSpot').level = level.toLoggerLevel;
Logger('RoundSpot').onRecord.listen((record) {
var prefix = '${record.level.name} - ${record.loggerName}';
print('$prefix: ${record.message}');
var message = '$prefix: ${record.message}';
if (record.level == Level.SEVERE) {
if (record.error != null) {
message += '\n${record.error.runtimeType} was thrown';
}
if (record.stackTrace != null) {
message += '\nStacktrace:\n${record.stackTrace}';
}
}
print(message);
});
}

Expand Down
4 changes: 2 additions & 2 deletions lib/src/models/detector_status.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import 'package:flutter/widgets.dart';

import '../components/screenshot_provider.dart';
import '../components/background_manager.dart';
import '../components/session_manager.dart';
import '../widgets/detector.dart';
import 'scrolling_status.dart';

/// Holds the [Detector] status for [SessionManager] use.
class DetectorStatus {
/// A key referring to a [RepaintBoundary] used by the [ScreenshotProvider]
/// A key referring to a [RepaintBoundary] used by the [BackgroundManager]
final GlobalKey areaKey;

/// [Detector.areaID]
Expand Down
4 changes: 2 additions & 2 deletions lib/src/utils/components.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:get_it/get_it.dart';

import '../components/background_manager.dart';
import '../components/processors/graphical_processor.dart';
import '../components/processors/raw_data_processor.dart';
import '../components/screenshot_provider.dart';
import '../components/session_manager.dart';
import '../entry_point.dart';
import '../models/config/config.dart';
Expand All @@ -16,7 +16,7 @@ GetIt get S => _instance;
void initializeComponents(Config? config, OutputCallback? heatMapCallback,
OutputCallback? rawDataCallback) {
S.registerSingleton<Config>(config ?? Config());
S.registerSingleton<ScreenshotProvider>(ScreenshotProvider());
S.registerSingleton<BackgroundManager>(BackgroundManager());
S.registerSingleton<GraphicalProcessor>(GraphicalProcessor());
S.registerSingleton<RawDataProcessor>(RawDataProcessor());
S.registerSingleton<SessionManager>(
Expand Down
3 changes: 3 additions & 0 deletions lib/src/utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import 'package:flutter/widgets.dart' show Axis;

/// [Offset] axis utility extension
extension Offsets on Offset {
/// Returns [Offset] component along [axis]
double alongAxis(Axis axis) => axis == Axis.vertical ? dy : dx;

/// Constructs [Offset] from an [offset] along [axis]
static Offset fromAxis(Axis axis, double offset, [double other = 0]) =>
axis == Axis.vertical ? Offset(other, offset) : Offset(offset, other);
Expand Down
6 changes: 4 additions & 2 deletions lib/src/widgets/detector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ import '../utils/components.dart';
/// and cannot put the [Detector] directly around one of the standard Flutter
/// widgets listed above, use the [Detector.custom()] constructor.
///
/// Nested scroll views are currently not supported and can
/// potentially impact the way that the outer scroll area is reported.
/// ### Not supported / untested
/// * Nested scroll views
/// * Widgets changing their size
/// * Directly using slivers
///
/// ## Detector scope
/// Detectors can either have a _local_ or a _global_ scope:
Expand Down

0 comments on commit 0e17e7f

Please sign in to comment.