diff --git a/pkg/arvo/app/launch.hoon b/pkg/arvo/app/launch.hoon index 16997bfc0b..04df68453d 100644 --- a/pkg/arvo/app/launch.hoon +++ b/pkg/arvo/app/launch.hoon @@ -191,9 +191,14 @@ ^- (unit (unit cage)) ?. (team:title our.bowl src.bowl) ~ ?+ path [~ ~] - [%x %tiles ~] ``noun+!>([tiles tile-ordering]) - [%x %first-time ~] ``noun+!>(first-time) - [%x %keys ~] ``noun+!>(~(key by tiles)) + [%x %tiles ~] ``noun+!>([tiles tile-ordering]) + [%x %first-time ~] ``noun+!>(first-time) + [%x %keys ~] ``noun+!>(~(key by tiles)) + :: + [%x %runtime-lag ~] + :^ ~ ~ %json + !> ^- json + b+.^(? //(scot %p our.bowl)//(scot %da now.bowl)/zen/lag) == :: ++ on-arvo diff --git a/pkg/interface/src/logic/api/local.ts b/pkg/interface/src/logic/api/local.ts index 305ac71f89..fefc7e339a 100644 --- a/pkg/interface/src/logic/api/local.ts +++ b/pkg/interface/src/logic/api/local.ts @@ -8,6 +8,12 @@ export default class LocalApi extends BaseApi { }); } + getRuntimeLag() { + return this.scry('launch', '/runtime-lag').then((runtimeLag) => { + this.store.handleEvent({ data: { runtimeLag } }); + }); + } + dehydrate() { this.store.dehydrate(); } diff --git a/pkg/interface/src/logic/reducers/launch-update.ts b/pkg/interface/src/logic/reducers/launch-update.ts index 7dfe948e31..43718fffe7 100644 --- a/pkg/interface/src/logic/reducers/launch-update.ts +++ b/pkg/interface/src/logic/reducers/launch-update.ts @@ -38,6 +38,13 @@ export default class LaunchReducer { state.baseHash = baseHash; }) } + + const runtimeLag = _.get(json, 'runtimeLag', null); + if (runtimeLag !== null) { + useLaunchState.getState().set(state => { + state.runtimeLag = runtimeLag; + }); + } } } diff --git a/pkg/interface/src/logic/state/launch.ts b/pkg/interface/src/logic/state/launch.ts index 225c002944..24add92059 100644 --- a/pkg/interface/src/logic/state/launch.ts +++ b/pkg/interface/src/logic/state/launch.ts @@ -12,6 +12,7 @@ export interface LaunchState extends BaseState { weather: WeatherState | null | Record | boolean, userLocation: string | null; baseHash: string | null; + runtimeLag: boolean; }; const useLaunchState = createState('Launch', { @@ -20,7 +21,8 @@ const useLaunchState = createState('Launch', { tiles: {}, weather: null, userLocation: null, - baseHash: null + baseHash: null, + runtimeLag: false, }); diff --git a/pkg/interface/src/types/local-update.ts b/pkg/interface/src/types/local-update.ts index 9813729f37..d2308de2a1 100644 --- a/pkg/interface/src/types/local-update.ts +++ b/pkg/interface/src/types/local-update.ts @@ -13,6 +13,10 @@ interface LocalUpdateBaseHash { baseHash: string; } +interface LocalUpdateRuntimeLag { + runtimeLag: boolean; +} + interface LocalUpdateBackgroundConfig { backgroundConfig: BackgroundConfig; } @@ -51,6 +55,7 @@ export type BackgroundConfig = BackgroundConfigUrl | BackgroundConfigColor | und export type LocalUpdate = | LocalUpdateSetDark | LocalUpdateBaseHash +| LocalUpdateRuntimeLag | LocalUpdateBackgroundConfig | LocalUpdateHideAvatars | LocalUpdateHideNicknames diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 9e14446a27..685aa102f4 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -106,6 +106,7 @@ class App extends React.Component { this.updateTheme(this.themeWatcher); }, 500); this.api.local.getBaseHash(); + this.api.local.getRuntimeLag(); //TODO consider polling periodically this.api.settings.getAll(); gcpManager.start(); Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => { diff --git a/pkg/interface/src/views/apps/launch/app.js b/pkg/interface/src/views/apps/launch/app.js index eb4701ed43..0d525be958 100644 --- a/pkg/interface/src/views/apps/launch/app.js +++ b/pkg/interface/src/views/apps/launch/app.js @@ -47,7 +47,7 @@ const tutSelector = f.pick(['tutorialProgress', 'nextTutStep', 'hideGroups']); export default function LaunchApp(props) { const { connection } = props; - const baseHash = useLaunchState(state => state.baseHash); + const { baseHash, runtimeLag } = useLaunchState(state => state); const [hashText, setHashText] = useState(baseHash); const [exitingTut, setExitingTut] = useState(false); const seen = useSettingsState(s => s?.tutorial?.seen) ?? true; @@ -82,7 +82,10 @@ export default function LaunchApp(props) { }, 2000); }} > - + {hashText || baseHash} diff --git a/pkg/interface/src/views/apps/notifications/inbox.tsx b/pkg/interface/src/views/apps/notifications/inbox.tsx index 1746376afc..28a840dca5 100644 --- a/pkg/interface/src/views/apps/notifications/inbox.tsx +++ b/pkg/interface/src/views/apps/notifications/inbox.tsx @@ -4,7 +4,15 @@ import _ from 'lodash'; import moment from 'moment'; import { BigInteger } from 'big-integer'; -import { Col, Center, Box, Text, LoadingSpinner } from '@tlon/indigo-react'; +import { + Col, + Center, + Box, + Text, + LoadingSpinner, + Icon +} from '@tlon/indigo-react'; + import { Associations, Notifications, @@ -23,6 +31,7 @@ import GlobalApi from '~/logic/api/global'; import { Notification } from './notification'; import { Invites } from './invites'; import { useLazyScroll } from '~/logic/lib/useLazyScroll'; +import useLaunchState from '~/logic/state/launch'; import useHarkState from '~/logic/state/hark'; import useInviteState from '~/logic/state/invite'; import useMetadataState from '~/logic/state/metadata'; @@ -65,6 +74,8 @@ export default function Inbox(props: { }; }, []); + const runtimeLag = useLaunchState(state => state.runtimeLag); + const ready = useHarkState( s => Object.keys(s.unreads.graph).length > 0 ); @@ -122,6 +133,16 @@ export default function Inbox(props: { return ( + + {runtimeLag && ( + + + + Update your binary to continue receiving updates. + + + )} + {[...notificationsByDayMap.keys()].sort().reverse().map((day, index) => { const timeboxes = notificationsByDayMap.get(day)!; diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index f2bc362db9..8ea9936e58 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -18,6 +18,7 @@ import { uxToHex } from '~/logic/lib/util'; import { ProfileStatus } from './ProfileStatus'; import { useTutorialModal } from './useTutorialModal'; +import useLaunchState from '~/logic/state/launch'; import useHarkState from '~/logic/state/hark'; import useInviteState from '~/logic/state/invite'; import useContactState from '~/logic/state/contact'; @@ -30,6 +31,7 @@ const localSel = selectLocalState(['toggleOmnibox']); const StatusBar = (props) => { const { api, ship } = props; const history = useHistory(); + const runtimeLag = useLaunchState(state => state.runtimeLag); const ourContact = useContactState((state) => state.contacts[`~${ship}`]); const notificationsCount = useHarkState((state) => state.notificationsCount); const doNotDisturb = useHarkState((state) => state.doNotDisturb); @@ -86,6 +88,11 @@ const StatusBar = (props) => { toggleOmnibox()}> + {!doNotDisturb && runtimeLag && ( + + + + )} {!doNotDisturb && (notificationsCount > 0 || invites.length > 0) && ( diff --git a/pkg/interface/src/views/components/leap/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js index 87cdc07684..451830aaa3 100644 --- a/pkg/interface/src/views/components/leap/OmniboxResult.js +++ b/pkg/interface/src/views/components/leap/OmniboxResult.js @@ -4,6 +4,7 @@ import defaultApps from '~/logic/lib/default-apps'; import Sigil from '~/logic/lib/sigil'; import { uxToHex, cite } from '~/logic/lib/util'; import withState from '~/logic/lib/withState'; +import useLaunchState from '~/logic/state/launch'; import useHarkState from '~/logic/state/hark'; import useContactState from '~/logic/state/contact'; import useInviteState from '~/logic/state/invite'; @@ -31,11 +32,13 @@ export class OmniboxResult extends Component { } } - getIcon(icon, selected, link, invites, notifications, text, color) { + getIcon(icon, selected, link, invites, notifications, lag, text, color) { const iconFill = this.state.hovered || selected === link ? 'white' : 'black'; const bulletFill = this.state.hovered || selected === link ? 'white' : 'blue'; + const lagFill = + this.state.hovered || selected === link ? 'white' : 'yellow'; const inviteCount = [].concat( ...Object.values(invites).map((obj) => Object.values(obj)) @@ -70,6 +73,14 @@ export class OmniboxResult extends Component { size='18px' color={iconFill} /> + {lag && ( + + )} {(notifications > 0 || inviteCount.length > 0) && (