mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 15:52:02 +00:00
Merge pull request #694 from Stremio/refactor/unite-platform-logic
refactor: logic unite
This commit is contained in:
commit
02b9b5b435
7 changed files with 53 additions and 54 deletions
|
|
@ -1,15 +1,18 @@
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
import useShell from './useShell';
|
|
||||||
import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS';
|
import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS';
|
||||||
|
import useShell from './useShell';
|
||||||
|
import { name, isMobile } from './device';
|
||||||
|
|
||||||
interface PlatformContext {
|
interface PlatformContext {
|
||||||
openExternal: (url: string) => void,
|
name: string;
|
||||||
};
|
isMobile: boolean;
|
||||||
|
openExternal: (url: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
const PlatformContext = createContext<PlatformContext | null>(null);
|
const PlatformContext = createContext<PlatformContext | null>(null);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: JSX.Element,
|
children: JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PlatformProvider = ({ children }: Props) => {
|
const PlatformProvider = ({ children }: Props) => {
|
||||||
|
|
@ -19,8 +22,8 @@ const PlatformProvider = ({ children }: Props) => {
|
||||||
try {
|
try {
|
||||||
const { hostname } = new URL(url);
|
const { hostname } = new URL(url);
|
||||||
const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname.endsWith(host));
|
const isWhitelisted = WHITELISTED_HOSTS.some((host: string) => hostname.endsWith(host));
|
||||||
const finalUrl = !isWhitelisted ? 'https://www.stremio.com/warning#' + encodeURIComponent(url) : url;
|
const finalUrl = !isWhitelisted ? `https://www.stremio.com/warning#${encodeURIComponent(url)}` : url;
|
||||||
|
|
||||||
if (shell.active) {
|
if (shell.active) {
|
||||||
shell.send('open-external', finalUrl);
|
shell.send('open-external', finalUrl);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -28,11 +31,11 @@ const PlatformProvider = ({ children }: Props) => {
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to parse external url:', e);
|
console.error('Failed to parse external url:', e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlatformContext.Provider value={{ openExternal }}>
|
<PlatformContext.Provider value={{ openExternal, name, isMobile }}>
|
||||||
{children}
|
{children}
|
||||||
</PlatformContext.Provider>
|
</PlatformContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
@ -42,7 +45,7 @@ const usePlatform = () => {
|
||||||
return useContext(PlatformContext);
|
return useContext(PlatformContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
PlatformProvider,
|
PlatformProvider,
|
||||||
usePlatform,
|
usePlatform
|
||||||
};
|
};
|
||||||
|
|
|
||||||
31
src/common/Platform/device.ts
Normal file
31
src/common/Platform/device.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import Bowser from 'bowser';
|
||||||
|
|
||||||
|
const APPLE_MOBILE_DEVICES = [
|
||||||
|
'iPad Simulator',
|
||||||
|
'iPhone Simulator',
|
||||||
|
'iPod Simulator',
|
||||||
|
'iPad',
|
||||||
|
'iPhone',
|
||||||
|
'iPod',
|
||||||
|
];
|
||||||
|
|
||||||
|
const { userAgent, platform, maxTouchPoints } = globalThis.navigator;
|
||||||
|
|
||||||
|
// this detects ipad properly in safari
|
||||||
|
// while bowser does not
|
||||||
|
const isIOS = APPLE_MOBILE_DEVICES.includes(platform) || (userAgent.includes('Mac') && 'ontouchend' in document);
|
||||||
|
|
||||||
|
// Edge case: iPad is included in this function
|
||||||
|
// Keep in mind maxTouchPoints for Vision Pro might change in the future
|
||||||
|
const isVisionOS = userAgent.includes('Macintosh') || maxTouchPoints === 5;
|
||||||
|
|
||||||
|
const bowser = Bowser.getParser(userAgent);
|
||||||
|
const os = bowser.getOSName().toLowerCase();
|
||||||
|
|
||||||
|
const name = isVisionOS ? 'visionos' : isIOS ? 'ios' : os || 'unknown';
|
||||||
|
const isMobile = ['ios', 'android'].includes(name);
|
||||||
|
|
||||||
|
export {
|
||||||
|
name,
|
||||||
|
isMobile,
|
||||||
|
};
|
||||||
|
|
@ -46,7 +46,6 @@ const useProfile = require('./useProfile');
|
||||||
const useStreamingServer = require('./useStreamingServer');
|
const useStreamingServer = require('./useStreamingServer');
|
||||||
const useTorrent = require('./useTorrent');
|
const useTorrent = require('./useTorrent');
|
||||||
const useTranslate = require('./useTranslate');
|
const useTranslate = require('./useTranslate');
|
||||||
const platform = require('./platform');
|
|
||||||
const EventModal = require('./EventModal');
|
const EventModal = require('./EventModal');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -101,6 +100,5 @@ module.exports = {
|
||||||
useStreamingServer,
|
useStreamingServer,
|
||||||
useTorrent,
|
useTorrent,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
platform,
|
|
||||||
EventModal,
|
EventModal,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
// Copyright (C) 2017-2024 Smart code 203358507
|
|
||||||
|
|
||||||
// this detects ipad properly in safari
|
|
||||||
// while bowser does not
|
|
||||||
const iOS = () => {
|
|
||||||
return [
|
|
||||||
'iPad Simulator',
|
|
||||||
'iPhone Simulator',
|
|
||||||
'iPod Simulator',
|
|
||||||
'iPad',
|
|
||||||
'iPhone',
|
|
||||||
'iPod'
|
|
||||||
].includes(navigator.platform)
|
|
||||||
|| (navigator.userAgent.includes('Mac') && 'ontouchend' in document);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Bowser = require('bowser');
|
|
||||||
|
|
||||||
const browser = Bowser.parse(window.navigator?.userAgent || '');
|
|
||||||
|
|
||||||
// Edge case: iPad is included in this function
|
|
||||||
// Keep in mind maxTouchPoints for Vision Pro might change in the future
|
|
||||||
const isVisionProUser = () => {
|
|
||||||
const isMacintosh = navigator.userAgent.includes('Macintosh');
|
|
||||||
const hasFiveTouchPoints = navigator.maxTouchPoints === 5;
|
|
||||||
return isMacintosh && hasFiveTouchPoints;
|
|
||||||
};
|
|
||||||
|
|
||||||
const name = isVisionProUser() ? 'visionos' : (iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase());
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name,
|
|
||||||
isMobile: () => {
|
|
||||||
return name === 'ios' || name === 'android';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -5,7 +5,7 @@ const PropTypes = require('prop-types');
|
||||||
const classnames = require('classnames');
|
const classnames = require('classnames');
|
||||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||||
const { t } = require('i18next');
|
const { t } = require('i18next');
|
||||||
const { Button, Image, useProfile, platform, useToast, Popup, useBinaryState } = require('stremio/common');
|
const { Button, Image, useProfile, usePlatform, useToast, Popup, useBinaryState } = require('stremio/common');
|
||||||
const { useServices } = require('stremio/services');
|
const { useServices } = require('stremio/services');
|
||||||
const { useRouteFocused } = require('stremio-router');
|
const { useRouteFocused } = require('stremio-router');
|
||||||
const StreamPlaceholder = require('./StreamPlaceholder');
|
const StreamPlaceholder = require('./StreamPlaceholder');
|
||||||
|
|
@ -14,6 +14,7 @@ const styles = require('./styles');
|
||||||
const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => {
|
const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => {
|
||||||
const profile = useProfile();
|
const profile = useProfile();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const platform = usePlatform();
|
||||||
const { core } = useServices();
|
const { core } = useServices();
|
||||||
const routeFocused = useRouteFocused();
|
const routeFocused = useRouteFocused();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ const { Button, Checkbox, MainNavBars, Multiselect, ColorInput, TextInput, Modal
|
||||||
const useProfileSettingsInputs = require('./useProfileSettingsInputs');
|
const useProfileSettingsInputs = require('./useProfileSettingsInputs');
|
||||||
const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs');
|
const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs');
|
||||||
const useDataExport = require('./useDataExport');
|
const useDataExport = require('./useDataExport');
|
||||||
const { name: platformName } = require('stremio/common/platform');
|
|
||||||
const styles = require('./styles');
|
const styles = require('./styles');
|
||||||
|
|
||||||
const GENERAL_SECTION = 'general';
|
const GENERAL_SECTION = 'general';
|
||||||
|
|
@ -104,16 +103,18 @@ const Settings = () => {
|
||||||
}
|
}
|
||||||
}, [isTraktAuthenticated, profile.auth]);
|
}, [isTraktAuthenticated, profile.auth]);
|
||||||
const subscribeCalendarOnClick = React.useCallback(() => {
|
const subscribeCalendarOnClick = React.useCallback(() => {
|
||||||
const protocol = platformName === 'ios' ? 'webcal' : 'https';
|
if (!profile.auth) return;
|
||||||
|
|
||||||
|
const protocol = platform.name === 'ios' ? 'webcal' : 'https';
|
||||||
const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`;
|
const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`;
|
||||||
platform.openExternal(url);
|
platform.openExternal(url);
|
||||||
toast.show({
|
toast.show({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: platformName === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') : t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'),
|
title: platform.name === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') : t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'),
|
||||||
timeout: 25000
|
timeout: 25000
|
||||||
});
|
});
|
||||||
// Stremio 4 emits not documented event subscribeCalendar
|
// Stremio 4 emits not documented event subscribeCalendar
|
||||||
}, [profile.auth.user._id]);
|
}, [profile.auth]);
|
||||||
const exportDataOnClick = React.useCallback(() => {
|
const exportDataOnClick = React.useCallback(() => {
|
||||||
loadDataExport();
|
loadDataExport();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const { useTranslation } = require('react-i18next');
|
const { useTranslation } = require('react-i18next');
|
||||||
const { useServices } = require('stremio/services');
|
const { useServices } = require('stremio/services');
|
||||||
const { CONSTANTS, interfaceLanguages, languageNames, platform } = require('stremio/common');
|
const { CONSTANTS, usePlatform, interfaceLanguages, languageNames } = require('stremio/common');
|
||||||
|
|
||||||
const useProfileSettingsInputs = (profile) => {
|
const useProfileSettingsInputs = (profile) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { core } = useServices();
|
const { core } = useServices();
|
||||||
|
const platform = usePlatform();
|
||||||
// TODO combine those useMemo in one
|
// TODO combine those useMemo in one
|
||||||
const interfaceLanguageSelect = React.useMemo(() => ({
|
const interfaceLanguageSelect = React.useMemo(() => ({
|
||||||
options: interfaceLanguages.map(({ name, codes }) => ({
|
options: interfaceLanguages.map(({ name, codes }) => ({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue