-
-
-
-
-
-
-
-
-
+
+ @if (isLoading) {
+
+
+
+ {{ 'PREJOIN.PREPARING' | translate }}
+
+
+ } @else {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+ @if (backgroundEffectEnabled && hasVideoDevices) {
+
+
+
+ }
-
-
- @if (backgroundEffectEnabled && hasVideoDevices) {
-
-
-
- }
+
+ @if (showBackgroundPanel) {
+
+
+
+
+ } @else {
+
+
+
+
+
+
+
+
+
+
+ error_outline
+ {{ _error }}
+
+
+
+
+
+
+
+ }
-
- @if (showBackgroundPanel) {
-
-
-
- } @else {
-
-
-
-
-
-
-
-
-
-
- error_outline
- {{ _error }}
-
-
-
-
-
-
-
- }
-
- }
-
+ }
+
+}
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.html
index eaf7dc2e..499a6866 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.html
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.html
@@ -4,14 +4,8 @@
{{ 'ROOM.JOINING' | translate }}
} @else {
- @if (viewportService.isMobile() && viewportService.orientation() === 'landscape') {
-
-
-
- screen_rotation
- {{ 'ROOM.LANDSCAPE_WARNING' | translate }}
-
-
+ @if (viewportService.shouldShowLandscapeWarning()) {
+
}
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.scss b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.scss
index 820d8d9c..be5731f7 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.scss
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.scss
@@ -4,39 +4,6 @@
height: 100%;
}
-#landscape-warning {
- width: 100%;
- height: 100%;
- background-color: var(--ov-background-color);
- opacity: 95%;
- align-content: space-evenly;
- text-align: center;
- color: var(--ov-text-primary-color);
-
- .warning-message {
- display: inline-grid;
- display: -moz-inline-grid;
- place-items: center;
- }
-
- mat-icon {
- width: 50px;
- height: 50px;
- font-size: 50px;
- margin: auto;
- margin-bottom: 10px;
- animation: boomerang 1.2s ease-in-out infinite alternate;
-
- @keyframes boomerang {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(45deg);
- }
- }
- }
-}
#spinner {
position: absolute;
top: 40%;
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/models/viewport.model.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/models/viewport.model.ts
index 0e29bb95..acaba29b 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/models/viewport.model.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/models/viewport.model.ts
@@ -24,4 +24,7 @@ export interface ViewportInfo {
isDesktop: boolean;
isWide: boolean;
isTouchDevice: boolean;
+ isPhysicalMobile: boolean;
+ isPhysicalTablet: boolean;
+ shouldShowLandscapeWarning: boolean;
}
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts
index eaf85a66..f3271a29 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts
@@ -47,6 +47,7 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
import { OpenViduComponentsDirectiveModule } from './directives/template/openvidu-components-angular.directive.module';
import { AppMaterialModule } from './openvidu-components-angular.material.module';
import { ThemeSelectorComponent } from './components/settings/theme-selector/theme-selector.component';
+import { LandscapeWarningComponent } from './components/landscape-warning/landscape-warning.component';
const publicComponents = [
AdminDashboardComponent,
@@ -81,7 +82,8 @@ const privateComponents = [
LangSelectorComponent,
ToolbarMediaButtonsComponent,
ToolbarPanelButtonsComponent,
- ThemeSelectorComponent
+ ThemeSelectorComponent,
+ LandscapeWarningComponent
];
@NgModule({
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/platform/platform.service.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/platform/platform.service.ts
index 4d2c7390..712d6b87 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/platform/platform.service.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/platform/platform.service.ts
@@ -22,17 +22,60 @@ export class PlatformService {
}
/**
- * Detect Android Mobile
+ * Returns true if the device is physically a mobile device (iPhone, Android phone)
+ * This method is orientation-independent and hardware-based
+ */
+ isPhysicalMobile(): boolean {
+ return this.isIPhone() || this.isAndroidPhone();
+ }
+
+ /**
+ * Returns true if the device is physically a tablet (iPad, Android tablet)
+ */
+ isPhysicalTablet(): boolean {
+ return this.isIPad() || this.isAndroidTablet();
+ }
+
+ /**
+ * Detect Android phone specifically (not tablet)
+ */
+ isAndroidPhone(): boolean {
+ return /\b(\w*Android\w*)\b/.test(this.userAgent) && /\b(\w*Mobile\w*)\b/.test(this.userAgent);
+ }
+
+ /**
+ * Detect Android tablet specifically
+ */
+ isAndroidTablet(): boolean {
+ return /\b(\w*Android\w*)\b/.test(this.userAgent) && !/\b(\w*Mobile\w*)\b/.test(this.userAgent);
+ }
+
+ /**
+ * Detect Android Mobile (legacy method for compatibility)
*/
isAndroid(): boolean {
- return /\b(\w*Android\w*)\b/.test(this.userAgent) && /\b(\w*Mobile\w*)\b/.test(this.userAgent);
+ return this.isAndroidPhone() || this.isAndroidTablet();
+ }
+
+ /**
+ * Detect iPhone specifically
+ */
+ isIPhone(): boolean {
+ return /\biPhone\b/.test(this.userAgent) && /\bMobile\b/.test(this.userAgent);
+ }
+
+ /**
+ * Detect iPad specifically
+ */
+ isIPad(): boolean {
+ return /\bMacintosh\b/.test(this.userAgent) && 'ontouchend' in document;
}
/**
* Detect iOS device (iPhone or iPad)
*/
isIos(): boolean {
- return this.isIosDevice(this.userAgent);
+ return this.isIPhone() || this.isIPad();
}
/**
@@ -43,12 +86,42 @@ export class PlatformService {
}
/**
- * Detect if the device is an iPhone or iPad
+ * Get the maximum screen dimension (useful for detecting device capabilities)
*/
- private isIosDevice(userAgent: string): boolean {
- const isIPad = /\bMacintosh\b/.test(userAgent) && 'ontouchend' in document;
- const isIPhone = /\biPhone\b/.test(userAgent) && /\bMobile\b/.test(userAgent);
- return isIPad || isIPhone;
+ getMaxScreenDimension(): number {
+ if (typeof screen === 'undefined') return 1024;
+ return Math.max(screen.width, screen.height);
+ }
+
+ /**
+ * Get the minimum screen dimension
+ */
+ getMinScreenDimension(): number {
+ if (typeof screen === 'undefined') return 768;
+ return Math.min(screen.width, screen.height);
+ }
+
+ /**
+ * Enhanced mobile detection that considers physical device characteristics
+ * This is orientation-independent and more reliable for landscape warnings
+ */
+ isPhysicalMobileDevice(): boolean {
+ // First check: User agent based detection (most reliable)
+ if (this.isPhysicalMobile()) {
+ return true;
+ }
+
+ // Second check: Screen dimensions for edge cases
+ // Most mobile devices have a max dimension <= 950px even in landscape
+ const maxDimension = this.getMaxScreenDimension();
+ const minDimension = this.getMinScreenDimension();
+
+ // If touch device with small screen dimensions, likely mobile
+ if (this.isTouchDevice() && maxDimension <= 950 && minDimension <= 500) {
+ return true;
+ }
+
+ return false;
}
// ===== Browser Detection =====
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/viewport/viewport.service.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/viewport/viewport.service.ts
index af2b9d7b..e0203739 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/viewport/viewport.service.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/viewport/viewport.service.ts
@@ -49,6 +49,17 @@ export class ViewportService implements OnDestroy {
*/
readonly isTouchDevice = computed(() => this.platform.isTouchDevice());
+ /**
+ * Whether device is physically a mobile device (orientation-independent)
+ * This uses hardware detection, not just screen size
+ */
+ readonly isPhysicalMobile = computed(() => this.platform.isPhysicalMobileDevice());
+
+ /**
+ * Whether device is physically a tablet (orientation-independent)
+ */
+ readonly isPhysicalTablet = computed(() => this.platform.isPhysicalTablet());
+
/**
* Current viewport size category
*/
@@ -68,7 +79,8 @@ export class ViewportService implements OnDestroy {
});
/**
- * Whether current viewport is mobile size
+ * Whether current viewport is mobile size (legacy method)
+ * For landscape warnings, use isPhysicalMobile instead
*/
readonly isMobile = computed(() => this.viewportSize() === 'mobile' && this.platform.isTouchDevice());
@@ -77,6 +89,14 @@ export class ViewportService implements OnDestroy {
*/
readonly isTablet = computed(() => this.viewportSize() === 'tablet' && this.platform.isTouchDevice());
+ /**
+ * Whether device should show mobile landscape warning
+ * This is orientation-independent and hardware-based detection
+ */
+ readonly shouldShowLandscapeWarning = computed(() =>
+ this.isPhysicalMobile() && this.orientation() === 'landscape'
+ );
+
/**
* Whether current viewport is desktop size
*/
@@ -119,7 +139,10 @@ export class ViewportService implements OnDestroy {
isTablet: this.isTablet(),
isDesktop: this.isDesktop(),
isWide: this.isWide(),
- isTouchDevice: this.isTouchDevice()
+ isTouchDevice: this.isTouchDevice(),
+ isPhysicalMobile: this.isPhysicalMobile(),
+ isPhysicalTablet: this.isPhysicalTablet(),
+ shouldShowLandscapeWarning: this.shouldShowLandscapeWarning()
}));
// ==== PUBLIC UTILITY METHODS ====
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts
index 2fdc29cb..f3e1c671 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts
@@ -18,6 +18,7 @@ export * from './lib/components/toolbar/toolbar.component';
export * from './lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component';
export * from './lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component';
export * from './lib/components/videoconference/videoconference.component';
+export * from './lib/components/landscape-warning/landscape-warning.component';
export * from './lib/config/openvidu-components-angular.config';
// Directives
export * from './lib/directives/api/activities-panel.directive';