@applicaster/quick-brick-core
Version:
Core package for Applicaster's Quick Brick App
241 lines (198 loc) • 7.38 kB
text/typescript
/// <reference types="@types/tizen-tv-webapis" />
import * as R from "ramda";
import { NetInfoState } from "@react-native-community/netinfo";
import { NETWORK_HOOKS_KEYS } from "./const";
import {
isVizioPlatform,
platformSelect,
} from "@applicaster/zapp-react-native-utils/reactUtils";
import { Platform } from "react-native";
type ConnectionStatus = boolean;
type NetInfoNotReady = null;
// Cmn eslint... It's not a hook...
// eslint-disable-next-line react-hooks/rules-of-hooks
export const pluckPath = R.useWith(R.map, [R.path, R.identity]);
export const callAllWith = (func: ((...any) => void)[], arg) =>
R.forEach((x) => R.call(x, arg), func);
export const getNetworkHooks = (plugins): NetworkHooks => {
const filterModulesWithNetworkHooks = R.filter(
R.where({ module: R.prop("networkHooks") })
);
const networkHooks = R.compose(
// @ts-ignore
pluckPath(["module", "networkHooks"]),
filterModulesWithNetworkHooks
)(plugins);
return R.compose(
R.reject(R.isEmpty),
R.reduce(
(acc, key) =>
R.mergeLeft(
acc,
// @ts-ignore
R.compose(
// @ts-ignore
R.objOf(key),
R.without([undefined]),
// @ts-ignore
R.pluck(key)
)(networkHooks)
),
{}
)
)(NETWORK_HOOKS_KEYS);
};
export function isConnectionInfoReady(
connectionInfo: NetInfoState & { deviceStatus?: NetStatus }
) {
const { details, isConnected, isInternetReachable, deviceStatus } =
connectionInfo;
const hasNetInfo = !R.isNil(isConnected) && !R.isNil(isInternetReachable);
const hasDeviceInfo = !R.isNil(deviceStatus?.online);
// Details returns null on web when offline, it is incorrect to label it as non-ready
return platformSelect({
native: !!details && !R.isNil(isConnected) && !R.isNil(isInternetReachable),
web: hasDeviceInfo || hasNetInfo,
});
}
export const isOnline = (
connectionInfo: NetInfoState & { deviceStatus?: NetStatus }
): ConnectionStatus | NetInfoNotReady => {
if (!isConnectionInfoReady(connectionInfo)) {
return true;
}
const netInfoIsOnline =
connectionInfo.isConnected === true &&
connectionInfo.isInternetReachable === true;
const deviceIsOnline = connectionInfo?.deviceStatus?.online;
return deviceIsOnline || netInfoIsOnline;
};
// REGISTERED DEVICE LISTENERS
let registeredListener = 0;
/**
* This method detects whether we have the necesarry APIs to check network status
* We have created a few ways to detect whether the target device is a Samsung Tizen
* isSamsungPlatform checks if there is a global tizen object, or checks the UserAgent
* The only thing missing is whether we have the necesarry WebAPIs. This method does that.
*/
export const hasTizenAPIs = () => {
const hasWebAPI = typeof webapis !== "undefined";
const isSamsungOS = Platform.OS === ("samsung_tv" as string);
if (isSamsungOS && hasWebAPI) {
return true;
} else {
return false;
}
};
/**
* This method is designed to be a handler for Tizen's networkStateChangeListener
* The first argument is a callback provided by whatever is requesting the network state info
* The second argument is invoked by the networkStateChangeListener and it is supposed to return networkState
* ChangeCb - https://developer.samsung.com/smarttv/develop/api-references/samsung-product-api-references/network-api.html#1.3-NetworkStateChangedCallback
* NetworkState - https://developer.samsung.com/smarttv/develop/api-references/samsung-product-api-references/network-api.html#1.6-NetworkState
*/
const samsungNetworkChangeHandler = (callback: NetCb) => (networkState) => {
let online: NetStatus["online"] = null;
const details: NetStatus["details"] = {
internetConnected: null,
lanCableAttached: null,
gatewayConnected: null,
wifiModuleStateAttached: null,
networkState,
};
if (webapis.network.NetworkState) {
const {
LAN_CABLE_ATTACHED,
LAN_CABLE_DETACHED,
LAN_CABLE_STATE_UNKNOWN,
GATEWAY_CONNECTED,
GATEWAY_DISCONNECTED,
WIFI_MODULE_STATE_ATTACHED,
WIFI_MODULE_STATE_DETACHED,
WIFI_MODULE_STATE_UNKNOWN,
} = webapis.network.NetworkState;
// @ts-ignore
const { INTERNET_CONNECTED, INTERNET_DISCONNECTED } =
webapis.network.NetworkState;
// Our type declaration says internet enums don't exist
// Link says otherwise ^
switch (networkState) {
case GATEWAY_DISCONNECTED:
details.gatewayConnected = false;
online = false;
break;
case GATEWAY_CONNECTED:
details.gatewayConnected = true;
online = true;
break;
case INTERNET_CONNECTED:
details.internetConnected = true;
online = true;
break;
case INTERNET_DISCONNECTED:
details.internetConnected = false;
online = false;
break;
case LAN_CABLE_ATTACHED:
details.lanCableAttached = true;
break;
case LAN_CABLE_DETACHED:
details.lanCableAttached = false;
break;
case LAN_CABLE_STATE_UNKNOWN:
details.lanCableAttached = null;
break;
case WIFI_MODULE_STATE_ATTACHED:
details.wifiModuleStateAttached = true;
break;
case WIFI_MODULE_STATE_DETACHED:
details.wifiModuleStateAttached = false;
break;
case WIFI_MODULE_STATE_UNKNOWN:
details.wifiModuleStateAttached = null;
break;
default:
break;
}
}
return callback({ online, details });
};
/**
* This method helps you subscribe to networkchanges for each device. It is designed to replace NetInfo.
* The NetInfo library does not seem to work in all test scenarios on the web tvs so this method uses the native
* APIs for each device. At the moment we only support Tizen which is using the native addNetworkStateChangeListener
* https://developer.samsung.com/smarttv/develop/api-references/samsung-product-api-references/network-api.html#NetworkManager-addNetworkStateChangeListener
* The native Samsung listener returns an ID which can be used to unregister the listener.
* TODO: come up with way to store IDs for unregister, at the moment using local var in memory
*/
export const subscribeToDeviceNetworkChanges = (callback: NetCb) => {
if (hasTizenAPIs()) {
registeredListener = webapis.network.addNetworkStateChangeListener(
samsungNetworkChangeHandler(callback)
);
return;
}
if (isVizioPlatform()) {
window.addEventListener("online", function () {
callback({ online: true });
});
window.addEventListener("offline", function () {
callback({ online: false });
});
}
};
/**
* Method used to unsubscribe to any device network changes or updates
* The only thing you need to unsubscribe is the id given to you when you subscribed
* https://developer.samsung.com/smarttv/develop/api-references/samsung-product-api-references/network-api.html#NetworkManager-removeNetworkStateChangeListener
*/
export const unsubscribeToDeviceNetworkChanges = (id = registeredListener) => {
if (hasTizenAPIs()) {
webapis.network.removeNetworkStateChangeListener(id);
return;
}
if (isVizioPlatform()) {
window.removeEventListener("online", function () {});
window.removeEventListener("offline", function () {});
}
};