Implementation
void nudgeSpotlight(
BuildContext context,
Root rootData,
String eventName,
) async {
OverlayEntry? overlayForegroundEntry;
OverlayEntry? overlayBackgroundEntry;
Nudge.getInstance().submit(
taskId: NudgeNudgesUi.taskID!,
response: [
{
"root_id": rootData.id,
"widget_id": rootData.components[NudgeNudgesUi.currentNudgeIndex].id,
// "component_id": rootData.components[NudgeNudgesUi.currentNudgeIndex].id,
"widget_type": null,
"answers": [],
"action": "OPENED",
}
],
onSuccessCallback: (response) {
print("Spotlight Opened, $response");
},
onErrorCallback: (error, stackTrace) {
print("Error: $error");
},
);
NudgeNudgesUi.componentName = rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.elementId ??
"";
print('Component Name: ${NudgeNudgesUi.componentName}');
// return;
String? referenceSize = rootData.rootProps.size;
Size referenceDimensions = Size(
int.parse(referenceSize.split('x')[0]).toDouble(),
int.parse(referenceSize.split('x')[1]).toDouble(),
);
int referenceHeight = referenceDimensions.height.toInt();
int referenceWidth = referenceDimensions.width.toInt();
Size screenSize = MediaQuery.of(context).size;
double screenHeight = screenSize.height;
double screenWidth = screenSize.width;
double scaleHeight = screenHeight / referenceHeight;
double scaleWidth = screenWidth / referenceWidth;
Color fillColor = HexColor.fromHex(
rootData.components[NudgeNudgesUi.currentNudgeIndex].componentProps
.overlayColor ??
"#000000",
);
overlayBackgroundEntry = OverlayEntry(builder: (context) {
return Positioned(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: GestureDetector(
onTap: () {
// overlayBackgroundEntry!.remove();
// overlayForegroundEntry!.remove();
},
child: Container(
color: fillColor.withOpacity(0),
),
),
);
});
NudgeProviderState.navigatorKey.currentState!.overlay!.insert(
overlayBackgroundEntry,
);
// NudgeNudgesUi.componentName = rootData
// .components[NudgeNudgesUi.currentNudgeIndex]
// .componentProps
// .elementProps!
// .name ??
// "";
WidgetDetails? targetView = NudgeWidgetTracker.findWidgetPositionByLabel(
NudgeNudgesUi.componentName,
scaleWidth,
scaleHeight,
);
bool isPositionBased = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.isPositionBased ??
false;
if (targetView == null && !isPositionBased) {
overlayBackgroundEntry.remove();
}
final NudgeNudgesUi nudgeNudgesUi = NudgeNudgesUi();
nudgeNudgesUi
.scrollToTargetWidget(
targetView?.key,
isPositionBased: isPositionBased,
)
.then(
(value) => Future.delayed(
const Duration(milliseconds: 1),
),
)
.then((value) {
WidgetDetails? targetViewMain =
NudgeWidgetTracker.findWidgetPositionByLabel(
NudgeNudgesUi.componentName,
scaleWidth,
scaleHeight,
);
if (isPositionBased) {
// logger.e("Position Based");
NudgeNudgesUi.componentY = rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.elementProps!
.y
.roundToDouble() *
scaleHeight;
NudgeNudgesUi.componentX = rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.elementProps!
.x
.roundToDouble() *
scaleWidth;
NudgeNudgesUi.componentHeight = rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.elementProps!
.height
.roundToDouble() *
scaleHeight;
NudgeNudgesUi.componentWidth = rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.elementProps!
.width
.roundToDouble() *
scaleWidth;
// logger.i("""
// Component Height: ${NudgeNudgesUi.componentHeight},
// Component Width: ${NudgeNudgesUi.componentWidth},
// Component X: ${NudgeNudgesUi.componentX},
// Component Y: ${NudgeNudgesUi.componentY}
// """);
} else if (targetViewMain != null) {
NudgeNudgesUi.componentHeight = targetViewMain.height;
NudgeNudgesUi.componentWidth = targetViewMain.width;
NudgeNudgesUi.componentX = targetViewMain.x;
NudgeNudgesUi.componentY = targetViewMain.y;
}
var componentHeight = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.elementProps?.height ??
0;
var componentWidth = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.elementProps?.width ??
0;
var heightRatioDist = (NudgeNudgesUi.componentHeight / componentHeight);
var widthRatioDist = (NudgeNudgesUi.componentWidth / componentWidth);
ImageSize imageSize = extractSize(
rootData.rootProps.size,
);
try {
nudgeNudgesUi.heightRatio =
(MediaQuery.of(context).size.height / imageSize.height);
nudgeNudgesUi.widthRatio =
(MediaQuery.of(context).size.width / imageSize.width);
} catch (e) {
print(e);
}
double contentX = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.contentX!
.toDouble() *
widthRatioDist;
double contentY = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.contentY!
.toDouble() *
heightRatioDist;
Color fillColor = HexColor.fromHex(rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.overlayColor ??
"#000000")
.withOpacity(
rootData.components[NudgeNudgesUi.currentNudgeIndex].componentProps
.overlayOpacity! /
100,
);
// double bgOpacity = double.parse(
// rootData.components[NudgeNudgesUi.currentNudgeIndex].componentProps
// .overlayOpacity
// .toString(),
// );
double arrowImageX = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowX!
.toDouble() *
widthRatioDist;
double arrowImageY = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowY!
.toDouble() *
heightRatioDist;
// log("arrowImageX: $arrowImageX, arrowImageY: $arrowImageY", name: "Arrow");
overlayForegroundEntry = OverlayEntry(builder: (context) {
return Positioned(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Opacity(
opacity: 0,
child: ClipPath(
clipper: RectangularHoleClipper(
xPosition: NudgeNudgesUi.componentX,
yPosition: NudgeNudgesUi.componentY,
width: NudgeNudgesUi.componentWidth,
height: NudgeNudgesUi.componentHeight,
),
child: Stack(
children: [
GestureDetector(
onTap: () {
overlayForegroundEntry?.remove();
},
child: Container(
color: fillColor,
),
),
Positioned(
top: NudgeNudgesUi.componentY,
left: NudgeNudgesUi.componentX,
child: UIPage(
rootId: rootData.id,
taskId: NudgeNudgesUi.taskID!,
key: nudgeNudgesUi.contentKey,
nudgeProps: rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.toJson(),
type: () {
if (rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.orientation ==
"vertical") {
return 24;
} else {
return 25;
}
}(),
json: rootData
.components[NudgeNudgesUi.currentNudgeIndex].widgets!,
assetUrl: assetUrl,
assets: Nudge.assets,
),
),
rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowAsset !=
null &&
rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowAsset!.isNotEmpty
? Positioned(
top: NudgeNudgesUi.componentY +
NudgeNudgesUi.componentHeight / 2 -
arrowImageY,
left: NudgeNudgesUi.componentX +
NudgeNudgesUi.componentWidth / 2 -
arrowImageX,
child: rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!
.split("?")[0]
.isNotEmpty
? Image.network(
() {
if (rootData
.components[
NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!
.contains('.gif')) {
return rootData
.components[
NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!;
}
var asset = rootData
.components[
NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!
.split("?")[0];
if (asset.isEmpty) {
return "";
}
return assetUrl + asset;
}(),
fit: BoxFit.fill,
scale: 1.0,
height: rootData
.components[
NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowHeight!
.toDouble() *
nudgeNudgesUi.heightRatio,
width: rootData
.components[
NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowWidth!
.toDouble() *
nudgeNudgesUi.widthRatio,
)
: const SizedBox.shrink(),
)
: const SizedBox.shrink(),
],
),
),
),
);
});
NudgeProviderState.navigatorKey.currentState!.overlay!.insert(
overlayForegroundEntry!,
);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
double newTop;
double newLeft;
double newArrowTop;
double newArrowLeft;
try {
final RenderBox renderBox = nudgeNudgesUi.contentKey.currentContext!
.findRenderObject() as RenderBox;
NudgeNudgesUi.spotlightContainerHeight = renderBox.size.height;
NudgeNudgesUi.spotlightContainerWidth = renderBox.size.width;
// print(
// "Spotlight Container Height: ${NudgeNudgesUi.spotlightContainerHeight}");
// print(
// "Spotlight Container Width: ${NudgeNudgesUi.spotlightContainerWidth}");
var baseX = NudgeNudgesUi.componentX + NudgeNudgesUi.componentWidth / 2;
var baseY =
NudgeNudgesUi.componentY + NudgeNudgesUi.componentHeight / 2;
var contentHeight = NudgeNudgesUi.spotlightContainerHeight;
var contentWidth = NudgeNudgesUi.spotlightContainerWidth;
// print("Content Height: $contentHeight, Content Width: $contentWidth");
// print("Base X: $baseX, Base Y: $baseY");
// print("Content X: $contentX, Content Y: $contentY");
newTop = baseY - contentHeight / 2 + contentY;
newLeft = baseX - contentWidth / 2 + contentX;
var arrowHeight = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowHeight!
.toDouble() *
nudgeNudgesUi.heightRatio;
var arrowWidth = rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowWidth!
.toDouble() *
nudgeNudgesUi.widthRatio;
newArrowTop = baseY - arrowHeight / 2 + arrowImageY;
newArrowLeft = baseX - arrowWidth / 2 + arrowImageX;
overlayForegroundEntry?.remove();
// print("New Top: $newTop, New Left: $newLeft");
// print(
// "Component Y: ${NudgeNudgesUi.componentY}, Component X: ${NudgeNudgesUi.componentX}");
overlayForegroundEntry = OverlayEntry(builder: (context) {
return ClipPath(
clipper: RectangularHoleClipper(
xPosition: NudgeNudgesUi.componentX,
yPosition: NudgeNudgesUi.componentY,
width: NudgeNudgesUi.componentWidth,
height: NudgeNudgesUi.componentHeight,
),
child: Stack(
children: [
GestureDetector(
onTap: () {
overlayBackgroundEntry!.remove();
overlayForegroundEntry!.remove();
Nudge.getInstance().submit(
taskId: NudgeNudgesUi.taskID!,
response: [
{
"root_id": rootData.id,
"widget_id": rootData
.components[NudgeNudgesUi.currentNudgeIndex].id,
// "component_id": rootData
// .components[NudgeNudgesUi.currentNudgeIndex].id,
// "wt": null,
"answers": [],
"action": "DISMISSED",
}
],
onSuccessCallback: (response) {
print("Spotlight Dismissed, $response");
},
onErrorCallback: (error, stackTrace) {
print("Error: $error");
},
);
},
child: Container(
color: fillColor,
),
),
Positioned(
top: newArrowTop,
left: newArrowLeft,
child: rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowAsset !=
null &&
rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.spotlightArrowAsset !=
""
? Image.network(
() {
if (rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!
.contains('.gif')) {
return rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!;
}
var asset = rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowAsset!
.split("?")[0];
return assetUrl + asset;
}(),
fit: BoxFit.fill,
scale: 1.0,
height: rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowHeight!
.toDouble() *
nudgeNudgesUi.heightRatio,
width: rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.spotlightArrowWidth!
.toDouble() *
nudgeNudgesUi.widthRatio,
)
: const SizedBox(),
),
Positioned(
top: newTop,
left: newLeft,
child: UIPage(
rootId: rootData.id,
taskId: NudgeNudgesUi.taskID!,
callBack: ({widgetId, target, clickType, widgetType}) {
Nudge.getInstance().submit(
taskId: NudgeNudgesUi.taskID!,
response: [
{
"root_id": rootData.id,
"widget_id": rootData
.components[NudgeNudgesUi.currentNudgeIndex].id,
// "component_id": rootData
// .components[NudgeNudgesUi.currentNudgeIndex].id,
"wt": widgetType,
"answers": [],
"action": "CTA_CLICKED",
}
],
onSuccessCallback: (response) {
print("Spotlight CTA Clicked, $response");
},
onErrorCallback: (error, stackTrace) {
print("Error: $error");
},
);
if (clickType == "DEEP_LINK") {
_launchUrl(target!);
} else if (clickType == "EXTERNAL_URL") {
_launchUrl(target!);
} else if (clickType == "NEXT_NUDGE") {
if (NudgeNudgesUi.currentNudgeIndex ==
NudgeNudgesUi.nudgesLength - 1) {
overlayBackgroundEntry?.remove();
overlayForegroundEntry?.remove();
return;
}
NudgeNudgesUi.currentNudgeIndex++;
// print(
// "Next Nudge Index: ${NudgeNudgesUi.currentNudgeIndex}, type : ${rootData.components[NudgeNudgesUi.currentNudgeIndex].componentProps.name}");
if (rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.type ==
"spotlight") {
print("Spotlight");
overlayForegroundEntry?.remove();
overlayBackgroundEntry?.remove();
nudgeSpotlight(context, rootData, eventName);
} else if (rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.type ==
"coachmark") {
print("Coachmark");
overlayForegroundEntry?.remove();
overlayBackgroundEntry?.remove();
nudgeCoachMark(context, rootData, eventName);
} else if (rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.type ==
"tooltip") {
print("Tooltip");
overlayForegroundEntry?.remove();
overlayBackgroundEntry?.remove();
nudgeTooltip(context, rootData, eventName);
}
} else {
overlayBackgroundEntry?.remove();
overlayForegroundEntry?.remove();
}
},
// key: nudgeNudgesUi.contentKey,
nudgeProps: rootData
.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps
.toJson(),
// width: NudgeNudgesUi.spotlightContainerWidth,
type: () {
if (rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.orientation ==
"vertical") {
return 24;
} else {
return 25;
}
}(),
width: NudgeNudgesUi.spotlightContainerWidth -
(rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.padding.left) -
(rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.padding.right),
json: rootData
.components[NudgeNudgesUi.currentNudgeIndex].widgets!,
assetUrl: assetUrl,
assets: Nudge.assets,
),
),
],
),
);
});
logger.e("UPDATING NEXT CALLBACK, SPOTLIGHT!!!!");
Future<void> newNextCallback(nextRootId) async {
logger.e("NEXT CALLBACK, SPOTLIGHT!!!!, $nextRootId");
if (NudgeNudgesUi.currentNudgeIndex ==
NudgeNudgesUi.nudgesLength - 1) {
overlayBackgroundEntry?.remove();
overlayForegroundEntry?.remove();
return;
}
NudgeNudgesUi.currentNudgeIndex++;
if (rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.type ==
"spotlight") {
overlayForegroundEntry?.remove();
overlayBackgroundEntry?.remove();
nudgeSpotlight(context, rootData, eventName);
} else if (rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.type ==
"coachmark") {
overlayForegroundEntry?.remove();
overlayBackgroundEntry?.remove();
nudgeCoachMark(context, rootData, eventName);
} else if (rootData.components[NudgeNudgesUi.currentNudgeIndex]
.componentProps.type ==
"tooltip") {
overlayForegroundEntry?.remove();
overlayBackgroundEntry?.remove();
nudgeTooltip(context, rootData, eventName);
}
}
Future<void> newCloseCallback(param) async {
overlayBackgroundEntry?.remove();
overlayForegroundEntry?.remove();
}
CentralDataRepository.updateInstance(
NudgeNudgesUi.taskID!,
closeCallback: ({
rootId,
widgetId,
widgetType,
context,
}) async {
overlayBackgroundEntry?.remove();
overlayForegroundEntry?.remove();
Nudge.getInstance().submit(
taskId: NudgeNudgesUi.taskID!,
response: [
{
"root_id": rootData.id,
"widget_id":
rootData.components[NudgeNudgesUi.currentNudgeIndex].id,
"answers": [],
"action": "DISMISSED",
}
],
onSuccessCallback: (data) {},
onErrorCallback: (error, stacktrace) {},
);
},
nextCallBack: newNextCallback,
);
WidgetDetails? targetViewFinal =
NudgeWidgetTracker.findWidgetPositionByLabel(
NudgeNudgesUi.componentName,
scaleWidth,
scaleHeight,
);
if (targetViewFinal != null) {
if (targetViewFinal.x == NudgeNudgesUi.componentX &&
targetViewFinal.y == NudgeNudgesUi.componentY) {
NudgeProviderState.navigatorKey.currentState!.overlay!.insert(
overlayForegroundEntry!,
);
print(NudgeProviderState.navigatorKey.currentState!.overlay!);
}
} else if (isPositionBased) {
NudgeProviderState.navigatorKey.currentState?.overlay
?.insert(overlayForegroundEntry!);
}
} catch (e, st) {
print(e);
print(st);
}
});
}).catchError((e, stackTrace) {
log(e.toString(), name: 'NudgeSpotlight');
log(stackTrace.toString(), name: 'NudgeSpotlight');
});
}