OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-store / store / chat / list-view / list-view.reducer.js

239 lines · javascript ref:
import { isEmpty as t } from "../../lib/array"
import { chatInit as e } from "../init"
import { setChatMessageCount as s } from "../message"
import { CHAT_EMPTY_COUNT as i } from "../chat.constant"
import {
  setChatListViewMode as o,
  setChatListViewPaused as n,
  setChatMessageAnchor as r,
  setChatMessagesInView as a,
  setChatListViewStopAnchor as c,
  setChatListViewPeerSeenSeq as l,
  updateAnchorStatus as u,
  incChatListAnchorRetryCount as w,
  setChatListViewStartSeenSeq as m,
} from "./list-view.action"
import {
  VIEW_MODE as d,
  ANCHOR_STATUS as V,
  CHAT_LIST_VIEW_CONFIG as p,
  CHAT_LIST_VIEW_STATE_KEY as E,
  ANCHOR_LOADED_RETRY_COUNT as S,
} from "./list-view.constant"
import {
  calcStartLastSeen as f,
  createAnchorToBottom as D,
  createAnchorToMessage as h,
  isAnchorInView as y,
  isAnchorScrolling as R,
  isChatListLive as g,
  shouldStartHistory as b,
} from "./list-view.model"
import { sharedCoreMessagesUpdate as q } from "../../api/data.action"
export const findMessageBySeq = ({ message: t }, e) => {
  const { byId: s, ids: i } = t
  for (let t = 0; t < i.length; t += 1) {
    const o = s[i[t]]
    if (o?.seq === e) return o
  }
  return null
}
export const chatListViewInViewReducer = (e, { payload: s }) => {
  const {
    message: { count: o, byId: n, ids: r, seqLoaded: a },
    listView: { inView: c, anchor: l, mode: u },
  } = e
  if (o === i || t(r)) return e
  let { top: w, bottom: m } = s
  if (!Number.isInteger(w)) {
    const { topId: t } = s
    t && (w = n[t]?.seq)
  }
  if (!Number.isInteger(m)) {
    const { bottomId: t } = s
    t && (m = n[t]?.groupSeq ?? n[t]?.seq)
  }
  if (!Number.isInteger(w) || !Number.isInteger(m)) return e
  if (c.top === w && c.bottom === m)
    return l && R(l.status) && y(c, l, o)
      ? { ...e, listView: { ...e.listView, anchor: { ...l, status: V.RENDERED } } }
      : e
  const p = { top: w, bottom: m }
  let E = l
  l && R(l.status) && y(p, l, o) && (E = { ...l, status: V.RENDERED })
  let S = u
  if (g(u) && c.bottom !== m && (!E || E.status === V.RENDERED)) {
    const t = ("down" == (c.bottom - m > 0 ? "up" : "down") || m === a.bottom) && u === d.LATEST
    S = m + 1 >= o || t ? d.LATEST : d.HISTORY
  }
  return { ...e, listView: { ...e.listView, inView: p, anchor: E, mode: S } }
}
export const chatListViewReducer = (t, i) => {
  switch (i.type) {
    case n.type: {
      const {
          message: e,
          listView: { mode: s, inView: o, lastSeenSeq: n },
        } = t,
        r = i.payload
      if (r || !g(s)) return { ...t, listView: { ...t.listView, paused: r, anchor: null } }
      const { count: a, ids: c } = e,
        l = f({ lastSeenSeq: n, count: a }),
        u = findMessageBySeq(t, n),
        w = u && b({ startSeq: l, count: a }),
        m = w
          ? h({ messageId: u.id, seq: l, status: o.bottom === l ? V.RENDERED : V.LOADED })
          : D({ status: o.bottom === a - 1 ? V.RENDERED : V.LOADED, messageId: c[0] })
      return {
        ...t,
        listView: {
          ...t.listView,
          startLastSeen: l,
          mode: w ? d.HISTORY : d.LATEST,
          anchor: m,
          stopAnchor: !1,
          paused: !1,
        },
      }
    }
    case q.type: {
      const {
        message: e,
        listView: {
          mode: s,
          startSeq: i,
          inView: o,
          anchor: n,
          stopAnchor: r,
          lastSeenSeq: a,
          paused: c,
        },
      } = t
      if (s === d.FRESH_LOADING) {
        const { count: s, ids: n } = e,
          l = findMessageBySeq(t, i),
          u = l && b({ startSeq: i, count: s }),
          w = f({ lastSeenSeq: a, count: s }),
          m = u
            ? h({ messageId: l.id, seq: i, status: o.bottom === i ? V.RENDERED : V.LOADED })
            : D({ status: o.bottom === s - 1 ? V.RENDERED : V.LOADED, messageId: n[0] })
        return {
          ...t,
          listView: {
            ...t.listView,
            startLastSeen: w,
            mode: u || r ? d.HISTORY : d.LATEST,
            anchor: r || c ? null : m,
            stopAnchor: !1,
          },
        }
      }
      if (s === d.LATEST) {
        const { byId: s, count: i } = e,
          n = i - 1
        if (o.bottom > 0 && o.bottom === n) return t
        const r = Object.values(s).find((t) => t.seq === n)
        if (!r) {
          const e = t.listView.anchor
          return e?.lastMessage && e.status !== V.ASKED
            ? { ...t, listView: { ...t.listView, anchor: { ...e, status: V.ASKED } } }
            : t
        }
        return {
          ...t,
          listView: { ...t.listView, anchor: c ? null : D({ status: V.LOADED, messageId: r.id }) },
        }
      }
      if (t.listView.anchor?.status === V.ASKED) {
        const {
          message: { ids: e, seqLoaded: s, count: i },
        } = t
        let o
        if (
          ((o = n.lastMessage
            ? s.bottom === i - 1
              ? e[0]
              : ""
            : e.find((t) => t === n.messageId) || ""),
          o)
        )
          return {
            ...t,
            listView: {
              ...t.listView,
              anchor: { ...n, messageId: o, status: V.LOADED, retryCountProcessed: S },
            },
          }
      }
      return t
    }
    case o.type: {
      const e = i.payload,
        { mode: s } = t.listView
      return e === s || (g(e) && !g(s)) ? t : { ...t, listView: { ...t.listView, mode: e } }
    }
    case r.type: {
      const { mode: e, anchor: s, inView: o } = t.listView,
        { message: n } = t,
        r = i.payload
      if (!g(e)) return { ...t, listView: { ...t.listView, anchor: r } }
      let a = e
      if (r) {
        const { lastMessage: e, seq: s } = r
        if (e) a = d.LATEST
        else {
          const {
            message: { count: e },
          } = t
          a = s + 1 >= e ? d.LATEST : d.HISTORY
        }
      } else s && s.status !== V.RENDERED && o.bottom !== n.count - 1 && (a = d.HISTORY)
      return { ...t, listView: { ...t.listView, anchor: r, mode: a } }
    }
    case u.type: {
      const e = i.payload,
        { anchor: s } = t.listView
      if (!s || s?.status === e || s?.status === V.RENDERED) return t
      const o = { ...s, status: e }
      return { ...t, listView: { ...t.listView, anchor: o } }
    }
    case s.type: {
      const {
        message: { count: e },
        listView: { startSeq: s, mode: i, inView: o, anchor: n, lastSeenSeq: r, paused: a },
      } = t
      if (0 === e)
        return { ...t, listView: { ...t.listView, mode: d.LATEST, inView: { top: 0, bottom: 0 } } }
      if (-1 === s || s + 1 > e) return { ...t, listView: { ...t.listView, startSeq: e - 1 } }
      const c = r === s && !b({ count: e, startSeq: s })
      if (i === d.RESTORE_LAST && c) return { ...t, listView: { ...t.listView, startSeq: e - 1 } }
      const l = n && n.status !== V.RENDERED
      return i === d.LATEST && !l && e > o.bottom + 1 && !a
        ? { ...t, listView: { ...t.listView, anchor: D() } }
        : t
    }
    case w.type: {
      const { anchor: e } = t.listView
      if (!e || !R(e.status)) return t
      const s = { ...e, retryCountProcessed: e.retryCountProcessed + 1 }
      return { ...t, listView: { ...t.listView, anchor: s } }
    }
    case a.type:
      return chatListViewInViewReducer(t, i)
    case e.type: {
      const e = i.payload?.[E]
      return e ? { ...t, listView: { ...t.listView, config: { ...p, ...e } } } : t
    }
    case c.type: {
      const e = i.payload
      return e === t.listView.stopAnchor ? t : { ...t, listView: { ...t.listView, stopAnchor: e } }
    }
    case l.type:
      return { ...t, listView: { ...t.listView, peerSeenSeq: i.payload } }
    case m.type:
      return { ...t, listView: { ...t.listView, startLastSeen: i.payload } }
    default:
      return t
  }
}