forked from EVOgeek/Vmeda.Online
		
	
						commit
						3ddd53c1ed
					
				@ -6,12 +6,17 @@
 | 
				
			|||||||
        <clobbers target="cordova.MoodleApp" />
 | 
					        <clobbers target="cordova.MoodleApp" />
 | 
				
			||||||
    </js-module>
 | 
					    </js-module>
 | 
				
			||||||
    <platform name="android">
 | 
					    <platform name="android">
 | 
				
			||||||
 | 
					        <framework src="com.android.installreferrer:installreferrer:2.2" />
 | 
				
			||||||
        <config-file target="res/xml/config.xml" parent="/*">
 | 
					        <config-file target="res/xml/config.xml" parent="/*">
 | 
				
			||||||
            <feature name="SecureStorage">
 | 
					            <feature name="SecureStorage">
 | 
				
			||||||
                <param name="android-package" value="com.moodle.moodlemobile.SecureStorage"/>
 | 
					                <param name="android-package" value="com.moodle.moodlemobile.SecureStorage"/>
 | 
				
			||||||
            </feature>
 | 
					            </feature>
 | 
				
			||||||
 | 
					            <feature name="InstallReferrer">
 | 
				
			||||||
 | 
					                <param name="android-package" value="com.moodle.moodlemobile.InstallReferrer"/>
 | 
				
			||||||
 | 
					            </feature>
 | 
				
			||||||
        </config-file>
 | 
					        </config-file>
 | 
				
			||||||
        <source-file src="src/android/SecureStorage.java" target-dir="src/com/moodle/moodlemobile" />
 | 
					        <source-file src="src/android/SecureStorage.java" target-dir="src/com/moodle/moodlemobile" />
 | 
				
			||||||
 | 
					        <source-file src="src/android/InstallReferrer.java" target-dir="src/com/moodle/moodlemobile" />
 | 
				
			||||||
    </platform>
 | 
					    </platform>
 | 
				
			||||||
    <platform name="ios">
 | 
					    <platform name="ios">
 | 
				
			||||||
        <config-file target="config.xml" parent="/*">
 | 
					        <config-file target="config.xml" parent="/*">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										148
									
								
								cordova-plugin-moodleapp/src/android/InstallReferrer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								cordova-plugin-moodleapp/src/android/InstallReferrer.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Moodle Pty Ltd.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.moodle.moodlemobile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.util.Log;
 | 
				
			||||||
 | 
					import android.os.RemoteException;
 | 
				
			||||||
 | 
					import org.json.JSONArray;
 | 
				
			||||||
 | 
					import org.json.JSONObject;
 | 
				
			||||||
 | 
					import org.apache.cordova.CordovaPlugin;
 | 
				
			||||||
 | 
					import org.apache.cordova.CallbackContext;
 | 
				
			||||||
 | 
					import org.apache.cordova.PluginResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.android.installreferrer.api.InstallReferrerClient;
 | 
				
			||||||
 | 
					import com.android.installreferrer.api.InstallReferrerStateListener;
 | 
				
			||||||
 | 
					import com.android.installreferrer.api.ReferrerDetails;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class InstallReferrer extends CordovaPlugin implements InstallReferrerStateListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final String TAG = "InstallReferrer";
 | 
				
			||||||
 | 
					    private static final int UNKNOWN_ERROR = 1;
 | 
				
			||||||
 | 
					    private static final int FEATURE_NOT_SUPPORTED = 2;
 | 
				
			||||||
 | 
					    private static final int SERVICE_UNAVAILABLE = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private InstallReferrerClient referrerClient;
 | 
				
			||||||
 | 
					    private CallbackContext callbackContext;
 | 
				
			||||||
 | 
					    private JSONObject referrerResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            switch (action) {
 | 
				
			||||||
 | 
					                case "getReferrer":
 | 
				
			||||||
 | 
					                    this.getReferrer(callbackContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (Throwable e) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "Failed executing action: " + action, e);
 | 
				
			||||||
 | 
					            callbackContext.error(e.getMessage());
 | 
				
			||||||
 | 
					            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Connect to the referrer client and obtain the referrer data when connected.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param callbackContext The callback context used when calling back into JavaScript.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void getReferrer(CallbackContext callbackContext) {
 | 
				
			||||||
 | 
					        if (this.referrerResult != null) {
 | 
				
			||||||
 | 
					            callbackContext.success(this.referrerResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.callbackContext = callbackContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (this.referrerClient == null) {
 | 
				
			||||||
 | 
					                this.referrerClient = InstallReferrerClient.newBuilder(this.cordova.getActivity().getApplicationContext()).build();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.referrerClient.startConnection(this);
 | 
				
			||||||
 | 
					        } catch (Exception exception) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "startConnection error: " + exception.getMessage());
 | 
				
			||||||
 | 
					            callbackContext.error(exception.getMessage());
 | 
				
			||||||
 | 
					            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get referral data from an already established connection and pass it to current callback context.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void getReferralData() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            ReferrerDetails response = referrerClient.getInstallReferrer();
 | 
				
			||||||
 | 
					            JSONObject referrerResult = new JSONObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            referrerResult.put("referrer", response.getInstallReferrer());
 | 
				
			||||||
 | 
					            referrerResult.put("clickTime", response.getReferrerClickTimestampSeconds());
 | 
				
			||||||
 | 
					            referrerResult.put("appInstallTime", response.getInstallBeginTimestampSeconds());
 | 
				
			||||||
 | 
					            referrerResult.put("instantExperienceLaunched", response.getGooglePlayInstantParam());
 | 
				
			||||||
 | 
					            this.referrerResult = referrerResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (this.callbackContext != null) {
 | 
				
			||||||
 | 
					                this.callbackContext.success(this.referrerResult);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (Exception exception) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "getReferralData error: " + exception.getMessage());
 | 
				
			||||||
 | 
					            if (this.callbackContext != null) {
 | 
				
			||||||
 | 
					                this.callbackContext.error(exception.getMessage());
 | 
				
			||||||
 | 
					                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.referrerClient.endConnection();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            this.referrerClient.endConnection();
 | 
				
			||||||
 | 
					        } catch (Exception exception) {
 | 
				
			||||||
 | 
					            // Ignore errors.
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onInstallReferrerSetupFinished(int responseCode) {
 | 
				
			||||||
 | 
					        switch (responseCode) {
 | 
				
			||||||
 | 
					            case InstallReferrerClient.InstallReferrerResponse.OK:
 | 
				
			||||||
 | 
					                // Connection established.
 | 
				
			||||||
 | 
					                this.getReferralData();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
 | 
				
			||||||
 | 
					                // API not available on the current Play Store app.
 | 
				
			||||||
 | 
					                if (this.callbackContext != null) {
 | 
				
			||||||
 | 
					                    this.callbackContext.error("Referrer feature not supported.");
 | 
				
			||||||
 | 
					                    this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FEATURE_NOT_SUPPORTED));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
 | 
				
			||||||
 | 
					                // Connection couldn't be established.
 | 
				
			||||||
 | 
					                if (this.callbackContext != null) {
 | 
				
			||||||
 | 
					                    this.callbackContext.error("Referrer service unavailable.");
 | 
				
			||||||
 | 
					                    this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, SERVICE_UNAVAILABLE));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onInstallReferrerServiceDisconnected() {
 | 
				
			||||||
 | 
					        // Nothing to do.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -12,10 +12,12 @@
 | 
				
			|||||||
// See the License for the specific language governing permissions and
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { InstallReferrer } from './plugins/InstallReferrer';
 | 
				
			||||||
import { SecureStorage } from './plugins/SecureStorage';
 | 
					import { SecureStorage } from './plugins/SecureStorage';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const api: MoodleAppPlugins = {
 | 
					const api: MoodleAppPlugins = {
 | 
				
			||||||
    secureStorage: new SecureStorage(),
 | 
					    secureStorage: new SecureStorage(),
 | 
				
			||||||
 | 
					    installReferrer: new InstallReferrer(),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This is necessary to work around the default transpilation behavior,
 | 
					// This is necessary to work around the default transpilation behavior,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								cordova-plugin-moodleapp/src/ts/plugins/InstallReferrer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								cordova-plugin-moodleapp/src/ts/plugins/InstallReferrer.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Moodle Pty Ltd.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Allows retrieving install referrer data.
 | 
				
			||||||
 | 
					 * https://developer.android.com/google/play/installreferrer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class InstallReferrer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get referrer data.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @returns Referrer data.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getReferrer(): Promise<InstallReferrerResult> {
 | 
				
			||||||
 | 
					        return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
					            cordova.exec(resolve, reject, 'InstallReferrer', 'getReferrer', []);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type InstallReferrerResult = {
 | 
				
			||||||
 | 
					    referrer: string;
 | 
				
			||||||
 | 
					    clickTime: number;
 | 
				
			||||||
 | 
					    appInstallTime: number;
 | 
				
			||||||
 | 
					    instantExperienceLaunched: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										2
									
								
								cordova-plugin-moodleapp/types/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								cordova-plugin-moodleapp/types/index.d.ts
									
									
									
									
										vendored
									
									
								
							@ -12,12 +12,14 @@
 | 
				
			|||||||
// See the License for the specific language governing permissions and
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { InstallReferrer } from '../src/ts/plugins/InstallReferrer';
 | 
				
			||||||
import { SecureStorage as SecureStorageImpl } from '../src/ts/plugins/SecureStorage';
 | 
					import { SecureStorage as SecureStorageImpl } from '../src/ts/plugins/SecureStorage';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare global {
 | 
					declare global {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    interface MoodleAppPlugins {
 | 
					    interface MoodleAppPlugins {
 | 
				
			||||||
        secureStorage: SecureStorageImpl;
 | 
					        secureStorage: SecureStorageImpl;
 | 
				
			||||||
 | 
					        installReferrer: InstallReferrer;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    interface Cordova {
 | 
					    interface Cordova {
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@
 | 
				
			|||||||
        <div class="ion-text-center ion-padding ion-margin-bottom core-login-site-logo" [class.hidden]="hasSites || enteredSiteUrl">
 | 
					        <div class="ion-text-center ion-padding ion-margin-bottom core-login-site-logo" [class.hidden]="hasSites || enteredSiteUrl">
 | 
				
			||||||
            <img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation" alt="">
 | 
					            <img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation" alt="">
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <form [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites && siteForm" #siteFormEl>
 | 
					        <form [formGroup]="siteForm" (ngSubmit)="connect(siteForm.value.siteUrl, $event)" *ngIf="!fixedSites && siteForm" #siteFormEl>
 | 
				
			||||||
            <!-- Form to input the site URL if there are no fixed sites. -->
 | 
					            <!-- Form to input the site URL if there are no fixed sites. -->
 | 
				
			||||||
            <ng-container *ngIf=" siteSelector=='url'">
 | 
					            <ng-container *ngIf=" siteSelector=='url'">
 | 
				
			||||||
                <ion-item>
 | 
					                <ion-item>
 | 
				
			||||||
@ -48,7 +48,7 @@
 | 
				
			|||||||
                            <h2 class="item-heading">{{ 'core.login.selectsite' | translate }}</h2>
 | 
					                            <h2 class="item-heading">{{ 'core.login.selectsite' | translate }}</h2>
 | 
				
			||||||
                        </ion-label>
 | 
					                        </ion-label>
 | 
				
			||||||
                    </ion-item>
 | 
					                    </ion-item>
 | 
				
			||||||
                    <ion-item button *ngIf="enteredSiteUrl" (click)="connect($event, enteredSiteUrl.url)"
 | 
					                    <ion-item button *ngIf="enteredSiteUrl" (click)="connect(enteredSiteUrl.url, $event)"
 | 
				
			||||||
                        [attr.aria-label]="'core.login.connect' | translate" detail="true" class="core-login-entered-site">
 | 
					                        [attr.aria-label]="'core.login.connect' | translate" detail="true" class="core-login-entered-site">
 | 
				
			||||||
                        <ion-thumbnail slot="start" aria-hidden="true">
 | 
					                        <ion-thumbnail slot="start" aria-hidden="true">
 | 
				
			||||||
                            <ion-icon name="fas-pen" aria-hidden="true"></ion-icon>
 | 
					                            <ion-icon name="fas-pen" aria-hidden="true"></ion-icon>
 | 
				
			||||||
@ -120,7 +120,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<!-- Template site selector. -->
 | 
					<!-- Template site selector. -->
 | 
				
			||||||
<ng-template #sitelisting let-site="site">
 | 
					<ng-template #sitelisting let-site="site">
 | 
				
			||||||
    <ion-item button (click)="connect($event, site.url, site)" [ngClass]="site.className" [attr.aria-label]="site.name" detail="true">
 | 
					    <ion-item button (click)="connect(site.url, $event, site)" [ngClass]="site.className" [attr.aria-label]="site.name" detail="true">
 | 
				
			||||||
        <ion-thumbnail *ngIf="siteFinderSettings.displayimage" slot="start">
 | 
					        <ion-thumbnail *ngIf="siteFinderSettings.displayimage" slot="start">
 | 
				
			||||||
            <img [src]="site.imageurl" *ngIf="site.imageurl" onError="this.src='assets/icon/icon.png'" alt="" role="presentation">
 | 
					            <img [src]="site.imageurl" *ngIf="site.imageurl" onError="this.src='assets/icon/icon.png'" alt="" role="presentation">
 | 
				
			||||||
            <img src="assets/icon/icon.png" *ngIf="!site.imageurl" class="core-login-default-icon" alt="" role="presentation">
 | 
					            <img src="assets/icon/icon.png" *ngIf="!site.imageurl" class="core-login-default-icon" alt="" role="presentation">
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,7 @@ import { CoreUserSupportConfig } from '@features/user/classes/support/support-co
 | 
				
			|||||||
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
 | 
					import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
 | 
				
			||||||
import { CoreLoginError } from '@classes/errors/loginerror';
 | 
					import { CoreLoginError } from '@classes/errors/loginerror';
 | 
				
			||||||
import { CorePlatform } from '@services/platform';
 | 
					import { CorePlatform } from '@services/platform';
 | 
				
			||||||
 | 
					import { CoreReferrer } from '@services/referrer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Site (url) chooser when adding a new site.
 | 
					 * Site (url) chooser when adding a new site.
 | 
				
			||||||
@ -98,9 +99,22 @@ export class CoreLoginSitePage implements OnInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (sites.length) {
 | 
					        if (sites.length) {
 | 
				
			||||||
            url = await this.initSiteSelector();
 | 
					            url = await this.initSiteSelector();
 | 
				
			||||||
        } else if (CoreConstants.CONFIG.enableonboarding && !CorePlatform.isIOS()) {
 | 
					        } else {
 | 
				
			||||||
 | 
					            url = await this.consumeInstallReferrerUrl() ?? '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const showOnboarding = CoreConstants.CONFIG.enableonboarding && !CorePlatform.isIOS();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (url) {
 | 
				
			||||||
 | 
					                this.connect(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (showOnboarding) {
 | 
				
			||||||
 | 
					                    // Don't display onboarding in this case, and don't display it again later.
 | 
				
			||||||
 | 
					                    CoreConfig.set(CoreLoginHelperProvider.ONBOARDING_DONE, 1);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (showOnboarding) {
 | 
				
			||||||
                this.initOnboarding();
 | 
					                this.initOnboarding();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.showScanQR = CoreLoginHelper.displayQRInSiteScreen();
 | 
					        this.showScanQR = CoreLoginHelper.displayQRInSiteScreen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -150,6 +164,26 @@ export class CoreLoginSitePage implements OnInit {
 | 
				
			|||||||
        return this.fixedSites[0].url;
 | 
					        return this.fixedSites[0].url;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Consume install referrer URL.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @returns Referrer URL, undefined if no URL to use.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected async consumeInstallReferrerUrl(): Promise<string | undefined> {
 | 
				
			||||||
 | 
					        const url = await CoreUtils.ignoreErrors(CoreUtils.timeoutPromise(CoreReferrer.consumeInstallReferrerUrl(), 1000));
 | 
				
			||||||
 | 
					        if (!url) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const hasSites = (await CoreUtils.ignoreErrors(CoreSites.getSites(), [])).length > 0;
 | 
				
			||||||
 | 
					        if (hasSites) {
 | 
				
			||||||
 | 
					            // There are sites stored already, don't use the referrer URL since it's an update or a backup was restored.
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return url;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Initialize and show onboarding if needed.
 | 
					     * Initialize and show onboarding if needed.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -241,14 +275,14 @@ export class CoreLoginSitePage implements OnInit {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Try to connect to a site.
 | 
					     * Try to connect to a site.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param e Event.
 | 
					 | 
				
			||||||
     * @param url The URL to connect to.
 | 
					     * @param url The URL to connect to.
 | 
				
			||||||
 | 
					     * @param e Event (if any).
 | 
				
			||||||
     * @param foundSite The site clicked, if any, from the found sites list.
 | 
					     * @param foundSite The site clicked, if any, from the found sites list.
 | 
				
			||||||
     * @returns Promise resolved when done.
 | 
					     * @returns Promise resolved when done.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async connect(e: Event, url: string, foundSite?: CoreLoginSiteInfoExtended): Promise<void> {
 | 
					    async connect(url: string, e?: Event, foundSite?: CoreLoginSiteInfoExtended): Promise<void> {
 | 
				
			||||||
        e.preventDefault();
 | 
					        e?.preventDefault();
 | 
				
			||||||
        e.stopPropagation();
 | 
					        e?.stopPropagation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CoreApp.closeKeyboard();
 | 
					        CoreApp.closeKeyboard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -540,7 +574,7 @@ export class CoreLoginSitePage implements OnInit {
 | 
				
			|||||||
            // Put the text in the field (if present).
 | 
					            // Put the text in the field (if present).
 | 
				
			||||||
            this.siteForm.controls.siteUrl.setValue(text);
 | 
					            this.siteForm.controls.siteUrl.setValue(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.connect(new Event('click'), text);
 | 
					            this.connect(text);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            CoreDomUtils.showErrorModal('core.errorurlschemeinvalidsite', true);
 | 
					            CoreDomUtils.showErrorModal('core.errorurlschemeinvalidsite', true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -30,9 +30,13 @@ export class CoreNativeService {
 | 
				
			|||||||
     * Get a native plugin instance.
 | 
					     * Get a native plugin instance.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param plugin Plugin name.
 | 
					     * @param plugin Plugin name.
 | 
				
			||||||
     * @returns Plugin instance.
 | 
					     * @returns Plugin instance, null if plugin is not supported for current platform.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    plugin<Plugin extends keyof MoodleAppPlugins>(plugin: Plugin): AsyncInstance<MoodleAppPlugins[Plugin]> {
 | 
					    plugin<Plugin extends keyof MoodleAppPlugins>(plugin: Plugin): AsyncInstance<MoodleAppPlugins[Plugin]> | null {
 | 
				
			||||||
 | 
					        if (plugin === 'installReferrer' && !CorePlatform.isAndroid()) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(plugin in this.plugins)) {
 | 
					        if (!(plugin in this.plugins)) {
 | 
				
			||||||
            this.plugins[plugin] = asyncInstance(async () => {
 | 
					            this.plugins[plugin] = asyncInstance(async () => {
 | 
				
			||||||
                await CorePlatform.ready();
 | 
					                await CorePlatform.ready();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										61
									
								
								src/core/services/referrer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/core/services/referrer.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Moodle Pty Ltd.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					import { CoreConfig } from './config';
 | 
				
			||||||
 | 
					import { CoreNative } from '@features/native/services/native';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Manage referrers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable({ providedIn: 'root' })
 | 
				
			||||||
 | 
					export class CoreReferrerService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected static readonly INSTALL_REFERRER_CONSUMED = 'install_referrer_consumed';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Consume the install referrer URL (Android only).
 | 
				
			||||||
 | 
					     * This function will try to retrieve the siteurl supplied as referrer to Google Play.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @returns Referrer URL, undefined if not supported, already consumed or no referrer URL.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async consumeInstallReferrerUrl(): Promise<string | undefined> {
 | 
				
			||||||
 | 
					        const installReferrerPlugin = CoreNative.plugin('installReferrer');
 | 
				
			||||||
 | 
					        if (!installReferrerPlugin) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Only get the referrer URL once, it's only needed when the app is installed.
 | 
				
			||||||
 | 
					        const referredConsumed = await CoreConfig.get(CoreReferrerService.INSTALL_REFERRER_CONSUMED, 0);
 | 
				
			||||||
 | 
					        if (referredConsumed) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            const result = await installReferrerPlugin.getReferrer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const siteUrlMatch = (result.referrer ?? '').match(/siteurl=([^&]+)/);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return siteUrlMatch?.[1];
 | 
				
			||||||
 | 
					        } catch {
 | 
				
			||||||
 | 
					            // Error getting referrer, it probably means Google Play is not available.
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            await CoreConfig.set(CoreReferrerService.INSTALL_REFERRER_CONSUMED, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const CoreReferrer = makeSingleton(CoreReferrerService);
 | 
				
			||||||
@ -1106,7 +1106,7 @@ export class CoreSitesProvider {
 | 
				
			|||||||
        // Site deleted from sites list, now delete the folder.
 | 
					        // Site deleted from sites list, now delete the folder.
 | 
				
			||||||
        await site.deleteFolder();
 | 
					        await site.deleteFolder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await CoreUtils.ignoreErrors(CoreNative.plugin('secureStorage').deleteCollection(siteId));
 | 
					        await CoreUtils.ignoreErrors(CoreNative.plugin('secureStorage')?.deleteCollection(siteId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CoreEvents.trigger(CoreEvents.SITE_DELETED, site, siteId);
 | 
					        CoreEvents.trigger(CoreEvents.SITE_DELETED, site, siteId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2063,7 +2063,7 @@ export class CoreSitesProvider {
 | 
				
			|||||||
     * @returns Stored tokens.
 | 
					     * @returns Stored tokens.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected async getTokensFromSecureStorage(siteId: string): Promise<{ token: string; privateToken?: string }> {
 | 
					    protected async getTokensFromSecureStorage(siteId: string): Promise<{ token: string; privateToken?: string }> {
 | 
				
			||||||
        const result = await CoreNative.plugin('secureStorage').get(['token', 'privateToken'], siteId);
 | 
					        const result = await CoreNative.plugin('secureStorage')?.get(['token', 'privateToken'], siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            token: result?.token ?? '',
 | 
					            token: result?.token ?? '',
 | 
				
			||||||
@ -2083,7 +2083,7 @@ export class CoreSitesProvider {
 | 
				
			|||||||
        token: string,
 | 
					        token: string,
 | 
				
			||||||
        privateToken?: string,
 | 
					        privateToken?: string,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        await CoreNative.plugin('secureStorage').store({
 | 
					        await CoreNative.plugin('secureStorage')?.store({
 | 
				
			||||||
            token: token,
 | 
					            token: token,
 | 
				
			||||||
            privateToken: privateToken ?? '',
 | 
					            privateToken: privateToken ?? '',
 | 
				
			||||||
        }, siteId);
 | 
					        }, siteId);
 | 
				
			||||||
 | 
				
			|||||||
@ -260,7 +260,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            const response = await this.timeoutPromise(window.fetch(url, initOptions), CoreWS.getRequestTimeout());
 | 
					            const response = await this.timeoutPromise(window.fetch(url, initOptions), CoreWS.getRequestTimeout());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return !!response && response.redirected;
 | 
					            return response.redirected;
 | 
				
			||||||
        } catch (error) {
 | 
					        } catch (error) {
 | 
				
			||||||
            if (error.timeout && controller) {
 | 
					            if (error.timeout && controller) {
 | 
				
			||||||
                // Timeout, abort the request.
 | 
					                // Timeout, abort the request.
 | 
				
			||||||
@ -1547,14 +1547,14 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param time Number of milliseconds of the timeout.
 | 
					     * @param time Number of milliseconds of the timeout.
 | 
				
			||||||
     * @returns Promise with the timeout.
 | 
					     * @returns Promise with the timeout.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    timeoutPromise<T>(promise: Promise<T>, time: number): Promise<T | void> {
 | 
					    timeoutPromise<T>(promise: Promise<T>, time: number): Promise<T> {
 | 
				
			||||||
        return new Promise((resolve, reject): void => {
 | 
					        return new Promise((resolve, reject): void => {
 | 
				
			||||||
            let timedOut = false;
 | 
					            let timedOut = false;
 | 
				
			||||||
            const resolveBeforeTimeout = () => {
 | 
					            const resolveBeforeTimeout = (value: T) => {
 | 
				
			||||||
                if (timedOut) {
 | 
					                if (timedOut) {
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                resolve();
 | 
					                resolve(value);
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            const timeout = setTimeout(
 | 
					            const timeout = setTimeout(
 | 
				
			||||||
                () => {
 | 
					                () => {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user