From 52e64e806b6b218a4e9edf4f3cad80349c1c345d Mon Sep 17 00:00:00 2001 From: kholood Date: Tue, 3 Jun 2025 15:42:25 +0300 Subject: [PATCH 01/10] chore(example): update example app --- example/lib/main.dart | 2 + example/lib/src/app_routes.dart | 2 + example/lib/src/screens/bug_reporting.dart | 261 +++++++++++++++++++++ example/lib/src/screens/my_home_page.dart | 162 +++++++------ 4 files changed, 351 insertions(+), 76 deletions(-) create mode 100644 example/lib/src/screens/bug_reporting.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 91b0a67e7..257bdde5b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,6 +20,8 @@ import 'src/widget/section_title.dart'; part 'src/screens/crashes_page.dart'; +part 'src/screens/bug_reporting.dart'; + part 'src/screens/complex_page.dart'; part 'src/screens/apm_page.dart'; diff --git a/example/lib/src/app_routes.dart b/example/lib/src/app_routes.dart index 9175d5405..f52636cde 100644 --- a/example/lib/src/app_routes.dart +++ b/example/lib/src/app_routes.dart @@ -9,6 +9,8 @@ final appRoutes = { "/": (BuildContext context) => const MyHomePage(title: 'Flutter Demo Home Pag'), CrashesPage.screenName: (BuildContext context) => const CrashesPage(), + BugReportingPage.screenName: (BuildContext context) => + const BugReportingPage(), ComplexPage.screenName: (BuildContext context) => const ComplexPage(), ApmPage.screenName: (BuildContext context) => const ApmPage(), ScreenLoadingPage.screenName: (BuildContext context) => diff --git a/example/lib/src/screens/bug_reporting.dart b/example/lib/src/screens/bug_reporting.dart new file mode 100644 index 000000000..aa241f56a --- /dev/null +++ b/example/lib/src/screens/bug_reporting.dart @@ -0,0 +1,261 @@ +part of '../../main.dart'; + +class BugReportingPage extends StatefulWidget { + static const screenName = 'bugReporting'; + + const BugReportingPage({Key? key}) : super(key: key); + + @override + _BugReportingPageState createState() => _BugReportingPageState(); +} + +class _BugReportingPageState extends State { + List reportTypes = []; + List invocationOptions = []; + + final disclaimerTextController = TextEditingController(); + + void restartInstabug() { + Instabug.setEnabled(false); + Instabug.setEnabled(true); + BugReporting.setInvocationEvents([InvocationEvent.floatingButton]); + } + + void setInvocationEvent(InvocationEvent invocationEvent) { + BugReporting.setInvocationEvents([invocationEvent]); + } + + void show() { + Instabug.show(); + } + + void toggleReportType(ReportType reportType) { + if (reportTypes.contains(reportType)) { + reportTypes.remove(reportType); + } else { + reportTypes.add(reportType); + } + BugReporting.setReportTypes(reportTypes); + } + + void addInvocationOption(InvocationOption invocationOption) { + if (invocationOptions.contains(invocationOption)) { + invocationOptions.remove(invocationOption); + } else { + invocationOptions.add(invocationOption); + } + BugReporting.setInvocationOptions(invocationOptions); + // BugReporting.setInvocationOptions([invocationOption]); + } + + void setOnDismissCallback() { + BugReporting.setOnDismissCallback((dismissType, reportType) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('On Dismiss'), + content: Text( + 'onDismiss callback called with $dismissType and $reportType', + ), + ); + }, + ); + }); + } + + void setDisclaimerText() { + BugReporting.setDisclaimerText(disclaimerTextController.text); + } + + @override + void dispose() { + disclaimerTextController.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Page( + title: 'Bug Reporting', + children: [ + const SectionTitle('Enabling Bug Reporting'), + InstabugButton( + key: const Key('instabug_restart'), + onPressed: restartInstabug, + text: 'Restart Instabug', + ), + InstabugButton( + key: const Key('instabug_disable'), + onPressed: () => Instabug.setEnabled(false), + text: "Disable Instabug", + ), + InstabugButton( + key: const Key('instabug_enable'), + onPressed: () => Instabug.setEnabled(true), + text: "Enable Instabug", + ), + const SectionTitle('Invocation events'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('invocation_event_none'), + onPressed: () => setInvocationEvent(InvocationEvent.none), + child: const Text('None'), + ), + ElevatedButton( + key: const Key('invocation_event_shake'), + onPressed: () => setInvocationEvent(InvocationEvent.shake), + child: const Text('Shake'), + ), + ElevatedButton( + key: const Key('invocation_event_screenshot'), + onPressed: () => setInvocationEvent(InvocationEvent.screenshot), + child: const Text('Screenshot'), + ), + ], + ), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('invocation_event_floating'), + onPressed: () => + setInvocationEvent(InvocationEvent.floatingButton), + child: const Text('Floating Button'), + ), + ElevatedButton( + key: const Key('invocation_event_two_fingers'), + onPressed: () => + setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), + child: const Text('Two Fingers Swipe Left'), + ), + ], + ), + const SectionTitle('Invocation Options'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('invocation_option_disable_post_sending_dialog'), + onPressed: () => addInvocationOption( + InvocationOption.disablePostSendingDialog), + child: const Text('disablePostSendingDialog'), + ), + ElevatedButton( + key: const Key('invocation_option_email_hidden'), + onPressed: () => + addInvocationOption(InvocationOption.emailFieldHidden), + child: const Text('emailFieldHidden'), + ), + ], + ), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('invocation_option_comment_required'), + onPressed: () => + addInvocationOption(InvocationOption.commentFieldRequired), + child: const Text('commentFieldRequired'), + ), + ElevatedButton( + onPressed: () => + addInvocationOption(InvocationOption.emailFieldOptional), + child: const Text('emailFieldOptional'), + ), + ], + ), + InstabugButton( + key: const Key('instabug_show'), + onPressed: show, + text: 'Invoke', + ), + const SectionTitle('Disclaimer Text'), + InstabugTextField( + key: const Key('disclaimer_text'), + controller: disclaimerTextController, + label: 'Enter disclaimer Text', + ), + ElevatedButton( + key: const Key('set_disclaimer_text'), + onPressed: () => setDisclaimerText, + child: const Text('set disclaimer text'), + ), + const SectionTitle('Bug Report Types'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('bug_report_type_bug'), + onPressed: () => toggleReportType(ReportType.bug), + child: const Text('Bug'), + ), + ElevatedButton( + key: const Key('bug_report_type_feedback'), + onPressed: () => toggleReportType(ReportType.feedback), + child: const Text('Feedback'), + ), + ElevatedButton( + key: const Key('bug_report_type_question'), + onPressed: () => toggleReportType(ReportType.question), + child: const Text('Question'), + ), + ], + ), + InstabugButton( + onPressed: () => { + BugReporting.show( + ReportType.bug, [InvocationOption.emailFieldOptional]) + }, + text: 'Send Bug Report', + ), + const SectionTitle('Extended Bug Reporting'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('extended_bug_report_mode_disabled'), + onPressed: () => BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.disabled), + child: const Text('disabled'), + ), + ElevatedButton( + key: + const Key('extended_bug_report_mode_required_fields_enabled'), + onPressed: () => BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.enabledWithRequiredFields), + child: const Text('enabledWithRequiredFields'), + ), + ], + ), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: + const Key('extended_bug_report_mode_optional_fields_enabled'), + onPressed: () => BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.enabledWithOptionalFields), + child: const Text('enabledWithOptionalFields'), + ), + ], + ), + const SectionTitle('Set Callback After Discarding'), + InstabugButton( + onPressed: setOnDismissCallback, + text: 'Set On Dismiss Callback', + ), + ], // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 404d79cdd..ab9cb1482 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -124,6 +124,11 @@ class _MyHomePageState extends State { Instabug.setColorTheme(colorTheme); } + void _navigateToBugs() { + ///This way of navigation utilize screenLoading automatic approach [Navigator 1] + Navigator.pushNamed(context, BugReportingPage.screenName); + } + void _navigateToCrashes() { ///This way of navigation utilize screenLoading automatic approach [Navigator 1] Navigator.pushNamed(context, CrashesPage.screenName); @@ -174,10 +179,15 @@ class _MyHomePageState extends State { textAlign: TextAlign.center, ), ), + // InstabugButton( + // onPressed: restartInstabug, + // text: 'Restart Instabug', + // ), InstabugButton( - onPressed: restartInstabug, - text: 'Restart Instabug', + onPressed: _navigateToBugs, + text: 'Bug Reporting', ), + const SectionTitle('Primary Color'), InstabugTextField( controller: primaryColorController, @@ -187,54 +197,54 @@ class _MyHomePageState extends State { text: 'Change Primary Color', onPressed: changePrimaryColor, ), - const SectionTitle('Change Invocation Event'), - ButtonBar( - mainAxisSize: MainAxisSize.min, - alignment: MainAxisAlignment.start, - children: [ - ElevatedButton( - onPressed: () => setInvocationEvent(InvocationEvent.none), - style: buttonStyle, - child: const Text('None'), - ), - ElevatedButton( - onPressed: () => setInvocationEvent(InvocationEvent.shake), - style: buttonStyle, - child: const Text('Shake'), - ), - ElevatedButton( - onPressed: () => setInvocationEvent(InvocationEvent.screenshot), - style: buttonStyle, - child: const Text('Screenshot'), - ), - ], - ), - ButtonBar( - mainAxisSize: MainAxisSize.min, - alignment: MainAxisAlignment.start, - children: [ - ElevatedButton( - onPressed: () => - setInvocationEvent(InvocationEvent.floatingButton), - style: buttonStyle, - child: const Text('Floating Button'), - ), - ElevatedButton( - onPressed: () => - setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), - style: buttonStyle, - child: const Text('Two Fingers Swipe Left'), - ), - ], - ), - InstabugButton( - onPressed: show, - text: 'Invoke', - ), - InstabugButton( - onPressed: setOnDismissCallback, - text: 'Set On Dismiss Callback', - ), + // const SectionTitle('Change Invocation Event'), + // ButtonBar( + // mainAxisSize: MainAxisSize.min, + // alignment: MainAxisAlignment.start, + // children: [ + // ElevatedButton( + // onPressed: () => setInvocationEvent(InvocationEvent.none), + // style: buttonStyle, + // child: const Text('None'), + // ), + // ElevatedButton( + // onPressed: () => setInvocationEvent(InvocationEvent.shake), + // style: buttonStyle, + // child: const Text('Shake'), + // ), + // ElevatedButton( + // onPressed: () => setInvocationEvent(InvocationEvent.screenshot), + // style: buttonStyle, + // child: const Text('Screenshot'), + // ), + // ], + // ), + // ButtonBar( + // mainAxisSize: MainAxisSize.min, + // alignment: MainAxisAlignment.start, + // children: [ + // ElevatedButton( + // onPressed: () => + // setInvocationEvent(InvocationEvent.floatingButton), + // style: buttonStyle, + // child: const Text('Floating Button'), + // ), + // ElevatedButton( + // onPressed: () => + // setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), + // style: buttonStyle, + // child: const Text('Two Fingers Swipe Left'), + // ), + // ], + // ), + // InstabugButton( + // onPressed: show, + // text: 'Invoke', + // ), + // InstabugButton( + // onPressed: setOnDismissCallback, + // text: 'Set On Dismiss Callback', + // ), const SectionTitle('Repro Steps'), InstabugTextField( controller: screenNameController, @@ -244,36 +254,36 @@ class _MyHomePageState extends State { text: 'Report Screen Change', onPressed: reportScreenChange, ), - InstabugButton( - onPressed: sendBugReport, - text: 'Send Bug Report', - ), + // InstabugButton( + // onPressed: sendBugReport, + // text: 'Send Bug Report', + // ), InstabugButton( onPressed: showManualSurvey, text: 'Show Manual Survey', ), - const SectionTitle('Change Report Types'), - ButtonBar( - mainAxisSize: MainAxisSize.min, - alignment: MainAxisAlignment.start, - children: [ - ElevatedButton( - onPressed: () => toggleReportType(ReportType.bug), - style: buttonStyle, - child: const Text('Bug'), - ), - ElevatedButton( - onPressed: () => toggleReportType(ReportType.feedback), - style: buttonStyle, - child: const Text('Feedback'), - ), - ElevatedButton( - onPressed: () => toggleReportType(ReportType.question), - style: buttonStyle, - child: const Text('Question'), - ), - ], - ), + // const SectionTitle('Change Report Types'), + // ButtonBar( + // mainAxisSize: MainAxisSize.min, + // alignment: MainAxisAlignment.start, + // children: [ + // ElevatedButton( + // onPressed: () => toggleReportType(ReportType.bug), + // style: buttonStyle, + // child: const Text('Bug'), + // ), + // ElevatedButton( + // onPressed: () => toggleReportType(ReportType.feedback), + // style: buttonStyle, + // child: const Text('Feedback'), + // ), + // ElevatedButton( + // onPressed: () => toggleReportType(ReportType.question), + // style: buttonStyle, + // child: const Text('Question'), + // ), + // ], + // ), InstabugButton( onPressed: changeFloatingButtonEdge, text: 'Move Floating Button to Left', From a3643285ebda5553cec425257432fa3fffc1953f Mon Sep 17 00:00:00 2001 From: kholood Date: Tue, 3 Jun 2025 17:39:54 +0300 Subject: [PATCH 02/10] chore(example): update lock files --- example/ios/Podfile.lock | 2 +- example/pubspec.lock | 92 ++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 484d0ae99..fb6db9601 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -25,7 +25,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Instabug: 97a4e694731f46bbc02dbe49ab29cc552c5e2f41 - instabug_flutter: 4e4a9b162d77d5624d08ccdf81745d923745e062 + instabug_flutter: ef9cb6bf3c9dd29b1e4bf3129a16dcbcb2d332e6 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 PODFILE CHECKSUM: 8f7552fd115ace1988c3db54a69e4a123c448f84 diff --git a/example/pubspec.lock b/example/pubspec.lock index 93971dc8b..c6b9dd525 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,58 +5,58 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -120,18 +120,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -152,10 +152,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -168,71 +168,71 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" process: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" sync_http: dependency: transitive description: @@ -245,18 +245,18 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.4" typed_data: dependency: transitive description: @@ -277,18 +277,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.1" webdriver: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" sdks: - dart: ">=3.5.0 <4.0.0" + dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" From 195714be60410633fbf12e455f2068f4d8b7947d Mon Sep 17 00:00:00 2001 From: kholood Date: Wed, 4 Jun 2025 15:07:57 +0300 Subject: [PATCH 03/10] chore(example): activate bug reporting buttons in home page --- example/lib/src/screens/my_home_page.dart | 157 +++++++++++----------- 1 file changed, 78 insertions(+), 79 deletions(-) diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index ab9cb1482..09a46f340 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -179,15 +179,14 @@ class _MyHomePageState extends State { textAlign: TextAlign.center, ), ), - // InstabugButton( - // onPressed: restartInstabug, - // text: 'Restart Instabug', - // ), + InstabugButton( + onPressed: restartInstabug, + text: 'Restart Instabug', + ), InstabugButton( onPressed: _navigateToBugs, text: 'Bug Reporting', ), - const SectionTitle('Primary Color'), InstabugTextField( controller: primaryColorController, @@ -197,54 +196,54 @@ class _MyHomePageState extends State { text: 'Change Primary Color', onPressed: changePrimaryColor, ), - // const SectionTitle('Change Invocation Event'), - // ButtonBar( - // mainAxisSize: MainAxisSize.min, - // alignment: MainAxisAlignment.start, - // children: [ - // ElevatedButton( - // onPressed: () => setInvocationEvent(InvocationEvent.none), - // style: buttonStyle, - // child: const Text('None'), - // ), - // ElevatedButton( - // onPressed: () => setInvocationEvent(InvocationEvent.shake), - // style: buttonStyle, - // child: const Text('Shake'), - // ), - // ElevatedButton( - // onPressed: () => setInvocationEvent(InvocationEvent.screenshot), - // style: buttonStyle, - // child: const Text('Screenshot'), - // ), - // ], - // ), - // ButtonBar( - // mainAxisSize: MainAxisSize.min, - // alignment: MainAxisAlignment.start, - // children: [ - // ElevatedButton( - // onPressed: () => - // setInvocationEvent(InvocationEvent.floatingButton), - // style: buttonStyle, - // child: const Text('Floating Button'), - // ), - // ElevatedButton( - // onPressed: () => - // setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), - // style: buttonStyle, - // child: const Text('Two Fingers Swipe Left'), - // ), - // ], - // ), - // InstabugButton( - // onPressed: show, - // text: 'Invoke', - // ), - // InstabugButton( - // onPressed: setOnDismissCallback, - // text: 'Set On Dismiss Callback', - // ), + const SectionTitle('Change Invocation Event'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + onPressed: () => setInvocationEvent(InvocationEvent.none), + style: buttonStyle, + child: const Text('None'), + ), + ElevatedButton( + onPressed: () => setInvocationEvent(InvocationEvent.shake), + style: buttonStyle, + child: const Text('Shake'), + ), + ElevatedButton( + onPressed: () => setInvocationEvent(InvocationEvent.screenshot), + style: buttonStyle, + child: const Text('Screenshot'), + ), + ], + ), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + onPressed: () => + setInvocationEvent(InvocationEvent.floatingButton), + style: buttonStyle, + child: const Text('Floating Button'), + ), + ElevatedButton( + onPressed: () => + setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), + style: buttonStyle, + child: const Text('Two Fingers Swipe Left'), + ), + ], + ), + InstabugButton( + onPressed: show, + text: 'Invoke', + ), + InstabugButton( + onPressed: setOnDismissCallback, + text: 'Set On Dismiss Callback', + ), const SectionTitle('Repro Steps'), InstabugTextField( controller: screenNameController, @@ -254,36 +253,36 @@ class _MyHomePageState extends State { text: 'Report Screen Change', onPressed: reportScreenChange, ), - // InstabugButton( - // onPressed: sendBugReport, - // text: 'Send Bug Report', - // ), + InstabugButton( + onPressed: sendBugReport, + text: 'Send Bug Report', + ), InstabugButton( onPressed: showManualSurvey, text: 'Show Manual Survey', ), - // const SectionTitle('Change Report Types'), - // ButtonBar( - // mainAxisSize: MainAxisSize.min, - // alignment: MainAxisAlignment.start, - // children: [ - // ElevatedButton( - // onPressed: () => toggleReportType(ReportType.bug), - // style: buttonStyle, - // child: const Text('Bug'), - // ), - // ElevatedButton( - // onPressed: () => toggleReportType(ReportType.feedback), - // style: buttonStyle, - // child: const Text('Feedback'), - // ), - // ElevatedButton( - // onPressed: () => toggleReportType(ReportType.question), - // style: buttonStyle, - // child: const Text('Question'), - // ), - // ], - // ), + const SectionTitle('Change Report Types'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + onPressed: () => toggleReportType(ReportType.bug), + style: buttonStyle, + child: const Text('Bug'), + ), + ElevatedButton( + onPressed: () => toggleReportType(ReportType.feedback), + style: buttonStyle, + child: const Text('Feedback'), + ), + ElevatedButton( + onPressed: () => toggleReportType(ReportType.question), + style: buttonStyle, + child: const Text('Question'), + ), + ], + ), InstabugButton( onPressed: changeFloatingButtonEdge, text: 'Move Floating Button to Left', From 5bd052381a999481842579d8e61a9fe9543fa6fa Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Wed, 25 Jun 2025 13:50:21 +0300 Subject: [PATCH 04/10] feat: add bug reporting & crash reporting cases --- .../InstabugExampleMethodCallHandler.kt | 57 ++--- .../Runner/InstabugExampleMethodCallHandler.m | 28 +-- .../src/components/fatal_crashes_content.dart | 10 + .../components/non_fatal_crashes_content.dart | 31 ++- example/lib/src/screens/bug_reporting.dart | 200 ++++++++++++++++-- example/lib/src/screens/my_home_page.dart | 64 +++++- 6 files changed, 323 insertions(+), 67 deletions(-) diff --git a/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt b/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt index 17a7d35c6..67e7d5bab 100644 --- a/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt +++ b/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt @@ -24,12 +24,12 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { } SEND_NATIVE_FATAL_HANG -> { Log.d(TAG, "Sending native fatal hang for 3000 ms") - sendANR() + sendFatalHang() result.success(null) } SEND_ANR -> { Log.d(TAG, "Sending android not responding 'ANR' hanging for 20000 ms") - sendFatalHang() + sendANR() result.success(null) } SEND_OOM -> { @@ -71,58 +71,41 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { } private fun sendANR() { + android.os.Handler(Looper.getMainLooper()).post { try { Thread.sleep(20000) } catch (e: InterruptedException) { throw RuntimeException(e) } + } } private fun sendFatalHang() { - try { - Thread.sleep(3000) - } catch (e: InterruptedException) { - throw RuntimeException(e) + android.os.Handler(Looper.getMainLooper()).post { + + try { + Thread.sleep(3000) + } catch (e: InterruptedException) { + throw RuntimeException(e) + } } } private fun sendOOM() { + android.os.Handler(Looper.getMainLooper()).post { + + oomCrash() + } } private fun oomCrash() { - Thread { - val stringList: MutableList = ArrayList() - for (i in 0 until 1000000) { - stringList.add(getRandomString(10000)) - } - }.start() - } - - private fun getRandomString(length: Int): String { - val charset: MutableList = ArrayList() - var ch = 'a' - while (ch <= 'z') { - charset.add(ch) - ch++ + val list = ArrayList() + while (true) { + list.add(ByteArray(10 * 1024 * 1024)) // Allocate 10MB chunks } - ch = 'A' - while (ch <= 'Z') { - charset.add(ch) - ch++ - } - ch = '0' - while (ch <= '9') { - charset.add(ch) - ch++ - } - val randomString = StringBuilder() - val random = java.util.Random() - for (i in 0 until length) { - val randomChar = charset[random.nextInt(charset.size)] - randomString.append(randomChar) - } - return randomString.toString() } + + } diff --git a/example/ios/Runner/InstabugExampleMethodCallHandler.m b/example/ios/Runner/InstabugExampleMethodCallHandler.m index 6b1331587..7e62025cb 100644 --- a/example/ios/Runner/InstabugExampleMethodCallHandler.m +++ b/example/ios/Runner/InstabugExampleMethodCallHandler.m @@ -55,19 +55,21 @@ + (BOOL)requiresMainQueueSetup } - (void)oomCrash { - dispatch_async(self.serialQueue, ^{ - self.oomBelly = [NSMutableArray array]; - [UIApplication.sharedApplication beginBackgroundTaskWithName:@"OOM Crash" expirationHandler:nil]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSMutableArray *belly = [NSMutableArray array]; while (true) { - unsigned long dinnerLength = 1024 * 1024 * 10; - char *dinner = malloc(sizeof(char) * dinnerLength); - for (int i=0; i < dinnerLength; i++) - { - //write to each byte ensure that the memory pages are actually allocated - dinner[i] = '0'; + // 20 MB chunks to speed up OOM + void *buffer = malloc(20 * 1024 * 1024); + if (buffer == NULL) { + NSLog(@"OOM: malloc failed"); + break; } - NSData *plate = [NSData dataWithBytesNoCopy:dinner length:dinnerLength freeWhenDone:YES]; - [self.oomBelly addObject:plate]; + memset(buffer, 1, 20 * 1024 * 1024); + NSData *data = [NSData dataWithBytesNoCopy:buffer length:20 * 1024 * 1024 freeWhenDone:YES]; + [belly addObject:data]; + + // Optional: slight delay to avoid CPU spike + [NSThread sleepForTimeInterval:0.01]; } }); } @@ -108,7 +110,9 @@ - (void)sendNativeFatalCrash { } - (void)sendFatalHang { - [NSThread sleepForTimeInterval:3.0f]; + dispatch_async(dispatch_get_main_queue(), ^{ + sleep(20); // Block main thread for 20 seconds + }); } - (void)sendOOM { diff --git a/example/lib/src/components/fatal_crashes_content.dart b/example/lib/src/components/fatal_crashes_content.dart index c262b63a6..909f2fde3 100644 --- a/example/lib/src/components/fatal_crashes_content.dart +++ b/example/lib/src/components/fatal_crashes_content.dart @@ -20,31 +20,37 @@ class FatalCrashesContent extends StatelessWidget { children: [ InstabugButton( text: 'Throw Exception', + key: const Key('fatal_crash_exception'), onPressed: () => throwUnhandledException( Exception('This is a generic exception.')), ), InstabugButton( text: 'Throw StateError', + key: const Key('fatal_crash_state_exception'), onPressed: () => throwUnhandledException(StateError('This is a StateError.')), ), InstabugButton( text: 'Throw ArgumentError', + key: const Key('fatal_crash_argument_exception'), onPressed: () => throwUnhandledException( ArgumentError('This is an ArgumentError.')), ), InstabugButton( text: 'Throw RangeError', + key: const Key('fatal_crash_range_exception'), onPressed: () => throwUnhandledException( RangeError.range(5, 0, 3, 'Index out of range')), ), InstabugButton( text: 'Throw FormatException', + key: const Key('fatal_crash_format_exception'), onPressed: () => throwUnhandledException(UnsupportedError('Invalid format.')), ), InstabugButton( text: 'Throw NoSuchMethodError', + key: const Key('fatal_crash_no_such_method_error_exception'), onPressed: () { // This intentionally triggers a NoSuchMethodError dynamic obj; @@ -53,20 +59,24 @@ class FatalCrashesContent extends StatelessWidget { ), const InstabugButton( text: 'Throw Native Fatal Crash', + key: const Key('fatal_crash_native_exception'), onPressed: InstabugFlutterExampleMethodChannel.sendNativeFatalCrash, ), const InstabugButton( text: 'Send Native Fatal Hang', + key: const Key('fatal_crash_native_hang'), onPressed: InstabugFlutterExampleMethodChannel.sendNativeFatalHang, ), Platform.isAndroid ? const InstabugButton( text: 'Send Native ANR', + key: const Key('fatal_crash_anr'), onPressed: InstabugFlutterExampleMethodChannel.sendAnr, ) : const SizedBox.shrink(), const InstabugButton( text: 'Throw Unhandled Native OOM Exception', + key: const Key('fatal_crash_oom'), onPressed: InstabugFlutterExampleMethodChannel.sendOom, ), ], diff --git a/example/lib/src/components/non_fatal_crashes_content.dart b/example/lib/src/components/non_fatal_crashes_content.dart index c3d331187..8d3bb7fb3 100644 --- a/example/lib/src/components/non_fatal_crashes_content.dart +++ b/example/lib/src/components/non_fatal_crashes_content.dart @@ -42,31 +42,41 @@ class _NonFatalCrashesContentState extends State { children: [ InstabugButton( text: 'Throw Exception', + key: const Key('non_fatal_exception'), onPressed: () => throwHandledException(Exception('This is a generic exception.')), ), InstabugButton( text: 'Throw StateError', + key: const Key('non_fatal_state_exception'), onPressed: () => throwHandledException(StateError('This is a StateError.')), ), InstabugButton( text: 'Throw ArgumentError', + key: const Key('non_fatal_argument_exception'), + onPressed: () => throwHandledException(ArgumentError('This is an ArgumentError.')), ), InstabugButton( text: 'Throw RangeError', + key: const Key('non_fatal_range_exception'), + onPressed: () => throwHandledException( RangeError.range(5, 0, 3, 'Index out of range')), ), InstabugButton( text: 'Throw FormatException', + key: const Key('non_fatal_format_exception'), + onPressed: () => throwHandledException(UnsupportedError('Invalid format.')), ), InstabugButton( text: 'Throw NoSuchMethodError', + key: const Key('non_fatal_no_such_method_exception'), + onPressed: () { dynamic obj; throwHandledException(obj.methodThatDoesNotExist()); @@ -74,6 +84,8 @@ class _NonFatalCrashesContentState extends State { ), const InstabugButton( text: 'Throw Handled Native Exception', + key: Key('non_fatal_native_exception'), + onPressed: InstabugFlutterExampleMethodChannel.sendNativeNonFatalCrash, ), @@ -86,6 +98,7 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "Crash title", + key: const Key("non_fatal_crash_title_textfield"), controller: crashNameController, validator: (value) { if (value?.trim().isNotEmpty == true) return null; @@ -100,7 +113,9 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "User Attribute key", - controller: crashUserAttributeKeyController, + key: const Key("non_fatal_user_attribute_key_textfield"), + + controller: crashUserAttributeKeyController, validator: (value) { if (crashUserAttributeValueController.text.isNotEmpty) { if (value?.trim().isNotEmpty == true) return null; @@ -113,7 +128,9 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "User Attribute Value", - controller: crashUserAttributeValueController, + key: const Key("non_fatal_user_attribute_value_textfield"), + + controller: crashUserAttributeValueController, validator: (value) { if (crashUserAttributeKeyController.text.isNotEmpty) { if (value?.trim().isNotEmpty == true) return null; @@ -130,7 +147,9 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "Fingerprint", - controller: crashfingerPrintController, + key: const Key("non_fatal_user_attribute_fingerprint_textfield"), + + controller: crashfingerPrintController, )), ], ), @@ -141,6 +160,8 @@ class _NonFatalCrashesContentState extends State { Expanded( flex: 5, child: DropdownButtonHideUnderline( + key: const Key("non_fatal_crash_level_dropdown"), + child: DropdownButtonFormField( value: crashType, @@ -161,7 +182,7 @@ class _NonFatalCrashesContentState extends State { ], ), ), - SizedBox( + const SizedBox( height: 8, ), InstabugButton( @@ -190,7 +211,7 @@ class _NonFatalCrashesContentState extends State { fingerprint: crashfingerPrintController.text, level: crashType); ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("Crash sent"))); + .showSnackBar(const SnackBar(content: Text("Crash sent"))); crashNameController.text = ''; crashfingerPrintController.text = ''; crashUserAttributeValueController.text = ''; diff --git a/example/lib/src/screens/bug_reporting.dart b/example/lib/src/screens/bug_reporting.dart index aa241f56a..121e24292 100644 --- a/example/lib/src/screens/bug_reporting.dart +++ b/example/lib/src/screens/bug_reporting.dart @@ -10,11 +10,16 @@ class BugReportingPage extends StatefulWidget { } class _BugReportingPageState extends State { - List reportTypes = []; + List reportTypes = [ReportType.bug,ReportType.feedback,ReportType.question]; List invocationOptions = []; final disclaimerTextController = TextEditingController(); + bool attachmentsOptionsScreenshot = true; + bool attachmentsOptionsExtraScreenshot = true; + bool attachmentsOptionsGalleryImage = true; + bool attachmentsOptionsScreenRecording = true; + void restartInstabug() { Instabug.setEnabled(false); Instabug.setEnabled(true); @@ -25,16 +30,42 @@ class _BugReportingPageState extends State { BugReporting.setInvocationEvents([invocationEvent]); } + void setUserConsent( + String key, + String description, + bool mandatory, + bool checked, + UserConsentActionType? actionType, + ) { + BugReporting.addUserConsents( + key: key, + description: description, + mandatory: mandatory, + checked: true, + actionType: actionType); + } + void show() { Instabug.show(); } + void addAttachmentOptions() { + BugReporting.setEnabledAttachmentTypes( + attachmentsOptionsScreenshot, + attachmentsOptionsExtraScreenshot, + attachmentsOptionsGalleryImage, + attachmentsOptionsScreenRecording); + } + void toggleReportType(ReportType reportType) { if (reportTypes.contains(reportType)) { reportTypes.remove(reportType); } else { reportTypes.add(reportType); } + setState(() { + + }); BugReporting.setReportTypes(reportTypes); } @@ -48,6 +79,18 @@ class _BugReportingPageState extends State { // BugReporting.setInvocationOptions([invocationOption]); } + void showDialogOnInvoke(BuildContext context) { + BugReporting.setOnDismissCallback((dismissType, reportType) { + if (dismissType == DismissType.submit) { + showDialog( + context: context, + builder: (_) => const AlertDialog( + title: Text('Bug Reporting sent'), + )); + } + }); + } + void setOnDismissCallback() { BugReporting.setOnDismissCallback((dismissType, reportType) { showDialog( @@ -96,6 +139,11 @@ class _BugReportingPageState extends State { onPressed: () => Instabug.setEnabled(true), text: "Enable Instabug", ), + InstabugButton( + key: const Key('instabug_post_sending_dialog'), + onPressed: () => {showDialogOnInvoke(context)}, + text: "Set the post sending dialog", + ), const SectionTitle('Invocation events'), ButtonBar( mainAxisSize: MainAxisSize.min, @@ -136,6 +184,61 @@ class _BugReportingPageState extends State { ), ], ), + const SectionTitle('User Consent'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + layoutBehavior: ButtonBarLayoutBehavior.padded, + children: [ + ElevatedButton( + key: const Key('user_consent_media_manadatory'), + onPressed: () => setUserConsent( + 'media_mandatory', + "Mandatory for Media", + true, + true, + UserConsentActionType.dropAutoCapturedMedia), + child: const Text('Drop Media Mandatory'), + ), + ElevatedButton( + key: const Key('user_consent_no_chat_manadatory'), + onPressed: () => setUserConsent( + 'noChat_mandatory', + "Mandatory for No Chat", + true, + true, + UserConsentActionType.noChat), + child: const Text('No Chat Mandatory'), + ), + ], + ), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + layoutBehavior: ButtonBarLayoutBehavior.padded, + children: [ + ElevatedButton( + key: const Key('user_consent_drop_logs_manadatory'), + onPressed: () => setUserConsent( + 'dropLogs_mandatory', + "Mandatory for Drop logs", + true, + true, + UserConsentActionType.dropLogs), + child: const Text('Drop logs Mandatory'), + ), + ElevatedButton( + key: const Key('user_consent_no_chat_optional'), + onPressed: () => setUserConsent( + 'noChat_mandatory', + "Optional for No Chat", + false, + true, + UserConsentActionType.noChat), + child: const Text('No Chat optional'), + ), + ], + ), const SectionTitle('Invocation Options'), ButtonBar( mainAxisSize: MainAxisSize.min, @@ -177,35 +280,96 @@ class _BugReportingPageState extends State { onPressed: show, text: 'Invoke', ), - const SectionTitle('Disclaimer Text'), - InstabugTextField( - key: const Key('disclaimer_text'), - controller: disclaimerTextController, - label: 'Enter disclaimer Text', - ), - ElevatedButton( - key: const Key('set_disclaimer_text'), - onPressed: () => setDisclaimerText, - child: const Text('set disclaimer text'), + const SectionTitle('Attachment Options'), + Wrap( + children: [ + CheckboxListTile( + isThreeLine: false, + tristate: false, + value: attachmentsOptionsScreenshot, + onChanged: (value) { + setState(() { + attachmentsOptionsScreenshot = value ?? false; + }); + addAttachmentOptions(); + }, + title: const Text("Screenshot"), + subtitle: const Text('Enable attachment for screenShot'), + key: const Key('attachment_option_screenshot'), + + ), + CheckboxListTile( + value: attachmentsOptionsExtraScreenshot, + onChanged: (value) { + setState(() { + attachmentsOptionsExtraScreenshot = value ?? false; + }); + addAttachmentOptions(); + + }, + title: const Text("Extra Screenshot"), + subtitle: const Text('Enable attachment for extra screenShot'), + key: const Key('attachment_option_extra_screenshot'), + + ), + CheckboxListTile( + value: attachmentsOptionsGalleryImage, + onChanged: (value) { + setState(() { + attachmentsOptionsGalleryImage = value ?? false; + }); + addAttachmentOptions(); + + }, + title: const Text("Gallery"), + subtitle: const Text('Enable attachment for gallery'), + key: const Key('attachment_option_gallery'), + + ), + CheckboxListTile( + value: attachmentsOptionsScreenRecording, + onChanged: (value) { + setState(() { + attachmentsOptionsScreenRecording = value ?? false; + }); + addAttachmentOptions(); + + }, + title: const Text("Screen Recording"), + subtitle: const Text('Enable attachment for screen Recording'), + key: const Key('attachment_option_screen_recording'), + + ), + ], ), - const SectionTitle('Bug Report Types'), + const SectionTitle('Bug reporting type'), + ButtonBar( mainAxisSize: MainAxisSize.min, alignment: MainAxisAlignment.start, children: [ ElevatedButton( key: const Key('bug_report_type_bug'), + style: ElevatedButton.styleFrom( + backgroundColor: reportTypes.contains(ReportType.bug)?Colors.grey.shade400:null + ), onPressed: () => toggleReportType(ReportType.bug), child: const Text('Bug'), ), ElevatedButton( key: const Key('bug_report_type_feedback'), onPressed: () => toggleReportType(ReportType.feedback), + style: ElevatedButton.styleFrom( + backgroundColor: reportTypes.contains(ReportType.feedback)?Colors.grey.shade400:null + ), child: const Text('Feedback'), ), ElevatedButton( key: const Key('bug_report_type_question'), onPressed: () => toggleReportType(ReportType.question), + style: ElevatedButton.styleFrom( + backgroundColor: reportTypes.contains(ReportType.question)?Colors.grey.shade400:null + ), child: const Text('Question'), ), ], @@ -217,6 +381,18 @@ class _BugReportingPageState extends State { }, text: 'Send Bug Report', ), + const SectionTitle('Disclaimer Text'), + InstabugTextField( + key: const Key('disclaimer_text'), + controller: disclaimerTextController, + label: 'Enter disclaimer Text', + ), + ElevatedButton( + key: const Key('set_disclaimer_text'), + onPressed: () => setDisclaimerText, + child: const Text('set disclaimer text'), + ), + const SectionTitle('Extended Bug Reporting'), ButtonBar( mainAxisSize: MainAxisSize.min, diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 09a46f340..293e2fa18 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -20,6 +20,9 @@ class _MyHomePageState extends State { final primaryColorController = TextEditingController(); final screenNameController = TextEditingController(); final featureFlagsController = TextEditingController(); + final userAttributeKeyController = TextEditingController(); + + final userAttributeValueController = TextEditingController(); @override void dispose() { @@ -166,6 +169,8 @@ class _MyHomePageState extends State { ); } + final _formUserAttributeKey = GlobalKey(); + @override Widget build(BuildContext context) { return Page( @@ -343,7 +348,7 @@ class _MyHomePageState extends State { ), ], ), - SectionTitle('FeatureFlags'), + const SectionTitle('FeatureFlags'), InstabugTextField( controller: featureFlagsController, label: 'Feature Flag name', @@ -360,6 +365,63 @@ class _MyHomePageState extends State { onPressed: () => removeAllFeatureFlags(), text: 'RemoveAllFeatureFlags', ), + + const SectionTitle('Set User Attribute'), + + Form( + key: _formUserAttributeKey, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: InstabugTextField( + label: "User Attribute key", + key: const Key("user_attribute_key_textfield"), + controller: userAttributeKeyController, + validator: (value) { + if (value?.trim().isNotEmpty == true) return null; + return 'this field is required'; + }, + )), + Expanded( + child: InstabugTextField( + label: "User Attribute Value", + key: const Key("user_attribute_value_textfield"), + controller: userAttributeValueController, + validator: (value) { + if (value?.trim().isNotEmpty == true) return null; + + return 'this field is required'; + }, + )), + ], + ), + SizedBox(height: 8,), + InstabugButton( + text: 'Set User attribute', + key: const Key('set_user_data_btn'), + onPressed: () { + if (_formUserAttributeKey.currentState?.validate() == true) { + Instabug.setUserAttribute(userAttributeKeyController.text, + userAttributeValueController.text); + } + }, + ), + InstabugButton( + text: 'remove User attribute', + key: const Key('remove_user_data_btn'), + onPressed: () { + if (_formUserAttributeKey.currentState?.validate() == true) { + Instabug.removeUserAttribute(userAttributeKeyController.text); + } + }, + ), + SizedBox(height: 10,), + + ], + ), + ), ], ); } From e3a75cb173ca7096be9e0388f9d66672727b15ce Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Tue, 15 Jul 2025 13:06:12 +0300 Subject: [PATCH 05/10] fix: bug reporting --- example/lib/src/screens/bug_reporting.dart | 197 +++++++++++++-------- 1 file changed, 119 insertions(+), 78 deletions(-) diff --git a/example/lib/src/screens/bug_reporting.dart b/example/lib/src/screens/bug_reporting.dart index 121e24292..e76cd186a 100644 --- a/example/lib/src/screens/bug_reporting.dart +++ b/example/lib/src/screens/bug_reporting.dart @@ -10,7 +10,11 @@ class BugReportingPage extends StatefulWidget { } class _BugReportingPageState extends State { - List reportTypes = [ReportType.bug,ReportType.feedback,ReportType.question]; + List reportTypes = [ + ReportType.bug, + ReportType.feedback, + ReportType.question + ]; List invocationOptions = []; final disclaimerTextController = TextEditingController(); @@ -19,6 +23,7 @@ class _BugReportingPageState extends State { bool attachmentsOptionsExtraScreenshot = true; bool attachmentsOptionsGalleryImage = true; bool attachmentsOptionsScreenRecording = true; + File? fileAttachment; void restartInstabug() { Instabug.setEnabled(false); @@ -30,13 +35,11 @@ class _BugReportingPageState extends State { BugReporting.setInvocationEvents([invocationEvent]); } - void setUserConsent( - String key, - String description, - bool mandatory, - bool checked, - UserConsentActionType? actionType, - ) { + void setUserConsent(String key, + String description, + bool mandatory, + bool checked, + UserConsentActionType? actionType,) { BugReporting.addUserConsents( key: key, description: description, @@ -49,6 +52,21 @@ class _BugReportingPageState extends State { Instabug.show(); } + Future addFileAttachment() async { + FilePickerResult? result = await FilePicker.platform.pickFiles(); + + if (result != null) { + fileAttachment = File(result.files.single.path!); + Instabug.addFileAttachmentWithURL(fileAttachment!.path, fileAttachment!.path + .split('/') + .last.substring(0)); + } + } + + void removeFileAttachment() { + Instabug.clearFileAttachments(); + } + void addAttachmentOptions() { BugReporting.setEnabledAttachmentTypes( attachmentsOptionsScreenshot, @@ -84,9 +102,10 @@ class _BugReportingPageState extends State { if (dismissType == DismissType.submit) { showDialog( context: context, - builder: (_) => const AlertDialog( - title: Text('Bug Reporting sent'), - )); + builder: (_) => + const AlertDialog( + title: Text('Bug Reporting sent'), + )); } }); } @@ -192,22 +211,24 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('user_consent_media_manadatory'), - onPressed: () => setUserConsent( - 'media_mandatory', - "Mandatory for Media", - true, - true, - UserConsentActionType.dropAutoCapturedMedia), + onPressed: () => + setUserConsent( + 'media_mandatory', + "Mandatory for Media", + true, + true, + UserConsentActionType.dropAutoCapturedMedia), child: const Text('Drop Media Mandatory'), ), ElevatedButton( key: const Key('user_consent_no_chat_manadatory'), - onPressed: () => setUserConsent( - 'noChat_mandatory', - "Mandatory for No Chat", - true, - true, - UserConsentActionType.noChat), + onPressed: () => + setUserConsent( + 'noChat_mandatory', + "Mandatory for No Chat", + true, + true, + UserConsentActionType.noChat), child: const Text('No Chat Mandatory'), ), ], @@ -219,22 +240,24 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('user_consent_drop_logs_manadatory'), - onPressed: () => setUserConsent( - 'dropLogs_mandatory', - "Mandatory for Drop logs", - true, - true, - UserConsentActionType.dropLogs), + onPressed: () => + setUserConsent( + 'dropLogs_mandatory', + "Mandatory for Drop logs", + true, + true, + UserConsentActionType.dropLogs), child: const Text('Drop logs Mandatory'), ), ElevatedButton( key: const Key('user_consent_no_chat_optional'), - onPressed: () => setUserConsent( - 'noChat_mandatory', - "Optional for No Chat", - false, - true, - UserConsentActionType.noChat), + onPressed: () => + setUserConsent( + 'noChat_mandatory', + "Optional for No Chat", + false, + true, + UserConsentActionType.noChat), child: const Text('No Chat optional'), ), ], @@ -246,8 +269,9 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('invocation_option_disable_post_sending_dialog'), - onPressed: () => addInvocationOption( - InvocationOption.disablePostSendingDialog), + onPressed: () => + addInvocationOption( + InvocationOption.disablePostSendingDialog), child: const Text('disablePostSendingDialog'), ), ElevatedButton( @@ -305,7 +329,6 @@ class _BugReportingPageState extends State { attachmentsOptionsExtraScreenshot = value ?? false; }); addAttachmentOptions(); - }, title: const Text("Extra Screenshot"), subtitle: const Text('Enable attachment for extra screenShot'), @@ -319,7 +342,6 @@ class _BugReportingPageState extends State { attachmentsOptionsGalleryImage = value ?? false; }); addAttachmentOptions(); - }, title: const Text("Gallery"), subtitle: const Text('Enable attachment for gallery'), @@ -333,7 +355,6 @@ class _BugReportingPageState extends State { attachmentsOptionsScreenRecording = value ?? false; }); addAttachmentOptions(); - }, title: const Text("Screen Recording"), subtitle: const Text('Enable attachment for screen Recording'), @@ -344,38 +365,46 @@ class _BugReportingPageState extends State { ), const SectionTitle('Bug reporting type'), - ButtonBar( - mainAxisSize: MainAxisSize.min, - alignment: MainAxisAlignment.start, - children: [ - ElevatedButton( - key: const Key('bug_report_type_bug'), - style: ElevatedButton.styleFrom( - backgroundColor: reportTypes.contains(ReportType.bug)?Colors.grey.shade400:null - ), - onPressed: () => toggleReportType(ReportType.bug), - child: const Text('Bug'), - ), - ElevatedButton( - key: const Key('bug_report_type_feedback'), - onPressed: () => toggleReportType(ReportType.feedback), - style: ElevatedButton.styleFrom( - backgroundColor: reportTypes.contains(ReportType.feedback)?Colors.grey.shade400:null - ), - child: const Text('Feedback'), - ), - ElevatedButton( - key: const Key('bug_report_type_question'), - onPressed: () => toggleReportType(ReportType.question), - style: ElevatedButton.styleFrom( - backgroundColor: reportTypes.contains(ReportType.question)?Colors.grey.shade400:null - ), - child: const Text('Question'), - ), - ], + CheckboxListTile( + value: reportTypes.contains(ReportType.bug), + onChanged: (value) { + toggleReportType(ReportType.bug); + setState(() { + }); + }, + title: const Text("Bug"), + subtitle: const Text('Enable Bug reporting type'), + key: const Key('bug_report_type_bug'), + + ), + CheckboxListTile( + value: reportTypes.contains(ReportType.feedback), + onChanged: (value) { + toggleReportType(ReportType.feedback); + setState(() { + }); + }, + title: const Text("Feedback"), + subtitle: const Text('Enable Feedback reporting type'), + key: const Key('bug_report_type_feedback'), + + ), + + CheckboxListTile( + value: reportTypes.contains(ReportType.question), + onChanged: (value) { + toggleReportType(ReportType.question); + setState(() { + }); + }, + title: const Text("Question"), + subtitle: const Text('Enable Question reporting type'), + key: const Key('bug_report_type_question'), + ), InstabugButton( - onPressed: () => { + onPressed: () => + { BugReporting.show( ReportType.bug, [InvocationOption.emailFieldOptional]) }, @@ -400,15 +429,17 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('extended_bug_report_mode_disabled'), - onPressed: () => BugReporting.setExtendedBugReportMode( - ExtendedBugReportMode.disabled), + onPressed: () => + BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.disabled), child: const Text('disabled'), ), ElevatedButton( key: - const Key('extended_bug_report_mode_required_fields_enabled'), - onPressed: () => BugReporting.setExtendedBugReportMode( - ExtendedBugReportMode.enabledWithRequiredFields), + const Key('extended_bug_report_mode_required_fields_enabled'), + onPressed: () => + BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.enabledWithRequiredFields), child: const Text('enabledWithRequiredFields'), ), ], @@ -419,9 +450,10 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: - const Key('extended_bug_report_mode_optional_fields_enabled'), - onPressed: () => BugReporting.setExtendedBugReportMode( - ExtendedBugReportMode.enabledWithOptionalFields), + const Key('extended_bug_report_mode_optional_fields_enabled'), + onPressed: () => + BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.enabledWithOptionalFields), child: const Text('enabledWithOptionalFields'), ), ], @@ -431,6 +463,15 @@ class _BugReportingPageState extends State { onPressed: setOnDismissCallback, text: 'Set On Dismiss Callback', ), + const SectionTitle('Attachments'), + InstabugButton( + onPressed: addFileAttachment, + text: 'Add file attachment', + ), + InstabugButton( + onPressed: removeFileAttachment, + text: 'Clear All attachment', + ), ], // This trailing comma makes auto-formatting nicer for build methods. ); } From 86f9ca3cc05d20520d8dc3b67fe9674e2c66bf50 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Tue, 15 Jul 2025 13:09:11 +0300 Subject: [PATCH 06/10] fix: bug reporting --- example/lib/src/screens/bug_reporting.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/example/lib/src/screens/bug_reporting.dart b/example/lib/src/screens/bug_reporting.dart index e76cd186a..d30136712 100644 --- a/example/lib/src/screens/bug_reporting.dart +++ b/example/lib/src/screens/bug_reporting.dart @@ -60,6 +60,9 @@ class _BugReportingPageState extends State { Instabug.addFileAttachmentWithURL(fileAttachment!.path, fileAttachment!.path .split('/') .last.substring(0)); + setState(() { + + }); } } @@ -464,6 +467,10 @@ class _BugReportingPageState extends State { text: 'Set On Dismiss Callback', ), const SectionTitle('Attachments'), + if(fileAttachment!=null) + Text(fileAttachment!.path + .split('/') + .last.substring(0) +" Attached"), InstabugButton( onPressed: addFileAttachment, text: 'Add file attachment', From 9b4191b972a05ecbb1bb3f1ad6b4497a899aad98 Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Sun, 17 Aug 2025 23:22:59 +0300 Subject: [PATCH 07/10] chore: update example app (#600) * chore: update example app * chore: update example app --- example/lib/main.dart | 2 + example/lib/src/app_routes.dart | 5 + .../lib/src/components/network_content.dart | 36 ++++++ .../components/non_fatal_crashes_content.dart | 22 ++-- example/lib/src/screens/bug_reporting.dart | 81 +++++++++++-- example/lib/src/screens/my_home_page.dart | 103 +++++++++++++++- .../lib/src/screens/session_replay_page.dart | 114 ++++++++++++++++++ example/lib/src/widget/instabug_button.dart | 6 +- 8 files changed, 337 insertions(+), 32 deletions(-) create mode 100644 example/lib/src/screens/session_replay_page.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 257bdde5b..e3edb3c09 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,6 +22,8 @@ part 'src/screens/crashes_page.dart'; part 'src/screens/bug_reporting.dart'; +part 'src/screens/session_replay_page.dart'; + part 'src/screens/complex_page.dart'; part 'src/screens/apm_page.dart'; diff --git a/example/lib/src/app_routes.dart b/example/lib/src/app_routes.dart index f52636cde..bfc429dab 100644 --- a/example/lib/src/app_routes.dart +++ b/example/lib/src/app_routes.dart @@ -1,4 +1,5 @@ import 'package:flutter/widgets.dart' show BuildContext; +import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter_example/main.dart'; final appRoutes = { @@ -12,6 +13,10 @@ final appRoutes = { BugReportingPage.screenName: (BuildContext context) => const BugReportingPage(), ComplexPage.screenName: (BuildContext context) => const ComplexPage(), + SessionReplayPage.screenName: (BuildContext context) => + const SessionReplayPage(), + TopTabBarScreen.route: (BuildContext context) => const TopTabBarScreen(), + ApmPage.screenName: (BuildContext context) => const ApmPage(), ScreenLoadingPage.screenName: (BuildContext context) => const ScreenLoadingPage(), diff --git a/example/lib/src/components/network_content.dart b/example/lib/src/components/network_content.dart index 23eaa4dd2..e5380a85c 100644 --- a/example/lib/src/components/network_content.dart +++ b/example/lib/src/components/network_content.dart @@ -36,6 +36,42 @@ class _NetworkContentState extends State { text: 'Send Request Without Custom traceparent header', onPressed: () => _sendRequestToUrl(endpointUrlController.text), ), + InstabugButton( + text: 'obfuscateLog', + onPressed: () { + NetworkLogger.obfuscateLog((networkData) async { + return networkData.copyWith(url: 'fake url'); + }); + }, + ), + InstabugButton( + text: 'omitLog', + onPressed: () { + NetworkLogger.omitLog((networkData) async { + return networkData.url.contains('google.com'); + }); + }, + ), + InstabugButton( + text: 'obfuscateLogWithException', + onPressed: () { + NetworkLogger.obfuscateLog((networkData) async { + throw Exception("obfuscateLogWithException"); + + return networkData.copyWith(url: 'fake url'); + }); + }, + ), + InstabugButton( + text: 'omitLogWithException', + onPressed: () { + NetworkLogger.omitLog((networkData) async { + throw Exception("OmitLog with exception"); + + return networkData.url.contains('google.com'); + }); + }, + ), ], ); } diff --git a/example/lib/src/components/non_fatal_crashes_content.dart b/example/lib/src/components/non_fatal_crashes_content.dart index 8d3bb7fb3..25e5ab790 100644 --- a/example/lib/src/components/non_fatal_crashes_content.dart +++ b/example/lib/src/components/non_fatal_crashes_content.dart @@ -55,28 +55,24 @@ class _NonFatalCrashesContentState extends State { InstabugButton( text: 'Throw ArgumentError', key: const Key('non_fatal_argument_exception'), - onPressed: () => throwHandledException(ArgumentError('This is an ArgumentError.')), ), InstabugButton( text: 'Throw RangeError', key: const Key('non_fatal_range_exception'), - onPressed: () => throwHandledException( RangeError.range(5, 0, 3, 'Index out of range')), ), InstabugButton( text: 'Throw FormatException', key: const Key('non_fatal_format_exception'), - onPressed: () => throwHandledException(UnsupportedError('Invalid format.')), ), InstabugButton( text: 'Throw NoSuchMethodError', key: const Key('non_fatal_no_such_method_exception'), - onPressed: () { dynamic obj; throwHandledException(obj.methodThatDoesNotExist()); @@ -85,7 +81,6 @@ class _NonFatalCrashesContentState extends State { const InstabugButton( text: 'Throw Handled Native Exception', key: Key('non_fatal_native_exception'), - onPressed: InstabugFlutterExampleMethodChannel.sendNativeNonFatalCrash, ), @@ -113,9 +108,8 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "User Attribute key", - key: const Key("non_fatal_user_attribute_key_textfield"), - - controller: crashUserAttributeKeyController, + key: const Key("non_fatal_user_attribute_key_textfield"), + controller: crashUserAttributeKeyController, validator: (value) { if (crashUserAttributeValueController.text.isNotEmpty) { if (value?.trim().isNotEmpty == true) return null; @@ -128,9 +122,8 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "User Attribute Value", - key: const Key("non_fatal_user_attribute_value_textfield"), - - controller: crashUserAttributeValueController, + key: const Key("non_fatal_user_attribute_value_textfield"), + controller: crashUserAttributeValueController, validator: (value) { if (crashUserAttributeKeyController.text.isNotEmpty) { if (value?.trim().isNotEmpty == true) return null; @@ -147,9 +140,9 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "Fingerprint", - key: const Key("non_fatal_user_attribute_fingerprint_textfield"), - - controller: crashfingerPrintController, + key: const Key( + "non_fatal_user_attribute_fingerprint_textfield"), + controller: crashfingerPrintController, )), ], ), @@ -161,7 +154,6 @@ class _NonFatalCrashesContentState extends State { flex: 5, child: DropdownButtonHideUnderline( key: const Key("non_fatal_crash_level_dropdown"), - child: DropdownButtonFormField( value: crashType, diff --git a/example/lib/src/screens/bug_reporting.dart b/example/lib/src/screens/bug_reporting.dart index d30136712..f979dcc66 100644 --- a/example/lib/src/screens/bug_reporting.dart +++ b/example/lib/src/screens/bug_reporting.dart @@ -84,9 +84,7 @@ class _BugReportingPageState extends State { } else { reportTypes.add(reportType); } - setState(() { - - }); + setState(() {}); BugReporting.setReportTypes(reportTypes); } @@ -129,6 +127,34 @@ class _BugReportingPageState extends State { }); } + void setOnDismissCallbackWithException() { + BugReporting.setOnDismissCallback((dismissType, reportType) { + throw Exception("Test crash from dismiss callback"); + }); + } + + void setOnInvokeCallbackWithException() { + BugReporting.setOnInvokeCallback(() { + throw Exception("Test crash from invoke callback"); + }); + } + + void setOnInvoiceCallback() { + BugReporting.setOnInvokeCallback(() { + showDialog( + context: context, + builder: (context) { + return const AlertDialog( + title: Text('On Invoke'), + content: Text( + 'onInvoke callback called', + ), + ); + }, + ); + }); + } + void setDisclaimerText() { BugReporting.setDisclaimerText(disclaimerTextController.text); } @@ -323,7 +349,6 @@ class _BugReportingPageState extends State { title: const Text("Screenshot"), subtitle: const Text('Enable attachment for screenShot'), key: const Key('attachment_option_screenshot'), - ), CheckboxListTile( value: attachmentsOptionsExtraScreenshot, @@ -336,7 +361,6 @@ class _BugReportingPageState extends State { title: const Text("Extra Screenshot"), subtitle: const Text('Enable attachment for extra screenShot'), key: const Key('attachment_option_extra_screenshot'), - ), CheckboxListTile( value: attachmentsOptionsGalleryImage, @@ -349,7 +373,6 @@ class _BugReportingPageState extends State { title: const Text("Gallery"), subtitle: const Text('Enable attachment for gallery'), key: const Key('attachment_option_gallery'), - ), CheckboxListTile( value: attachmentsOptionsScreenRecording, @@ -362,11 +385,42 @@ class _BugReportingPageState extends State { title: const Text("Screen Recording"), subtitle: const Text('Enable attachment for screen Recording'), key: const Key('attachment_option_screen_recording'), - ), ], ), const SectionTitle('Bug reporting type'), + ButtonBar( + mainAxisSize: MainAxisSize.min, + alignment: MainAxisAlignment.start, + children: [ + ElevatedButton( + key: const Key('bug_report_type_bug'), + style: ElevatedButton.styleFrom( + backgroundColor: reportTypes.contains(ReportType.bug) + ? Colors.grey.shade400 + : null), + onPressed: () => toggleReportType(ReportType.bug), + child: const Text('Bug'), + ), + ElevatedButton( + key: const Key('bug_report_type_feedback'), + onPressed: () => toggleReportType(ReportType.feedback), + style: ElevatedButton.styleFrom( + backgroundColor: reportTypes.contains(ReportType.feedback) + ? Colors.grey.shade400 + : null), + child: const Text('Feedback'), + ), + ElevatedButton( + key: const Key('bug_report_type_question'), + onPressed: () => toggleReportType(ReportType.question), + style: ElevatedButton.styleFrom( + backgroundColor: reportTypes.contains(ReportType.question) + ? Colors.grey.shade400 + : null), + child: const Text('Question'), + ), + ], CheckboxListTile( value: reportTypes.contains(ReportType.bug), @@ -403,7 +457,6 @@ class _BugReportingPageState extends State { title: const Text("Question"), subtitle: const Text('Enable Question reporting type'), key: const Key('bug_report_type_question'), - ), InstabugButton( onPressed: () => @@ -424,7 +477,6 @@ class _BugReportingPageState extends State { onPressed: () => setDisclaimerText, child: const Text('set disclaimer text'), ), - const SectionTitle('Extended Bug Reporting'), ButtonBar( mainAxisSize: MainAxisSize.min, @@ -466,6 +518,17 @@ class _BugReportingPageState extends State { onPressed: setOnDismissCallback, text: 'Set On Dismiss Callback', ), + InstabugButton( + onPressed: setOnInvoiceCallback, + text: 'Set On Invoice Callback', + ), + InstabugButton( + onPressed: setOnDismissCallbackWithException, + text: 'Set On Dismiss Callback with Exception', + ), + InstabugButton( + onPressed: setOnInvokeCallbackWithException, + text: 'Set On Invoice Callback with Exception', const SectionTitle('Attachments'), if(fileAttachment!=null) Text(fileAttachment!.path diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 293e2fa18..29e2f66d7 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -169,6 +169,16 @@ class _MyHomePageState extends State { ); } + void _navigateToSessionReplay() { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SessionReplayPage(), + settings: const RouteSettings(name: SessionReplayPage.screenName), + ), + ); + } + final _formUserAttributeKey = GlobalKey(); @override @@ -320,6 +330,10 @@ class _MyHomePageState extends State { onPressed: _navigateToComplex, text: 'Complex', ), + InstabugButton( + onPressed: _navigateToSessionReplay, + text: 'Session Replay', + ), const SectionTitle('Sessions Replay'), InstabugButton( onPressed: getCurrentSessionReplaylink, @@ -365,9 +379,7 @@ class _MyHomePageState extends State { onPressed: () => removeAllFeatureFlags(), text: 'RemoveAllFeatureFlags', ), - const SectionTitle('Set User Attribute'), - Form( key: _formUserAttributeKey, child: Column( @@ -397,7 +409,9 @@ class _MyHomePageState extends State { )), ], ), - SizedBox(height: 8,), + const SizedBox( + height: 8, + ), InstabugButton( text: 'Set User attribute', key: const Key('set_user_data_btn'), @@ -413,12 +427,89 @@ class _MyHomePageState extends State { key: const Key('remove_user_data_btn'), onPressed: () { if (_formUserAttributeKey.currentState?.validate() == true) { - Instabug.removeUserAttribute(userAttributeKeyController.text); + Instabug.removeUserAttribute( + userAttributeKeyController.text); } }, ), - SizedBox(height: 10,), - + const SizedBox( + height: 10, + ), + const SectionTitle('Log'), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Expanded( + child: InstabugButton( + margin: const EdgeInsets.symmetric(horizontal: 2), + key: const ValueKey('log_hello_debug_btn'), + onPressed: () { + InstabugLog.logDebug("hello Debug"); + }, + text: 'Log Hello Debug', + ), + ), + Expanded( + child: InstabugButton( + margin: const EdgeInsets.symmetric(horizontal: 2), + key: const ValueKey('log_hello_error_btn'), + onPressed: () { + InstabugLog.logError("hello Error"); + }, + text: 'Log Hello Error', + ), + ), + Expanded( + child: InstabugButton( + margin: const EdgeInsets.symmetric(horizontal: 2), + key: const ValueKey('hello_warning_btn'), + onPressed: () { + InstabugLog.logWarn("hello Warning"); + }, + text: 'Log Hello Warn', + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Expanded( + child: InstabugButton( + margin: const EdgeInsets.symmetric(horizontal: 2), + key: const ValueKey('log_hello_info_btn'), + onPressed: () { + InstabugLog.logInfo("hello Info"); + }, + text: 'Log Hello Info', + ), + ), + Expanded( + child: InstabugButton( + margin: const EdgeInsets.symmetric(horizontal: 2), + key: const ValueKey('log_hello_verbose_btn'), + onPressed: () { + InstabugLog.logVerbose("hello Verbose"); + }, + text: 'Log Hello Verbose', + ), + ), + Expanded( + child: InstabugButton( + margin: const EdgeInsets.symmetric(horizontal: 2), + key: const ValueKey('clear_logs_btn'), + onPressed: () { + InstabugLog.clearAllLogs(); + }, + text: 'Clear All logs', + ), + ), + ], + ), + ), ], ), ), diff --git a/example/lib/src/screens/session_replay_page.dart b/example/lib/src/screens/session_replay_page.dart new file mode 100644 index 000000000..34d0d6d71 --- /dev/null +++ b/example/lib/src/screens/session_replay_page.dart @@ -0,0 +1,114 @@ +part of '../../main.dart'; + +class SessionReplayPage extends StatefulWidget { + static const screenName = 'SessionReplay'; + + const SessionReplayPage({Key? key}) : super(key: key); + + @override + State createState() => _SessionReplayPageState(); +} + +class _SessionReplayPageState extends State { + @override + Widget build(BuildContext context) { + return Page(title: 'Session Replay', children: [ + const SectionTitle('Enabling Session Replay'), + InstabugButton( + key: const Key('instabug_sesssion_replay_disable'), + onPressed: () => SessionReplay.setEnabled(false), + text: "Disable Session Replay", + ), + InstabugButton( + key: const Key('instabug_sesssion_replay_enable'), + onPressed: () => SessionReplay.setEnabled(true), + text: "Enable Session Replay", + ), + const SectionTitle('Enabling Session Replay Network'), + InstabugButton( + key: const Key('instabug_sesssion_replay_network_disable'), + onPressed: () => SessionReplay.setNetworkLogsEnabled(false), + text: "Disable Session Replay Network", + ), + InstabugButton( + key: const Key('instabug_sesssion_replay_network_enable'), + onPressed: () => SessionReplay.setNetworkLogsEnabled(true), + text: "Enable Session Replay Network", + ), + const SectionTitle('Enabling Session Replay User Steps'), + InstabugButton( + key: const Key('instabug_sesssion_replay_user_steps_disable'), + onPressed: () => SessionReplay.setUserStepsEnabled(false), + text: "Disable Session Replay User Steps", + ), + InstabugButton( + key: const Key('instabug_sesssion_replay_user_steps_enable'), + onPressed: () => SessionReplay.setUserStepsEnabled(true), + text: "Enable Session Replay User Steps", + ), + const SectionTitle('Enabling Session Replay Logs'), + InstabugButton( + key: const Key('instabug_sesssion_replay_logs_disable'), + onPressed: () => SessionReplay.setInstabugLogsEnabled(false), + text: "Disable Session Replay Logs", + ), + InstabugButton( + key: const Key('instabug_sesssion_replay_logs_enable'), + onPressed: () => SessionReplay.setInstabugLogsEnabled(true), + text: "Enable Session Replay Logs", + ), + const SectionTitle('Enabling Session Replay Repro steps'), + InstabugButton( + key: const Key('instabug_sesssion_replay_repro_steps_disable'), + onPressed: () => Instabug.setReproStepsConfig( + sessionReplay: ReproStepsMode.disabled), + text: "Disable Session Replay Repro steps", + ), + InstabugButton( + key: const Key('instabug_sesssion_replay_repro_steps_enable'), + onPressed: () => + Instabug.setReproStepsConfig(sessionReplay: ReproStepsMode.enabled), + text: "Enable Session Replay Repro steps", + ), + InstabugButton( + key: const Key('instabug_sesssion_replay_tab_screen'), + onPressed: () => Navigator.of(context).pushNamed(TopTabBarScreen.route), + text: 'Open Tab Screen', + ), + ]); + } +} + +class TopTabBarScreen extends StatelessWidget { + static const String route = "/tap"; + + const TopTabBarScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 4, // Number of tabs + child: Scaffold( + appBar: AppBar( + title: const Text('Top TabBar with 4 Tabs'), + bottom: const TabBar( + tabs: [ + Tab(text: 'Home', icon: Icon(Icons.home)), + Tab(text: 'Search', icon: Icon(Icons.search)), + Tab(text: 'Alerts', icon: Icon(Icons.notifications)), + Tab(text: 'Profile', icon: Icon(Icons.person)), + ], + ), + ), + body: const TabBarView( + children: [ + Center(child: Text('Home Screen')), + Center(child: Text('Search Screen')), + Center(child: Text('Alerts Screen')), + Center(child: Text('Profile Screen')), + ], + ), + ), + ); + } +} diff --git a/example/lib/src/widget/instabug_button.dart b/example/lib/src/widget/instabug_button.dart index 97e434061..5bdb31eef 100644 --- a/example/lib/src/widget/instabug_button.dart +++ b/example/lib/src/widget/instabug_button.dart @@ -7,6 +7,7 @@ class InstabugButton extends StatelessWidget { this.onPressed, this.fontSize, this.margin, + this.backgroundColor, }) : super(key: key); const InstabugButton.smallFontSize({ @@ -15,12 +16,13 @@ class InstabugButton extends StatelessWidget { this.onPressed, this.fontSize = 10.0, this.margin, + this.backgroundColor, }) : super(key: key); final String text; final Function()? onPressed; final double? fontSize; - + final Color? backgroundColor; final EdgeInsetsGeometry? margin; @override @@ -34,7 +36,7 @@ class InstabugButton extends StatelessWidget { child: ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( - backgroundColor: Colors.lightBlue, + backgroundColor: backgroundColor ?? Colors.lightBlue, foregroundColor: Colors.white, textStyle: Theme.of(context) .textTheme From 211d31919ea3c81b8f7a4a38191abd6ffdca4aee Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Mon, 18 Aug 2025 01:53:36 +0300 Subject: [PATCH 08/10] add extra scenarios --- example/lib/main.dart | 13 +- example/lib/src/app_routes.dart | 3 +- .../src/components/fatal_crashes_content.dart | 18 +- example/lib/src/components/flows_content.dart | 7 + .../lib/src/components/network_content.dart | 122 +++++++ .../components/non_fatal_crashes_content.dart | 21 +- .../lib/src/components/traces_content.dart | 7 + example/lib/src/screens/apm_page.dart | 2 + example/lib/src/screens/bug_reporting.dart | 339 ++++++++++-------- .../callback/callback_handler_provider.dart | 32 ++ .../src/screens/callback/callback_page.dart | 110 ++++++ example/lib/src/screens/complex_page.dart | 7 + example/lib/src/screens/my_home_page.dart | 79 +++- .../lib/src/screens/screen_loading_page.dart | 5 + .../lib/src/screens/session_replay_page.dart | 11 + example/lib/src/utils/widget_ext.dart | 10 + example/lib/src/widget/instabug_button.dart | 63 ++-- .../src/widget/instabug_clipboard_input.dart | 24 +- .../lib/src/widget/instabug_text_field.dart | 47 +-- example/pubspec.lock | 113 +++++- example/pubspec.yaml | 2 + 21 files changed, 805 insertions(+), 230 deletions(-) create mode 100644 example/lib/src/screens/callback/callback_handler_provider.dart create mode 100644 example/lib/src/screens/callback/callback_page.dart create mode 100644 example/lib/src/utils/widget_ext.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index e3edb3c09..400d85003 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,13 +2,19 @@ import 'dart:async'; import 'dart:developer'; import 'dart:io'; import 'dart:convert'; +import 'dart:math' as math; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter_example/src/components/apm_switch.dart'; +import 'package:instabug_flutter_example/src/screens/callback/callback_handler_provider.dart'; +import 'package:instabug_flutter_example/src/screens/callback/callback_page.dart'; +import 'package:instabug_flutter_example/src/utils/widget_ext.dart'; import 'package:instabug_http_client/instabug_http_client.dart'; import 'package:instabug_flutter_example/src/app_routes.dart'; import 'package:instabug_flutter_example/src/widget/nested_view.dart'; +import 'package:provider/provider.dart'; import 'src/native/instabug_flutter_example_method_channel.dart'; import 'src/widget/instabug_button.dart'; @@ -61,7 +67,12 @@ void main() { Zone.current.handleUncaughtError(details.exception, details.stack!); }; - runApp(const MyApp()); + runApp( + ChangeNotifierProvider( + create: (_) => CallbackHandlersProvider(), + child: const MyApp(), + ), + ); }, CrashReporting.reportCrash, ); diff --git a/example/lib/src/app_routes.dart b/example/lib/src/app_routes.dart index bfc429dab..e348b1a86 100644 --- a/example/lib/src/app_routes.dart +++ b/example/lib/src/app_routes.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart' show BuildContext; -import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter_example/main.dart'; +import 'package:instabug_flutter_example/src/screens/callback/callback_page.dart'; final appRoutes = { /// ["/"] route name should only be used with [onGenerateRoute:] when no @@ -12,6 +12,7 @@ final appRoutes = { CrashesPage.screenName: (BuildContext context) => const CrashesPage(), BugReportingPage.screenName: (BuildContext context) => const BugReportingPage(), + CallbackScreen.screenName: (BuildContext context) => const CallbackScreen(), ComplexPage.screenName: (BuildContext context) => const ComplexPage(), SessionReplayPage.screenName: (BuildContext context) => const SessionReplayPage(), diff --git a/example/lib/src/components/fatal_crashes_content.dart b/example/lib/src/components/fatal_crashes_content.dart index 909f2fde3..d1a1048b2 100644 --- a/example/lib/src/components/fatal_crashes_content.dart +++ b/example/lib/src/components/fatal_crashes_content.dart @@ -19,36 +19,42 @@ class FatalCrashesContent extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ InstabugButton( + symanticLabel: 'fatal_crash_exception', text: 'Throw Exception', key: const Key('fatal_crash_exception'), onPressed: () => throwUnhandledException( Exception('This is a generic exception.')), ), InstabugButton( + symanticLabel: 'fatal_crash_state_exception', text: 'Throw StateError', key: const Key('fatal_crash_state_exception'), onPressed: () => throwUnhandledException(StateError('This is a StateError.')), ), InstabugButton( + symanticLabel: 'fatal_crash_argument_exception', text: 'Throw ArgumentError', key: const Key('fatal_crash_argument_exception'), onPressed: () => throwUnhandledException( ArgumentError('This is an ArgumentError.')), ), InstabugButton( + symanticLabel: 'fatal_crash_range_exception', text: 'Throw RangeError', key: const Key('fatal_crash_range_exception'), onPressed: () => throwUnhandledException( RangeError.range(5, 0, 3, 'Index out of range')), ), InstabugButton( + symanticLabel: 'fatal_crash_format_exception', text: 'Throw FormatException', key: const Key('fatal_crash_format_exception'), onPressed: () => throwUnhandledException(UnsupportedError('Invalid format.')), ), InstabugButton( + symanticLabel: 'fatal_crash_no_such_method_error_exception', text: 'Throw NoSuchMethodError', key: const Key('fatal_crash_no_such_method_error_exception'), onPressed: () { @@ -57,24 +63,28 @@ class FatalCrashesContent extends StatelessWidget { throwUnhandledException(obj.methodThatDoesNotExist()); }, ), - const InstabugButton( + InstabugButton( + symanticLabel: 'fatal_crash_native_exception', text: 'Throw Native Fatal Crash', key: const Key('fatal_crash_native_exception'), onPressed: InstabugFlutterExampleMethodChannel.sendNativeFatalCrash, ), - const InstabugButton( + InstabugButton( + symanticLabel: 'fatal_crash_native_hang', text: 'Send Native Fatal Hang', key: const Key('fatal_crash_native_hang'), onPressed: InstabugFlutterExampleMethodChannel.sendNativeFatalHang, ), Platform.isAndroid - ? const InstabugButton( + ? InstabugButton( + symanticLabel: 'fatal_crash_anr', text: 'Send Native ANR', key: const Key('fatal_crash_anr'), onPressed: InstabugFlutterExampleMethodChannel.sendAnr, ) : const SizedBox.shrink(), - const InstabugButton( + InstabugButton( + symanticLabel: 'fatal_crash_oom', text: 'Throw Unhandled Native OOM Exception', key: const Key('fatal_crash_oom'), onPressed: InstabugFlutterExampleMethodChannel.sendOom, diff --git a/example/lib/src/components/flows_content.dart b/example/lib/src/components/flows_content.dart index ecd8163f9..c0cbea7fe 100644 --- a/example/lib/src/components/flows_content.dart +++ b/example/lib/src/components/flows_content.dart @@ -21,6 +21,7 @@ class _FlowsContentState extends State { children: [ InstabugTextField( label: 'Flow name', + symanticLabel: 'flow_name_input', labelStyle: textTheme.labelMedium, controller: flowNameController, ), @@ -33,6 +34,7 @@ class _FlowsContentState extends State { flex: 5, child: InstabugButton.smallFontSize( text: 'Start Flow', + symanticLabel: 'start_flow', onPressed: () => _startFlow(flowNameController.text), margin: const EdgeInsetsDirectional.only( start: 20.0, @@ -44,6 +46,7 @@ class _FlowsContentState extends State { flex: 5, child: InstabugButton.smallFontSize( text: 'Start flow With Delay', + symanticLabel: 'start_flow_with_delay', onPressed: () => _startFlow( flowNameController.text, delayInMilliseconds: 5000, @@ -62,6 +65,7 @@ class _FlowsContentState extends State { flex: 5, child: InstabugTextField( label: 'Flow Key Attribute', + symanticLabel: 'flow_key_input', controller: flowKeyAttributeController, labelStyle: textTheme.labelMedium, margin: const EdgeInsetsDirectional.only( @@ -74,6 +78,7 @@ class _FlowsContentState extends State { flex: 5, child: InstabugTextField( label: 'Flow Value Attribute', + symanticLabel: 'flow_value_input', labelStyle: textTheme.labelMedium, controller: flowValueAttributeController, margin: const EdgeInsetsDirectional.only( @@ -89,6 +94,7 @@ class _FlowsContentState extends State { ), InstabugButton( text: 'Set Flow Attribute', + symanticLabel: 'set_flow_attribute', onPressed: () => _setFlowAttribute( flowNameController.text, flowKeyAttribute: flowKeyAttributeController.text, @@ -97,6 +103,7 @@ class _FlowsContentState extends State { ), InstabugButton( text: 'End Flow', + symanticLabel: 'end_flow', onPressed: () => _endFlow(flowNameController.text), ), ], diff --git a/example/lib/src/components/network_content.dart b/example/lib/src/components/network_content.dart index e5380a85c..ea432162a 100644 --- a/example/lib/src/components/network_content.dart +++ b/example/lib/src/components/network_content.dart @@ -20,24 +20,55 @@ class _NetworkContentState extends State { children: [ InstabugClipboardInput( label: 'Endpoint Url', + symanticLabel: 'endpoint_url_input', controller: endpointUrlController, ), InstabugButton( text: 'Send Request To Url', + symanticLabel: 'make_http_request', onPressed: () => _sendRequestToUrl(endpointUrlController.text), ), + InstabugButton( + text: 'Send Get Request ', + symanticLabel: 'make_get_request', + onPressed: () => _sendGetRequestToUrl('https://httpbin.org/get'), + ), + InstabugButton( + text: 'Send Post Request ', + symanticLabel: 'make_post_request', + onPressed: () => _sendPostRequestToUrl('https://httpbin.org/post'), + ), + InstabugButton( + text: 'Send put Request ', + symanticLabel: 'make_put_request', + onPressed: () => _sendPutRequestToUrl('https://httpbin.org/put'), + ), + InstabugButton( + text: 'Send delete Request ', + symanticLabel: 'make_delete_request', + onPressed: () => + _sendDeleteRequestToUrl('https://httpbin.org/delete'), + ), + InstabugButton( + text: 'Send patch Request ', + symanticLabel: 'make_patch_request', + onPressed: () => _sendPatchRequestToUrl('https://httpbin.org/patch'), + ), const Text("W3C Header Section"), InstabugButton( text: 'Send Request With Custom traceparent header', + symanticLabel: 'make_http_request_with_traceparent_header', onPressed: () => _sendRequestToUrl(endpointUrlController.text, headers: {"traceparent": "Custom traceparent header"}), ), InstabugButton( text: 'Send Request Without Custom traceparent header', + symanticLabel: 'make_http_request_with_w3c_header', onPressed: () => _sendRequestToUrl(endpointUrlController.text), ), InstabugButton( text: 'obfuscateLog', + symanticLabel: 'obfuscate_log', onPressed: () { NetworkLogger.obfuscateLog((networkData) async { return networkData.copyWith(url: 'fake url'); @@ -46,6 +77,7 @@ class _NetworkContentState extends State { ), InstabugButton( text: 'omitLog', + symanticLabel: 'omit_log', onPressed: () { NetworkLogger.omitLog((networkData) async { return networkData.url.contains('google.com'); @@ -54,6 +86,7 @@ class _NetworkContentState extends State { ), InstabugButton( text: 'obfuscateLogWithException', + symanticLabel: 'obfuscate_log_with_exception', onPressed: () { NetworkLogger.obfuscateLog((networkData) async { throw Exception("obfuscateLogWithException"); @@ -64,6 +97,7 @@ class _NetworkContentState extends State { ), InstabugButton( text: 'omitLogWithException', + symanticLabel: 'omit_log_with_exception', onPressed: () { NetworkLogger.omitLog((networkData) async { throw Exception("OmitLog with exception"); @@ -92,4 +126,92 @@ class _NetworkContentState extends State { log('Error sending request: $e'); } } + + void _sendGetRequestToUrl(String text, {Map? headers}) async { + try { + String url = text.trim().isEmpty ? widget.defaultRequestUrl : text; + final response = await http.get(Uri.parse(url), headers: headers); + + // Handle the response here + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + log(jsonEncode(jsonData)); + } else { + log('Request failed with status: ${response.statusCode}'); + } + } catch (e) { + log('Error sending request: $e'); + } + } + + void _sendPostRequestToUrl(String text, + {Map? headers}) async { + try { + String url = text.trim().isEmpty ? widget.defaultRequestUrl : text; + final response = await http.post(Uri.parse(url), headers: headers); + + // Handle the response here + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + log(jsonEncode(jsonData)); + } else { + log('Request failed with status: ${response.statusCode}'); + } + } catch (e) { + log('Error sending request: $e'); + } + } + + void _sendPutRequestToUrl(String text, {Map? headers}) async { + try { + String url = text.trim().isEmpty ? widget.defaultRequestUrl : text; + final response = await http.put(Uri.parse(url), headers: headers); + + // Handle the response here + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + log(jsonEncode(jsonData)); + } else { + log('Request failed with status: ${response.statusCode}'); + } + } catch (e) { + log('Error sending request: $e'); + } + } + + void _sendDeleteRequestToUrl(String text, + {Map? headers}) async { + try { + String url = text.trim().isEmpty ? widget.defaultRequestUrl : text; + final response = await http.delete(Uri.parse(url), headers: headers); + + // Handle the response here + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + log(jsonEncode(jsonData)); + } else { + log('Request failed with status: ${response.statusCode}'); + } + } catch (e) { + log('Error sending request: $e'); + } + } + + void _sendPatchRequestToUrl(String text, + {Map? headers}) async { + try { + String url = text.trim().isEmpty ? widget.defaultRequestUrl : text; + final response = await http.patch(Uri.parse(url), headers: headers); + + // Handle the response here + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + log(jsonEncode(jsonData)); + } else { + log('Request failed with status: ${response.statusCode}'); + } + } catch (e) { + log('Error sending request: $e'); + } + } } diff --git a/example/lib/src/components/non_fatal_crashes_content.dart b/example/lib/src/components/non_fatal_crashes_content.dart index 25e5ab790..19a6a7476 100644 --- a/example/lib/src/components/non_fatal_crashes_content.dart +++ b/example/lib/src/components/non_fatal_crashes_content.dart @@ -43,44 +43,51 @@ class _NonFatalCrashesContentState extends State { InstabugButton( text: 'Throw Exception', key: const Key('non_fatal_exception'), + symanticLabel: 'non_fatal_exception', onPressed: () => throwHandledException(Exception('This is a generic exception.')), ), InstabugButton( text: 'Throw StateError', key: const Key('non_fatal_state_exception'), + symanticLabel: 'non_fatal_state_exception', onPressed: () => throwHandledException(StateError('This is a StateError.')), ), InstabugButton( text: 'Throw ArgumentError', key: const Key('non_fatal_argument_exception'), + symanticLabel: 'non_fatal_argument_exception', onPressed: () => throwHandledException(ArgumentError('This is an ArgumentError.')), ), InstabugButton( text: 'Throw RangeError', key: const Key('non_fatal_range_exception'), + symanticLabel: 'non_fatal_range_exception', onPressed: () => throwHandledException( RangeError.range(5, 0, 3, 'Index out of range')), ), InstabugButton( text: 'Throw FormatException', key: const Key('non_fatal_format_exception'), + symanticLabel: 'non_fatal_format_exception', onPressed: () => throwHandledException(UnsupportedError('Invalid format.')), ), InstabugButton( text: 'Throw NoSuchMethodError', + symanticLabel: 'non_fatal_no_such_method_exception', key: const Key('non_fatal_no_such_method_exception'), onPressed: () { dynamic obj; throwHandledException(obj.methodThatDoesNotExist()); }, ), - const InstabugButton( + InstabugButton( text: 'Throw Handled Native Exception', - key: Key('non_fatal_native_exception'), + symanticLabel: 'non_fatal_native_exception', + key: const Key('non_fatal_native_exception'), onPressed: InstabugFlutterExampleMethodChannel.sendNativeNonFatalCrash, ), @@ -93,6 +100,7 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "Crash title", + symanticLabel: 'non_fatal_crash_title_textfield', key: const Key("non_fatal_crash_title_textfield"), controller: crashNameController, validator: (value) { @@ -108,6 +116,7 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "User Attribute key", + symanticLabel: 'non_fatal_user_attribute_key_textfield', key: const Key("non_fatal_user_attribute_key_textfield"), controller: crashUserAttributeKeyController, validator: (value) { @@ -121,7 +130,8 @@ class _NonFatalCrashesContentState extends State { )), Expanded( child: InstabugTextField( - label: "User Attribute Value", + label: "User Attribute Value", + symanticLabel: 'non_fatal_user_attribute_value_textfield', key: const Key("non_fatal_user_attribute_value_textfield"), controller: crashUserAttributeValueController, validator: (value) { @@ -140,6 +150,8 @@ class _NonFatalCrashesContentState extends State { Expanded( child: InstabugTextField( label: "Fingerprint", + symanticLabel: + 'non_fatal_user_attribute_fingerprint_textfield', key: const Key( "non_fatal_user_attribute_fingerprint_textfield"), controller: crashfingerPrintController, @@ -170,7 +182,7 @@ class _NonFatalCrashesContentState extends State { crashType = value!; }, ), - )), + ).withSemanticsLabel('non_fatal_crash_level_dropdown')), ], ), ), @@ -180,6 +192,7 @@ class _NonFatalCrashesContentState extends State { InstabugButton( text: 'Send Non Fatal Crash', onPressed: sendNonFatalCrash, + symanticLabel: 'send_non_fatal_crash', ) ], ), diff --git a/example/lib/src/components/traces_content.dart b/example/lib/src/components/traces_content.dart index 888460d43..0d6c3d105 100644 --- a/example/lib/src/components/traces_content.dart +++ b/example/lib/src/components/traces_content.dart @@ -25,6 +25,7 @@ class _TracesContentState extends State { label: 'Trace name', labelStyle: textTheme.labelMedium, controller: traceNameController, + symanticLabel: 'trace_name_input', ), SizedBox.fromSize( size: const Size.fromHeight(10.0), @@ -35,6 +36,7 @@ class _TracesContentState extends State { flex: 5, child: InstabugButton.smallFontSize( text: 'Start Trace', + symanticLabel: 'start_trace', onPressed: () => _startTrace(traceNameController.text), margin: const EdgeInsetsDirectional.only( start: 20.0, @@ -46,6 +48,7 @@ class _TracesContentState extends State { flex: 5, child: InstabugButton.smallFontSize( text: 'Start Trace With Delay', + symanticLabel: 'start_trace_with_delay', onPressed: () => _startTrace( traceNameController.text, delayInMilliseconds: 5000, @@ -64,6 +67,7 @@ class _TracesContentState extends State { flex: 5, child: InstabugTextField( label: 'Trace Key Attribute', + symanticLabel: 'trace_key_attribute_input', controller: traceKeyAttributeController, labelStyle: textTheme.labelMedium, margin: const EdgeInsetsDirectional.only( @@ -76,6 +80,7 @@ class _TracesContentState extends State { flex: 5, child: InstabugTextField( label: 'Trace Value Attribute', + symanticLabel: 'trace_value_attribute_input', labelStyle: textTheme.labelMedium, controller: traceValueAttributeController, margin: const EdgeInsetsDirectional.only( @@ -91,6 +96,7 @@ class _TracesContentState extends State { ), InstabugButton( text: 'Set Trace Attribute', + symanticLabel: 'set_trace_attribute', onPressed: () => _setTraceAttribute( trace, traceKeyAttribute: traceKeyAttributeController.text, @@ -99,6 +105,7 @@ class _TracesContentState extends State { ), InstabugButton( text: 'End Trace', + symanticLabel: 'end_trace', onPressed: () => _endTrace(), ), ], diff --git a/example/lib/src/screens/apm_page.dart b/example/lib/src/screens/apm_page.dart index 798e906fa..bc83141f2 100644 --- a/example/lib/src/screens/apm_page.dart +++ b/example/lib/src/screens/apm_page.dart @@ -32,6 +32,7 @@ class _ApmPageState extends State { const APMSwitch(), InstabugButton( text: 'End App Launch', + symanticLabel: 'end_app_launch', onPressed: _endAppLaunch, ), const SectionTitle('Network'), @@ -47,6 +48,7 @@ class _ApmPageState extends State { InstabugButton( text: 'Screen Loading', onPressed: _navigateToScreenLoading, + symanticLabel: 'end_screen_loading', ), SizedBox.fromSize( size: const Size.fromHeight(12), diff --git a/example/lib/src/screens/bug_reporting.dart b/example/lib/src/screens/bug_reporting.dart index f979dcc66..182c72470 100644 --- a/example/lib/src/screens/bug_reporting.dart +++ b/example/lib/src/screens/bug_reporting.dart @@ -24,6 +24,7 @@ class _BugReportingPageState extends State { bool attachmentsOptionsGalleryImage = true; bool attachmentsOptionsScreenRecording = true; File? fileAttachment; + CallbackHandlersProvider? callbackHandlerProvider; void restartInstabug() { Instabug.setEnabled(false); @@ -35,11 +36,18 @@ class _BugReportingPageState extends State { BugReporting.setInvocationEvents([invocationEvent]); } - void setUserConsent(String key, - String description, - bool mandatory, - bool checked, - UserConsentActionType? actionType,) { + @override + void initState() { + super.initState(); + } + + void setUserConsent( + String key, + String description, + bool mandatory, + bool checked, + UserConsentActionType? actionType, + ) { BugReporting.addUserConsents( key: key, description: description, @@ -57,17 +65,14 @@ class _BugReportingPageState extends State { if (result != null) { fileAttachment = File(result.files.single.path!); - Instabug.addFileAttachmentWithURL(fileAttachment!.path, fileAttachment!.path - .split('/') - .last.substring(0)); - setState(() { - - }); + Instabug.addFileAttachmentWithURL(fileAttachment!.path, + fileAttachment!.path.split('/').last.substring(0)); + setState(() {}); } } void removeFileAttachment() { - Instabug.clearFileAttachments(); + Instabug.clearFileAttachments(); } void addAttachmentOptions() { @@ -103,55 +108,22 @@ class _BugReportingPageState extends State { if (dismissType == DismissType.submit) { showDialog( context: context, - builder: (_) => - const AlertDialog( - title: Text('Bug Reporting sent'), - )); + builder: (_) => const AlertDialog( + title: Text('Bug Reporting sent'), + )); } }); } - void setOnDismissCallback() { + void setOnDismissCallback(void Function(DismissType, ReportType) callback) { BugReporting.setOnDismissCallback((dismissType, reportType) { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('On Dismiss'), - content: Text( - 'onDismiss callback called with $dismissType and $reportType', - ), - ); - }, - ); + callback(dismissType, reportType); }); } - void setOnDismissCallbackWithException() { - BugReporting.setOnDismissCallback((dismissType, reportType) { - throw Exception("Test crash from dismiss callback"); - }); - } - - void setOnInvokeCallbackWithException() { - BugReporting.setOnInvokeCallback(() { - throw Exception("Test crash from invoke callback"); - }); - } - - void setOnInvoiceCallback() { + void setOnInvoiceCallback(VoidCallback callback) { BugReporting.setOnInvokeCallback(() { - showDialog( - context: context, - builder: (context) { - return const AlertDialog( - title: Text('On Invoke'), - content: Text( - 'onInvoke callback called', - ), - ); - }, - ); + callback.call(); }); } @@ -168,26 +140,32 @@ class _BugReportingPageState extends State { @override Widget build(BuildContext context) { + callbackHandlerProvider = context.read(); + return Page( title: 'Bug Reporting', children: [ const SectionTitle('Enabling Bug Reporting'), InstabugButton( + symanticLabel: 'id_restart_instabug_btn', key: const Key('instabug_restart'), onPressed: restartInstabug, text: 'Restart Instabug', ), InstabugButton( + symanticLabel: 'id_disable_instabug_btn', key: const Key('instabug_disable'), onPressed: () => Instabug.setEnabled(false), text: "Disable Instabug", ), InstabugButton( + symanticLabel: 'id_enable_instabug_btn', key: const Key('instabug_enable'), onPressed: () => Instabug.setEnabled(true), text: "Enable Instabug", ), InstabugButton( + symanticLabel: 'id_enable_instabug_btn', key: const Key('instabug_post_sending_dialog'), onPressed: () => {showDialogOnInvoke(context)}, text: "Set the post sending dialog", @@ -201,17 +179,17 @@ class _BugReportingPageState extends State { key: const Key('invocation_event_none'), onPressed: () => setInvocationEvent(InvocationEvent.none), child: const Text('None'), - ), + ).withSemanticsLabel('invocation_event_none'), ElevatedButton( key: const Key('invocation_event_shake'), onPressed: () => setInvocationEvent(InvocationEvent.shake), child: const Text('Shake'), - ), + ).withSemanticsLabel('invocation_event_shake'), ElevatedButton( key: const Key('invocation_event_screenshot'), onPressed: () => setInvocationEvent(InvocationEvent.screenshot), child: const Text('Screenshot'), - ), + ).withSemanticsLabel('invocation_event_screenshot'), ], ), ButtonBar( @@ -223,13 +201,13 @@ class _BugReportingPageState extends State { onPressed: () => setInvocationEvent(InvocationEvent.floatingButton), child: const Text('Floating Button'), - ), + ).withSemanticsLabel('invocation_event_floating'), ElevatedButton( key: const Key('invocation_event_two_fingers'), onPressed: () => setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), child: const Text('Two Fingers Swipe Left'), - ), + ).withSemanticsLabel('invocation_event_two_fingers'), ], ), const SectionTitle('User Consent'), @@ -240,26 +218,24 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('user_consent_media_manadatory'), - onPressed: () => - setUserConsent( - 'media_mandatory', - "Mandatory for Media", - true, - true, - UserConsentActionType.dropAutoCapturedMedia), + onPressed: () => setUserConsent( + 'media_mandatory', + "Mandatory for Media", + true, + true, + UserConsentActionType.dropAutoCapturedMedia), child: const Text('Drop Media Mandatory'), - ), + ).withSemanticsLabel('user_consent_media_manadatory'), ElevatedButton( key: const Key('user_consent_no_chat_manadatory'), - onPressed: () => - setUserConsent( - 'noChat_mandatory', - "Mandatory for No Chat", - true, - true, - UserConsentActionType.noChat), + onPressed: () => setUserConsent( + 'noChat_mandatory', + "Mandatory for No Chat", + true, + true, + UserConsentActionType.noChat), child: const Text('No Chat Mandatory'), - ), + ).withSemanticsLabel('user_consent_no_chat_manadatory'), ], ), ButtonBar( @@ -269,26 +245,24 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('user_consent_drop_logs_manadatory'), - onPressed: () => - setUserConsent( - 'dropLogs_mandatory', - "Mandatory for Drop logs", - true, - true, - UserConsentActionType.dropLogs), + onPressed: () => setUserConsent( + 'dropLogs_mandatory', + "Mandatory for Drop logs", + true, + true, + UserConsentActionType.dropLogs), child: const Text('Drop logs Mandatory'), - ), + ).withSemanticsLabel('user_consent_drop_logs_manadatory'), ElevatedButton( key: const Key('user_consent_no_chat_optional'), - onPressed: () => - setUserConsent( - 'noChat_mandatory', - "Optional for No Chat", - false, - true, - UserConsentActionType.noChat), + onPressed: () => setUserConsent( + 'noChat_mandatory', + "Optional for No Chat", + false, + true, + UserConsentActionType.noChat), child: const Text('No Chat optional'), - ), + ).withSemanticsLabel('user_consent_no_chat_optional'), ], ), const SectionTitle('Invocation Options'), @@ -298,17 +272,17 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('invocation_option_disable_post_sending_dialog'), - onPressed: () => - addInvocationOption( - InvocationOption.disablePostSendingDialog), + onPressed: () => addInvocationOption( + InvocationOption.disablePostSendingDialog), child: const Text('disablePostSendingDialog'), - ), + ).withSemanticsLabel( + 'invocation_option_disable_post_sending_dialog'), ElevatedButton( key: const Key('invocation_option_email_hidden'), onPressed: () => addInvocationOption(InvocationOption.emailFieldHidden), child: const Text('emailFieldHidden'), - ), + ).withSemanticsLabel('invocation_option_email_hidden'), ], ), ButtonBar( @@ -320,17 +294,18 @@ class _BugReportingPageState extends State { onPressed: () => addInvocationOption(InvocationOption.commentFieldRequired), child: const Text('commentFieldRequired'), - ), + ).withSemanticsLabel('invocation_option_comment_required'), ElevatedButton( onPressed: () => addInvocationOption(InvocationOption.emailFieldOptional), child: const Text('emailFieldOptional'), - ), + ).withSemanticsLabel('invocation_option_email_required'), ], ), InstabugButton( key: const Key('instabug_show'), onPressed: show, + symanticLabel: 'instabug_show', text: 'Invoke', ), const SectionTitle('Attachment Options'), @@ -349,7 +324,7 @@ class _BugReportingPageState extends State { title: const Text("Screenshot"), subtitle: const Text('Enable attachment for screenShot'), key: const Key('attachment_option_screenshot'), - ), + ).withSemanticsLabel('attachment_option_screenshot'), CheckboxListTile( value: attachmentsOptionsExtraScreenshot, onChanged: (value) { @@ -361,7 +336,7 @@ class _BugReportingPageState extends State { title: const Text("Extra Screenshot"), subtitle: const Text('Enable attachment for extra screenShot'), key: const Key('attachment_option_extra_screenshot'), - ), + ).withSemanticsLabel('attachment_option_extra_screenshot'), CheckboxListTile( value: attachmentsOptionsGalleryImage, onChanged: (value) { @@ -373,7 +348,7 @@ class _BugReportingPageState extends State { title: const Text("Gallery"), subtitle: const Text('Enable attachment for gallery'), key: const Key('attachment_option_gallery'), - ), + ).withSemanticsLabel('attachment_option_gallery'), CheckboxListTile( value: attachmentsOptionsScreenRecording, onChanged: (value) { @@ -385,7 +360,7 @@ class _BugReportingPageState extends State { title: const Text("Screen Recording"), subtitle: const Text('Enable attachment for screen Recording'), key: const Key('attachment_option_screen_recording'), - ), + ).withSemanticsLabel('attachment_option_screen_recording'), ], ), const SectionTitle('Bug reporting type'), @@ -401,7 +376,7 @@ class _BugReportingPageState extends State { : null), onPressed: () => toggleReportType(ReportType.bug), child: const Text('Bug'), - ), + ).withSemanticsLabel('bug_report_type_bug'), ElevatedButton( key: const Key('bug_report_type_feedback'), onPressed: () => toggleReportType(ReportType.feedback), @@ -410,7 +385,7 @@ class _BugReportingPageState extends State { ? Colors.grey.shade400 : null), child: const Text('Feedback'), - ), + ).withSemanticsLabel('bug_report_type_feedback'), ElevatedButton( key: const Key('bug_report_type_question'), onPressed: () => toggleReportType(ReportType.question), @@ -419,48 +394,42 @@ class _BugReportingPageState extends State { ? Colors.grey.shade400 : null), child: const Text('Question'), - ), + ).withSemanticsLabel('bug_report_type_question'), ], - + ), CheckboxListTile( value: reportTypes.contains(ReportType.bug), onChanged: (value) { toggleReportType(ReportType.bug); - setState(() { - }); + setState(() {}); }, title: const Text("Bug"), subtitle: const Text('Enable Bug reporting type'), key: const Key('bug_report_type_bug'), - - ), + ).withSemanticsLabel('bug_report_type_question'), CheckboxListTile( value: reportTypes.contains(ReportType.feedback), onChanged: (value) { toggleReportType(ReportType.feedback); - setState(() { - }); + setState(() {}); }, title: const Text("Feedback"), subtitle: const Text('Enable Feedback reporting type'), key: const Key('bug_report_type_feedback'), - - ), - + ).withSemanticsLabel('bug_report_type_question'), CheckboxListTile( value: reportTypes.contains(ReportType.question), onChanged: (value) { toggleReportType(ReportType.question); - setState(() { - }); + setState(() {}); }, title: const Text("Question"), subtitle: const Text('Enable Question reporting type'), key: const Key('bug_report_type_question'), - ), + ).withSemanticsLabel('bug_report_type_question'), InstabugButton( - onPressed: () => - { + symanticLabel: 'id_send_bug', + onPressed: () => { BugReporting.show( ReportType.bug, [InvocationOption.emailFieldOptional]) }, @@ -471,12 +440,13 @@ class _BugReportingPageState extends State { key: const Key('disclaimer_text'), controller: disclaimerTextController, label: 'Enter disclaimer Text', + symanticLabel: 'id_disclaimer_input', ), ElevatedButton( key: const Key('set_disclaimer_text'), onPressed: () => setDisclaimerText, child: const Text('set disclaimer text'), - ), + ).withSemanticsLabel('set_disclaimer_text'), const SectionTitle('Extended Bug Reporting'), ButtonBar( mainAxisSize: MainAxisSize.min, @@ -484,19 +454,18 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: const Key('extended_bug_report_mode_disabled'), - onPressed: () => - BugReporting.setExtendedBugReportMode( - ExtendedBugReportMode.disabled), + onPressed: () => BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.disabled), child: const Text('disabled'), - ), + ).withSemanticsLabel('extended_bug_report_mode_disabled'), ElevatedButton( key: - const Key('extended_bug_report_mode_required_fields_enabled'), - onPressed: () => - BugReporting.setExtendedBugReportMode( - ExtendedBugReportMode.enabledWithRequiredFields), + const Key('extended_bug_report_mode_required_fields_enabled'), + onPressed: () => BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.enabledWithRequiredFields), child: const Text('enabledWithRequiredFields'), - ), + ).withSemanticsLabel( + 'extended_bug_report_mode_required_fields_enabled'), ], ), ButtonBar( @@ -505,42 +474,124 @@ class _BugReportingPageState extends State { children: [ ElevatedButton( key: - const Key('extended_bug_report_mode_optional_fields_enabled'), - onPressed: () => - BugReporting.setExtendedBugReportMode( - ExtendedBugReportMode.enabledWithOptionalFields), + const Key('extended_bug_report_mode_optional_fields_enabled'), + onPressed: () => BugReporting.setExtendedBugReportMode( + ExtendedBugReportMode.enabledWithOptionalFields), child: const Text('enabledWithOptionalFields'), - ), + ).withSemanticsLabel( + 'extended_bug_report_mode_optional_fields_enabled'), ], ), const SectionTitle('Set Callback After Discarding'), InstabugButton( - onPressed: setOnDismissCallback, - text: 'Set On Dismiss Callback', + symanticLabel: 'enable_onDismiss_callback', + onPressed: () { + setOnDismissCallback((dismissType, reportType) { + callbackHandlerProvider?.addItem( + 'On Dismiss Handler', + Item(id: 'event - ${math.Random().nextInt(99999)}', fields: [ + KeyValuePair( + key: 'Date', value: DateTime.now().toIso8601String()) + ])); + + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('On Dismiss'), + content: Text( + 'onDismiss callback called with $dismissType and $reportType', + ), + ); + }, + ); + }); + }, + text: 'Enable Set On Dismiss Callback', ), InstabugButton( - onPressed: setOnInvoiceCallback, - text: 'Set On Invoice Callback', + symanticLabel: 'disable_onDismiss_callback', + onPressed: () { + setOnDismissCallback((dismissType, reportType) {}); + }, + text: 'Disable Set On Dismiss Callback', ), InstabugButton( - onPressed: setOnDismissCallbackWithException, + symanticLabel: 'crash_onDismiss_callback', + onPressed: () { + setOnDismissCallback((dismissType, reportType) { + callbackHandlerProvider?.addItem( + 'On Dismiss Handler', + Item(id: 'event - ${math.Random().nextInt(99999)}', fields: [ + KeyValuePair( + key: 'Date', value: DateTime.now().toIso8601String()) + ])); + throw Exception("Exception from setOnDismissCallback"); + }); + }, text: 'Set On Dismiss Callback with Exception', ), InstabugButton( - onPressed: setOnInvokeCallbackWithException, - text: 'Set On Invoice Callback with Exception', + symanticLabel: 'disable_onInvoice_callback', + onPressed: () { + setOnInvoiceCallback(() { + callbackHandlerProvider?.addItem( + 'Invoke Handler', + Item(id: 'event - ${math.Random().nextInt(99999)}', fields: [ + KeyValuePair( + key: 'Date', value: DateTime.now().toIso8601String()) + ])); + + showDialog( + context: context, + builder: (context) { + return const AlertDialog( + title: Text('On Invoice Callback'), + content: Text( + 'setOnInvoice callback called', + ), + ); + }, + ); + }); + }, + text: 'Set On Invoice Callback', + ), + InstabugButton( + onPressed: () { + setOnInvoiceCallback(() {}); + }, + text: 'Disable On Invoice Callback', + ), + InstabugButton( + symanticLabel: 'crash_onInvoice_callback', + onPressed: () { + setOnInvoiceCallback(() { + callbackHandlerProvider?.addItem( + 'Invoke Handler', + Item( + id: 'event - ${math.Random().nextInt(99999)}', + fields: [ + KeyValuePair( + key: 'Date', + value: DateTime.now().toIso8601String()) + ])); + throw Exception("Exception from setOnInvoiceCallback"); + }); + }, + text: 'Set On Invoice Callback with Exception'), const SectionTitle('Attachments'), - if(fileAttachment!=null) - Text(fileAttachment!.path - .split('/') - .last.substring(0) +" Attached"), + if (fileAttachment != null) + Text(fileAttachment!.path.split('/').last.substring(0) + " Attached"), InstabugButton( onPressed: addFileAttachment, text: 'Add file attachment', + symanticLabel: 'add_file_attachment', ), InstabugButton( onPressed: removeFileAttachment, text: 'Clear All attachment', + symanticLabel: 'clear_file_attachment', ), ], // This trailing comma makes auto-formatting nicer for build methods. ); diff --git a/example/lib/src/screens/callback/callback_handler_provider.dart b/example/lib/src/screens/callback/callback_handler_provider.dart new file mode 100644 index 000000000..59a06468e --- /dev/null +++ b/example/lib/src/screens/callback/callback_handler_provider.dart @@ -0,0 +1,32 @@ +import 'package:flutter/foundation.dart'; + +class KeyValuePair { + final String key; + final String value; + + KeyValuePair({required this.key, required this.value}); +} + +class Item { + final String id; + final List fields; + + Item({required this.id, required this.fields}); +} + +class CallbackHandlersProvider extends ChangeNotifier { + final Map> _callbackHandlers = {}; + + Map> get callbackHandlers => _callbackHandlers; + + void clearList(String title) { + _callbackHandlers[title] = []; + notifyListeners(); + } + + void addItem(String title, Item item) { + final existingList = _callbackHandlers[title] ?? []; + _callbackHandlers[title] = [...existingList, item]; + notifyListeners(); + } +} diff --git a/example/lib/src/screens/callback/callback_page.dart b/example/lib/src/screens/callback/callback_page.dart new file mode 100644 index 000000000..d0ff5bdb6 --- /dev/null +++ b/example/lib/src/screens/callback/callback_page.dart @@ -0,0 +1,110 @@ +// callback_screen.dart +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'callback_handler_provider.dart'; + +class CallbackScreen extends StatelessWidget { + static var screenName = "/callback"; + + const CallbackScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final handlers = context.watch().callbackHandlers; + final titles = handlers.keys.toList(); + + return DefaultTabController( + length: titles.isEmpty ? 1 : titles.length, + child: Scaffold( + appBar: AppBar( + title: const Text("Callback Handlers"), + bottom: TabBar( + isScrollable: true, + tabs: titles.isEmpty + ? [const Tab(text: "No Data")] + : titles.map((t) => Tab(text: t)).toList(), + ), + ), + body: TabBarView( + children: titles.isEmpty + ? [ + const Center(child: Text("No callback handlers yet")), + ] + : titles.map((title) { + return CallBackTabScreen(title: title); + }).toList(), + ), + ), + ); + } +} + +class CallBackTabScreen extends StatelessWidget { + final String title; + const CallBackTabScreen({Key? key, required this.title}) : super(key: key); + + @override + Widget build(BuildContext context) { + final provider = context.watch(); + final items = provider.callbackHandlers[title] ?? []; + + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("Items: ${items.length}", + style: const TextStyle(fontWeight: FontWeight.bold)), + ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), + onPressed: () => provider.clearList(title), + child: const Text("Clear Data", + style: TextStyle(color: Colors.white)), + ), + ], + ), + const SizedBox(height: 10), + Expanded( + child: items.isEmpty + ? const Center(child: Text("No items")) + : ListView.builder( + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return Card( + margin: const EdgeInsets.only(bottom: 8), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: item.fields.map((field) { + return Padding( + padding: + const EdgeInsets.symmetric(vertical: 2), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text(field.key, + style: const TextStyle( + fontWeight: FontWeight.bold)), + Text(field.value, + style: const TextStyle( + color: Colors.grey)), + ], + ), + ); + }).toList(), + ), + ), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/example/lib/src/screens/complex_page.dart b/example/lib/src/screens/complex_page.dart index 65fdd8a57..059f9b7a6 100644 --- a/example/lib/src/screens/complex_page.dart +++ b/example/lib/src/screens/complex_page.dart @@ -75,11 +75,13 @@ class _ComplexPageState extends State { label: 'Depth (default: ${ComplexPage.initialDepth})', labelStyle: textTheme.labelMedium, controller: depthController, + symanticLabel: 'depth_input', ), InstabugTextField( label: 'Breadth (default: ${ComplexPage.initialBreadth})', labelStyle: textTheme.labelMedium, controller: breadthController, + symanticLabel: 'breadth_input', ), InstabugButton( onPressed: _handleRender, @@ -93,22 +95,27 @@ class _ComplexPageState extends State { InstabugButton( onPressed: _enableScreenLoading, text: 'Enable Screen loading', + symanticLabel: 'enable_screen_loading', ), InstabugButton( onPressed: _disableScreenLoading, text: 'Disable Screen Loading', + symanticLabel: 'disable_screen_loading', ), InstabugButton( onPressed: _resetDidStartScreenLoading, text: 'Reset Did Start Screen Loading', + symanticLabel: 'reset_start_screen_loading', ), InstabugButton( onPressed: _resetDidReportScreenLoading, text: 'Reset Did Report Screen Loading', + symanticLabel: 'reset_report_screen_loading', ), InstabugButton( onPressed: _resetDidExtendScreenLoading, text: 'Reset Did Extend Screen Loading', + symanticLabel: 'reset_extend_screen_loading', ), SingleChildScrollView( scrollDirection: Axis.horizontal, diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 29e2f66d7..188bad169 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -169,6 +169,16 @@ class _MyHomePageState extends State { ); } + void _navigateToCallbackHandler() { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const CallbackScreen(), + settings: RouteSettings(name: CallbackScreen.screenName), + ), + ); + } + void _navigateToSessionReplay() { Navigator.push( context, @@ -197,19 +207,28 @@ class _MyHomePageState extends State { InstabugButton( onPressed: restartInstabug, text: 'Restart Instabug', + symanticLabel: 'restart_page', ), InstabugButton( onPressed: _navigateToBugs, text: 'Bug Reporting', + symanticLabel: 'open_bug_reporting', + ), + InstabugButton( + onPressed: _navigateToCallbackHandler, + text: 'Callback Page', + symanticLabel: 'open_callback_page', ), const SectionTitle('Primary Color'), InstabugTextField( controller: primaryColorController, label: 'Enter primary color', + symanticLabel: 'primary_color_input', ), InstabugButton( text: 'Change Primary Color', onPressed: changePrimaryColor, + symanticLabel: 'set_primary_color', ), const SectionTitle('Change Invocation Event'), ButtonBar( @@ -220,17 +239,17 @@ class _MyHomePageState extends State { onPressed: () => setInvocationEvent(InvocationEvent.none), style: buttonStyle, child: const Text('None'), - ), + ).withSemanticsLabel('invocation_event_none'), ElevatedButton( onPressed: () => setInvocationEvent(InvocationEvent.shake), style: buttonStyle, child: const Text('Shake'), - ), + ).withSemanticsLabel('invocation_event_shake'), ElevatedButton( onPressed: () => setInvocationEvent(InvocationEvent.screenshot), style: buttonStyle, child: const Text('Screenshot'), - ), + ).withSemanticsLabel('invocation_event_screenshot'), ], ), ButtonBar( @@ -242,13 +261,13 @@ class _MyHomePageState extends State { setInvocationEvent(InvocationEvent.floatingButton), style: buttonStyle, child: const Text('Floating Button'), - ), + ).withSemanticsLabel('invocation_event_floating_button'), ElevatedButton( onPressed: () => setInvocationEvent(InvocationEvent.twoFingersSwipeLeft), style: buttonStyle, child: const Text('Two Fingers Swipe Left'), - ), + ).withSemanticsLabel('invocation_event_two_fingers'), ], ), InstabugButton( @@ -263,18 +282,22 @@ class _MyHomePageState extends State { InstabugTextField( controller: screenNameController, label: 'Enter screen name', + symanticLabel: 'screen_name_input', ), InstabugButton( text: 'Report Screen Change', onPressed: reportScreenChange, + symanticLabel: 'set_screen_name', ), InstabugButton( onPressed: sendBugReport, text: 'Send Bug Report', + symanticLabel: 'send_bug_report', ), InstabugButton( onPressed: showManualSurvey, text: 'Show Manual Survey', + symanticLabel: 'show_manual_survery', ), const SectionTitle('Change Report Types'), ButtonBar( @@ -285,59 +308,69 @@ class _MyHomePageState extends State { onPressed: () => toggleReportType(ReportType.bug), style: buttonStyle, child: const Text('Bug'), - ), + ).withSemanticsLabel('bug_report_type_bug'), ElevatedButton( onPressed: () => toggleReportType(ReportType.feedback), style: buttonStyle, child: const Text('Feedback'), - ), + ).withSemanticsLabel('bug_report_type_feedback'), ElevatedButton( onPressed: () => toggleReportType(ReportType.question), style: buttonStyle, child: const Text('Question'), - ), + ).withSemanticsLabel('bug_report_type_question'), ], ), InstabugButton( onPressed: changeFloatingButtonEdge, text: 'Move Floating Button to Left', + symanticLabel: 'move_floating_button_to_left', ), InstabugButton( onPressed: sendFeedback, text: 'Send Feedback', + symanticLabel: 'sending_feedback', ), InstabugButton( onPressed: showNpsSurvey, text: 'Show NPS Survey', + symanticLabel: 'show_nps_survey', ), InstabugButton( onPressed: showManualSurvey, text: 'Show Multiple Questions Survey', + symanticLabel: 'show_multi_question_survey', ), InstabugButton( onPressed: showFeatureRequests, text: 'Show Feature Requests', + symanticLabel: 'show_feature_requests', ), InstabugButton( onPressed: _navigateToCrashes, text: 'Crashes', + symanticLabel: 'open_crash_page', ), InstabugButton( onPressed: _navigateToApm, text: 'APM', + symanticLabel: 'open_apm_page', ), InstabugButton( onPressed: _navigateToComplex, text: 'Complex', + symanticLabel: 'open_complex_page', ), InstabugButton( onPressed: _navigateToSessionReplay, text: 'Session Replay', + symanticLabel: 'open_session_replay_page', ), const SectionTitle('Sessions Replay'), InstabugButton( onPressed: getCurrentSessionReplaylink, text: 'Get current session replay link', + symanticLabel: 'get_current_session_replay_link', ), const SectionTitle('Color Theme'), ButtonBar( @@ -347,37 +380,41 @@ class _MyHomePageState extends State { ElevatedButton( onPressed: () => setColorTheme(ColorTheme.light), style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(Colors.white), - foregroundColor: MaterialStateProperty.all(Colors.lightBlue), + backgroundColor: WidgetStateProperty.all(Colors.white), + foregroundColor: WidgetStateProperty.all(Colors.lightBlue), ), - child: const Text('Light'), - ), + child: const Text('set_color_theme_light'), + ).withSemanticsLabel(''), ElevatedButton( onPressed: () => setColorTheme(ColorTheme.dark), style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(Colors.black), - foregroundColor: MaterialStateProperty.all(Colors.white), + backgroundColor: WidgetStateProperty.all(Colors.black), + foregroundColor: WidgetStateProperty.all(Colors.white), ), - child: const Text('Dark'), - ), + child: const Text('set_color_theme_dark'), + ).withSemanticsLabel(''), ], ), const SectionTitle('FeatureFlags'), InstabugTextField( controller: featureFlagsController, label: 'Feature Flag name', + symanticLabel: 'feature_flag_name_input', ), InstabugButton( onPressed: () => setFeatureFlag(), text: 'SetFeatureFlag', + symanticLabel: 'set_feature_flag', ), InstabugButton( onPressed: () => removeFeatureFlag(), text: 'RemoveFeatureFlag', + symanticLabel: 'remove_feature_flag', ), InstabugButton( onPressed: () => removeAllFeatureFlags(), text: 'RemoveAllFeatureFlags', + symanticLabel: 'remove_all_feature_flags', ), const SectionTitle('Set User Attribute'), Form( @@ -389,6 +426,7 @@ class _MyHomePageState extends State { Expanded( child: InstabugTextField( label: "User Attribute key", + symanticLabel: 'user_attribute_key_input', key: const Key("user_attribute_key_textfield"), controller: userAttributeKeyController, validator: (value) { @@ -399,6 +437,7 @@ class _MyHomePageState extends State { Expanded( child: InstabugTextField( label: "User Attribute Value", + symanticLabel: 'user_attribute_value_input', key: const Key("user_attribute_value_textfield"), controller: userAttributeValueController, validator: (value) { @@ -414,6 +453,7 @@ class _MyHomePageState extends State { ), InstabugButton( text: 'Set User attribute', + symanticLabel: 'set_user_attribute', key: const Key('set_user_data_btn'), onPressed: () { if (_formUserAttributeKey.currentState?.validate() == true) { @@ -424,6 +464,7 @@ class _MyHomePageState extends State { ), InstabugButton( text: 'remove User attribute', + symanticLabel: 'remove_user_attribute', key: const Key('remove_user_data_btn'), onPressed: () { if (_formUserAttributeKey.currentState?.validate() == true) { @@ -442,6 +483,7 @@ class _MyHomePageState extends State { children: [ Expanded( child: InstabugButton( + symanticLabel: 'log_hello_debug', margin: const EdgeInsets.symmetric(horizontal: 2), key: const ValueKey('log_hello_debug_btn'), onPressed: () { @@ -452,6 +494,7 @@ class _MyHomePageState extends State { ), Expanded( child: InstabugButton( + symanticLabel: 'log_hello_error', margin: const EdgeInsets.symmetric(horizontal: 2), key: const ValueKey('log_hello_error_btn'), onPressed: () { @@ -462,6 +505,7 @@ class _MyHomePageState extends State { ), Expanded( child: InstabugButton( + symanticLabel: 'log_hello_warning', margin: const EdgeInsets.symmetric(horizontal: 2), key: const ValueKey('hello_warning_btn'), onPressed: () { @@ -479,6 +523,7 @@ class _MyHomePageState extends State { children: [ Expanded( child: InstabugButton( + symanticLabel: 'log_hello_info_btn', margin: const EdgeInsets.symmetric(horizontal: 2), key: const ValueKey('log_hello_info_btn'), onPressed: () { @@ -489,6 +534,7 @@ class _MyHomePageState extends State { ), Expanded( child: InstabugButton( + symanticLabel: 'log_hello_verbose_btn', margin: const EdgeInsets.symmetric(horizontal: 2), key: const ValueKey('log_hello_verbose_btn'), onPressed: () { @@ -499,6 +545,7 @@ class _MyHomePageState extends State { ), Expanded( child: InstabugButton( + symanticLabel: 'clear_logs', margin: const EdgeInsets.symmetric(horizontal: 2), key: const ValueKey('clear_logs_btn'), onPressed: () { diff --git a/example/lib/src/screens/screen_loading_page.dart b/example/lib/src/screens/screen_loading_page.dart index a2b49e681..cf589dd0f 100644 --- a/example/lib/src/screens/screen_loading_page.dart +++ b/example/lib/src/screens/screen_loading_page.dart @@ -132,6 +132,7 @@ class _ScreenLoadingPageState extends State { label: 'Duration', controller: durationController, keyboardType: TextInputType.number, + symanticLabel: 'duration_input', ), Container( margin: const EdgeInsets.only(top: 12), @@ -142,20 +143,24 @@ class _ScreenLoadingPageState extends State { InstabugButton( text: 'Extend Screen Loading (Testing)', onPressed: _extendScreenLoadingTestingEnvironment, + symanticLabel: 'extend_screen_loading_testing', ), InstabugButton( text: 'Extend Screen Loading (Production)', onPressed: _extendScreenLoading, + symanticLabel: 'extend_screen_loading_production', ), ], )), InstabugButton( text: 'Monitored Complex Page', onPressed: _navigateToComplexPage, + symanticLabel: 'monitored_complex_page', ), InstabugButton( text: 'Screen Capture Premature Extension Page', onPressed: _navigateToMonitoredScreenCapturePrematureExtensionPage, + symanticLabel: 'screen_capture_premature_extension_page', ), SectionTitle('Dynamic Screen Loading list'), SizedBox( diff --git a/example/lib/src/screens/session_replay_page.dart b/example/lib/src/screens/session_replay_page.dart index 34d0d6d71..534c41fd6 100644 --- a/example/lib/src/screens/session_replay_page.dart +++ b/example/lib/src/screens/session_replay_page.dart @@ -18,44 +18,52 @@ class _SessionReplayPageState extends State { key: const Key('instabug_sesssion_replay_disable'), onPressed: () => SessionReplay.setEnabled(false), text: "Disable Session Replay", + symanticLabel: 'instabug_sesssion_replay_disable', ), InstabugButton( key: const Key('instabug_sesssion_replay_enable'), onPressed: () => SessionReplay.setEnabled(true), text: "Enable Session Replay", + symanticLabel: 'instabug_sesssion_replay_enable', ), const SectionTitle('Enabling Session Replay Network'), InstabugButton( key: const Key('instabug_sesssion_replay_network_disable'), onPressed: () => SessionReplay.setNetworkLogsEnabled(false), text: "Disable Session Replay Network", + symanticLabel: 'instabug_sesssion_replay_network_disable', ), InstabugButton( key: const Key('instabug_sesssion_replay_network_enable'), onPressed: () => SessionReplay.setNetworkLogsEnabled(true), text: "Enable Session Replay Network", + symanticLabel: 'instabug_sesssion_replay_network_enable', ), const SectionTitle('Enabling Session Replay User Steps'), InstabugButton( key: const Key('instabug_sesssion_replay_user_steps_disable'), onPressed: () => SessionReplay.setUserStepsEnabled(false), text: "Disable Session Replay User Steps", + symanticLabel: 'instabug_sesssion_replay_user_steps_disable', ), InstabugButton( key: const Key('instabug_sesssion_replay_user_steps_enable'), onPressed: () => SessionReplay.setUserStepsEnabled(true), text: "Enable Session Replay User Steps", + symanticLabel: 'instabug_sesssion_replay_user_steps_enable', ), const SectionTitle('Enabling Session Replay Logs'), InstabugButton( key: const Key('instabug_sesssion_replay_logs_disable'), onPressed: () => SessionReplay.setInstabugLogsEnabled(false), text: "Disable Session Replay Logs", + symanticLabel: 'instabug_sesssion_replay_logs_disable', ), InstabugButton( key: const Key('instabug_sesssion_replay_logs_enable'), onPressed: () => SessionReplay.setInstabugLogsEnabled(true), text: "Enable Session Replay Logs", + symanticLabel: 'instabug_sesssion_replay_logs_enable', ), const SectionTitle('Enabling Session Replay Repro steps'), InstabugButton( @@ -63,17 +71,20 @@ class _SessionReplayPageState extends State { onPressed: () => Instabug.setReproStepsConfig( sessionReplay: ReproStepsMode.disabled), text: "Disable Session Replay Repro steps", + symanticLabel: 'instabug_sesssion_replay_repro_steps_disable', ), InstabugButton( key: const Key('instabug_sesssion_replay_repro_steps_enable'), onPressed: () => Instabug.setReproStepsConfig(sessionReplay: ReproStepsMode.enabled), text: "Enable Session Replay Repro steps", + symanticLabel: 'instabug_sesssion_replay_repro_steps_enable', ), InstabugButton( key: const Key('instabug_sesssion_replay_tab_screen'), onPressed: () => Navigator.of(context).pushNamed(TopTabBarScreen.route), text: 'Open Tab Screen', + symanticLabel: 'instabug_sesssion_replay_tab_screen', ), ]); } diff --git a/example/lib/src/utils/widget_ext.dart b/example/lib/src/utils/widget_ext.dart new file mode 100644 index 000000000..504c9bcb2 --- /dev/null +++ b/example/lib/src/utils/widget_ext.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +extension WidgetExt on Widget { + Widget withSemanticsLabel(String label) { + return Semantics( + label: label, + child: this, + ); + } +} diff --git a/example/lib/src/widget/instabug_button.dart b/example/lib/src/widget/instabug_button.dart index 5bdb31eef..32477b1a7 100644 --- a/example/lib/src/widget/instabug_button.dart +++ b/example/lib/src/widget/instabug_button.dart @@ -1,23 +1,27 @@ import 'package:flutter/material.dart'; class InstabugButton extends StatelessWidget { - const InstabugButton({ - Key? key, - required this.text, - this.onPressed, - this.fontSize, - this.margin, - this.backgroundColor, - }) : super(key: key); + InstabugButton( + {Key? key, + required this.text, + this.onPressed, + this.fontSize, + this.margin, + this.backgroundColor, + this.symanticLabel}) + : super( + key: + key ?? (symanticLabel != null ? ValueKey(symanticLabel) : key)); - const InstabugButton.smallFontSize({ - Key? key, - required this.text, - this.onPressed, - this.fontSize = 10.0, - this.margin, - this.backgroundColor, - }) : super(key: key); + const InstabugButton.smallFontSize( + {Key? key, + required this.text, + this.onPressed, + this.fontSize = 10.0, + this.margin, + this.backgroundColor, + this.symanticLabel}) + : super(key: key); final String text; final Function()? onPressed; @@ -25,6 +29,8 @@ class InstabugButton extends StatelessWidget { final Color? backgroundColor; final EdgeInsetsGeometry? margin; + final String? symanticLabel; + @override Widget build(BuildContext context) { return Container( @@ -33,17 +39,22 @@ class InstabugButton extends StatelessWidget { const EdgeInsets.symmetric( horizontal: 20.0, ), - child: ElevatedButton( - onPressed: onPressed, - style: ElevatedButton.styleFrom( - backgroundColor: backgroundColor ?? Colors.lightBlue, - foregroundColor: Colors.white, - textStyle: Theme.of(context) - .textTheme - .labelLarge - ?.copyWith(fontSize: fontSize), + child: Semantics( + label: symanticLabel, + child: ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: backgroundColor ?? Colors.lightBlue, + foregroundColor: Colors.white, + textStyle: Theme.of(context).textTheme.labelLarge?.copyWith( + fontSize: fontSize, + ), + ), + child: Text( + text, + textAlign: TextAlign.center, + ), ), - child: Text(text), ), ); } diff --git a/example/lib/src/widget/instabug_clipboard_input.dart b/example/lib/src/widget/instabug_clipboard_input.dart index 584faea81..09799b355 100644 --- a/example/lib/src/widget/instabug_clipboard_input.dart +++ b/example/lib/src/widget/instabug_clipboard_input.dart @@ -3,14 +3,16 @@ import 'package:instabug_flutter_example/src/widget/instabug_text_field.dart'; import 'package:instabug_flutter_example/src/widget/instabug_clipboard_icon_button.dart'; class InstabugClipboardInput extends StatelessWidget { - const InstabugClipboardInput({ - Key? key, - required this.label, - required this.controller, - }) : super(key: key); + const InstabugClipboardInput( + {Key? key, + required this.label, + required this.controller, + this.symanticLabel}) + : super(key: key); final String label; final TextEditingController controller; + final String? symanticLabel; @override Widget build(BuildContext context) { @@ -18,12 +20,12 @@ class InstabugClipboardInput extends StatelessWidget { children: [ Expanded( child: InstabugTextField( - label: label, - margin: const EdgeInsetsDirectional.only( - start: 20.0, - ), - controller: controller, - ), + label: label, + margin: const EdgeInsetsDirectional.only( + start: 20.0, + ), + controller: controller, + symanticLabel: symanticLabel), ), InstabugClipboardIconButton( onPaste: (String? clipboardText) { diff --git a/example/lib/src/widget/instabug_text_field.dart b/example/lib/src/widget/instabug_text_field.dart index 3d01cc623..1e3c23870 100644 --- a/example/lib/src/widget/instabug_text_field.dart +++ b/example/lib/src/widget/instabug_text_field.dart @@ -1,15 +1,16 @@ import 'package:flutter/material.dart'; class InstabugTextField extends StatelessWidget { - const InstabugTextField({ - Key? key, - required this.label, - required this.controller, - this.labelStyle, - this.margin, - this.keyboardType, - this.validator, - }) : super(key: key); + const InstabugTextField( + {Key? key, + required this.label, + required this.controller, + this.labelStyle, + this.margin, + this.keyboardType, + this.validator, + this.symanticLabel}) + : super(key: key); final String label; final TextEditingController controller; @@ -17,6 +18,7 @@ class InstabugTextField extends StatelessWidget { final TextStyle? labelStyle; final TextInputType? keyboardType; final FormFieldValidator? validator; + final String? symanticLabel; @override Widget build(BuildContext context) { @@ -25,18 +27,21 @@ class InstabugTextField extends StatelessWidget { const EdgeInsets.symmetric( horizontal: 20.0, ), - child: TextFormField( - controller: controller, - keyboardType: keyboardType, - validator: validator, - decoration: InputDecoration( - labelText: label, - labelStyle: labelStyle ?? Theme.of(context).textTheme.labelLarge, - suffixIcon: IconButton( - onPressed: controller.clear, - iconSize: 12.0, - icon: const Icon( - Icons.clear, + child: Semantics( + label: label, + child: TextFormField( + controller: controller, + keyboardType: keyboardType, + validator: validator, + decoration: InputDecoration( + labelText: label, + labelStyle: labelStyle ?? Theme.of(context).textTheme.labelLarge, + suffixIcon: IconButton( + onPressed: controller.clear, + iconSize: 12.0, + icon: const Icon( + Icons.clear, + ), ), ), ), diff --git a/example/pubspec.lock b/example/pubspec.lock index 99e8f9d56..af0b84012 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" async: dependency: transitive description: @@ -41,6 +49,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" fake_async: dependency: transitive description: @@ -49,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" file: dependency: transitive description: @@ -57,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: ef7d2a085c1b1d69d17b6842d0734aad90156de08df6bd3c12496d0bd6ddf8e2 + url: "https://pub.dev" + source: hosted + version: "10.3.1" flutter: dependency: "direct main" description: flutter @@ -75,11 +115,24 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "6382ce712ff69b0f719640ce957559dde459e55ecd433c767e06d139ddf16cab" + url: "https://pub.dev" + source: hosted + version: "2.0.29" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -172,6 +225,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.15.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -180,6 +241,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" platform: dependency: transitive description: @@ -188,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" process: dependency: transitive description: @@ -196,6 +273,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.2" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" sky_engine: dependency: transitive description: flutter @@ -281,6 +366,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" webdriver: dependency: transitive description: @@ -289,6 +382,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.4" + win32: + dependency: transitive + description: + name: win32 + sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e + url: "https://pub.dev" + source: hosted + version: "5.10.1" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.6.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fe72aaa2d..92761be28 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -27,6 +27,8 @@ dependencies: instabug_flutter: path: ../ instabug_http_client: ^2.4.0 + file_picker: + provider: dev_dependencies: flutter_driver: From e4450bf379bcfc6b8b285f97cfae65b28292ab0e Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Mon, 18 Aug 2025 02:02:30 +0300 Subject: [PATCH 09/10] add extra scenarios --- example/pubspec.lock | 36 ++---------------------------------- example/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index af0b84012..7dcb19811 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,14 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" async: dependency: transitive description: @@ -57,14 +49,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.4+2" - dbus: - dependency: transitive - description: - name: dbus - sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" - url: "https://pub.dev" - source: hosted - version: "0.7.11" fake_async: dependency: transitive description: @@ -93,10 +77,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: ef7d2a085c1b1d69d17b6842d0734aad90156de08df6bd3c12496d0bd6ddf8e2 + sha256: c904b4ab56d53385563c7c39d8e9fa9af086f91495dfc48717ad84a42c3cf204 url: "https://pub.dev" source: hosted - version: "10.3.1" + version: "8.1.7" flutter: dependency: "direct main" description: flutter @@ -241,14 +225,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 - url: "https://pub.dev" - source: hosted - version: "6.0.2" platform: dependency: transitive description: @@ -390,14 +366,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.10.1" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" sdks: dart: ">=3.6.0 <4.0.0" flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f9ee6f6e4..a951bcf8f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: instabug_flutter: path: ../ instabug_http_client: ^2.4.0 - file_picker: + file_picker: 8.1.7 provider: dev_dependencies: From 8d34e234045407a700d69b5c134b84498505d113 Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Mon, 18 Aug 2025 02:05:43 +0300 Subject: [PATCH 10/10] add extra scenarios --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a951bcf8f..4d28d3a50 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: instabug_flutter: path: ../ instabug_http_client: ^2.4.0 - file_picker: 8.1.7 + file_picker: <10.0.0 provider: dev_dependencies: