diff --git a/android/app/src/main/ic_launcher_new_splash-playstore.png b/android/app/src/main/ic_launcher_new_splash-playstore.png
new file mode 100644
index 0000000000..6155261e93
Binary files /dev/null and b/android/app/src/main/ic_launcher_new_splash-playstore.png differ
diff --git a/android/app/src/main/res/drawable/ic_launcher_new_splash_background.xml b/android/app/src/main/res/drawable/ic_launcher_new_splash_background.xml
new file mode 100644
index 0000000000..ca3826a46c
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_launcher_new_splash_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_launcher_new_splash_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_new_splash_foreground.xml
index b6ff074f5f..187227c55a 100644
--- a/android/app/src/main/res/drawable/ic_launcher_new_splash_foreground.xml
+++ b/android/app/src/main/res/drawable/ic_launcher_new_splash_foreground.xml
@@ -1,34 +1,36 @@
-
-
-
-
-
-
-
-
+ android:viewportWidth="768"
+ android:viewportHeight="768">
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash.xml
index 3f18e9ffc9..56c2c7af0c 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash_round.xml
index 3f18e9ffc9..56c2c7af0c 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash_round.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_new_splash_round.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash.webp
index ad2642ff46..67e8d871a1 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash.webp and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash.webp differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash_round.webp
new file mode 100644
index 0000000000..8c423e15c2
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_new_splash_round.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash.webp
index 7213949a7e..227159afd1 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash_round.webp
index 2f10fcc36d..e7d3141d81 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash_round.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_new_splash_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_new_splash.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_new_splash.webp
new file mode 100644
index 0000000000..023a246326
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_new_splash.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_new_splash_round.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_new_splash_round.webp
new file mode 100644
index 0000000000..d708ec82d8
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_new_splash_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash.webp
index dff53babfc..d6b1efd409 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash_round.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash_round.webp
index 94dd502d5d..d5da2a651d 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash_round.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_new_splash_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash.webp
index b2d893d881..01b1fbc69b 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash_round.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash_round.webp
index fee5841ff0..6e4518593c 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash_round.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_new_splash_round.webp differ
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 7dc9aefdec..57f9ca78b3 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -105,7 +105,7 @@ export class AppComponent implements OnInit {
style: Style.Default,
});
- setTimeout(async () => await SplashScreen.hide(), 1000);
+ setTimeout(async () => await SplashScreen.hide(), 500);
/*
* Use the app's font size irrespective of the user's device font size.
diff --git a/src/app/auth/sign-in/sign-in.page.html b/src/app/auth/sign-in/sign-in.page.html
index 0fbb779586..c34f951475 100644
--- a/src/app/auth/sign-in/sign-in.page.html
+++ b/src/app/auth/sign-in/sign-in.page.html
@@ -7,6 +7,7 @@
height="auto"
onloadedmetadata="this.muted = true"
oncanplay="this.play()"
+ poster="../../../assets/images/video-default-background.png"
loop
>
diff --git a/src/app/auth/sign-in/sign-in.page.scss b/src/app/auth/sign-in/sign-in.page.scss
index 957ae2928b..39cfb9ceb8 100644
--- a/src/app/auth/sign-in/sign-in.page.scss
+++ b/src/app/auth/sign-in/sign-in.page.scss
@@ -41,7 +41,7 @@
&__select-sign-in {
display: flex;
flex-direction: column;
- height: 96vh;
+ height: 100vh;
padding: 20px 20px 0 20px;
}
@@ -49,6 +49,7 @@
margin-top: 24px;
position: relative;
height: 144px;
+ margin-bottom: 24px;
}
&__divider-container {
@@ -62,7 +63,7 @@
&__divider {
height: 1px;
- background-color: $grey;
+ background-color: $border-tertiary;
width: 100%;
}
@@ -70,7 +71,7 @@
height: 96vh;
margin-top: 18px;
padding: 20px;
- padding: 28px 20px 44px 20px;
+ padding: 24px 20px 44px 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
@@ -134,8 +135,9 @@
&__disabled-email {
font-size: 14px;
font-weight: 500;
- line-height: 1.28;
+ line-height: 1.3;
color: $blue-black;
+ padding-top: 4px;
margin-bottom: 24px;
display: flex;
align-items: center;
@@ -269,3 +271,16 @@
}
}
}
+
+.fade-in {
+ animation: fadeIn 0.5s ease-in-out;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
diff --git a/src/app/auth/sign-in/sign-in.page.spec.ts b/src/app/auth/sign-in/sign-in.page.spec.ts
index 130c3cf8a0..4ca8ea1a06 100644
--- a/src/app/auth/sign-in/sign-in.page.spec.ts
+++ b/src/app/auth/sign-in/sign-in.page.spec.ts
@@ -15,7 +15,7 @@ import { Router, ActivatedRoute, RouterModule } from '@angular/router';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import { of, throwError } from 'rxjs';
+import { of, Subscription, throwError } from 'rxjs';
import { extendedDeviceInfoMockData } from 'src/app/core/mock-data/extended-device-info.data';
import { ErrorComponent } from './error/error.component';
import { authResData1, authResData2, samlResData1, samlResData2 } from 'src/app/core/mock-data/auth-reponse.data';
@@ -28,6 +28,9 @@ import { click, getElementBySelector, getTextContent } from 'src/app/core/dom-he
import { By } from '@angular/platform-browser';
import { HttpErrorResponse } from '@angular/common/http';
import { SignInPageState } from './sign-in-page-state.enum';
+import { PlatformHandlerService } from 'src/app/core/services/platform-handler.service';
+import { BackButtonService } from 'src/app/core/services/back-button.service';
+import { BackButtonActionPriority } from 'src/app/core/models/back-button-action-priority.enum';
describe('SignInPage', () => {
let component: SignInPage;
@@ -45,6 +48,8 @@ describe('SignInPage', () => {
let deviceService: jasmine.SpyObj;
let loginInfoService: jasmine.SpyObj;
let inAppBrowserService: jasmine.SpyObj;
+ let platformHandlerService: jasmine.SpyObj;
+ let backButtonService: jasmine.SpyObj;
beforeEach(waitForAsync(() => {
const routerAuthServiceSpy = jasmine.createSpyObj('RouterAuthService', [
@@ -64,7 +69,8 @@ describe('SignInPage', () => {
const deviceServiceSpy = jasmine.createSpyObj('DeviceService', ['getDeviceInfo']);
const loginInfoServiceSpy = jasmine.createSpyObj('LoginInfoService', ['addLoginInfo']);
const inAppBrowserServiceSpy = jasmine.createSpyObj('InAppBrowserService', ['create']);
-
+ const platformHandlerServiceSpy = jasmine.createSpyObj('PlatformHandlerService', ['registerBackButtonAction']);
+ const backButtonServiceSpy = jasmine.createSpyObj('BackButtonService', ['showAppCloseAlert']);
TestBed.configureTestingModule({
declarations: [SignInPage, MatButton],
imports: [
@@ -128,6 +134,14 @@ describe('SignInPage', () => {
provide: InAppBrowserService,
useValue: inAppBrowserServiceSpy,
},
+ {
+ provide: PlatformHandlerService,
+ useValue: platformHandlerServiceSpy,
+ },
+ {
+ provide: BackButtonService,
+ useValue: backButtonServiceSpy,
+ },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
}).compileComponents();
@@ -147,6 +161,8 @@ describe('SignInPage', () => {
deviceService = TestBed.inject(DeviceService) as jasmine.SpyObj;
loginInfoService = TestBed.inject(LoginInfoService) as jasmine.SpyObj;
inAppBrowserService = TestBed.inject(InAppBrowserService) as jasmine.SpyObj;
+ platformHandlerService = TestBed.inject(PlatformHandlerService) as jasmine.SpyObj;
+ backButtonService = TestBed.inject(BackButtonService) as jasmine.SpyObj;
loaderService.showLoader.and.returnValue(new Promise(() => {}));
router.navigate.and.stub();
@@ -206,6 +222,73 @@ describe('SignInPage', () => {
});
});
+ it('ionViewWillEnter(): should set up back button actions', () => {
+ const mockSubscription = new Subscription();
+ platformHandlerService.registerBackButtonAction.and.returnValue(mockSubscription);
+ spyOn(component, 'goBack');
+ component.ionViewWillEnter();
+ expect(component.hardwareBackButtonAction).toEqual(mockSubscription);
+ expect(platformHandlerService.registerBackButtonAction).toHaveBeenCalledOnceWith(
+ BackButtonActionPriority.MEDIUM,
+ component.goBack
+ );
+ });
+
+ describe('goBack(): ', () => {
+ it('should navigate to ENTER_EMAIL when current step is ENTER_PASSWORD', () => {
+ spyOn(component, 'changeState');
+
+ component.currentStep = SignInPageState.ENTER_PASSWORD;
+ component.goBack();
+
+ expect(component.changeState).toHaveBeenCalledWith(SignInPageState.ENTER_EMAIL);
+ expect(backButtonService.showAppCloseAlert).not.toHaveBeenCalled();
+ });
+
+ it('should show app close alert for other states', () => {
+ spyOn(component, 'changeState');
+
+ component.currentStep = SignInPageState.SELECT_SIGN_IN_METHOD;
+ component.goBack();
+
+ expect(backButtonService.showAppCloseAlert).toHaveBeenCalledTimes(1);
+ expect(component.changeState).not.toHaveBeenCalled();
+ });
+
+ it('should show app close alert for other states', () => {
+ spyOn(component, 'changeState');
+
+ component.currentStep = SignInPageState.ENTER_EMAIL;
+ component.goBack();
+
+ expect(component.changeState).toHaveBeenCalledWith(SignInPageState.SELECT_SIGN_IN_METHOD);
+ });
+ });
+
+ it('ionViewWillLeave(): should unsubscribe from hardwareBackButtonAction', () => {
+ component.hardwareBackButtonAction = new Subscription();
+ spyOn(component.hardwareBackButtonAction, 'unsubscribe');
+ component.ionViewWillLeave();
+
+ expect(component.hardwareBackButtonAction.unsubscribe).toHaveBeenCalled();
+ });
+
+ it('changeState(): should update the current step', () => {
+ component.changeState(SignInPageState.ENTER_EMAIL);
+
+ expect(component.currentStep).toBe(SignInPageState.ENTER_EMAIL);
+
+ component.changeState(SignInPageState.ENTER_PASSWORD);
+
+ expect(component.currentStep).toBe(SignInPageState.ENTER_PASSWORD);
+ });
+
+ it('goToForgotPasswordPage(): should navigate to the reset password page with the email parameter', () => {
+ component.goToForgotPasswordPage();
+
+ expect(router.navigate).toHaveBeenCalledWith(['/', 'auth', 'reset_password', { email: 'ajain@fyle.in' }]);
+ });
+
describe('checkIfEmailExists(): ', () => {
it('should check if value email exists', (done) => {
component.fg.controls.email.setValue('email@gmail.com');
@@ -419,15 +502,6 @@ describe('SignInPage', () => {
expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'auth', 'switch_org', { choose: true }]);
expect(component.trackLoginInfo).toHaveBeenCalledTimes(1);
});
-
- it("should throw an error if google reponse doesn't contain access token", async () => {
- googleAuthService.login.and.resolveTo(authResData1);
- spyOn(component, 'handleError');
-
- await component.googleSignIn();
- expect(googleAuthService.login).toHaveBeenCalledTimes(1);
- expect(component.handleError).toHaveBeenCalledOnceWith(undefined);
- });
});
it('trackLoginInfo(): should track login', async () => {
diff --git a/src/app/auth/sign-in/sign-in.page.ts b/src/app/auth/sign-in/sign-in.page.ts
index f0eecd33f8..98a12a01b3 100644
--- a/src/app/auth/sign-in/sign-in.page.ts
+++ b/src/app/auth/sign-in/sign-in.page.ts
@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { RouterAuthService } from 'src/app/core/services/router-auth.service';
-import { from, throwError, Observable, of, noop } from 'rxjs';
+import { from, throwError, Observable, of, noop, Subscription } from 'rxjs';
import { PopoverController } from '@ionic/angular';
import { ErrorComponent } from './error/error.component';
import { shareReplay, filter, finalize, switchMap, map, tap, take } from 'rxjs/operators';
@@ -17,6 +17,9 @@ import { HttpErrorResponse } from '@angular/common/http';
import { EmailExistsResponse } from 'src/app/core/models/email-exists-response.model';
import { SamlResponse } from 'src/app/core/models/saml-response.model';
import { SignInPageState } from './sign-in-page-state.enum';
+import { BackButtonActionPriority } from 'src/app/core/models/back-button-action-priority.enum';
+import { PlatformHandlerService } from 'src/app/core/services/platform-handler.service';
+import { BackButtonService } from 'src/app/core/services/back-button.service';
@Component({
selector: 'app-sign-in',
@@ -40,6 +43,8 @@ export class SignInPage implements OnInit {
signInPageState: typeof SignInPageState = SignInPageState;
+ hardwareBackButtonAction: Subscription;
+
constructor(
private formBuilder: FormBuilder,
private routerAuthService: RouterAuthService,
@@ -52,7 +57,9 @@ export class SignInPage implements OnInit {
private trackingService: TrackingService,
private deviceService: DeviceService,
private loginInfoService: LoginInfoService,
- private inAppBrowserService: InAppBrowserService
+ private inAppBrowserService: InAppBrowserService,
+ private platformHandlerService: PlatformHandlerService,
+ private backButtonService: BackButtonService
) {}
async checkSAMLResponseAndSignInUser(data: SamlResponse): Promise {
@@ -250,7 +257,6 @@ export class SignInPage implements OnInit {
this.fg.reset();
this.router.navigate(['/', 'auth', 'switch_org', { choose: true }]);
},
- error: (err: HttpErrorResponse) => this.handleError(err),
});
}
@@ -260,14 +266,24 @@ export class SignInPage implements OnInit {
await this.loginInfoService.addLoginInfo(deviceInfo.appVersion, new Date());
}
- ionViewWillEnter(): void {
- if (this.activatedRoute.snapshot.params.email) {
- this.currentStep = SignInPageState.ENTER_PASSWORD;
- } else {
- this.currentStep = SignInPageState.SELECT_SIGN_IN_METHOD;
+ goBack(): void {
+ switch (this.currentStep) {
+ case SignInPageState.ENTER_EMAIL:
+ this.changeState(SignInPageState.SELECT_SIGN_IN_METHOD);
+ break;
+ case SignInPageState.ENTER_PASSWORD:
+ this.changeState(SignInPageState.ENTER_EMAIL);
+ break;
+ default:
+ this.backButtonService.showAppCloseAlert();
}
}
+ ionViewWillEnter(): void {
+ const priority = BackButtonActionPriority.MEDIUM;
+ this.hardwareBackButtonAction = this.platformHandlerService.registerBackButtonAction(priority, this.goBack);
+ }
+
changeState(state: SignInPageState): void {
this.currentStep = state;
}
@@ -290,4 +306,8 @@ export class SignInPage implements OnInit {
}
});
}
+
+ ionViewWillLeave(): void {
+ this.hardwareBackButtonAction.unsubscribe();
+ }
}
diff --git a/src/assets/images/video-default-background.png b/src/assets/images/video-default-background.png
new file mode 100644
index 0000000000..ede5b2084f
Binary files /dev/null and b/src/assets/images/video-default-background.png differ