|
6 | 6 |
|
7 | 7 | import android.app.Application;
|
8 | 8 | import android.graphics.Bitmap;
|
| 9 | +import android.graphics.Color; |
| 10 | +import android.graphics.Typeface; |
9 | 11 | import android.net.Uri;
|
10 | 12 | import android.util.Log;
|
11 | 13 | import android.view.View;
|
12 | 14 |
|
| 15 | +import com.facebook.react.bridge.ReactApplicationContext; |
| 16 | + |
13 | 17 | import androidx.annotation.NonNull;
|
14 | 18 | import androidx.annotation.UiThread;
|
15 | 19 |
|
|
45 | 49 | import com.instabug.library.internal.module.InstabugLocale;
|
46 | 50 | import com.instabug.library.invocation.InstabugInvocationEvent;
|
47 | 51 | import com.instabug.library.logging.InstabugLog;
|
| 52 | +import com.instabug.library.model.IBGTheme; |
48 | 53 | import com.instabug.library.model.NetworkLog;
|
49 | 54 | import com.instabug.library.model.Report;
|
50 | 55 | import com.instabug.library.ui.onboarding.WelcomeMessage;
|
@@ -1351,4 +1356,203 @@ public void run() {
|
1351 | 1356 | }
|
1352 | 1357 | });
|
1353 | 1358 | }
|
| 1359 | + /** |
| 1360 | + * Sets the theme for Instabug using a configuration object. |
| 1361 | + * |
| 1362 | + * @param themeConfig A ReadableMap containing theme properties such as colors, fonts, and text styles. |
| 1363 | + */ |
| 1364 | + @ReactMethod |
| 1365 | + public void setTheme(final ReadableMap themeConfig) { |
| 1366 | + MainThreadHandler.runOnMainThread(new Runnable() { |
| 1367 | + @Override |
| 1368 | + public void run() { |
| 1369 | + try { |
| 1370 | + com.instabug.library.model.IBGTheme.Builder builder = new com.instabug.library.model.IBGTheme.Builder(); |
| 1371 | + |
| 1372 | + if (themeConfig.hasKey("primaryColor")) { |
| 1373 | + builder.setPrimaryColor(getColor(themeConfig, "primaryColor")); |
| 1374 | + } |
| 1375 | + if (themeConfig.hasKey("secondaryTextColor")) { |
| 1376 | + builder.setSecondaryTextColor(getColor(themeConfig, "secondaryTextColor")); |
| 1377 | + } |
| 1378 | + if (themeConfig.hasKey("primaryTextColor")) { |
| 1379 | + builder.setPrimaryTextColor(getColor(themeConfig, "primaryTextColor")); |
| 1380 | + } |
| 1381 | + if (themeConfig.hasKey("titleTextColor")) { |
| 1382 | + builder.setTitleTextColor(getColor(themeConfig, "titleTextColor")); |
| 1383 | + } |
| 1384 | + if (themeConfig.hasKey("backgroundColor")) { |
| 1385 | + builder.setBackgroundColor(getColor(themeConfig, "backgroundColor")); |
| 1386 | + } |
| 1387 | + |
| 1388 | + if (themeConfig.hasKey("primaryTextStyle")) { |
| 1389 | + builder.setPrimaryTextStyle(getTextStyle(themeConfig, "primaryTextStyle")); |
| 1390 | + } |
| 1391 | + if (themeConfig.hasKey("secondaryTextStyle")) { |
| 1392 | + builder.setSecondaryTextStyle(getTextStyle(themeConfig, "secondaryTextStyle")); |
| 1393 | + } |
| 1394 | + if (themeConfig.hasKey("ctaTextStyle")) { |
| 1395 | + builder.setCtaTextStyle(getTextStyle(themeConfig, "ctaTextStyle")); |
| 1396 | + } |
| 1397 | + if (themeConfig.hasKey("primaryFontPath") || themeConfig.hasKey("primaryFontAsset")) { |
| 1398 | + Typeface primaryTypeface = getTypeface(themeConfig, "primaryFontPath", "primaryFontAsset"); |
| 1399 | + if (primaryTypeface != null) { |
| 1400 | + builder.setPrimaryTextFont(primaryTypeface); |
| 1401 | + } else { |
| 1402 | + Log.e("InstabugModule", "Failed to load primary font"); |
| 1403 | + } |
| 1404 | + } |
| 1405 | + |
| 1406 | + if (themeConfig.hasKey("secondaryFontPath") || themeConfig.hasKey("secondaryFontAsset")) { |
| 1407 | + Typeface secondaryTypeface = getTypeface(themeConfig, "secondaryFontPath", "secondaryFontAsset"); |
| 1408 | + if (secondaryTypeface != null) { |
| 1409 | + builder.setSecondaryTextFont(secondaryTypeface); |
| 1410 | + } else { |
| 1411 | + Log.e("InstabugModule", "Failed to load secondary font"); |
| 1412 | + } |
| 1413 | + } |
| 1414 | + |
| 1415 | + if (themeConfig.hasKey("ctaFontPath") || themeConfig.hasKey("ctaFontAsset")) { |
| 1416 | + Typeface ctaTypeface = getTypeface(themeConfig, "ctaFontPath", "ctaFontAsset"); |
| 1417 | + if (ctaTypeface != null) { |
| 1418 | + builder.setCtaTextFont(ctaTypeface); |
| 1419 | + } else { |
| 1420 | + Log.e("InstabugModule", "Failed to load CTA font"); |
| 1421 | + } |
| 1422 | + } |
| 1423 | + |
| 1424 | + IBGTheme theme = builder.build(); |
| 1425 | + Instabug.setTheme(theme); |
| 1426 | + |
| 1427 | + } catch (Exception e) { |
| 1428 | + e.printStackTrace(); |
| 1429 | + } |
| 1430 | + } |
| 1431 | + }); |
| 1432 | + } |
| 1433 | + |
| 1434 | + /** |
| 1435 | + * Retrieves a color value from the ReadableMap. |
| 1436 | + * |
| 1437 | + * @param map The ReadableMap object. |
| 1438 | + * @param key The key to look for. |
| 1439 | + * @return The parsed color as an integer, or black if missing or invalid. |
| 1440 | + */ |
| 1441 | + private int getColor(ReadableMap map, String key) { |
| 1442 | + try { |
| 1443 | + if (map != null && map.hasKey(key) && !map.isNull(key)) { |
| 1444 | + String colorString = map.getString(key); |
| 1445 | + return Color.parseColor(colorString); |
| 1446 | + } |
| 1447 | + } catch (Exception e) { |
| 1448 | + e.printStackTrace(); |
| 1449 | + } |
| 1450 | + return Color.BLACK; |
| 1451 | + } |
| 1452 | + |
| 1453 | + /** |
| 1454 | + * Retrieves a text style from the ReadableMap. |
| 1455 | + * |
| 1456 | + * @param map The ReadableMap object. |
| 1457 | + * @param key The key to look for. |
| 1458 | + * @return The corresponding Typeface style, or Typeface.NORMAL if missing or invalid. |
| 1459 | + */ |
| 1460 | + private int getTextStyle(ReadableMap map, String key) { |
| 1461 | + try { |
| 1462 | + if (map != null && map.hasKey(key) && !map.isNull(key)) { |
| 1463 | + String style = map.getString(key); |
| 1464 | + switch (style.toLowerCase()) { |
| 1465 | + case "bold": |
| 1466 | + return Typeface.BOLD; |
| 1467 | + case "italic": |
| 1468 | + return Typeface.ITALIC; |
| 1469 | + case "bold_italic": |
| 1470 | + return Typeface.BOLD_ITALIC; |
| 1471 | + case "normal": |
| 1472 | + default: |
| 1473 | + return Typeface.NORMAL; |
| 1474 | + } |
| 1475 | + } |
| 1476 | + } catch (Exception e) { |
| 1477 | + e.printStackTrace(); |
| 1478 | + } |
| 1479 | + return Typeface.NORMAL; |
| 1480 | + } |
| 1481 | + |
| 1482 | +private Typeface getTypeface(ReadableMap map, String fileKey, String assetKey) { |
| 1483 | + try { |
| 1484 | + if (fileKey != null && map.hasKey(fileKey) && !map.isNull(fileKey)) { |
| 1485 | + String fontPath = map.getString(fileKey); |
| 1486 | + String fileName = getFileName(fontPath); |
| 1487 | + |
| 1488 | + try { |
| 1489 | + Typeface typeface = Typeface.create(fileName, Typeface.NORMAL); |
| 1490 | + if (typeface != null && !typeface.equals(Typeface.DEFAULT)) { |
| 1491 | + return typeface; |
| 1492 | + } |
| 1493 | + } catch (Exception e) { |
| 1494 | + e.printStackTrace(); |
| 1495 | + } |
| 1496 | + |
| 1497 | + try { |
| 1498 | + Typeface typeface = Typeface.createFromAsset(getReactApplicationContext().getAssets(), "fonts/" + fileName); |
| 1499 | + return typeface; |
| 1500 | + } catch (Exception e) { |
| 1501 | + e.printStackTrace(); |
| 1502 | + } |
| 1503 | + } |
| 1504 | + |
| 1505 | + if (assetKey != null && map.hasKey(assetKey) && !map.isNull(assetKey)) { |
| 1506 | + String assetPath = map.getString(assetKey); |
| 1507 | + String fileName = getFileName(assetPath); |
| 1508 | + try { |
| 1509 | + Typeface typeface = Typeface.createFromAsset(getReactApplicationContext().getAssets(), "fonts/" + fileName); |
| 1510 | + return typeface; |
| 1511 | + } catch (Exception e) { |
| 1512 | + e.printStackTrace(); |
| 1513 | + } |
| 1514 | + } |
| 1515 | + } catch (Exception e) { |
| 1516 | + e.printStackTrace(); |
| 1517 | + } |
| 1518 | + |
| 1519 | + return Typeface.DEFAULT; |
| 1520 | +} |
| 1521 | + |
| 1522 | +/** |
| 1523 | + * Extracts the filename from a path, removing any directory prefixes. |
| 1524 | + * |
| 1525 | + * @param path The full path to the file |
| 1526 | + * @return Just the filename with extension |
| 1527 | + */ |
| 1528 | +private String getFileName(String path) { |
| 1529 | + if (path == null || path.isEmpty()) { |
| 1530 | + return path; |
| 1531 | + } |
| 1532 | + |
| 1533 | + int lastSeparator = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); |
| 1534 | + if (lastSeparator >= 0 && lastSeparator < path.length() - 1) { |
| 1535 | + return path.substring(lastSeparator + 1); |
| 1536 | + } |
| 1537 | + |
| 1538 | + return path; |
| 1539 | +} |
| 1540 | + |
| 1541 | + /** |
| 1542 | + * Enables or disables displaying in full-screen mode, hiding the status and navigation bars. |
| 1543 | + * @param isEnabled A boolean to enable/disable setFullscreen. |
| 1544 | + */ |
| 1545 | + @ReactMethod |
| 1546 | + public void setFullscreen(final boolean isEnabled) { |
| 1547 | + MainThreadHandler.runOnMainThread(new Runnable() { |
| 1548 | + @Override |
| 1549 | + public void run() { |
| 1550 | + try { |
| 1551 | + Instabug.setFullscreen(isEnabled); |
| 1552 | + } catch (Exception e) { |
| 1553 | + e.printStackTrace(); |
| 1554 | + } |
| 1555 | + } |
| 1556 | + }); |
| 1557 | + } |
1354 | 1558 | }
|
0 commit comments