@cardsjd/portal 0.1.1 → 0.1.3

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/README.md CHANGED
Binary file
@@ -0,0 +1,193 @@
1
+ import {
2
+ AdMob, AdmobConsentStatus, InterstitialAdPluginEvents, RewardAdPluginEvents,
3
+ } from '@capacitor-community/admob';
4
+
5
+ import { BasePortal } from './BasePortal';
6
+
7
+ export class AdMobPortal extends BasePortal {
8
+ name = 'AdMobPortal';
9
+ autoLogin = false;
10
+
11
+ constructor(appConfig) {
12
+ super();
13
+ this.appConfig = appConfig;
14
+
15
+ // Ad callback properties
16
+ this.onAdLoaded = null;
17
+ this.onAdOpened = null;
18
+ this.onAdClosed = null;
19
+ this.onAdError = null;
20
+ this.onAdRewarded = null;
21
+
22
+ this.adProviderName = 'CapacitorAdmob';
23
+ this.isSetup = false;
24
+ this.isSetupLoading = false;
25
+ this.isInterstitialAdReady = false;
26
+ this._isRewardedAdLoaded = false;
27
+ this._receivedReward = false;
28
+ this._rewardInfo = null;
29
+ this.isTesting = false;
30
+ }
31
+
32
+ // ----- Ad methods -----
33
+
34
+ async setupAds() {
35
+ if (this.isSetup) {
36
+ console.log('CapacitorAdmob is already setup');
37
+ return;
38
+ }
39
+
40
+ if (this.isSetupLoading) {
41
+ throw Error('Capacitor AdMob setup is in progress already');
42
+ }
43
+
44
+ this.isSetupLoading = true;
45
+
46
+ await AdMob.initialize({
47
+ initializeForTesting: this.isTesting,
48
+ testingDevices: [],
49
+ });
50
+
51
+ const trackingInfo = await AdMob.trackingAuthorizationStatus();
52
+ let consentInfo;
53
+ try {
54
+ consentInfo = await AdMob.requestConsentInfo();
55
+ } catch (error) {
56
+ console.error('Failed to get consent info:', error);
57
+ consentInfo = {
58
+ isConsentFormAvailable: false,
59
+ status: null,
60
+ };
61
+ }
62
+
63
+ if (trackingInfo.status === 'notDetermined') {
64
+ await AdMob.requestTrackingAuthorization();
65
+ }
66
+
67
+ const authorizationStatus = await AdMob.trackingAuthorizationStatus();
68
+
69
+ if (
70
+ authorizationStatus.status === 'authorized' &&
71
+ consentInfo.isConsentFormAvailable &&
72
+ consentInfo.status === AdmobConsentStatus.REQUIRED
73
+ ) {
74
+ await AdMob.showConsentForm();
75
+ }
76
+
77
+ AdMob.addListener(InterstitialAdPluginEvents.Loaded, () => {
78
+ this.isInterstitialAdReady = true;
79
+ });
80
+ AdMob.addListener(InterstitialAdPluginEvents.Showed, () => {
81
+ this.isInterstitialAdReady = false;
82
+ if (this.onAdOpened) {
83
+ this.onAdOpened({
84
+ adType: 'interstitial',
85
+ adProvider: this.adProviderName,
86
+ });
87
+ }
88
+ });
89
+ AdMob.addListener(InterstitialAdPluginEvents.Dismissed, () => {
90
+ this.isInterstitialAdReady = false;
91
+ if (this.onAdClosed) {
92
+ this.onAdClosed({
93
+ adType: 'interstitial',
94
+ adProvider: this.adProviderName,
95
+ });
96
+ }
97
+ });
98
+ AdMob.addListener(InterstitialAdPluginEvents.FailedToLoad, () => {
99
+ if (this.onAdError) {
100
+ this.onAdError(new Error('InterstitialAd failed to load'));
101
+ }
102
+ });
103
+ AdMob.addListener(RewardAdPluginEvents.Loaded, () => {
104
+ this._isRewardedAdLoaded = true;
105
+ this._receivedReward = false;
106
+ this._rewardInfo = null;
107
+ });
108
+ AdMob.addListener(RewardAdPluginEvents.Rewarded, (info) => {
109
+ this._receivedReward = true;
110
+ this._rewardInfo = info;
111
+ });
112
+ AdMob.addListener(RewardAdPluginEvents.Dismissed, () => {
113
+ this._isRewardedAdLoaded = false;
114
+ if (this.onAdClosed) {
115
+ this.onAdClosed({
116
+ adType: 'rewarded',
117
+ adProvider: this.adProviderName,
118
+ });
119
+ }
120
+
121
+ if (this._receivedReward && this.onAdRewarded) {
122
+ this.onAdRewarded(this._rewardInfo);
123
+ }
124
+ });
125
+ AdMob.addListener(RewardAdPluginEvents.FailedToLoad, () => {
126
+ if (this.onAdError) {
127
+ this.onAdError(new Error('RewardAd failed to load'));
128
+ }
129
+ });
130
+
131
+ this.isSetup = true;
132
+ this.isSetupLoading = false;
133
+ }
134
+
135
+ isAdLoaded() {
136
+ return this.isInterstitialAdReady;
137
+ }
138
+
139
+ isRewardedAdLoaded() {
140
+ return this._isRewardedAdLoaded;
141
+ }
142
+
143
+ async loadInterstitialAd() {
144
+ if (this.isSetup === false) {
145
+ return;
146
+ }
147
+
148
+ if (this.isAdLoaded()) {
149
+ return;
150
+ }
151
+
152
+ return AdMob.prepareInterstitial({
153
+ adId: this.appConfig?.interstitialAdId,
154
+ });
155
+ }
156
+
157
+ async showInterstitialAd() {
158
+ if (!this.isAdLoaded()) {
159
+ await this.loadInterstitialAd();
160
+ return; // no auto show
161
+ }
162
+
163
+ this.isInterstitialAdReady = false;
164
+ return AdMob.showInterstitial();
165
+ }
166
+
167
+ async loadRewardedAd() {
168
+ if (this.isSetup === false) {
169
+ return;
170
+ }
171
+
172
+ if (this.isRewardedAdLoaded()) {
173
+ return;
174
+ }
175
+
176
+ return AdMob.prepareRewardVideoAd({
177
+ adId: this.appConfig?.rewardedAdId,
178
+ });
179
+ }
180
+
181
+ async showRewardedAd() {
182
+ if (this.isSetup === false) {
183
+ return;
184
+ }
185
+
186
+ if (!this.isRewardedAdLoaded()) {
187
+ await this.loadRewardedAd();
188
+ }
189
+
190
+ this._isRewardedAdLoaded = false;
191
+ return AdMob.showRewardVideoAd();
192
+ }
193
+ }
@@ -0,0 +1,99 @@
1
+ export class Advertisement {
2
+ isInterstitialAdReady(options) {
3
+ //only load/show if ads enabled
4
+ if (this.isSetup === false) { return; }
5
+
6
+ const config = this.config;
7
+ const offsetStartdelay = options?.offsetStartdelay || config.offsetStartdelay || 120; //start with 1 min passed to get the first ad to show faster
8
+ const delayBetweenAds = options?.delayBetweenAds || config.delayBetweenAds || 240; //check for 240 (4 min) seconds passed was 180
9
+ const awayResetTime = options?.awayResetTime || config.awayResetTime || 1200; //check if over 20 min, may have not been in the app and reopened it with out restarting
10
+ const delayBetweenRewardedAds = options?.delayBetweenRewardedAds || config.delayBetweenRewardedAds || 300; //check for 600 seconds passed
11
+
12
+
13
+ //0. if ads removed, dont even load the ad
14
+ //1. only allow ad to be shown/loaded once every 150 second (Advertisement.delayBetweenAds)
15
+ //2. check if over 20 min, may have not been in the app and reopened it with out restarting
16
+ //3. load ad ether way
17
+ //4. show ad if conditions met
18
+ if (this.removeAds) { return false; }
19
+
20
+ let readyToShowAd = false;
21
+
22
+ //reset timer
23
+ if (this.lastShownInterstitial === null) {
24
+ this.lastShownInterstitial = Date.now();//now
25
+ //add start offset delay
26
+ const newDate = new Date();
27
+ newDate.setSeconds(newDate.getSeconds() - offsetStartdelay);
28
+ this.lastShownInterstitial = newDate;
29
+ }
30
+
31
+ const secondsSinceLastAd = (Date.now() - this.lastShownInterstitial) / 1000;
32
+
33
+ //check for delayBetweenAds seconds passed
34
+ if (secondsSinceLastAd > delayBetweenAds) {
35
+ readyToShowAd = true;
36
+ }
37
+
38
+ //check if over 20 min, may have not been in the app and reopened it with out restarting
39
+ if (secondsSinceLastAd > awayResetTime) {
40
+ readyToShowAd = false;
41
+ this.lastShownInterstitial = Date.now();//now, reset
42
+ }
43
+
44
+ console.log('readyToShowInterstitialAd: ' + readyToShowAd + ' : ' + secondsSinceLastAd + ' of ' + delayBetweenAds);
45
+
46
+ // show ad or just load ad
47
+ if (readyToShowAd) {
48
+ true;
49
+ } else {
50
+ false;
51
+ }
52
+ }
53
+ async showAppOpenAdWithMaxDelay(maxDelay) {
54
+ if (this.isSetUp === false) { return; }
55
+ if (this.adProvider == null) { return; }
56
+
57
+
58
+
59
+ if (!maxDelay) {
60
+ maxDelay = 4000;
61
+ }
62
+
63
+ //todo: fix if long loader time than maxDelay, then skip ad
64
+ //something like this:
65
+ //return new Promise(async (resolve, reject) => {
66
+ // if (this.adProvider && this.adProvider.showAppOpenAd) {
67
+ // timeoutPromise = setTimeout(() => {
68
+ // //stop ad from showing
69
+ // if (this.adProvider) this.adProvider.appOpenAdAutoShow = false;
70
+ // reject(new Error('showAppOpenAd has not fired after 4 seconds. Skipping ad'));
71
+ // }, maxDelay);
72
+ // await this.adProvider.showAppOpenAd();
73
+ // clearTimeout(timeoutPromise);
74
+ // resolve();
75
+ // }
76
+ // else {
77
+ // reject();
78
+ // }
79
+
80
+
81
+ //get start time
82
+ const startTime = Date.now();
83
+ if (this.adProvider.loadAppOpenAd) {
84
+ await this.adProvider.loadAppOpenAd();
85
+ }
86
+
87
+ //this wont work...
88
+ //is timer over maxDelay
89
+ const timePassed = Date.now() - startTime;
90
+ if (timePassed > maxDelay) {
91
+ console.log(`showAppOpenAdWithMaxDelay took too long to load [${timePassed}ms/${maxDelay}ms], skipping ad`);
92
+ return;
93
+ }
94
+
95
+ if (this.adProvider.showAppOpenAd) {
96
+ await this.adProvider.showAppOpenAd();
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,17 @@
1
+ import { AdMobPortal } from './AdMobPortal';
2
+
3
+ export class AndroidPortal extends AdMobPortal {
4
+ name = 'AndroidPortal';
5
+
6
+ updateConfig(config = {}, adConfig = {}) {
7
+ const configToUpdate = structuredClone(config);
8
+
9
+ // Map android-specific ad config items to generic "ad" config items
10
+ configToUpdate.interstitialAdId = adConfig.admobInterstitialAdId_Android;
11
+ configToUpdate.rewardedAdId = adConfig.admobRewardedAdId_Android;
12
+ configToUpdate.appOpenAdId = adConfig.admobAppOpenAdId_Android;
13
+ configToUpdate.appId = adConfig.admobAppId_Android;
14
+
15
+ return configToUpdate;
16
+ }
17
+ }
package/lib/BasePortal.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Advertisement } from './Advertisement.js';
1
2
  export class BasePortal {
2
3
 
3
4
  async init() { }
@@ -5,7 +6,7 @@ export class BasePortal {
5
6
  async load() { }
6
7
 
7
8
  async save(data, forceSave) { }
8
-
9
+
9
10
  async delete() { }
10
11
 
11
12
  gameStart() { }
@@ -16,6 +17,8 @@ export class BasePortal {
16
17
 
17
18
  loadStop() { }
18
19
 
20
+ subscribeBot() { }
21
+
19
22
  async getInvite() { }
20
23
 
21
24
  async inviteSend(user, room) { }
@@ -24,7 +27,36 @@ export class BasePortal {
24
27
 
25
28
  async getFriends() { }
26
29
 
27
- tryShowInterstitialAd() { }
30
+ tryShowInterstitialAd(options) {
31
+ const readyToShowAd = Advertisement.isInterstitialAdReady(options);
32
+ if (readyToShowAd) {
33
+ this.showInterstitialAd();
34
+ } else {
35
+ this.loadInterstitialAd();
36
+ }
37
+ }
38
+
39
+ setupAds() { }
40
+
41
+ loadInterstitialAd(_force) { }
42
+
43
+ showInterstitialAd() { }
44
+
45
+ loadRewardedAd(_onLoaded) { }
46
+
47
+ showRewardedAd() { }
48
+
49
+ loadAppOpenAd() { }
50
+
51
+ showAppOpenAd(maxDelay) { }
52
+
53
+ isAdLoaded() { }
54
+
55
+ isRewardedAdLoaded() { }
56
+
57
+ logError(_errorCode) { }
58
+
59
+ isErrorState() { }
28
60
 
29
61
  createShortCut() { }
30
62
  }
@@ -7,6 +7,21 @@ export class CrazyGamesPortal extends BasePortal {
7
7
  hideSuggestions = false;
8
8
  hideReportBug = false;
9
9
 
10
+ constructor(appConfig) {
11
+ super();
12
+ this.appConfig = appConfig;
13
+
14
+ // Ad callback properties
15
+ this.onAdLoaded = null;
16
+ this.onAdOpened = null;
17
+ this.onAdClosed = null;
18
+ this.onAdError = null;
19
+ this.onAdRewarded = null;
20
+
21
+ this.adProviderName = 'crazygames';
22
+ this.isSetup = false;
23
+ }
24
+
10
25
  async init() {
11
26
  try {
12
27
  await import('https://sdk.crazygames.com/crazygames-sdk-v3.js');
@@ -18,17 +33,24 @@ export class CrazyGamesPortal extends BasePortal {
18
33
  }
19
34
 
20
35
  }
36
+
21
37
  isCrazyGames() {
22
- if (typeof globalThis.CrazyGames === 'undefined') return false;
23
- if (!globalThis.CrazyGames.SDK) return false;
24
- if (globalThis.CrazyGames.SDK.environment === "disabled") {
38
+ if (typeof globalThis.CrazyGames === 'undefined' || !globalThis.CrazyGames.SDK) {
39
+ return false;
40
+ }
41
+
42
+ if (globalThis.CrazyGames.SDK.environment === 'disabled') {
25
43
  console.log('CrazyGames SDK is disabled');
26
44
  return false;
27
45
  }
46
+
28
47
  return true;
29
48
  }
49
+
30
50
  async load() {
31
- if (!this.isCrazyGames()) return;
51
+ if (!this.isCrazyGames()) {
52
+ return;
53
+ }
32
54
 
33
55
  const data = {};
34
56
  try {
@@ -37,34 +59,46 @@ export class CrazyGamesPortal extends BasePortal {
37
59
  } catch (err) {
38
60
  console.warn('Failed to call CrazyGames SDK load:', err);
39
61
  }
62
+
40
63
  return data;
41
64
  }
42
- async save(data, forceSave) {
65
+
66
+ async save(data, _forceSave) {
43
67
  if (!this.isCrazyGames()) {
44
68
  return;
45
69
  }
46
70
 
47
71
  const sdk = globalThis.CrazyGames.SDK;
48
- if (!sdk.data) return;
72
+ if (!sdk.data) {
73
+ return;
74
+ }
49
75
 
50
- sdk.data.setItem("userdata", JSON.stringify(data));
76
+ sdk.data.setItem('userdata', JSON.stringify(data));
51
77
 
52
78
  }
79
+
53
80
  async delete() {
54
81
  if (!this.isCrazyGames()) {
55
82
  return;
56
83
  }
84
+
57
85
  const sdk = globalThis.CrazyGames.SDK;
58
- if (!sdk.data) return;
86
+ if (!sdk.data) {
87
+ return;
88
+ }
59
89
 
60
90
  sdk.data.clear();
61
91
  }
92
+
62
93
  async loadData() {
63
94
  if (!this.isCrazyGames()) {
64
95
  return null;
65
96
  }
97
+
66
98
  const sdk = globalThis.CrazyGames.SDK;
67
- if (!sdk.data) return null;
99
+ if (!sdk.data) {
100
+ return null;
101
+ }
68
102
 
69
103
  //get userdata from crazygames storage - and get newest data
70
104
  const userdata_crazyGame_string = sdk.data.getItem('userdata');
@@ -81,15 +115,16 @@ export class CrazyGamesPortal extends BasePortal {
81
115
  }
82
116
 
83
117
  }
118
+
84
119
  async loadUser() {
85
120
  if (!this.isCrazyGames()) {
86
121
  return null;
87
122
  }
88
123
 
89
124
  const sdk = globalThis.CrazyGames.SDK;
90
- if (!sdk.data) return null;
91
-
92
-
125
+ if (!sdk.data) {
126
+ return null;
127
+ }
93
128
 
94
129
  if (!sdk.user.isUserAccountAvailable) {
95
130
  return null;
@@ -109,6 +144,7 @@ export class CrazyGamesPortal extends BasePortal {
109
144
  user.name = userdetails.username;
110
145
  user.crazyGamesId = userdetails.username; //use username for now, not actual userid from crazy games, too many steps and higher risk of failure
111
146
  }
147
+
112
148
  if (userdetails?.profilePictureUrl) {
113
149
  user.avatar = userdetails.profilePictureUrl;
114
150
  }
@@ -131,7 +167,6 @@ export class CrazyGamesPortal extends BasePortal {
131
167
  // // // }
132
168
  // // // } catch (e) { }
133
169
 
134
-
135
170
  return user;
136
171
  }
137
172
 
@@ -187,4 +222,155 @@ export class CrazyGamesPortal extends BasePortal {
187
222
  }
188
223
  }
189
224
 
225
+ // ----- Ad methods -----
226
+
227
+ async setupAds() {
228
+ if (!this.isCrazyGames()) {
229
+ return false;
230
+ }
231
+
232
+ if (this.isSetup) {
233
+ console.log('CrazyGames.isSetup is already done');
234
+ return true;
235
+ }
236
+
237
+ await globalThis.CrazyGames.SDK.init();
238
+
239
+ this.isSetup = true;
240
+
241
+ return true;
242
+ }
243
+
244
+ isAdReady() {
245
+ return this.isCrazyGames();
246
+ }
247
+
248
+ async loadInterstitialAd() {
249
+ console.log('CrazyGames.loadAd');
250
+
251
+ if (!this.isCrazyGames()) {
252
+ return false;
253
+ }
254
+
255
+ if (!this.isSetup) {
256
+ await this.setupAds();
257
+ }
258
+ }
259
+
260
+ async showInterstitialAd() {
261
+ console.log('CrazyGames.showAd');
262
+
263
+ if (!this.isCrazyGames()) {
264
+ return false;
265
+ }
266
+
267
+ if (!this.isSetup) {
268
+ await this.setupAds();
269
+ }
270
+
271
+ const adType = 'interstitial';
272
+ const adProvider = this.adProviderName;
273
+
274
+ const callbacks = {
275
+ adFinished: () => {
276
+ if (typeof this.onAdClosed === 'function') {
277
+ this.onAdClosed({
278
+ adType,
279
+ adProvider,
280
+ });
281
+ }
282
+ },
283
+ adError: (error) => {
284
+ if (typeof this.onAdError === 'function') {
285
+ this.onAdError({
286
+ error,
287
+ adType,
288
+ adProvider,
289
+ });
290
+ }
291
+ },
292
+ adStarted: () => {
293
+ if (typeof this.onAdOpened === 'function') {
294
+ this.onAdOpened({
295
+ adType,
296
+ adProvider,
297
+ });
298
+ }
299
+ },
300
+ };
301
+
302
+ globalThis.CrazyGames.SDK.ad.requestAd('midgame', callbacks);
303
+ }
304
+
305
+ isAdLoaded() {
306
+ return true;
307
+ }
308
+
309
+ isRewardedAdLoaded() {
310
+ return true;
311
+ }
312
+
313
+ async showRewardedAd() {
314
+ console.log('CrazyGames.ShowRewardedAd');
315
+
316
+ if (!this.isCrazyGames()) {
317
+ return false;
318
+ }
319
+
320
+ if (!this.isSetup) {
321
+ await this.setupAds();
322
+ }
323
+
324
+ const adType = 'rewarded';
325
+ const adProvider = this.adProviderName;
326
+
327
+ const callbacks = {
328
+ adFinished: () => {
329
+ if (typeof this.onAdClosed === 'function') {
330
+ this.onAdClosed({
331
+ adType,
332
+ adProvider,
333
+ });
334
+ }
335
+
336
+ if (typeof this.onAdRewarded === 'function') {
337
+ this.onAdRewarded({
338
+ adType,
339
+ adProvider,
340
+ });
341
+ }
342
+ },
343
+ adError: (error) => {
344
+ if (typeof this.onAdError === 'function') {
345
+ this.onAdError({
346
+ error,
347
+ adType,
348
+ adProvider,
349
+ });
350
+ }
351
+ },
352
+ adStarted: () => {
353
+ if (typeof this.onAdOpened === 'function') {
354
+ this.onAdOpened({
355
+ adType,
356
+ adProvider,
357
+ });
358
+ }
359
+ },
360
+ };
361
+
362
+ globalThis.CrazyGames.SDK.ad.requestAd('rewarded', callbacks);
363
+ }
364
+
365
+ async loadRewardedAd() {
366
+ console.log('CrazyGames.loadRewardedAd');
367
+
368
+ if (!this.isCrazyGames()) {
369
+ return false;
370
+ }
371
+
372
+ if (!this.isSetup) {
373
+ await this.setupAds();
374
+ }
375
+ }
190
376
  }