diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 7e59fa1..759a05e 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -10,4 +10,6 @@ jobs: uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 with: flutter_channel: stable - flutter_version: 3.3.7 + flutter_version: 3.22.3 + min_coverage: 75 + exclude: "lib/no_screenshot_platform_interface.dart lib/no_screenshot_method_channel.dart" diff --git a/CHANGELOG.md b/CHANGELOG.md index 14deabd..d789118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,4 +44,16 @@ Updated readme and added sample usage. - Upgrade android to support AGP 8.X - merged fix by @alberto-cappellina PR[https://github.com/FlutterPlaza/no_screenshot/pull/27] - gradle:7.1.2 -> 7.4.2 -- kotlin_version = '1.6.10' -> '1.6.21' \ No newline at end of file +- kotlin_version = '1.6.10' -> '1.6.21' + + +## 0.2.1 + +### Summary of Changes + +- **Automatic State Persistence**: Removed the need to track `didChangeAppLifecycleState`. The state will now be automatically persisted using native platform SharedPreferences. +- **Enhanced Example**: Updated the example app to demonstrate the new automatic state persistence and usage of the `NoScreenshot` plugin. +- **Stream Support**: Provided a stream to listen for screenshot activities, making it easier to react to screenshots in real-time. +- **Bug Fixes**: Fixed various bugs related to screenshot detection and state management on both Android and iOS platforms. +- **Documentation Updates**: Improved documentation to reflect the new features and provide clearer usage examples. +- **Deprecation Notice**: Deprecated the use of the constructor `NoScreenshot()` in favor of the singleton `NoScreenshot.instance`. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c6b8fd1..2358909 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,3 +1,5 @@ # Contributors -- [Felix Junghans](https://github.com/felixjunghans) - Freelance software developer from the Stuttgart area. [Bio](http://felixjunghans.de/) +- [Geoffrey Giordano](https://github.com/ggiordan) [PR](https://github.com/FlutterPlaza/no_screenshot/pull/29) +- [Musaddiq Ahmed Khan](https://github.com/Musaddiq625) [PR](https://github.com/FlutterPlaza/no_screenshot/pull/26) +- [alberto-cappellina](https://github.com/alberto-cappellina) [PR](https://github.com/FlutterPlaza/no_screenshot/pull/27) \ No newline at end of file diff --git a/README.md b/README.md index 0eae471..b082131 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # no_screenshot +

+Pub +build +codecov +Star on Github +Flutter Website +

+ Flutter plugin to enable, disable or toggle screenshot support in your application. ## Features @@ -16,7 +24,7 @@ If you want to prevent user from taking screenshot or recording of your app. You class _MyHomePageState extends State with WidgetsBindingObserver { final _noScreenshot = NoScreenshot.instance; - AppLifecycleState? _notification; + AppLifecycleState? _notification; @override void didChangeAppLifecycleState(AppLifecycleState state) { case AppLifecycleState.resumed, : diff --git a/example/README.md b/example/README.md index 3e863cd..a799b7c 100644 --- a/example/README.md +++ b/example/README.md @@ -1,12 +1,30 @@ -# no_screenshot_example +# no_screenshot -Demonstrates how to use the no_screenshot plugin. +The Flutter plugin will enable, disable, or toggle screenshot support in your application. -## Getting Started +## Features + +- Disables screenshot and screen recording on Android and iOS. +- Enables screenshot and screen recording on Android and iOS. +- Toggles screenshot and screen recording on Android and iOS. +- Provides a stream to listen for screenshot activities. + +## Update + +Tracking `didChangeAppLifecycleState` is no longer required. The state will be persisted automatically in the native platform SharedPreferences. + +## Getting started + +Add `no_screenshot` to your `pubspec.yaml` dependencies. + +## Usage + +Call the singleton `NoScreenshot.instance` anywhere you want to use it. For instance: ```dart import 'package:flutter/material.dart'; import 'package:no_screenshot/no_screenshot.dart'; +import 'package:no_screenshot/screenshot_snapshot.dart'; void main() { runApp(const MyApp()); @@ -20,11 +38,24 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - final _noScreenshotPlugin = NoScreenshot(); + final _noScreenshot = NoScreenshot.instance; + bool _isListeningToScreenshotSnapshot = false; + ScreenshotSnapshot _latestValue = ScreenshotSnapshot( + isScreenshotProtectionOn: false, + wasScreenshotTaken: false, + + /// Returning screenshot path is not yet fully supported. And not function on iOS + screenshotPath: '', + ); @override void initState() { super.initState(); + _noScreenshot.screenshotStream.listen((value) { + setState(() { + _latestValue = value; + }); + }); } @override @@ -32,38 +63,66 @@ class _MyAppState extends State { return MaterialApp( home: Scaffold( appBar: AppBar( - title: const Text('Plugin example app'), + title: const Text('No Screenshot Plugin Example'), ), body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - ElevatedButton( - child: const Text('Press to toggle screenshot'), - onPressed: () async { - final result = await _noScreenshotPlugin.toggleScreenshot(); - print(result); - }, - ), - ElevatedButton( - child: const Text('Press to turn off screenshot'), - onPressed: () async { - final result = await _noScreenshotPlugin.screenshotOff(); - print(result); - }, - ), - ElevatedButton( - child: const Text('Press to turn on screenshot'), - onPressed: () async { - final result = await _noScreenshotPlugin.screenshotOn(); - print(result); - }, - ), - ], - )), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton( + onPressed: () async { + await _noScreenshot.startScreenshotListening(); + setState(() { + _isListeningToScreenshotSnapshot = true; + }); + }, + child: const Text('Start Listening'), + ), + ElevatedButton( + onPressed: () async { + await _noScreenshot.stopScreenshotListening(); + setState(() { + _isListeningToScreenshotSnapshot = false; + }); + }, + child: const Text('Stop Listening'), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Text( + "Screenshot Streaming is ${_isListeningToScreenshotSnapshot ? 'ON' : 'OFF'}\n\nIsScreenshotProtectionOn: ${_latestValue.isScreenshotProtectionOn}\nwasScreenshotTaken: ${_latestValue.wasScreenshotTaken}"), + ), + ElevatedButton( + onPressed: () async { + bool result = await _noScreenshot.screenshotOff(); + debugPrint('Screenshot Off: $result'); + }, + child: const Text('Disable Screenshot'), + ), + ElevatedButton( + onPressed: () async { + bool result = await _noScreenshot.screenshotOn(); + debugPrint('Enable Screenshot: $result'); + }, + child: const Text('Enable Screenshot'), + ), + ElevatedButton( + onPressed: () async { + bool result = await _noScreenshot.toggleScreenshot(); + debugPrint('Toggle Screenshot: $result'); + }, + child: const Text('Toggle Screenshot'), + ), + const SizedBox(height: 20), + ], + ), + ), ), ); } } - ``` + +## Additional information + +Check out our repo for Open-Source contributions. Contributions are welcome! \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 7ee1203..0b9ffbe 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -66,10 +66,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "4.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -103,10 +103,10 @@ packages: dependency: transitive description: name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "4.0.0" matcher: dependency: transitive description: @@ -137,7 +137,7 @@ packages: path: ".." relative: true source: path - version: "0.2.0" + version: "0.2.1" path: dependency: transitive description: @@ -224,5 +224,5 @@ packages: source: hosted version: "14.2.1" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.4.4 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5c106a5..353d642 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -6,7 +6,7 @@ description: Demonstrates how to use the no_screenshot plugin. publish_to: 'none' # Remove this line if you wish to publish to pub.dev environment: - sdk: '>=2.18.2 <3.0.0' + sdk: '>=3.4.4 <4.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -28,7 +28,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.8 dev_dependencies: flutter_test: @@ -39,7 +39,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^2.0.0 + flutter_lints: ^4.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/lib/no_screenshot.dart b/lib/no_screenshot.dart index 7acfd4a..f9469ad 100644 --- a/lib/no_screenshot.dart +++ b/lib/no_screenshot.dart @@ -2,6 +2,8 @@ import 'package:no_screenshot/screenshot_snapshot.dart'; import 'no_screenshot_platform_interface.dart'; +/// A class that provides a platform-agnostic way to disable screenshots. +/// class NoScreenshot implements NoScreenshotPlatform { final _instancePlatform = NoScreenshotPlatform.instance; NoScreenshot._(); @@ -10,43 +12,63 @@ class NoScreenshot implements NoScreenshotPlatform { "Using this may cause issue\nUse instance directly\ne.g: 'NoScreenshot.instance.screenshotOff()'") NoScreenshot(); - /// Made `NoScreenshot` class a singleton static NoScreenshot get instance => NoScreenshot._(); - /// Return `true` if screenshot capabilities has been successfully disabled - /// or is currently disabled and `false` otherwise. throw `UnmimplementedError` if not implement + /// Return `true` if screenshot capabilities has been + /// successfully disabled or is currently disabled and `false` otherwise. + /// throw `UnmimplementedError` if not implement + /// @override Future screenshotOff() { return _instancePlatform.screenshotOff(); } - /// Return `true` if screenshot capabilities has been successfully enable - /// or is currently enable and `false` otherwise. throw `UnmimplementedError` if not implement + /// Return `true` if screenshot capabilities has been + /// successfully enabled or is currently enabled and `false` otherwise. + /// throw `UnmimplementedError` if not implement + /// @override Future screenshotOn() { return _instancePlatform.screenshotOn(); } - ///Return `true` if screenshot capabilities has been successfully toggle from it previous state and - ///`false` if the attempt to toggle failed. throw `UnmimplementedError` if not implement + /// Return `true` if screenshot capabilities has been + /// successfully toggle from it previous state and `false` if the attempt + /// to toggle failed. + /// throw `UnmimplementedError` if not implement + /// @override Future toggleScreenshot() { return _instancePlatform.toggleScreenshot(); } - /// Stream to listen to the increment value + /// Stream to screenshot activities [ScreenshotSnapshot] + /// @override Stream get screenshotStream { return _instancePlatform.screenshotStream; } + /// Start listening to screenshot activities @override Future startScreenshotListening() { return _instancePlatform.startScreenshotListening(); } + /// Stop listening to screenshot activities @override Future stopScreenshotListening() { return _instancePlatform.stopScreenshotListening(); } + + @override + bool operator ==(Object other) { + return identical(this, other) || + other is NoScreenshot && + runtimeType == other.runtimeType && + _instancePlatform == other._instancePlatform; + } + + @override + int get hashCode => _instancePlatform.hashCode; } diff --git a/lib/no_screenshot_platform_interface.dart b/lib/no_screenshot_platform_interface.dart index 0b21f78..eac1732 100644 --- a/lib/no_screenshot_platform_interface.dart +++ b/lib/no_screenshot_platform_interface.dart @@ -45,17 +45,24 @@ abstract class NoScreenshotPlatform extends PlatformInterface { Future toggleScreenshot() { throw UnimplementedError('toggleScreenshot() has not been implemented.'); } - /// Stream to listen to the increment value + /// Stream to screenshot activities [ScreenshotSnapshot] + /// This stream will emit a [ScreenshotSnapshot] whenever a screenshot is taken. + /// The [ScreenshotSnapshot] contains the path to the screenshot file. + /// throw `UnmimplementedError` if not implement Stream get screenshotStream { throw UnimplementedError('incrementStream has not been implemented.'); } +// Start listening to screenshot activities Future startScreenshotListening() { - throw UnimplementedError('startScreenshotListening has not been implemented.'); + throw UnimplementedError( + 'startScreenshotListening has not been implemented.'); } + /// Stop listening to screenshot activities Future stopScreenshotListening() { - throw UnimplementedError('stopScreenshotListening has not been implemented.'); + throw UnimplementedError( + 'stopScreenshotListening has not been implemented.'); } } diff --git a/pubspec.yaml b/pubspec.yaml index 308312f..399d962 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,17 +1,17 @@ name: no_screenshot description: Flutter plugin to enable, disable or toggle screenshot support in your application. -version: 0.2.0 +version: 0.2.1 homepage: https://flutterplaza.com -repository: https://github.com/FlutterPlaza/no_screenshot/releases/tag/v0.0.1%2B6 +repository: https://github.com/FlutterPlaza/no_screenshot/releases/tag/v0.2.1 environment: - sdk: '>=2.18.2 <4.0.0' - flutter: ">=2.5.0" + sdk: '>=3.4.4 <4.0.0' + flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - plugin_platform_interface: ^2.0.2 + plugin_platform_interface: ^2.1.8 dev_dependencies: flutter_test: diff --git a/test/no_screenshot_method_channel_test.dart b/test/no_screenshot_method_channel_test.dart new file mode 100644 index 0000000..1033ec8 --- /dev/null +++ b/test/no_screenshot_method_channel_test.dart @@ -0,0 +1,166 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:no_screenshot/constants.dart'; +import 'package:no_screenshot/no_screenshot_method_channel.dart'; +import 'package:no_screenshot/screenshot_snapshot.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + late MethodChannelNoScreenshot platform; + + setUp(() { + platform = MethodChannelNoScreenshot(); + }); + + group('MethodChannelNoScreenshot', () { + const MethodChannel channel = MethodChannel(screenshotMethodChannel); + + test('screenshotOn', () async { + const bool expected = true; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == screenShotOnConst) { + return expected; + } + return null; + }); + + final result = await platform.screenshotOn(); + expect(result, expected); + }); + + test('screenshotOff', () async { + const bool expected = true; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == screenShotOffConst) { + return expected; + } + return null; + }); + + final result = await platform.screenshotOff(); + expect(result, expected); + }); + + test('toggleScreenshot', () async { + const bool expected = true; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == toggleScreenShotConst) { + return expected; + } + return null; + }); + + final result = await platform.toggleScreenshot(); + expect(result, expected); + }); + + test('startScreenshotListening', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == startScreenshotListeningConst) { + return null; + } + return null; + }); + + await platform.startScreenshotListening(); + expect(true, true); // Add more specific expectations if needed + }); + + test('stopScreenshotListening', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == stopScreenshotListeningConst) { + return null; + } + return null; + }); + + await platform.stopScreenshotListening(); + expect(true, true); // Add more specific expectations if needed + }); + }); + + group('ScreenshotSnapshot', () { + test('fromMap', () { + final map = { + 'screenshot_path': '/example/path', + 'is_screenshot_on': true, + 'was_screenshot_taken': true, + }; + final snapshot = ScreenshotSnapshot.fromMap(map); + expect(snapshot.screenshotPath, '/example/path'); + expect(snapshot.isScreenshotProtectionOn, true); + expect(snapshot.wasScreenshotTaken, true); + }); + + test('toMap', () { + final snapshot = ScreenshotSnapshot( + screenshotPath: '/example/path', + isScreenshotProtectionOn: true, + wasScreenshotTaken: true, + ); + final map = snapshot.toMap(); + expect(map['screenshot_path'], '/example/path'); + expect(map['is_screenshot_on'], true); + expect(map['was_screenshot_taken'], true); + }); + + test('equality operator', () { + final snapshot1 = ScreenshotSnapshot( + screenshotPath: '/example/path', + isScreenshotProtectionOn: true, + wasScreenshotTaken: true, + ); + final snapshot2 = ScreenshotSnapshot( + screenshotPath: '/example/path', + isScreenshotProtectionOn: true, + wasScreenshotTaken: true, + ); + final snapshot3 = ScreenshotSnapshot( + screenshotPath: '/different/path', + isScreenshotProtectionOn: false, + wasScreenshotTaken: false, + ); + + expect(snapshot1 == snapshot2, true); + expect(snapshot1 == snapshot3, false); + }); + + test('hashCode', () { + final snapshot1 = ScreenshotSnapshot( + screenshotPath: '/example/path', + isScreenshotProtectionOn: true, + wasScreenshotTaken: true, + ); + final snapshot2 = ScreenshotSnapshot( + screenshotPath: '/example/path', + isScreenshotProtectionOn: true, + wasScreenshotTaken: true, + ); + final snapshot3 = ScreenshotSnapshot( + screenshotPath: '/different/path', + isScreenshotProtectionOn: false, + wasScreenshotTaken: false, + ); + + expect(snapshot1.hashCode, snapshot2.hashCode); + expect(snapshot1.hashCode, isNot(snapshot3.hashCode)); + }); + + test('toString', () { + final snapshot = ScreenshotSnapshot( + screenshotPath: '/example/path', + isScreenshotProtectionOn: true, + wasScreenshotTaken: true, + ); + final string = snapshot.toString(); + expect(string, + 'ScreenshotSnapshot(\nscreenshotPath: /example/path, \nisScreenshotProtectionOn: true, \nwasScreenshotTaken: true\n)'); + }); + }); +} diff --git a/test/no_screenshot_platform_interface_test.dart b/test/no_screenshot_platform_interface_test.dart new file mode 100644 index 0000000..ab0a9d4 --- /dev/null +++ b/test/no_screenshot_platform_interface_test.dart @@ -0,0 +1,75 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:no_screenshot/no_screenshot_method_channel.dart'; +import 'package:no_screenshot/no_screenshot_platform_interface.dart'; +import 'package:no_screenshot/screenshot_snapshot.dart'; + +class MockNoScreenshotPlatform extends NoScreenshotPlatform { + @override + Future screenshotOff() async { + return true; + } + + @override + Future screenshotOn() async { + return true; + } + + @override + Future toggleScreenshot() async { + return true; + } + + @override + Stream get screenshotStream { + return const Stream.empty(); + } + + @override + Future startScreenshotListening() async { + return; + } + + @override + Future stopScreenshotListening() async { + return; + } +} + +void main() { + final platform = MockNoScreenshotPlatform(); + + group('NoScreenshotPlatform', () { + test('default instance should be MethodChannelNoScreenshot', () { + expect(NoScreenshotPlatform.instance, + isInstanceOf()); + }); + + test('screenshotOff should return true when called', () async { + expect(await platform.screenshotOff(), isTrue); + }); + + test('screenshotOn should return true when called', () async { + expect(await platform.screenshotOn(), isTrue); + }); + + test('toggleScreenshot should return true when called', () async { + expect(await platform.toggleScreenshot(), isTrue); + }); + + test('screenshotStream should not throw UnimplementedError when accessed', + () { + expect(() => platform.screenshotStream, isNot(throwsUnimplementedError)); + }); + test( + 'startScreenshotListening should not throw UnimplementedError when called', + () async { + expect(platform.startScreenshotListening(), completes); + }); + + test( + 'stopScreenshotListening should not throw UnimplementedError when called', + () async { + expect(platform.stopScreenshotListening(), completes); + }); + }); +} diff --git a/test/no_screenshot_test.dart b/test/no_screenshot_test.dart index 3ed6b73..86396bd 100644 --- a/test/no_screenshot_test.dart +++ b/test/no_screenshot_test.dart @@ -1,8 +1,8 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:no_screenshot/no_screenshot_platform_interface.dart'; import 'package:no_screenshot/no_screenshot_method_channel.dart'; import 'package:no_screenshot/screenshot_snapshot.dart'; +import 'package:no_screenshot/no_screenshot.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; class MockNoScreenshotPlatform @@ -40,25 +40,56 @@ class MockNoScreenshotPlatform } } -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); +void main() { final NoScreenshotPlatform initialPlatform = NoScreenshotPlatform.instance; MockNoScreenshotPlatform fakePlatform = MockNoScreenshotPlatform(); + setUp(() { + NoScreenshotPlatform.instance = fakePlatform; + }); + + tearDown(() { + NoScreenshotPlatform.instance = initialPlatform; + }); + test('$MethodChannelNoScreenshot is the default instance', () { expect(initialPlatform, isInstanceOf()); }); + test('NoScreenshot instance is a singleton', () { + final instance1 = NoScreenshot.instance; + final instance2 = NoScreenshot.instance; + expect(instance1, equals(instance2)); + }); + test('screenshotOn', () async { - expect(await fakePlatform.screenshotOn(), true); + expect(await NoScreenshot.instance.screenshotOn(), true); }); - // screenshotOff + test('screenshotOff', () async { - expect(await fakePlatform.screenshotOff(), true); + expect(await NoScreenshot.instance.screenshotOff(), true); }); - // toggleScreenshot test('toggleScreenshot', () async { - expect(await fakePlatform.toggleScreenshot(), true); + expect(await NoScreenshot.instance.toggleScreenshot(), true); + }); + + test('screenshotStream', () async { + expect(NoScreenshot.instance.screenshotStream, + isInstanceOf>()); + }); + test('startScreenshotListening', () async { + expect(NoScreenshot.instance.startScreenshotListening(), completes); + }); + + test('stopScreenshotListening', () async { + expect(NoScreenshot.instance.stopScreenshotListening(), completes); + }); + + test('NoScreenshot equality operator', () { + final instance1 = NoScreenshot.instance; + final instance2 = NoScreenshot.instance; + + expect(instance1 == instance2, true, reason: 'Instances should be equal'); }); } diff --git a/test_driver/app.dart b/test_driver/app.dart index f7cb2aa..6144972 100644 --- a/test_driver/app.dart +++ b/test_driver/app.dart @@ -1,4 +1,5 @@ import 'package:flutter_driver/driver_extension.dart'; +// ignore: avoid_relative_lib_imports import '../example/lib/main.dart' as app; void main() {