Test an "open in mobile app" message on android

This commit is contained in:
Chocobozzz 2025-01-17 11:15:37 +01:00
parent 890d6dc627
commit dbf9fce351
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
6 changed files with 117 additions and 10 deletions

View File

@ -1,3 +1,13 @@
<div *ngIf="mobileMsg" class="mobile-msg">
<div class="msg ellipsis me-auto" i18n>Open in the application?</div>
<a class="peertube-button-link secondary-button me-3" [href]="mobileAppUrl">Open</a>
<button class="border-0 p-0" title="Close this message" i18n-title (click)="hideMobileMsg()">
<my-global-icon iconName="cross"></my-global-icon>
</button>
</div>
<div class="root">
<a class="peertube-title" [routerLink]="getDefaultRoute()" [queryParams]="getDefaultRouteQuery()">

View File

@ -3,6 +3,27 @@
@use '_mixins' as *;
@use '_button-mixins' as *;
.mobile-msg {
display: flex;
align-items: center;
padding: 0 1.5rem;
height: $header-mobile-msg-height;
background: pvar(--bg-secondary-400);
.msg {
color: pvar(--fg-300);
font-weight: $font-bold;
@include font-size(14px);
}
button {
my-global-icon {
color: pvar(--fg-200);
}
}
}
.root {
--co-logo-size: 34px;
--co-root-padding: 1.5rem;

View File

@ -1,6 +1,6 @@
import { CommonModule } from '@angular/common'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { Router, RouterLink } from '@angular/router'
import { ActivatedRoute, NavigationEnd, Router, RouterLink } from '@angular/router'
import {
AuthService,
AuthStatus,
@ -25,6 +25,8 @@ import { Subscription } from 'rxjs'
import { GlobalIconComponent } from '../shared/shared-icons/global-icon.component'
import { ButtonComponent } from '../shared/shared-main/buttons/button.component'
import { SearchTypeaheadComponent } from './search-typeahead.component'
import { isAndroid, isIOS, isIphone } from '@root-helpers/web-browser'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
@Component({
selector: 'my-header',
@ -51,6 +53,8 @@ import { SearchTypeaheadComponent } from './search-typeahead.component'
})
export class HeaderComponent implements OnInit, OnDestroy {
private static LS_HIDE_MOBILE_MSG = 'hide-mobile-msg'
@ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
@ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
@ViewChild('dropdown') dropdown: NgbDropdown
@ -62,6 +66,9 @@ export class HeaderComponent implements OnInit, OnDestroy {
currentInterfaceLanguage: string
mobileMsg = false
mobileAppUrl = ''
private serverConfig: ServerConfig
private quickSettingsModalSub: Subscription
@ -76,6 +83,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
private screenService: ScreenService,
private modalService: PeertubeModalService,
private router: Router,
private route: ActivatedRoute,
private menu: MenuService
) { }
@ -127,6 +135,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
this.quickSettingsModalSub = this.modalService.openQuickSettingsSubject
.subscribe(() => this.openQuickSettings())
this.setupMobileMsg()
}
ngOnDestroy () {
@ -147,6 +157,58 @@ export class HeaderComponent implements OnInit, OnDestroy {
// ---------------------------------------------------------------------------
private setupMobileMsg () {
if (!this.isInMobileView()) return
if (peertubeLocalStorage.getItem(HeaderComponent.LS_HIDE_MOBILE_MSG) === 'true') return
if (!isAndroid()) return
this.mobileMsg = true
document.body.classList.add('mobile-app-msg')
const host = window.location.host
const getVideoId = (url: string) => {
const matches = url.match(/^\/w\/([^/]+)$/)
if (matches) return matches[1]
}
const getChannelId = (url: string) => {
const matches = url.match(/^\/c\/([^/]+)/)
if (matches) return matches[1]
}
this.router.events.subscribe(event => {
if (!(event instanceof NavigationEnd)) return
const url = event.url
const videoId = getVideoId(url)
if (videoId) {
this.mobileAppUrl = `peertube:///video/${videoId}?host=${host}`
return
}
const channelId = getChannelId(url)
if (channelId) {
this.mobileAppUrl = `peertube:///video-channel/${channelId}?host=${host}`
return
}
this.mobileAppUrl = `peertube:///?host=${host}`
})
}
hideMobileMsg () {
this.mobileMsg = false
document.body.classList.remove('mobile-app-msg')
peertubeLocalStorage.setItem(HeaderComponent.LS_HIDE_MOBILE_MSG, 'true')
}
// ---------------------------------------------------------------------------
isRegistrationAllowed () {
if (!this.serverConfig) return false

View File

@ -1,4 +1,4 @@
function isIOS () {
export function isIOS () {
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
return true
}
@ -9,16 +9,19 @@ function isIOS () {
navigator.platform.includes('MacIntel'))
}
function isSafari () {
export function isSafari () {
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
}
function isMobile () {
export function isMobile () {
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
}
export {
isIOS,
isSafari,
isMobile
export function isIphone () {
return /iPhone/i.test(navigator.userAgent)
}
export function isAndroid () {
return /Android/i.test(navigator.userAgent)
}

View File

@ -85,15 +85,27 @@ body {
--header-height: #{$header-height};
&.mobile-app-msg {
--header-height: #{$header-height + $header-mobile-msg-height};
}
--menu-fg: #{pvar(--fg-400)};
--menu-bg: #{pvar(--bg-secondary-400)};
@media screen and (max-width: $small-view) {
--header-height: #{$header-height-small-view};
&.mobile-app-msg {
--header-height: #{$header-height-small-view + $header-mobile-msg-height};
}
}
@media screen and (max-width: $mobile-view) {
--header-height: #{$header-height-mobile-view};
&.mobile-app-msg {
--header-height: #{$header-height-mobile-view + $header-mobile-msg-height};
}
}
// Light theme

View File

@ -23,14 +23,13 @@ $button-font-size: 1rem;
$header-height: 94px;
$header-height-small-view: 74px;
$header-height-mobile-view: 124px;
$header-mobile-msg-height: 48px;
$menu-width: 248px;
$menu-collapsed-width: 50px;
$menu-margin-left: 2rem;
$menu-overlay-view: 1200px;
$sub-menu-height: 81px;
$banner-inverted-ratio: math.div(1, 6);
$max-channels-width: 1200px;