about summary refs log tree commit diff
path: root/src/state/models
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/models')
-rw-r--r--src/state/models/navigation.ts434
-rw-r--r--src/state/models/root-store.ts12
-rw-r--r--src/state/models/shell-ui.ts11
-rw-r--r--src/state/models/user-local-photos.ts24
4 files changed, 11 insertions, 470 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
-      }
-    }*/
-  }
-}
diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts
index 4b62f501e..203dacce8 100644
--- a/src/state/models/root-store.ts
+++ b/src/state/models/root-store.ts
@@ -11,12 +11,12 @@ import {z} from 'zod'
 import {isObj, hasProp} from 'lib/type-guards'
 import {LogModel} from './log'
 import {SessionModel} from './session'
-import {NavigationModel} from './navigation'
 import {ShellUiModel} from './shell-ui'
 import {ProfilesViewModel} from './profiles-view'
 import {LinkMetasViewModel} from './link-metas-view'
 import {NotificationsViewItemModel} from './notifications-view'
 import {MeModel} from './me'
+import {resetToTab} from '../../Navigation'
 
 export const appInfo = z.object({
   build: z.string(),
@@ -31,7 +31,6 @@ export class RootStoreModel {
   appInfo?: AppInfo
   log = new LogModel()
   session = new SessionModel(this)
-  nav = new NavigationModel(this)
   shell = new ShellUiModel(this)
   me = new MeModel(this)
   profiles = new ProfilesViewModel(this)
@@ -82,7 +81,6 @@ export class RootStoreModel {
       log: this.log.serialize(),
       session: this.session.serialize(),
       me: this.me.serialize(),
-      nav: this.nav.serialize(),
       shell: this.shell.serialize(),
     }
   }
@@ -101,9 +99,6 @@ export class RootStoreModel {
       if (hasProp(v, 'me')) {
         this.me.hydrate(v.me)
       }
-      if (hasProp(v, 'nav')) {
-        this.nav.hydrate(v.nav)
-      }
       if (hasProp(v, 'session')) {
         this.session.hydrate(v.session)
       }
@@ -144,7 +139,7 @@ export class RootStoreModel {
    */
   async handleSessionDrop() {
     this.log.debug('RootStoreModel:handleSessionDrop')
-    this.nav.clear()
+    resetToTab('HomeTab')
     this.me.clear()
     this.emitSessionDropped()
   }
@@ -155,7 +150,7 @@ export class RootStoreModel {
   clearAllSessionState() {
     this.log.debug('RootStoreModel:clearAllSessionState')
     this.session.clear()
-    this.nav.clear()
+    resetToTab('HomeTab')
     this.me.clear()
   }
 
@@ -203,6 +198,7 @@ export class RootStoreModel {
   }
 
   // the current screen has changed
+  // TODO is this still needed?
   onNavigation(handler: () => void): EmitterSubscription {
     return DeviceEventEmitter.addListener('navigation', handler)
   }
diff --git a/src/state/models/shell-ui.ts b/src/state/models/shell-ui.ts
index 68d9cd3d0..8e4eed6eb 100644
--- a/src/state/models/shell-ui.ts
+++ b/src/state/models/shell-ui.ts
@@ -108,7 +108,6 @@ export interface ComposerOptsQuote {
   }
 }
 export interface ComposerOpts {
-  imagesOpen?: boolean
   replyTo?: ComposerOptsPostRef
   onPost?: () => void
   quote?: ComposerOptsQuote
@@ -117,7 +116,7 @@ export interface ComposerOpts {
 export class ShellUiModel {
   darkMode = false
   minimalShellMode = false
-  isMainMenuOpen = false
+  isDrawerOpen = false
   isModalActive = false
   activeModals: Modal[] = []
   isLightboxActive = false
@@ -156,8 +155,12 @@ export class ShellUiModel {
     this.minimalShellMode = v
   }
 
-  setMainMenuOpen(v: boolean) {
-    this.isMainMenuOpen = v
+  openDrawer() {
+    this.isDrawerOpen = true
+  }
+
+  closeDrawer() {
+    this.isDrawerOpen = false
   }
 
   openModal(modal: Modal) {
diff --git a/src/state/models/user-local-photos.ts b/src/state/models/user-local-photos.ts
deleted file mode 100644
index b14e8a6a4..000000000
--- a/src/state/models/user-local-photos.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import {PhotoIdentifier} from './../../../node_modules/@react-native-camera-roll/camera-roll/src/CameraRoll'
-import {makeAutoObservable, runInAction} from 'mobx'
-import {CameraRoll} from '@react-native-camera-roll/camera-roll'
-import {RootStoreModel} from './root-store'
-
-export type {PhotoIdentifier} from './../../../node_modules/@react-native-camera-roll/camera-roll/src/CameraRoll'
-
-export class UserLocalPhotosModel {
-  // state
-  photos: PhotoIdentifier[] = []
-
-  constructor(public rootStore: RootStoreModel) {
-    makeAutoObservable(this, {
-      rootStore: false,
-    })
-  }
-
-  async setup() {
-    const r = await CameraRoll.getPhotos({first: 20})
-    runInAction(() => {
-      this.photos = r.edges
-    })
-  }
-}