diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-03-13 16:01:43 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-13 16:01:43 -0500 |
commit | 56cf890debeb9872f791ccb992a5587f2c05fd9e (patch) | |
tree | 929453b41274a712d8b2fce441e98a0cd030d305 /src/state/models/navigation.ts | |
parent | 503e03d91e1de4bfeabec1eb2d97dcdceb13fcc5 (diff) | |
download | voidsky-56cf890debeb9872f791ccb992a5587f2c05fd9e.tar.zst |
Move to expo and react-navigation (#288)
* WIP - adding expo * WIP - adding expo 2 * Fix tsc * Finish adding expo * Disable the 'require cycle' warning * Tweak plist * Modify some dependency versions to make expo happy * Fix icon fill * Get Web compiling for expo * 1.7 * Switch to react-navigation in expo2 (#287) * WIP Switch to react-navigation * WIP Switch to react-navigation 2 * WIP Switch to react-navigation 3 * Convert all screens to react navigation * Update BottomBar for react navigation * Update mobile menu to be react-native drawer * Fixes to drawer and bottombar * Factor out some helpers * Replace the navigation model with react-navigation * Restructure the shell folder and fix the header positioning * Restore the error boundary * Fix tsc * Implement not-found page * Remove react-native-gesture-handler (no longer used) * Handle notifee card presses * Handle all navigations from the state layer * Fix drawer behaviors * Fix two linking issues * Switch to our react-native-progress fork to fix an svg rendering issue * Get Web working with react-navigation * Refactor routes and navigation for a bit more clarity * Remove dead code * Rework Web shell to left/right nav to make this easier * Fix ViewHeader for desktop web * Hide profileheader back btn on desktop web * Move the compose button to the left nav * Implement reply prompt in threads for desktop web * Composer refactors * Factor out all platform-specific text input behaviors from the composer * Small fix * Update the web build to use tiptap for the composer * Tune up the mention autocomplete dropdown * Simplify the default avatar and banner * Fixes to link cards in web composer * Fix dropdowns on web * Tweak load latest on desktop * Add web beta message and feedback link * Fix up links in desktop web
Diffstat (limited to 'src/state/models/navigation.ts')
-rw-r--r-- | src/state/models/navigation.ts | 434 |
1 files changed, 0 insertions, 434 deletions
diff --git a/src/state/models/navigation.ts b/src/state/models/navigation.ts deleted file mode 100644 index 11af65912..000000000 --- a/src/state/models/navigation.ts +++ /dev/null @@ -1,434 +0,0 @@ -import {RootStoreModel} from './root-store' -import {makeAutoObservable} from 'mobx' -import {TABS_ENABLED} from 'lib/build-flags' -import * as analytics from 'lib/analytics' -import {isNative} from 'platform/detection' - -let __id = 0 -function genId() { - return String(++__id) -} - -// NOTE -// this model was originally built for a freeform "tabs" concept like a browser -// we've since decided to pause that idea and do something more traditional -// until we're fully sure what that is, the tabs are being repurposed into a fixed topology -// - Tab 0: The "Default" tab -// - Tab 1: The "Search" tab -// - Tab 2: The "Notifications" tab -// These tabs always retain the first item in their history. -// -prf -export enum TabPurpose { - Default = 0, - Search = 1, - Notifs = 2, -} - -export const TabPurposeMainPath: Record<TabPurpose, string> = { - [TabPurpose.Default]: '/', - [TabPurpose.Search]: '/search', - [TabPurpose.Notifs]: '/notifications', -} - -interface HistoryItem { - url: string - ts: number - title?: string - id: string -} - -export type HistoryPtr = string // `{tabId}-{historyId}` - -export class NavigationTabModel { - id = genId() - history: HistoryItem[] - index = 0 - isNewTab = false - - constructor(public fixedTabPurpose: TabPurpose) { - this.history = [ - {url: TabPurposeMainPath[fixedTabPurpose], ts: Date.now(), id: genId()}, - ] - makeAutoObservable(this, { - serialize: false, - hydrate: false, - }) - } - // accessors - // = - - get current() { - return this.history[this.index] - } - - get canGoBack() { - return this.index > 0 - } - - get canGoForward() { - return this.index < this.history.length - 1 - } - - getBackList(n: number) { - const start = Math.max(this.index - n, 0) - const end = this.index - return this.history.slice(start, end).map((item, i) => ({ - url: item.url, - title: item.title, - index: start + i, - id: item.id, - })) - } - - get backTen() { - return this.getBackList(10) - } - - getForwardList(n: number) { - const start = Math.min(this.index + 1, this.history.length) - const end = Math.min(this.index + n + 1, this.history.length) - return this.history.slice(start, end).map((item, i) => ({ - url: item.url, - title: item.title, - index: start + i, - id: item.id, - })) - } - - get forwardTen() { - return this.getForwardList(10) - } - - // navigation - // = - - navigate(url: string, title?: string) { - try { - const path = url.split('/')[1] - analytics.track('Navigation', { - path, - }) - } catch (error) {} - - if (this.current?.url === url) { - this.refresh() - } else { - if (this.index < this.history.length - 1) { - this.history.length = this.index + 1 - } - // TEMP ensure the tab has its purpose's main view -prf - if (this.history.length < 1) { - const fixedUrl = TabPurposeMainPath[this.fixedTabPurpose] - this.history.push({url: fixedUrl, ts: Date.now(), id: genId()}) - } - this.history.push({url, title, ts: Date.now(), id: genId()}) - this.index = this.history.length - 1 - if (!isNative) { - window.history.pushState({hindex: this.index, hurl: url}, '', url) - } - } - } - - refresh() { - this.history = [ - ...this.history.slice(0, this.index), - { - url: this.current.url, - title: this.current.title, - ts: Date.now(), - id: this.current.id, - }, - ...this.history.slice(this.index + 1), - ] - } - - goBack() { - if (this.canGoBack) { - this.index-- - if (!isNative) { - window.history.back() - } - } - } - - // TEMP - // a helper to bring the tab back to its base state - // -prf - fixedTabReset() { - this.index = 0 - } - - goForward() { - if (this.canGoForward) { - this.index++ - if (!isNative) { - window.history.forward() - } - } - } - - goToIndex(index: number) { - if (index >= 0 && index <= this.history.length - 1) { - const delta = index - this.index - this.index = index - if (!isNative) { - window.history.go(delta) - } - } - } - - setTitle(id: string, title: string) { - this.history = this.history.map(h => { - if (h.id === id) { - return {...h, title} - } - return h - }) - } - - setIsNewTab(v: boolean) { - this.isNewTab = v - } - - // browser only - // = - - resetTo(url: string) { - this.index = 0 - this.history.push({url, title: '', ts: Date.now(), id: genId()}) - this.index = this.history.length - 1 - } - - // persistence - // = - - serialize(): unknown { - return { - history: this.history, - index: this.index, - } - } - - hydrate(_v: unknown) { - // TODO fixme - // if (isObj(v)) { - // if (hasProp(v, 'history') && Array.isArray(v.history)) { - // for (const item of v.history) { - // if ( - // isObj(item) && - // hasProp(item, 'url') && - // typeof item.url === 'string' - // ) { - // let copy: HistoryItem = { - // url: item.url, - // ts: - // hasProp(item, 'ts') && typeof item.ts === 'number' - // ? item.ts - // : Date.now(), - // } - // if (hasProp(item, 'title') && typeof item.title === 'string') { - // copy.title = item.title - // } - // this.history.push(copy) - // } - // } - // } - // if (hasProp(v, 'index') && typeof v.index === 'number') { - // this.index = v.index - // } - // if (this.index >= this.history.length - 1) { - // this.index = this.history.length - 1 - // } - // } - } -} - -export class NavigationModel { - tabs: NavigationTabModel[] = isNative - ? [ - new NavigationTabModel(TabPurpose.Default), - new NavigationTabModel(TabPurpose.Search), - new NavigationTabModel(TabPurpose.Notifs), - ] - : [new NavigationTabModel(TabPurpose.Default)] - tabIndex = 0 - - constructor(public rootStore: RootStoreModel) { - makeAutoObservable(this, { - rootStore: false, - serialize: false, - hydrate: false, - }) - } - - /** - * Used only in the web build to sync with browser history state - */ - bindWebNavigation() { - if (!isNative) { - window.addEventListener('popstate', e => { - const {hindex, hurl} = e.state - if (hindex >= 0 && hindex <= this.tab.history.length - 1) { - this.tab.index = hindex - } - if (this.tab.current.url !== hurl) { - // desynced because they went back to an old tab session- - // do a reset to match that - this.tab.resetTo(hurl) - } - - // sanity check - if (this.tab.current.url !== window.location.pathname) { - // state has completely desynced, reload - window.location.reload() - } - }) - } - } - - clear() { - this.tabs = isNative - ? [ - new NavigationTabModel(TabPurpose.Default), - new NavigationTabModel(TabPurpose.Search), - new NavigationTabModel(TabPurpose.Notifs), - ] - : [new NavigationTabModel(TabPurpose.Default)] - this.tabIndex = 0 - } - - // accessors - // = - - get tab() { - return this.tabs[this.tabIndex] - } - - get tabCount() { - return this.tabs.length - } - - isCurrentScreen(tabId: string, index: number) { - return this.tab.id === tabId && this.tab.index === index - } - - // navigation - // = - - navigate(url: string, title?: string) { - this.rootStore.emitNavigation() - this.tab.navigate(url, title) - } - - refresh() { - this.tab.refresh() - } - - setTitle(ptr: HistoryPtr, title: string) { - const [tid, hid] = ptr.split('-') - this.tabs.find(t => t.id === tid)?.setTitle(hid, title) - } - - handleLink(url: string) { - let path - if (url.startsWith('/')) { - path = url - } else if (url.startsWith('http')) { - try { - path = new URL(url).pathname - } catch (e) { - console.error('Invalid url', url, e) - return - } - } else { - console.error('Invalid url', url) - return - } - this.navigate(path) - } - - // tab management - // = - - // TEMP - // fixed tab helper function - // -prf - switchTo(purpose: TabPurpose, reset: boolean) { - this.rootStore.emitNavigation() - switch (purpose) { - case TabPurpose.Notifs: - this.tabIndex = 2 - break - case TabPurpose.Search: - this.tabIndex = 1 - break - default: - this.tabIndex = 0 - } - if (reset) { - this.tab.fixedTabReset() - } - } - - newTab(url: string, title?: string) { - if (!TABS_ENABLED) { - return this.navigate(url) - } - const tab = new NavigationTabModel(TabPurpose.Default) - tab.navigate(url, title) - tab.isNewTab = true - this.tabs.push(tab) - this.tabIndex = this.tabs.length - 1 - } - - setActiveTab(tabIndex: number) { - if (!TABS_ENABLED) { - return - } - this.tabIndex = Math.max(Math.min(tabIndex, this.tabs.length - 1), 0) - } - - closeTab(tabIndex: number) { - if (!TABS_ENABLED) { - return - } - this.tabs = [ - ...this.tabs.slice(0, tabIndex), - ...this.tabs.slice(tabIndex + 1), - ] - if (this.tabs.length === 0) { - this.newTab('/') - } else if (this.tabIndex >= this.tabs.length) { - this.tabIndex = this.tabs.length - 1 - } - } - - // persistence - // = - - serialize(): unknown { - return { - tabs: this.tabs.map(t => t.serialize()), - tabIndex: this.tabIndex, - } - } - - hydrate(_v: unknown) { - // TODO fixme - this.clear() - /*if (isObj(v)) { - if (hasProp(v, 'tabs') && Array.isArray(v.tabs)) { - for (const tab of v.tabs) { - const copy = new NavigationTabModel() - copy.hydrate(tab) - if (copy.history.length) { - this.tabs.push(copy) - } - } - } - if (hasProp(v, 'tabIndex') && typeof v.tabIndex === 'number') { - this.tabIndex = v.tabIndex - } - }*/ - } -} |