@adadapted/react-native-sdk 3.1.12 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/.project +1 -1
- package/android/.settings/org.eclipse.buildship.core.prefs +2 -2
- package/android/bin/build.gradle +6 -5
- package/android/bin/gradle.properties +4 -4
- package/android/build.gradle +6 -5
- package/android/gradle.properties +3 -3
- package/android/src/main/AndroidManifest.xml +1 -3
- package/lib/commonjs/api/adadaptedApiRequests.js.map +1 -1
- package/lib/commonjs/api/adadaptedApiRequests.mock.js +25 -8
- package/lib/commonjs/api/adadaptedApiRequests.mock.js.map +1 -1
- package/lib/commonjs/api/adadaptedApiTypes.js +72 -26
- package/lib/commonjs/api/adadaptedApiTypes.js.map +1 -1
- package/lib/commonjs/components/AdZone.js +200 -129
- package/lib/commonjs/components/AdZone.js.map +1 -1
- package/lib/commonjs/components/ReportAdButton.js +38 -0
- package/lib/commonjs/components/ReportAdButton.js.map +1 -0
- package/lib/commonjs/images/ReportIcon.png +0 -0
- package/lib/commonjs/index.js +162 -78
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.js +4 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/util.js +13 -0
- package/lib/commonjs/util.js.map +1 -1
- package/lib/module/api/adadaptedApiRequests.js.map +1 -1
- package/lib/module/api/adadaptedApiRequests.mock.js +25 -9
- package/lib/module/api/adadaptedApiRequests.mock.js.map +1 -1
- package/lib/module/api/adadaptedApiTypes.js +70 -24
- package/lib/module/api/adadaptedApiTypes.js.map +1 -1
- package/lib/module/components/AdZone.js +192 -128
- package/lib/module/components/AdZone.js.map +1 -1
- package/lib/module/components/ReportAdButton.js +30 -0
- package/lib/module/components/ReportAdButton.js.map +1 -0
- package/lib/module/images/ReportIcon.png +0 -0
- package/lib/module/index.js +162 -77
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/util.js +14 -2
- package/lib/module/util.js.map +1 -1
- package/lib/typescript/example/index.d.ts +1 -0
- package/lib/typescript/example/index.d.ts.map +1 -0
- package/lib/typescript/example/src/App.d.ts +15 -62
- package/lib/typescript/example/src/App.d.ts.map +1 -0
- package/lib/typescript/example/src/OffScreenAdZone.d.ts +38 -0
- package/lib/typescript/example/src/OffScreenAdZone.d.ts.map +1 -0
- package/lib/typescript/example/src/StandardAdZone.d.ts +38 -0
- package/lib/typescript/example/src/StandardAdZone.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/jest.setup.d.ts +2 -1
- package/lib/typescript/jest.setup.d.ts.map +1 -0
- package/lib/typescript/src/api/adadaptedApiRequests.d.ts +1 -0
- package/lib/typescript/src/api/adadaptedApiRequests.d.ts.map +1 -0
- package/lib/typescript/src/api/adadaptedApiRequests.mock.d.ts +1 -0
- package/lib/typescript/src/api/adadaptedApiRequests.mock.d.ts.map +1 -0
- package/lib/typescript/src/api/adadaptedApiTypes.d.ts +9 -0
- package/lib/typescript/src/api/adadaptedApiTypes.d.ts.map +1 -0
- package/lib/typescript/src/components/AdZone.d.ts +9 -80
- package/lib/typescript/src/components/AdZone.d.ts.map +1 -0
- package/lib/typescript/src/components/ReportAdButton.d.ts +19 -0
- package/lib/typescript/src/components/ReportAdButton.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +39 -1
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +3 -2
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/util.d.ts +13 -0
- package/lib/typescript/src/util.d.ts.map +1 -0
- package/package.json +155 -155
- package/src/api/adadaptedApiRequests.mock.ts +25 -9
- package/src/api/adadaptedApiTypes.ts +8 -0
- package/src/components/AdZone.tsx +222 -173
- package/src/components/ReportAdButton.tsx +46 -0
- package/src/images/ReportIcon.png +0 -0
- package/src/index.tsx +160 -56
- package/src/util.ts +13 -0
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
5
|
import * as React from "react";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
DeviceEventEmitter,
|
|
8
|
+
Linking,
|
|
9
|
+
StyleSheet,
|
|
10
|
+
View,
|
|
11
|
+
ViewStyle,
|
|
12
|
+
} from "react-native";
|
|
7
13
|
import * as adadaptedApiRequests from "../api/adadaptedApiRequests";
|
|
8
14
|
import {
|
|
9
15
|
Ad,
|
|
@@ -15,6 +21,8 @@ import {
|
|
|
15
21
|
import { WebView } from "react-native-webview";
|
|
16
22
|
import { ApiEnv, DeviceOS } from "../index";
|
|
17
23
|
import { safeInvoke } from "../util";
|
|
24
|
+
import { useEffect, useState } from "react";
|
|
25
|
+
import { ReportAdButton } from "./ReportAdButton";
|
|
18
26
|
|
|
19
27
|
/**
|
|
20
28
|
* Props interface for {@link AdZone}.
|
|
@@ -58,20 +66,14 @@ interface Props {
|
|
|
58
66
|
* @param items - The array of items to "add to list".
|
|
59
67
|
*/
|
|
60
68
|
onAddToListTriggered?(items: DetailedListItem[]): void;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* State interface for {@link AdZone}.
|
|
65
|
-
*/
|
|
66
|
-
interface State {
|
|
67
69
|
/**
|
|
68
|
-
*
|
|
70
|
+
* Is the ad zone visible on render.
|
|
69
71
|
*/
|
|
70
|
-
|
|
72
|
+
offScreenAdZone: boolean;
|
|
71
73
|
/**
|
|
72
|
-
*
|
|
74
|
+
* Track the ad zone visibility in parent component. (for off-screen ads)
|
|
73
75
|
*/
|
|
74
|
-
|
|
76
|
+
isAdZoneVisible?: boolean;
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
/**
|
|
@@ -100,157 +102,174 @@ interface StyleDef {
|
|
|
100
102
|
* Styles for the WebView element.
|
|
101
103
|
*/
|
|
102
104
|
webView: ViewStyle;
|
|
105
|
+
/**
|
|
106
|
+
* Styles for the ReportAdButton.
|
|
107
|
+
*/
|
|
108
|
+
reportAd: ViewStyle;
|
|
103
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Timer used for cycling through ads in the zone
|
|
112
|
+
* based on the ad "refresh time" for each ad.
|
|
113
|
+
*/
|
|
114
|
+
let cycleAdTimer: ReturnType<typeof setTimeout> | undefined;
|
|
104
115
|
|
|
105
116
|
/**
|
|
106
117
|
* Creates the AdZone component.
|
|
118
|
+
* @param props - properties passed to AdZone.
|
|
119
|
+
* @returns an AdZone JSX Element.
|
|
107
120
|
*/
|
|
108
|
-
export
|
|
121
|
+
export function AdZone(props: Props): JSX.Element {
|
|
122
|
+
// Generates a random number between 0 and (number of available ads - 1).
|
|
123
|
+
const startingAdIndex = Math.floor(
|
|
124
|
+
Math.random() * props.adZoneData.ads.length
|
|
125
|
+
);
|
|
126
|
+
|
|
109
127
|
/**
|
|
110
|
-
*
|
|
111
|
-
* based on the ad "refresh time" for each ad.
|
|
128
|
+
* Tracks the current ad index being shown.
|
|
112
129
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
130
|
+
const [adIndexShown, setAdIndexShown] = useState(startingAdIndex);
|
|
131
|
+
/**
|
|
132
|
+
* Tracks the coordinates when the user started touching the Ad View.
|
|
133
|
+
*/
|
|
134
|
+
const [touchStartCoords, setTouchStartCoords] = useState({ x: 0, y: 0 });
|
|
115
135
|
/**
|
|
116
|
-
*
|
|
136
|
+
* Track ad visibility (for off-screen ads).
|
|
117
137
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
138
|
+
const [isAdVisible, setIsAdVisibile] = useState(props.isAdZoneVisible);
|
|
139
|
+
|
|
140
|
+
// Setup device listeners.
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
DeviceEventEmitter.addListener("visibility-event", (event: boolean) => {
|
|
143
|
+
setIsAdVisibile(event);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
DeviceEventEmitter.addListener("acknowledge", (itemName: string) => {
|
|
147
|
+
acknowledge(itemName);
|
|
148
|
+
});
|
|
120
149
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
150
|
+
if (props.offScreenAdZone && isAdVisible) {
|
|
151
|
+
sendAdImpression();
|
|
152
|
+
} else if (!props.offScreenAdZone) {
|
|
153
|
+
sendAdImpression();
|
|
154
|
+
}
|
|
125
155
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
156
|
+
return () => {
|
|
157
|
+
clearTimeout(cycleAdTimer);
|
|
158
|
+
DeviceEventEmitter.removeAllListeners("visibility-event");
|
|
159
|
+
DeviceEventEmitter.removeAllListeners("acknowledge");
|
|
129
160
|
};
|
|
130
|
-
|
|
161
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
162
|
+
}, []);
|
|
131
163
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
164
|
+
// Send impression on ad cycle.
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
startAdTimer();
|
|
167
|
+
if (props.offScreenAdZone && isAdVisible) {
|
|
168
|
+
sendAdImpression();
|
|
169
|
+
} else if (!props.offScreenAdZone) {
|
|
170
|
+
sendAdImpression();
|
|
171
|
+
}
|
|
172
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
+
}, [adIndexShown]);
|
|
138
174
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
|
|
175
|
+
// Send impression based on visibility change. (for off-screen ads)
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
if (props.offScreenAdZone && isAdVisible) {
|
|
178
|
+
sendAdImpression();
|
|
179
|
+
} else if (!props.offScreenAdZone) {
|
|
180
|
+
sendAdImpression();
|
|
145
181
|
}
|
|
146
|
-
|
|
182
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
183
|
+
}, [isAdVisible]);
|
|
147
184
|
|
|
148
185
|
/**
|
|
149
|
-
*
|
|
186
|
+
* Generates all component related styles.
|
|
187
|
+
* @returns the styles needed for the component.
|
|
150
188
|
*/
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
<WebView
|
|
169
|
-
source={{
|
|
170
|
-
uri: currentAd.creative_url,
|
|
171
|
-
}}
|
|
172
|
-
androidLayerType="hardware"
|
|
173
|
-
automaticallyAdjustContentInsets={false}
|
|
174
|
-
style={styles.webView}
|
|
175
|
-
onTouchStart={(e) => {
|
|
176
|
-
this.setState({
|
|
177
|
-
touchStartCoords: {
|
|
178
|
-
x: e.nativeEvent.pageX,
|
|
179
|
-
y: e.nativeEvent.pageY,
|
|
180
|
-
},
|
|
181
|
-
});
|
|
182
|
-
}}
|
|
183
|
-
onTouchEnd={(e) => {
|
|
184
|
-
if (this.state.touchStartCoords) {
|
|
185
|
-
const touchEndCoords: TouchCoordinates = {
|
|
186
|
-
x: e.nativeEvent.pageX,
|
|
187
|
-
y: e.nativeEvent.pageY,
|
|
188
|
-
};
|
|
189
|
+
function generateStyles(): StyleDef {
|
|
190
|
+
return StyleSheet.create({
|
|
191
|
+
mainView: {
|
|
192
|
+
width: "100%",
|
|
193
|
+
height: "100%",
|
|
194
|
+
},
|
|
195
|
+
webView: {
|
|
196
|
+
width: "100%",
|
|
197
|
+
height: "100%",
|
|
198
|
+
},
|
|
199
|
+
reportAd: {
|
|
200
|
+
position: "absolute",
|
|
201
|
+
top: 10,
|
|
202
|
+
right: 10,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
}
|
|
189
206
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.state.touchStartCoords.y -
|
|
197
|
-
touchEndCoords.y
|
|
198
|
-
) < this.props.xyDragDistanceAllowed
|
|
199
|
-
) {
|
|
200
|
-
this.onAdZoneSelected(currentAd);
|
|
201
|
-
}
|
|
207
|
+
// Generate the styles each render in case the ad is updated with
|
|
208
|
+
// new settings that need to be reflected in the styles of the view.
|
|
209
|
+
const styles = generateStyles();
|
|
210
|
+
const currentAd: Ad | undefined =
|
|
211
|
+
props.adZoneData.ads[adIndexShown] || undefined;
|
|
212
|
+
const finalMainViewStyle = styles.mainView;
|
|
202
213
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
}}
|
|
209
|
-
/>
|
|
210
|
-
) : undefined}
|
|
211
|
-
</View>
|
|
212
|
-
);
|
|
214
|
+
if (!currentAd || !currentAd.creative_url) {
|
|
215
|
+
// If there is no ad to display, make the view take up no space.
|
|
216
|
+
finalMainViewStyle.width = 0;
|
|
217
|
+
finalMainViewStyle.height = 0;
|
|
213
218
|
}
|
|
214
219
|
|
|
215
220
|
/**
|
|
216
221
|
* Triggers when the user selects the ad zone.
|
|
217
|
-
* @param
|
|
222
|
+
* @param currentlyDisplayedAd - The ad currently displayed.
|
|
218
223
|
*/
|
|
219
|
-
|
|
224
|
+
function onAdZoneSelected(currentlyDisplayedAd: Ad): void {
|
|
220
225
|
// Determine the "action type" and perform that specific action.
|
|
221
226
|
if (
|
|
222
|
-
|
|
223
|
-
|
|
227
|
+
currentlyDisplayedAd.action_type === AdActionType.EXTERNAL &&
|
|
228
|
+
currentlyDisplayedAd.action_path
|
|
224
229
|
) {
|
|
225
230
|
// Action Type: EXTERNAL
|
|
226
|
-
Linking.openURL(
|
|
231
|
+
Linking.openURL(currentlyDisplayedAd.action_path).then();
|
|
227
232
|
} else if (
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
233
|
+
currentlyDisplayedAd.action_type === AdActionType.CONTENT &&
|
|
234
|
+
currentlyDisplayedAd.payload &&
|
|
235
|
+
currentlyDisplayedAd.payload.detailed_list_items
|
|
231
236
|
) {
|
|
232
237
|
safeInvoke(
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
props.onAddToListTriggered,
|
|
239
|
+
currentlyDisplayedAd.payload.detailed_list_items
|
|
235
240
|
);
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
243
|
+
cycleDisplayedAd();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Call to acknowledge ATL item(s) added to user list.
|
|
248
|
+
* @param itemName - Detailed list item title from ad that was clicked.
|
|
249
|
+
*/
|
|
250
|
+
function acknowledge(itemName: string): void {
|
|
251
|
+
if (props.adZoneData.ads) {
|
|
252
|
+
props.adZoneData.ads.forEach((ad) => {
|
|
253
|
+
if (ad.action_type === "c") {
|
|
254
|
+
ad.payload.detailed_list_items.forEach((item) => {
|
|
255
|
+
if (item.product_title === itemName) {
|
|
256
|
+
triggerReportAdEvent(
|
|
257
|
+
ad,
|
|
258
|
+
ReportedEventType.INTERACTION
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
241
264
|
}
|
|
242
|
-
this.cycleDisplayedAd();
|
|
243
265
|
}
|
|
244
266
|
|
|
245
267
|
/**
|
|
246
268
|
* Triggered when we need to report an ad event to the API.
|
|
247
|
-
* @param
|
|
269
|
+
* @param ad - The ad to send an event for.
|
|
248
270
|
* @param eventType - The event type for the reported event.
|
|
249
271
|
*/
|
|
250
|
-
|
|
251
|
-
currentAd: Ad,
|
|
252
|
-
eventType: ReportedEventType
|
|
253
|
-
): void {
|
|
272
|
+
function triggerReportAdEvent(ad: Ad, eventType: ReportedEventType): void {
|
|
254
273
|
// The event timestamp has to be sent as a unix timestamp.
|
|
255
274
|
const currentTs = Math.round(new Date().getTime() / 1000);
|
|
256
275
|
|
|
@@ -258,20 +277,20 @@ export class AdZone extends React.Component<Props, State> {
|
|
|
258
277
|
adadaptedApiRequests
|
|
259
278
|
.reportAdEvent(
|
|
260
279
|
{
|
|
261
|
-
app_id:
|
|
262
|
-
session_id:
|
|
263
|
-
udid:
|
|
280
|
+
app_id: props.appId,
|
|
281
|
+
session_id: props.sessionId,
|
|
282
|
+
udid: props.udid,
|
|
264
283
|
events: [
|
|
265
284
|
{
|
|
266
|
-
ad_id:
|
|
267
|
-
impression_id:
|
|
285
|
+
ad_id: ad.ad_id,
|
|
286
|
+
impression_id: ad.impression_id,
|
|
268
287
|
event_type: eventType,
|
|
269
288
|
created_at: currentTs,
|
|
270
289
|
},
|
|
271
290
|
],
|
|
272
291
|
},
|
|
273
|
-
|
|
274
|
-
|
|
292
|
+
props.deviceOs,
|
|
293
|
+
props.apiEnv
|
|
275
294
|
)
|
|
276
295
|
.then(() => {
|
|
277
296
|
// Do nothing with the response for now...
|
|
@@ -280,69 +299,99 @@ export class AdZone extends React.Component<Props, State> {
|
|
|
280
299
|
|
|
281
300
|
/**
|
|
282
301
|
* Generates a new timer for cycling to the next ad.
|
|
283
|
-
* @param timerLength - The length of time(in milliseconds) to initialize
|
|
284
|
-
* the timer with.
|
|
285
302
|
*/
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
303
|
+
function startAdTimer(): void {
|
|
304
|
+
clearTimeout(cycleAdTimer);
|
|
305
|
+
|
|
306
|
+
if (props.adZoneData.ads.length > 0) {
|
|
307
|
+
const refreshTime: number =
|
|
308
|
+
props.adZoneData.ads[adIndexShown].refresh_time * 1000;
|
|
309
|
+
cycleAdTimer = setTimeout(cycleDisplayedAd, refreshTime);
|
|
291
310
|
}
|
|
292
311
|
}
|
|
293
312
|
|
|
294
313
|
/**
|
|
295
314
|
* Cycles to the next ad to display in the current available sequence of ads.
|
|
296
315
|
*/
|
|
297
|
-
|
|
316
|
+
function cycleDisplayedAd(): void {
|
|
298
317
|
// Start by determining the next ad index to display.
|
|
299
318
|
let nextAdIndex = 0;
|
|
319
|
+
const lastAd = props.adZoneData.ads[adIndexShown];
|
|
300
320
|
|
|
301
|
-
if (
|
|
302
|
-
nextAdIndex =
|
|
321
|
+
if (adIndexShown < props.adZoneData.ads.length - 1) {
|
|
322
|
+
nextAdIndex = adIndexShown + 1;
|
|
303
323
|
}
|
|
304
324
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
325
|
+
if (nextAdIndex !== adIndexShown && lastAd.impression_tracked) {
|
|
326
|
+
// Reset ad impression tracking status.
|
|
327
|
+
lastAd.impression_tracked = false;
|
|
328
|
+
} else {
|
|
329
|
+
// Send invisible ad impression if ad was not visible before end of timer cycle.
|
|
330
|
+
triggerReportAdEvent(
|
|
331
|
+
lastAd,
|
|
332
|
+
ReportedEventType.INVISIBLE_IMPRESSION
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
setAdIndexShown(nextAdIndex);
|
|
313
337
|
}
|
|
314
338
|
|
|
315
339
|
/**
|
|
316
|
-
*
|
|
340
|
+
* Send ad tracking impression.
|
|
317
341
|
*/
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
this.createAdTimer(
|
|
321
|
-
this.props.adZoneData.ads[this.state.adIndexShown].refresh_time *
|
|
322
|
-
1000
|
|
323
|
-
);
|
|
342
|
+
function sendAdImpression(): void {
|
|
343
|
+
const ad = props.adZoneData.ads[adIndexShown];
|
|
324
344
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
);
|
|
345
|
+
if (!ad.impression_tracked) {
|
|
346
|
+
triggerReportAdEvent(ad, ReportedEventType.IMPRESSION);
|
|
347
|
+
ad.impression_tracked = true;
|
|
348
|
+
}
|
|
330
349
|
}
|
|
331
350
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
351
|
+
// Returned JSX.
|
|
352
|
+
return (
|
|
353
|
+
<View style={finalMainViewStyle}>
|
|
354
|
+
{currentAd && currentAd.creative_url ? (
|
|
355
|
+
<WebView
|
|
356
|
+
source={{
|
|
357
|
+
uri: currentAd.creative_url,
|
|
358
|
+
}}
|
|
359
|
+
androidLayerType="hardware"
|
|
360
|
+
automaticallyAdjustContentInsets={false}
|
|
361
|
+
style={styles.webView}
|
|
362
|
+
onTouchStart={(e) => {
|
|
363
|
+
setTouchStartCoords({
|
|
364
|
+
x: e.nativeEvent.pageX,
|
|
365
|
+
y: e.nativeEvent.pageY,
|
|
366
|
+
});
|
|
367
|
+
}}
|
|
368
|
+
onTouchEnd={(e) => {
|
|
369
|
+
if (touchStartCoords) {
|
|
370
|
+
const touchEndCoords: TouchCoordinates = {
|
|
371
|
+
x: e.nativeEvent.pageX,
|
|
372
|
+
y: e.nativeEvent.pageY,
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
if (
|
|
376
|
+
Math.abs(
|
|
377
|
+
touchStartCoords.x - touchEndCoords.x
|
|
378
|
+
) < props.xyDragDistanceAllowed &&
|
|
379
|
+
Math.abs(
|
|
380
|
+
touchStartCoords.y - touchEndCoords.y
|
|
381
|
+
) < props.xyDragDistanceAllowed
|
|
382
|
+
) {
|
|
383
|
+
onAdZoneSelected(currentAd);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Make sure to reset the start coords
|
|
387
|
+
setTouchStartCoords({ x: 0, y: 0 });
|
|
388
|
+
}
|
|
389
|
+
}}
|
|
390
|
+
/>
|
|
391
|
+
) : undefined}
|
|
392
|
+
<View style={styles.reportAd}>
|
|
393
|
+
<ReportAdButton adId={currentAd.ad_id} udid={props.udid} />
|
|
394
|
+
</View>
|
|
395
|
+
</View>
|
|
396
|
+
);
|
|
348
397
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { Image, Linking, StyleSheet, TouchableOpacity } from "react-native";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/**
|
|
6
|
+
* The ad id of the current ad.
|
|
7
|
+
*/
|
|
8
|
+
adId: string;
|
|
9
|
+
/**
|
|
10
|
+
* The current user's udid.
|
|
11
|
+
*/
|
|
12
|
+
udid: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates the ReportAdButton component.
|
|
17
|
+
* @param props The component's props.
|
|
18
|
+
* @returns a reportSdButton JSX Element.
|
|
19
|
+
*/
|
|
20
|
+
export function ReportAdButton(props: Props): JSX.Element {
|
|
21
|
+
const reportAdUrlBase = new URL("https://feedback.add-it.io/");
|
|
22
|
+
|
|
23
|
+
const styles = StyleSheet.create({
|
|
24
|
+
buttonStyle: {
|
|
25
|
+
width: 14,
|
|
26
|
+
height: 14,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
reportAdUrlBase.searchParams.append("aid", props.adId);
|
|
32
|
+
reportAdUrlBase.searchParams.append("uid", props.udid);
|
|
33
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
|
+
}, [props]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<TouchableOpacity
|
|
38
|
+
style={styles.buttonStyle}
|
|
39
|
+
onPress={() => {
|
|
40
|
+
Linking.openURL(reportAdUrlBase.toString());
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<Image source={require("../images/ReportIcon.png")} />
|
|
44
|
+
</TouchableOpacity>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
Binary file
|