Skip to content

Commit c2725a6

Browse files
feat: add proactive bug reporting
1 parent 03309e4 commit c2725a6

File tree

13 files changed

+197
-24
lines changed

13 files changed

+197
-24
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v14.1.0...dev)
4+
5+
### Added
6+
7+
- Add support proactive bug-reporting ([#471](https://github.com/Instabug/Instabug-Flutter/pull/471)).
8+
9+
310
## [14.1.0](https://github.com/Instabug/Instabug-Flutter/compare/v14.0.0...v14.1.0) (January 2, 2025)
411

512
### Changed

android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import androidx.annotation.Nullable;
77

88
import com.instabug.bug.BugReporting;
9+
import com.instabug.bug.ProactiveReportingConfigs;
910
import com.instabug.flutter.generated.BugReportingPigeon;
1011
import com.instabug.flutter.util.ArgsRegistry;
1112
import com.instabug.flutter.util.ThreadManager;
@@ -186,4 +187,21 @@ public void setCommentMinimumCharacterCount(@NonNull Long limit, @Nullable List<
186187
}
187188
BugReporting.setCommentMinimumCharacterCount(limit.intValue(), reportTypesArray);
188189
}
190+
191+
@Override
192+
public void setProactiveReportingConfigurations(@NonNull Boolean enabled, @NonNull Long gapBetweenModals, @NonNull Long modalDelayAfterDetection) {
193+
ThreadManager.runOnMainThread(new Runnable() {
194+
@Override
195+
public void run() {
196+
ProactiveReportingConfigs configs = new ProactiveReportingConfigs.Builder()
197+
.setGapBetweenModals(gapBetweenModals) // Time in seconds
198+
.setModalDelayAfterDetection(modalDelayAfterDetection) // Time in seconds
199+
.isEnabled(enabled) //Enable/disable
200+
.build();
201+
BugReporting.setProactiveReportingConfigurations(configs);
202+
203+
204+
}
205+
});
206+
}
189207
}

android/src/test/java/com/instabug/flutter/BugReportingApiTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.instabug.flutter;
22

33
import static org.mockito.ArgumentMatchers.any;
4+
import static org.mockito.ArgumentMatchers.argThat;
45
import static org.mockito.ArgumentMatchers.eq;
56
import static org.mockito.Mockito.mock;
67
import static org.mockito.Mockito.mockStatic;
@@ -194,4 +195,24 @@ public void testSetCommentMinimumCharacterCount() {
194195

195196
mBugReporting.verify(() -> BugReporting.setCommentMinimumCharacterCount(limit.intValue(), BugReporting.ReportType.BUG, BugReporting.ReportType.QUESTION));
196197
}
198+
199+
@Test
200+
public void testSetProactiveReportingConfigurations() {
201+
// given
202+
boolean enabled = true;
203+
long gapBetweekDialogs = 20;
204+
long modeDelay = 30;
205+
206+
// when
207+
api.setProactiveReportingConfigurations(enabled, gapBetweekDialogs, modeDelay);
208+
209+
// then
210+
mBugReporting.verify(() -> BugReporting.setProactiveReportingConfigurations(argThat(config ->
211+
config.getModalsGap() == gapBetweekDialogs &&
212+
config.getDetectionGap() == modeDelay &&
213+
config.isEnabled() == enabled
214+
)));
215+
216+
217+
}
197218
}

example/ios/InstabugTests/BugReportingApiTests.m

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,5 +174,29 @@ - (void)testSetCommentMinimumCharacterCountGivenNoReportTypes {
174174

175175
OCMVerify([self.mBugReporting setCommentMinimumCharacterCountForReportTypes:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeFeedback | IBGBugReportingReportTypeQuestion withLimit:limit.intValue]);
176176
}
177+
- (void) testSetProactiveReportingConfigurations {
178+
BOOL enabled = true;
179+
NSNumber* gap = @2;
180+
NSNumber* delay = @4;
181+
NSNumber *enabledNum = [NSNumber numberWithBool:enabled];
182+
FlutterError *error;
183+
184+
IBGProactiveReportingConfigurations *configurations = [[IBGProactiveReportingConfigurations alloc] init];
185+
configurations.enabled = enabled; //Enable/disable
186+
configurations.gapBetweenModals = gap; // Time in seconds
187+
configurations.modalDelayAfterDetection = delay; // Time in seconds
188+
189+
OCMStub([self.mBugReporting setProactiveReportingConfigurations:OCMOCK_ANY]);
190+
191+
[self.api setProactiveReportingConfigurationsEnabled:enabledNum gapBetweenModals:gap modalDelayAfterDetection:delay error:&error];
192+
193+
// Verify that the method is called with the correct properties (using OCMArg to match properties)
194+
OCMVerify([self.mBugReporting setProactiveReportingConfigurations:[OCMArg checkWithBlock:^BOOL(id obj) {
195+
IBGProactiveReportingConfigurations *config = (IBGProactiveReportingConfigurations *)obj;
196+
return config.enabled == enabled &&
197+
[config.gapBetweenModals isEqualToNumber:gap] &&
198+
[config.modalDelayAfterDetection isEqualToNumber:delay];
199+
}]]);
200+
}
177201

178202
@end

example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ EXTERNAL SOURCES:
2525
SPEC CHECKSUMS:
2626
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
2727
Instabug: 8cbca8974168c815658133e2813f5ac3a36f8e20
28-
instabug_flutter: a24751dfaedd29475da2af062d3e19d697438f72
28+
instabug_flutter: 6552acbd6ba0806e02ed478040d7b7e8a6d53121
2929
OCMock: 5ea90566be239f179ba766fd9fbae5885040b992
3030

3131
PODFILE CHECKSUM: 8f7552fd115ace1988c3db54a69e4a123c448f84

example/lib/main.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ void main() {
5656
Zone.current.handleUncaughtError(details.exception, details.stack!);
5757
};
5858

59+
BugReporting.setProactiveReportingConfigurations(
60+
ProactiveReportingConfigsBuilder()
61+
.setModalDelayAfterDetection(1)
62+
.setGapBetweenModals(1)
63+
.isEnabled(true)
64+
.build());
65+
5966
runApp(const MyApp());
6067
},
6168
CrashReporting.reportCrash,

example/pubspec.lock

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ packages:
3737
dependency: transitive
3838
description:
3939
name: collection
40-
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
40+
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
4141
url: "https://pub.dev"
4242
source: hosted
43-
version: "1.18.0"
43+
version: "1.19.0"
4444
fake_async:
4545
dependency: transitive
4646
description:
@@ -120,18 +120,18 @@ packages:
120120
dependency: transitive
121121
description:
122122
name: leak_tracker
123-
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
123+
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
124124
url: "https://pub.dev"
125125
source: hosted
126-
version: "10.0.5"
126+
version: "10.0.7"
127127
leak_tracker_flutter_testing:
128128
dependency: transitive
129129
description:
130130
name: leak_tracker_flutter_testing
131-
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
131+
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
132132
url: "https://pub.dev"
133133
source: hosted
134-
version: "3.0.5"
134+
version: "3.0.8"
135135
leak_tracker_testing:
136136
dependency: transitive
137137
description:
@@ -200,7 +200,7 @@ packages:
200200
dependency: transitive
201201
description: flutter
202202
source: sdk
203-
version: "0.0.99"
203+
version: "0.0.0"
204204
source_span:
205205
dependency: transitive
206206
description:
@@ -213,10 +213,10 @@ packages:
213213
dependency: transitive
214214
description:
215215
name: stack_trace
216-
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
216+
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
217217
url: "https://pub.dev"
218218
source: hosted
219-
version: "1.11.1"
219+
version: "1.12.0"
220220
stream_channel:
221221
dependency: transitive
222222
description:
@@ -229,10 +229,10 @@ packages:
229229
dependency: transitive
230230
description:
231231
name: string_scanner
232-
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
232+
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
233233
url: "https://pub.dev"
234234
source: hosted
235-
version: "1.2.0"
235+
version: "1.3.0"
236236
sync_http:
237237
dependency: transitive
238238
description:
@@ -253,10 +253,10 @@ packages:
253253
dependency: transitive
254254
description:
255255
name: test_api
256-
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
256+
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
257257
url: "https://pub.dev"
258258
source: hosted
259-
version: "0.7.2"
259+
version: "0.7.3"
260260
typed_data:
261261
dependency: transitive
262262
description:
@@ -277,18 +277,18 @@ packages:
277277
dependency: transitive
278278
description:
279279
name: vm_service
280-
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
280+
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
281281
url: "https://pub.dev"
282282
source: hosted
283-
version: "14.2.5"
283+
version: "14.3.0"
284284
webdriver:
285285
dependency: transitive
286286
description:
287287
name: webdriver
288-
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
288+
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
289289
url: "https://pub.dev"
290290
source: hosted
291-
version: "3.0.3"
291+
version: "3.0.4"
292292
sdks:
293293
dart: ">=3.5.0 <4.0.0"
294294
flutter: ">=3.18.0-18.0.pre.54"

ios/Classes/Modules/BugReportingApi.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,13 @@ - (void)setCommentMinimumCharacterCountLimit:(NSNumber *)limit reportTypes:(null
165165
[IBGBugReporting setCommentMinimumCharacterCountForReportTypes:resolvedTypes withLimit:limit.intValue];
166166
}
167167

168+
- (void)setProactiveReportingConfigurationsEnabled:(nonnull NSNumber *)enabled gapBetweenModals:(nonnull NSNumber *)gapBetweenModals modalDelayAfterDetection:(nonnull NSNumber *)modalDelayAfterDetection error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error {
169+
IBGProactiveReportingConfigurations *configurations = [[IBGProactiveReportingConfigurations alloc] init];
170+
configurations.enabled = [enabled boolValue]; //Enable/disable
171+
configurations.gapBetweenModals = gapBetweenModals; // Time in seconds
172+
configurations.modalDelayAfterDetection = modalDelayAfterDetection; // Time in seconds
173+
[IBGBugReporting setProactiveReportingConfigurations:configurations];
174+
}
175+
176+
168177
@end

lib/instabug_flutter.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ export 'src/models/crash_data.dart';
33
export 'src/models/exception_data.dart';
44
export 'src/models/feature_flag.dart';
55
export 'src/models/network_data.dart';
6+
export 'src/models/proactive_reporting_config.dart';
67
export 'src/models/trace.dart';
78
export 'src/models/w3c_header.dart';
8-
99
// Modules
1010
export 'src/modules/apm.dart';
1111
export 'src/modules/bug_reporting.dart';
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import 'package:flutter/foundation.dart';
2+
3+
class ProactiveReportingConfigs {
4+
final int gapBetweenModals; // Time in seconds
5+
final int modalDelayAfterDetection; // Time in seconds
6+
final bool enabled;
7+
8+
// Private constructor to ensure it can only be created through the builder
9+
const ProactiveReportingConfigs._({
10+
required this.gapBetweenModals,
11+
required this.modalDelayAfterDetection,
12+
required this.enabled,
13+
});
14+
}
15+
16+
// Builder class for ProactiveReportingConfigs
17+
class ProactiveReportingConfigsBuilder {
18+
int gapBetweenModals = 30; // Default: 30 seconds
19+
int modalDelayAfterDetection = 15; // Default: 15 seconds
20+
bool enabled = true; // Default: enabled
21+
22+
// Logger method to handle logging
23+
void _logWarning(String message) {
24+
if (kDebugMode) {
25+
print('Warning: $message');
26+
}
27+
}
28+
29+
/// Controls the time gap between showing 2 proactive reporting dialogs in seconds
30+
ProactiveReportingConfigsBuilder setGapBetweenModals(int gap) {
31+
if (gap <= 0) {
32+
_logWarning('gapBetweenModals must be a positive number. Using default value of 30 seconds.');
33+
return this;
34+
}
35+
gapBetweenModals = gap;
36+
return this;
37+
}
38+
39+
/// Controls the time gap between detecting a frustrating experience
40+
ProactiveReportingConfigsBuilder setModalDelayAfterDetection(int delay) {
41+
if (delay <= 0) {
42+
_logWarning('modalDelayAfterDetection must be a positive number. Using default value of 15 seconds.');
43+
return this;
44+
}
45+
modalDelayAfterDetection = delay;
46+
return this;
47+
}
48+
49+
/// Controls the state of the feature
50+
ProactiveReportingConfigsBuilder isEnabled(bool value) {
51+
enabled = value;
52+
return this;
53+
}
54+
55+
ProactiveReportingConfigs build() {
56+
return ProactiveReportingConfigs._(
57+
gapBetweenModals: gapBetweenModals,
58+
modalDelayAfterDetection: modalDelayAfterDetection,
59+
enabled: enabled,
60+
);
61+
}
62+
}

0 commit comments

Comments
 (0)