Skip to content

Commit

Permalink
closing application during active render session
Browse files Browse the repository at this point in the history
  • Loading branch information
polarby committed Apr 2, 2023
1 parent 5847527 commit 1e9859b
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 83 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@

## 0.1.1

* time capture bug resolved(laggy outcome)
* time capture bug resolved (laggy outcome)
* proper session disposal

## 0.1.2

* error on closing application during active render session
* doc update

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ stream.listen((event) { // listens to stream until it closes by itself (when res
});
// result can then be displayed (see Motion rendering)
final result = await stream.firstWhere((element) => element.isResult);
final result = await stream.firstWhere((event) => event.isResult || event.isFatalError);
```
[comment]: # (@formatter:on)

Expand Down
5 changes: 3 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ class _MyHomePageState extends State<MyHomePage>
setState(() {
functionController.attach(stream);
});
final result = await stream
.firstWhere((element) => element.isResult);
final result = await stream.firstWhere(
(event) => event.isResult || event.isFatalError);
if (result.isFatalError) return;
displayResult(result as RenderResult);
},
exampleAnimationController: functionController,
Expand Down
1 change: 0 additions & 1 deletion lib/render.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
library render;

export 'src/core.dart';
export 'src/service/motion_recorder.dart';
export 'src/service/exception.dart';
export 'src/service/settings.dart';
export 'src/service/notifier.dart';
Expand Down
140 changes: 124 additions & 16 deletions lib/src/core.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:render/src/service/exception.dart';
import 'package:render/src/service/task_identifier.dart';
import 'package:rich_console/printRich.dart';
import 'package:uuid/uuid.dart';
Expand All @@ -10,7 +11,6 @@ import 'package:render/src/formats/abstract.dart';
import 'package:render/src/formats/image.dart';
import 'package:render/src/formats/motion.dart';
import 'package:render/src/process.dart';
import 'package:render/src/service/motion_recorder.dart';
import 'package:render/src/service/session.dart';
import 'package:render/src/service/settings.dart';
import 'service/notifier.dart';
Expand All @@ -28,7 +28,10 @@ class RenderController {
/// mode.
final LogLevel logLevel;

//TODO: render controller doc (copy from read me)
/// All active render sessions
final List<RenderSession> _activeSessions = [];

/// The controller to initiate a render process. See doc for more info.
RenderController({this.logLevel = LogLevel.debug})
: id = UuidValue(const Uuid().v4());

Expand All @@ -43,11 +46,14 @@ class RenderController {
overwriteTask != null || _globalTask?.key.currentWidget != null,
"RenderController must have a Render instance "
"connected to create a session.");
return RenderSession.fromDetached(
detachedSession: detachedRenderSession,
notifier: notifier,
task: overwriteTask ?? _globalTask!,
);
final session = RenderSession.fromDetached(
detachedSession: detachedRenderSession,
notifier: notifier,
task: overwriteTask ?? _globalTask!,
onDispose: () => _activeSessions.removeWhere(
(s) => s.sessionId == detachedRenderSession.sessionId));
_activeSessions.add(session);
return session;
}

/// Listens to stream and prints out debug, if in debug mode.
Expand Down Expand Up @@ -92,8 +98,10 @@ class RenderController {
format: format,
);
_debugPrintOnStream(stream, "Capturing image started");
return await stream.firstWhere((element) => element.isResult)
as RenderResult;
final out = await stream
.firstWhere((event) => event.isResult || event.isFatalError);
if (out.isFatalError) throw (out as RenderError).exception;
return out as RenderResult;
}

/// Captures an image and returns the result as future.
Expand All @@ -119,8 +127,10 @@ class RenderController {
format: format,
);
_debugPrintOnStream(stream, "Capturing image from widget started");
return await stream.firstWhere((element) => element.isResult)
as RenderResult;
final out = await stream
.firstWhere((event) => event.isResult || event.isFatalError);
if (out.isFatalError) throw (out as RenderError).exception;
return out as RenderResult;
}

/// Captures the motion of a widget and returns a future of the result.
Expand All @@ -146,8 +156,10 @@ class RenderController {
format: format,
);
_debugPrintOnStream(stream, "Capturing motion started");
return await stream.firstWhere((element) => element.isResult)
as RenderResult;
final out = await stream
.firstWhere((event) => event.isResult || event.isFatalError);
if (out.isFatalError) throw (out as RenderError).exception;
return out as RenderResult;
}

/// Captures motion of a widget that is out of the widget tree
Expand Down Expand Up @@ -179,8 +191,10 @@ class RenderController {
format: format,
);
_debugPrintOnStream(stream, "Capturing motion from widget started");
return await stream.firstWhere((element) => element.isResult)
as RenderResult;
final out = await stream
.firstWhere((event) => event.isResult || event.isFatalError);
if (out.isFatalError) throw (out as RenderError).exception;
return out as RenderResult;
}

/// Captures an image and returns a stream of information of current
Expand Down Expand Up @@ -339,6 +353,7 @@ class RenderController {
LogLevel? logLevel,
MotionSettings settings = const MotionSettings(),
MotionFormat format = const MovFormat(),
bool logInConsole = false,
}) {
assert(!kIsWeb, "Render does not support Web yet");
assert(
Expand All @@ -350,6 +365,8 @@ class RenderController {
capturingSettings: settings,
task: _globalTask!,
logLevel: logLevel ?? this.logLevel,
controller: this,
logInConsole: logInConsole,
);
}

Expand All @@ -362,17 +379,82 @@ class RenderController {
LogLevel? logLevel,
MotionSettings settings = const MotionSettings(),
MotionFormat format = const MovFormat(),
bool logInConsole = false,
}) {
assert(!kIsWeb, "Render does not support Web yet");
return MotionRecorder.start(
format: format,
capturingSettings: settings,
task: WidgetIdentifier(controllerId: id, widget: widget),
logLevel: logLevel ?? this.logLevel,
controller: this,
logInConsole: logInConsole,
);
}
}

class MotionRecorder<T extends MotionFormat> {
final RenderController _controller;

/// All related render recording settings
final MotionSettings capturingSettings;

/// The output format of the recording
final T format;

final bool logInConsole;

/// What notifications should be displayed
final LogLevel logLevel;
late final StreamController<RenderNotifier> _notifier;
late final RenderSession<T, MotionSettings> _session;
late final RenderCapturer<T> _capturer;

/// Starts a motion recording process
MotionRecorder.start({
required RenderController controller,
required this.logLevel,
required this.format,
required this.capturingSettings,
required TaskIdentifier task,
required this.logInConsole,
}) : _controller = controller {
_notifier = StreamController<RenderNotifier>.broadcast();
DetachedRenderSession.create(format, capturingSettings, logLevel)
.then((detachedSession) {
_session = _controller._createRenderSessionFrom(
detachedSession,
_notifier,
task is WidgetIdentifier ? task : null,
);
_capturer = RenderCapturer(_session);
_capturer.start();
});
if (logInConsole) {
_controller._debugPrintOnStream(
_notifier.stream, "Recording motion started");
}
}

/// It is highly recommended to make use of stream for capturing motion,
/// as the process usually takes longer and the user will likely wants to get
/// notified the process of rendering for longer operations.
Stream<RenderNotifier> get stream => _notifier.stream;

/// Stops the recording and returns the result of the recording.
Future<RenderResult> stop() async {
final realSession = await _capturer.finish();
final processor = MotionProcessor(realSession);
processor.process(); // wait for result instead of process
final out = await stream
.firstWhere((event) => event.isResult || event.isFatalError);
if (out.isFatalError) throw (out as RenderError).exception;
_notifier.close();
await _session.dispose();
return out as RenderResult;
}
}

class Render extends StatefulWidget {
/// The render controller to initiate rendering
final RenderController? controller;
Expand Down Expand Up @@ -414,19 +496,45 @@ class Render extends StatefulWidget {
State<Render> createState() => _RenderState();
}

class _RenderState extends State<Render> {
class _RenderState extends State<Render> with WidgetsBindingObserver {
final GlobalKey renderKey = GlobalKey();
bool hasAttached = false;

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// Gets called when application has been closed/paused and is back to normal
// [Issue fix]: https://github.com/polarby/render/issues/11#issuecomment-1492948345
if (state == AppLifecycleState.detached ||
state == AppLifecycleState.paused ||
state == AppLifecycleState.inactive) {
final numberOfSessions = widget.controller?._activeSessions.length ?? 0;
for (int i = 0; i < numberOfSessions; i++) {
widget.controller?._activeSessions.first.recordError(
const RenderException(
"Application was paused during an active render session.",
fatal: true,
),
);
}
}
}

@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
if (widget.controller != null) {
attach();
hasAttached = true;
}
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) {
if (!hasAttached && widget.controller != null) {
Expand Down
61 changes: 0 additions & 61 deletions lib/src/service/motion_recorder.dart

This file was deleted.

2 changes: 2 additions & 0 deletions lib/src/service/notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ abstract class RenderNotifier {
bool get isActivity => this is RenderActivity;

bool get isLog => this is RenderLog;

bool get isFatalError => isError && (this as RenderError).fatal;
}

/// Used to notify the user about an error that has occurred in the
Expand Down
6 changes: 6 additions & 0 deletions lib/src/service/session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class RenderSession<T extends RenderFormat, K extends RenderSettings>
/// remaining time calculation.
final DateTime startTime;

final VoidCallback onDispose;

/// A class that holds all the information about the current session.
/// used to pass information between the different parts of the rendering
/// process.
Expand All @@ -138,6 +140,7 @@ class RenderSession<T extends RenderFormat, K extends RenderSettings>
required super.format,
required super.binding,
required this.task,
required this.onDispose,
required StreamController<RenderNotifier> notifier,
DateTime? startTime,
}) : _notifier = notifier,
Expand All @@ -151,6 +154,7 @@ class RenderSession<T extends RenderFormat, K extends RenderSettings>
required DetachedRenderSession<T, K> detachedSession,
required StreamController<RenderNotifier> notifier,
required this.task,
required this.onDispose,
DateTime? startTime,
}) : _notifier = notifier,
startTime = DateTime.now(),
Expand All @@ -176,6 +180,7 @@ class RenderSession<T extends RenderFormat, K extends RenderSettings>
capturingDuration: capturingDuration,
frameAmount: frameAmount,
),
onDispose: onDispose,
startTime: startTime,
logLevel: logLevel,
inputDirectory: inputDirectory,
Expand Down Expand Up @@ -260,6 +265,7 @@ class RenderSession<T extends RenderFormat, K extends RenderSettings>

/// Disposing the current render session.
Future<void> dispose() async {
onDispose();
if (Directory(inputDirectory).existsSync()) {
Directory(inputDirectory).deleteSync(recursive: true);
}
Expand Down
Loading

0 comments on commit 1e9859b

Please sign in to comment.