import { filter } from 'common/collections'; import { BooleanLike } from 'common/react'; import { decodeHtmlEntities, toTitleCase } from 'common/string'; import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; import { Box, ByondUi, Button, Flex, Icon, LabeledList, Input, Section, Table } from '../components'; import { Window } from '../layouts'; import { CrewManifestContent } from './CrewManifest'; const HOMETAB = 1; const PHONTAB = 2; const CONTTAB = 3; const MESSTAB = 4; const MESSSUBTAB = 40; const NEWSTAB = 5; const NOTETAB = 6; const WTHRTAB = 7; const MANITAB = 8; const SETTTAB = 9; let TabToTemplate = {}; // Populated under each template type Data = { // GENERAL currentTab: number; video_comm: BooleanLike; mapRef: string; // FOOTER time: string; connectionStatus: BooleanLike; owner: string; occupation: string; // HEADER flashlight: BooleanLike; // NOTIFICATIONS voice_mobs: []; communicating: []; requestsReceived: []; invitesSent: []; }; export const Communicator = (props, context) => { const { act, data } = useBackend(context); const { currentTab, video_comm, mapRef } = data; /* 0: Fullscreen Video * 1: Popup Video * 2: Minimized Video */ const [videoSetting, setVideoSetting] = useLocalState(context, 'videoSetting', 0); return ( {video_comm && } {(!video_comm || videoSetting !== 0) && ( {TabToTemplate[currentTab] || } )} ); }; const VideoComm = (props, context) => { const { act, data } = useBackend(context); const { video_comm, mapRef } = data; const { videoSetting, setVideoSetting } = props; if (videoSetting === 0) { return ( {app.module} ))} ); }; TabToTemplate[HOMETAB] = ; type PhoneTabData = { targetAddress: string; voice_mobs: { name: string; true_name: string; ref: string }[]; communicating: { address: string; name: string; true_name: string; ref: string }[]; requestsReceived: { address: string; name: string; ref: string }[]; invitesSent: { address: string; name: string }[]; video_comm: string; selfie_mode: BooleanLike; }; /* Phone tab, provides a phone interface! */ const PhoneTab = (props, context) => { const { act, data } = useBackend(context); const { targetAddress, voice_mobs, communicating, requestsReceived, invitesSent, video_comm, selfie_mode } = data; return (
act('write_target_address', { val: val })} />
{(!!communicating.length && ( {communicating.map((comm) => ( {decodeHtmlEntities(comm.name)}
)) || No connections}
{(!!requestsReceived.length && ( {requestsReceived.map((request) => ( {decodeHtmlEntities(request.address)}
{(!!invitesSent.length && ( {invitesSent.map((invite) => ( {decodeHtmlEntities(invite.address)}
); }; // Subtemplate const NumberPad = (props, context) => { const { act, data } = useBackend(context); const { targetAddress } = data; const validCharacters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; let buttonArray = validCharacters.map((char) => ( Dial {/* Message */} Message {/* Hang Up */} Hang Up ); }; TabToTemplate[PHONTAB] = ; type ContactsTabData = { knownDevices: { address: string; name: string }[]; }; /* Contacts */ const ContactsTab = (props, context) => { const { act, data } = useBackend(context); const { knownDevices } = data; return (
{(knownDevices.length && ( {knownDevices.map((device) => ( {decodeHtmlEntities(device.name)} {device.address}
)) || No devices detected on your local NTNet region.}
); }; TabToTemplate[CONTTAB] = ; type MessagingTabData = { // TAB imContacts: { address: string; name: string }[]; // THREAD targetAddressName: string; targetAddress: string; imList: { address: string; to_address: string; im: string }[]; }; /* Messaging */ const MessagingTab = (props, context) => { const { act, data } = useBackend(context); const { imContacts } = data; return (
{(imContacts.length && ( {imContacts.map((device) => ( {decodeHtmlEntities(device.name)}: {device.address}
)) || ( You haven't sent any messages yet.
); }; TabToTemplate[MESSTAB] = ; /* Actual messaging conversation */ const IsIMOurs = (im, targetAddress) => { return im.address !== targetAddress; }; const enforceLengthLimit = (prefix: string, name: string, length: number) => { if ((prefix + name).length > length) { if (name.length > length) { return name.slice(0, length) + '...'; } return name; } return prefix + name; }; const findClassMessage = (im, targetAddress, lastIndex, filterArray) => { if (lastIndex < 0 || lastIndex > filterArray.length) { return IsIMOurs(im, targetAddress) ? 'TinderMessage_First_Sent' : 'TinderMessage_First_Received'; } let thisSent = IsIMOurs(im, targetAddress); let lastSent = IsIMOurs(filterArray[lastIndex], targetAddress); if (thisSent && lastSent) { return 'TinderMessage_Subsequent_Sent'; } else if (!thisSent && !lastSent) { return 'TinderMessage_Subsequent_Received'; } return thisSent ? 'TinderMessage_First_Sent' : 'TinderMessage_First_Received'; }; const MessagingThreadTab = (props, context) => { const { act, data } = useBackend(context); const { targetAddressName, targetAddress, imList } = data; const [clipboardMode, setClipboardMode] = useLocalState(context, 'clipboardMode', false); if (clipboardMode) { return (
{enforceLengthLimit('Conversation with ', decodeHtmlEntities(targetAddressName), 30)} } buttons={
); } return (
{enforceLengthLimit('Conversation with ', decodeHtmlEntities(targetAddressName), 30)} } buttons={
); }; TabToTemplate[MESSSUBTAB] = ; type NewsTabData = { feeds: { index: number; name: string }[]; target_feed: { name: string; author: string; messages: NewsMessage[] }; latest_news: NewsMessage[]; }; type NewsMessage = { ref: string; body: string; img: string; caption: string; message_type: string; author: string; time_stamp: string; index: number; channel: string; }; /* News */ const NewsTab = (props, context) => { const { act, data } = useBackend(context); const { feeds, target_feed } = data; return (
{(!feeds.length && Error: No newsfeeds available. Please try again later.) || (target_feed && ) || }
); }; const NewsTargetFeed = (props, context) => { const { act, data } = useBackend(context); const { target_feed } = data; return (
act('newsfeed', { newsfeed: null })} />}> {target_feed.messages.map((message) => (
- {decodeHtmlEntities(message.body)} {!!message.img && ( {decodeHtmlEntities(message.caption) || null} )} [{message.message_type} by {decodeHtmlEntities(message.author)} - {message.time_stamp}]
))}
); }; const NewsFeed = (props, context) => { const { act, data } = useBackend(context); const { feeds, latest_news } = data; return (
{latest_news.map((news) => (
{decodeHtmlEntities(news.channel)}
- {decodeHtmlEntities(news.body)} {!!news.img && ( [image omitted, view story for more details] {news.caption || null} )} [{news.message_type} by{' '} {news.author} {' '} - {news.time_stamp}]
))}
{feeds.map((feed) => (
); }; TabToTemplate[NEWSTAB] = ; type NoteTabData = { note: string; }; /* Note Keeper */ const NoteTab = (props, context) => { const { act, data } = useBackend(context); const { note } = data; return (
act('edit')} content="Edit Notes" />}>
{note}
); }; TabToTemplate[NOTETAB] = ; /* Weather App */ const getItemColor = (value, min2, min1, max1, max2) => { if (value < min2) { return 'bad'; } else if (value < min1) { return 'average'; } else if (value > max1) { return 'average'; } else if (value > max2) { return 'bad'; } return 'good'; }; type WeatherTabData = { aircontents: AirContent[]; weather: Weather[]; }; type AirContent = { entry: string; val; bad_low: number; poor_low: number; poor_high: number; bad_high: number; units; }; type Weather = { Planet: string; Time: string; Weather: string; Temperature; High; Low; WindDir; WindSpeed; Forecast: string; }; const WeatherTab = (props, context) => { const { act, data } = useBackend(context); const { aircontents, weather } = data; return (
{filter((i: AirContent) => i.val !== '0' || i.entry === 'Pressure' || i.entry === 'Temperature')( aircontents ).map((item: AirContent) => ( {item.val} {decodeHtmlEntities(item.units)} ))}
{(!!weather.length && ( {weather.map((wr) => ( {wr.Time} {toTitleCase(wr.Weather)} Current: {wr.Temperature.toFixed()}°C | High: {wr.High.toFixed()}°C | Low:{' '} {wr.Low.toFixed()}°C {wr.WindDir} {wr.WindSpeed} {decodeHtmlEntities(wr.Forecast)} ))} )) || No weather reports available. Please check back later.}
); }; TabToTemplate[WTHRTAB] = ; /* Crew Manifest */ // Lol just steal it from the existing template TabToTemplate[MANITAB] = ; type SettingsTabData = { owner: string; occupation: string; connectionStatus: BooleanLike; address: string; visible: BooleanLike; ring: BooleanLike; selfie_mode: BooleanLike; }; /* Settings */ const SettingsTab = (props, context) => { const { act, data } = useBackend(context); const { owner, occupation, connectionStatus, address, visible, ring, selfie_mode } = data; return (
); }; TabToTemplate[SETTTAB] = ;