Skip to content

Commit f9d6d61

Browse files
feat: support advanced UI customization (#599)
* feat: support advanced UI customization * chore: add change log * fix: delete setFullScreen * fix: linting * fix: unit test * fix: linting * fix: resolve comments * fix: add full screen function * fix: ios tests * fix: ios tests * chore: remove deprecated apis (#614) * feat: support advanced UI customization * chore: add change log * fix: delete setFullScreen * fix: linting * fix: unit test * fix: linting * fix: resolve comments * chore: remove deprecated apis * chore: add changelog * fix: setTheme calling * fix: formatte * fix: formate * fix: formatting * fix: ios tests * fix: ios tests * fix: e2e tests * fix: formate analyze * fix: e2e ios testing * fix: format --------- Co-authored-by: ahmed alaa <[email protected]> --------- Co-authored-by: ahmed alaa <[email protected]>
1 parent cb85eda commit f9d6d61

30 files changed

+725
-762
lines changed

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
# Changelog
22

3-
## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025)
3+
## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v15.0.2...dev)
44

55
### Added
66

7+
- Add support for Advanced UI customization with comprehensive theming capabilities ([#599](https://github.com/Instabug/Instabug-Flutter/pull/599))
8+
-
79
- Add support for App variant. ([#585](https://github.com/Instabug/Instabug-Flutter/pull/585))
810

11+
### Changed
12+
13+
- **BREAKING** Remove deprecated APIs ([#614](https://github.com/Instabug/Instabug-Flutter/pull/614)). See migration guide for more details.
14+
15+
16+
## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025)
17+
18+
### Added
19+
20+
921
- Add support for xCode 16. ([#574](https://github.com/Instabug/Instabug-Flutter/pull/574))
1022

1123
- Add support for BugReporting user consents. ([#573](https://github.com/Instabug/Instabug-Flutter/pull/573))

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

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import com.instabug.apm.InternalAPM;
1010
import com.instabug.apm.configuration.cp.APMFeature;
1111
import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback;
12-
import com.instabug.apm.model.ExecutionTrace;
1312
import com.instabug.apm.networking.APMNetworkLogger;
1413
import com.instabug.apm.networkinterception.cp.APMCPNetworkLog;
1514
import com.instabug.flutter.generated.ApmPigeon;
@@ -26,7 +25,6 @@
2625

2726
public class ApmApi implements ApmPigeon.ApmHostApi {
2827
private final String TAG = ApmApi.class.getName();
29-
private final HashMap<String, ExecutionTrace> traces = new HashMap<>();
3028

3129
public static void init(BinaryMessenger messenger) {
3230
final ApmApi api = new ApmApi();
@@ -98,45 +96,7 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) {
9896
*
9997
* @deprecated see {@link #startFlow}
10098
*/
101-
@Override
102-
public void startExecutionTrace(@NonNull String id, @NonNull String name, ApmPigeon.Result<String> result) {
103-
ThreadManager.runOnBackground(
104-
new Runnable() {
105-
@Override
106-
public void run() {
107-
try {
108-
ExecutionTrace trace = APM.startExecutionTrace(name);
109-
if (trace != null) {
110-
traces.put(id, trace);
111-
112-
ThreadManager.runOnMainThread(new Runnable() {
113-
@Override
114-
public void run() {
115-
result.success(id);
116-
}
117-
});
118-
} else {
119-
ThreadManager.runOnMainThread(new Runnable() {
120-
@Override
121-
public void run() {
122-
result.success(null);
123-
}
124-
});
125-
}
126-
} catch (Exception e) {
127-
e.printStackTrace();
128-
129-
ThreadManager.runOnMainThread(new Runnable() {
130-
@Override
131-
public void run() {
132-
result.success(null);
133-
}
134-
});
135-
}
136-
}
137-
}
138-
);
139-
}
99+
140100

141101
/**
142102
* Starts an AppFlow with the specified name.
@@ -201,39 +161,7 @@ public void endFlow(@NonNull String name) {
201161
}
202162
}
203163

204-
/**
205-
* Adds a new attribute to trace
206-
*
207-
* @param id String id of the trace.
208-
* @param key attribute key
209-
* @param value attribute value. Null to remove attribute
210-
*
211-
* @deprecated see {@link #setFlowAttribute}
212-
*/
213-
@Override
214-
public void setExecutionTraceAttribute(@NonNull String id, @NonNull String key, @NonNull String value) {
215-
try {
216-
traces.get(id).setAttribute(key, value);
217-
} catch (Exception e) {
218-
e.printStackTrace();
219-
}
220-
}
221164

222-
/**
223-
* Ends a trace
224-
*
225-
* @param id string id of the trace.
226-
*
227-
* @deprecated see {@link #endFlow}
228-
*/
229-
@Override
230-
public void endExecutionTrace(@NonNull String id) {
231-
try {
232-
traces.get(id).end();
233-
} catch (Exception e) {
234-
e.printStackTrace();
235-
}
236-
}
237165

238166
/**
239167
* Starts a UI trace.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public void setCommentMinimumCharacterCount(@NonNull Long limit, @Nullable List<
184184
reportTypesArray[i] = ArgsRegistry.reportTypes.get(key);
185185
}
186186
}
187-
BugReporting.setCommentMinimumCharacterCount(limit.intValue(), reportTypesArray);
187+
BugReporting.setCommentMinimumCharacterCountForBugReportType(limit.intValue(), reportTypesArray);
188188
}
189189

190190
@Override

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

Lines changed: 165 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.graphics.Bitmap;
66
import android.graphics.BitmapFactory;
77
import android.net.Uri;
8+
import android.graphics.Typeface;
89
import android.util.Log;
910

1011
import androidx.annotation.NonNull;
@@ -196,7 +197,6 @@ public void setWelcomeMessageMode(@NonNull String mode) {
196197

197198
@Override
198199
public void setPrimaryColor(@NonNull Long color) {
199-
Instabug.setPrimaryColor(color.intValue());
200200
}
201201

202202
@Override
@@ -248,20 +248,7 @@ public void run() {
248248
);
249249
}
250250

251-
@Override
252-
public void addExperiments(@NonNull List<String> experiments) {
253-
Instabug.addExperiments(experiments);
254-
}
255251

256-
@Override
257-
public void removeExperiments(@NonNull List<String> experiments) {
258-
Instabug.removeExperiments(experiments);
259-
}
260-
261-
@Override
262-
public void clearAllExperiments() {
263-
Instabug.clearAllExperiments();
264-
}
265252

266253
@Override
267254
public void addFeatureFlags(@NonNull Map<String, String> featureFlags) {
@@ -529,4 +516,168 @@ public void setNetworkLogBodyEnabled(@NonNull Boolean isEnabled) {
529516
e.printStackTrace();
530517
}
531518
}
519+
520+
@Override
521+
public void setTheme(@NonNull Map<String, Object> themeConfig) {
522+
try {
523+
Log.d(TAG, "setTheme called with config: " + themeConfig.toString());
524+
525+
com.instabug.library.model.IBGTheme.Builder builder = new com.instabug.library.model.IBGTheme.Builder();
526+
527+
if (themeConfig.containsKey("primaryColor")) {
528+
builder.setPrimaryColor(getColor(themeConfig, "primaryColor"));
529+
}
530+
if (themeConfig.containsKey("secondaryTextColor")) {
531+
builder.setSecondaryTextColor(getColor(themeConfig, "secondaryTextColor"));
532+
}
533+
if (themeConfig.containsKey("primaryTextColor")) {
534+
builder.setPrimaryTextColor(getColor(themeConfig, "primaryTextColor"));
535+
}
536+
if (themeConfig.containsKey("titleTextColor")) {
537+
builder.setTitleTextColor(getColor(themeConfig, "titleTextColor"));
538+
}
539+
if (themeConfig.containsKey("backgroundColor")) {
540+
builder.setBackgroundColor(getColor(themeConfig, "backgroundColor"));
541+
}
542+
543+
if (themeConfig.containsKey("primaryTextStyle")) {
544+
builder.setPrimaryTextStyle(getTextStyle(themeConfig, "primaryTextStyle"));
545+
}
546+
if (themeConfig.containsKey("secondaryTextStyle")) {
547+
builder.setSecondaryTextStyle(getTextStyle(themeConfig, "secondaryTextStyle"));
548+
}
549+
if (themeConfig.containsKey("ctaTextStyle")) {
550+
builder.setCtaTextStyle(getTextStyle(themeConfig, "ctaTextStyle"));
551+
}
552+
553+
setFontIfPresent(themeConfig, builder, "primaryFontPath", "primaryFontAsset", "primary");
554+
setFontIfPresent(themeConfig, builder, "secondaryFontPath", "secondaryFontAsset", "secondary");
555+
setFontIfPresent(themeConfig, builder, "ctaFontPath", "ctaFontAsset", "CTA");
556+
557+
com.instabug.library.model.IBGTheme theme = builder.build();
558+
Instabug.setTheme(theme);
559+
Log.d(TAG, "Theme applied successfully");
560+
561+
} catch (Exception e) {
562+
Log.e(TAG, "Error in setTheme: " + e.getMessage());
563+
e.printStackTrace();
564+
}
565+
}
566+
567+
568+
569+
/**
570+
* Retrieves a color value from the Map.
571+
*
572+
* @param map The Map object.
573+
* @param key The key to look for.
574+
* @return The parsed color as an integer, or black if missing or invalid.
575+
*/
576+
private int getColor(Map<String, Object> map, String key) {
577+
try {
578+
if (map != null && map.containsKey(key) && map.get(key) != null) {
579+
String colorString = (String) map.get(key);
580+
return android.graphics.Color.parseColor(colorString);
581+
}
582+
} catch (Exception e) {
583+
e.printStackTrace();
584+
}
585+
return android.graphics.Color.BLACK;
586+
}
587+
588+
/**
589+
* Retrieves a text style from the Map.
590+
*
591+
* @param map The Map object.
592+
* @param key The key to look for.
593+
* @return The corresponding Typeface style, or Typeface.NORMAL if missing or invalid.
594+
*/
595+
private int getTextStyle(Map<String, Object> map, String key) {
596+
try {
597+
if (map != null && map.containsKey(key) && map.get(key) != null) {
598+
String style = (String) map.get(key);
599+
switch (style.toLowerCase()) {
600+
case "bold":
601+
return Typeface.BOLD;
602+
case "italic":
603+
return Typeface.ITALIC;
604+
case "bold_italic":
605+
return Typeface.BOLD_ITALIC;
606+
case "normal":
607+
default:
608+
return Typeface.NORMAL;
609+
}
610+
}
611+
} catch (Exception e) {
612+
e.printStackTrace();
613+
}
614+
return Typeface.NORMAL;
615+
}
616+
617+
/**
618+
* Sets a font on the theme builder if the font configuration is present in the theme config.
619+
*
620+
* @param themeConfig The theme configuration map
621+
* @param builder The theme builder
622+
* @param fileKey The key for font file path
623+
* @param assetKey The key for font asset path
624+
* @param fontType The type of font (for logging purposes)
625+
*/
626+
private void setFontIfPresent(Map<String, Object> themeConfig, com.instabug.library.model.IBGTheme.Builder builder,
627+
String fileKey, String assetKey, String fontType) {
628+
if (themeConfig.containsKey(fileKey) || themeConfig.containsKey(assetKey)) {
629+
Typeface typeface = getTypeface(themeConfig, fileKey, assetKey);
630+
if (typeface != null) {
631+
switch (fontType) {
632+
case "primary":
633+
builder.setPrimaryTextFont(typeface);
634+
break;
635+
case "secondary":
636+
builder.setSecondaryTextFont(typeface);
637+
break;
638+
case "CTA":
639+
builder.setCtaTextFont(typeface);
640+
break;
641+
}
642+
}
643+
}
644+
}
645+
646+
private Typeface getTypeface(Map<String, Object> map, String fileKey, String assetKey) {
647+
String fontName = null;
648+
649+
if (assetKey != null && map.containsKey(assetKey) && map.get(assetKey) != null) {
650+
fontName = (String) map.get(assetKey);
651+
} else if (fileKey != null && map.containsKey(fileKey) && map.get(fileKey) != null) {
652+
fontName = (String) map.get(fileKey);
653+
}
654+
655+
if (fontName == null) {
656+
return Typeface.DEFAULT;
657+
}
658+
659+
try {
660+
String assetPath = "fonts/" + fontName;
661+
return Typeface.createFromAsset(context.getAssets(), assetPath);
662+
} catch (Exception e) {
663+
try {
664+
return Typeface.create(fontName, Typeface.NORMAL);
665+
} catch (Exception e2) {
666+
return Typeface.DEFAULT;
667+
}
668+
}
669+
}
670+
/**
671+
* Enables or disables displaying in full-screen mode, hiding the status and navigation bars.
672+
* @param isEnabled A boolean to enable/disable setFullscreen.
673+
*/
674+
@Override
675+
public void setFullscreen(@NonNull final Boolean isEnabled) {
676+
try {
677+
Instabug.setFullscreen(isEnabled);
678+
} catch (Exception e) {
679+
e.printStackTrace();
680+
}
681+
}
682+
532683
}

0 commit comments

Comments
 (0)