fix #35: pass correct value to TootActionGroup
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				/ depoly (push) Successful in 1m19s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	/ depoly (push) Successful in 1m19s
				
			* add createDefaultTootEnv
This commit is contained in:
		
							parent
							
								
									6dd6065711
								
							
						
					
					
						commit
						5742932c86
					
				
					 7 changed files with 179 additions and 235 deletions
				
			
		| 
						 | 
				
			
			@ -26,8 +26,8 @@ export type Account = AccountKey & {
 | 
			
		|||
  inf?: mastodon.v1.AccountCredentials;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function isAccount(object: AccountKey) {
 | 
			
		||||
  return !!(object as Record<string, unknown>)["tokenType"];
 | 
			
		||||
export function isAccount(object: RemoteServer) {
 | 
			
		||||
  return isAccountKey(object) && !!(object as Record<string, unknown>)["tokenType"];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const $accounts = persistentAtom<Account[]>("accounts", [], {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import {
 | 
			
		|||
  untrack,
 | 
			
		||||
  useContext,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { Account } from "../accounts/stores";
 | 
			
		||||
import { Account, type RemoteServer } from "../accounts/stores";
 | 
			
		||||
import { createRestAPIClient, mastodon } from "masto";
 | 
			
		||||
import { useLocation } from "@solidjs/router";
 | 
			
		||||
import { useNavigator } from "~platform/StackedRouter";
 | 
			
		||||
| 
						 | 
				
			
			@ -131,8 +131,8 @@ export function useSessionForAcctStr(acct: Accessor<string>) {
 | 
			
		|||
    return (
 | 
			
		||||
      authedSession ?? {
 | 
			
		||||
        client: createUnauthorizedClient(inputSite),
 | 
			
		||||
        account: { site: inputSite }, // TODO: we need some security checks here?
 | 
			
		||||
      }
 | 
			
		||||
        account: { site: inputSite } as RemoteServer, // TODO: we need some security checks here?
 | 
			
		||||
      } as const
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import {
 | 
			
		||||
  catchError,
 | 
			
		||||
  createRenderEffect,
 | 
			
		||||
  createResource,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  createUniqueId,
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +13,6 @@ import {
 | 
			
		|||
} from "solid-js";
 | 
			
		||||
import Scaffold from "~material/Scaffold";
 | 
			
		||||
import {
 | 
			
		||||
  AppBar,
 | 
			
		||||
  Avatar,
 | 
			
		||||
  Button,
 | 
			
		||||
  Checkbox,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +24,6 @@ import {
 | 
			
		|||
  ListItemSecondaryAction,
 | 
			
		||||
  ListItemText,
 | 
			
		||||
  MenuItem,
 | 
			
		||||
  Toolbar,
 | 
			
		||||
} from "@suid/material";
 | 
			
		||||
import {
 | 
			
		||||
  Close,
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +60,7 @@ import {
 | 
			
		|||
  default as ItemSelectionProvider,
 | 
			
		||||
} from "../timelines/toots/ItemSelectionProvider";
 | 
			
		||||
import AppTopBar from "~material/AppTopBar";
 | 
			
		||||
import type { Account } from "../accounts/stores";
 | 
			
		||||
 | 
			
		||||
const Profile: Component = () => {
 | 
			
		||||
  const { pop } = useNavigator();
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +115,7 @@ const Profile: Component = () => {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  const isCurrentSessionProfile = () => {
 | 
			
		||||
    return session().account?.inf?.url === profile()?.url;
 | 
			
		||||
    return (session().account as Account).inf?.url === profile()?.url;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const [recentTootFilter, setRecentTootFilter] = createSignal({
 | 
			
		||||
| 
						 | 
				
			
			@ -172,8 +170,8 @@ const Profile: Component = () => {
 | 
			
		|||
 | 
			
		||||
  const sessionDisplayName = createMemo(() =>
 | 
			
		||||
    resolveCustomEmoji(
 | 
			
		||||
      session().account?.inf?.displayName || "",
 | 
			
		||||
      session().account?.inf?.emojis ?? [],
 | 
			
		||||
      (session().account as Account).inf?.displayName || "",
 | 
			
		||||
      (session().account as Account).inf?.emojis ?? [],
 | 
			
		||||
    ),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +242,7 @@ const Profile: Component = () => {
 | 
			
		|||
          <Show when={session().account}>
 | 
			
		||||
            <MenuItem>
 | 
			
		||||
              <ListItemAvatar>
 | 
			
		||||
                <Avatar src={session().account?.inf?.avatar} />
 | 
			
		||||
                <Avatar src={(session().account as Account).inf?.avatar} />
 | 
			
		||||
              </ListItemAvatar>
 | 
			
		||||
              <ListItemText secondary={"Default account"}>
 | 
			
		||||
                <span innerHTML={sessionDisplayName()}></span>
 | 
			
		||||
| 
						 | 
				
			
			@ -367,7 +365,7 @@ const Profile: Component = () => {
 | 
			
		|||
            aria-label={`${relationship()?.following ? "Unfollow" : "Follow"} on your home timeline`}
 | 
			
		||||
          >
 | 
			
		||||
            <ListItemAvatar>
 | 
			
		||||
              <Avatar src={session().account?.inf?.avatar}></Avatar>
 | 
			
		||||
              <Avatar src={(session().account as Account).inf?.avatar}></Avatar>
 | 
			
		||||
            </ListItemAvatar>
 | 
			
		||||
            <ListItemText
 | 
			
		||||
              secondary={
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ import TootPoll from "./toots/TootPoll";
 | 
			
		|||
import TootActionGroup from "./toots/TootActionGroup.js";
 | 
			
		||||
import TootAuthorGroup from "./toots/TootAuthorGroup.js";
 | 
			
		||||
import "./RegularToot.css";
 | 
			
		||||
import { vibrate } from "~platform/hardware.js";
 | 
			
		||||
 | 
			
		||||
export type TootEnv = {
 | 
			
		||||
  boost: (value: mastodon.v1.Status) => void;
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +53,107 @@ export function useTootEnv() {
 | 
			
		|||
  return env;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create default toot env.
 | 
			
		||||
 *
 | 
			
		||||
 * This function does not provides the "reply" action.
 | 
			
		||||
 */
 | 
			
		||||
export function createDefaultTootEnv(
 | 
			
		||||
  client: () => mastodon.rest.Client | undefined,
 | 
			
		||||
  setToot: (id: string, status: mastodon.v1.Status) => void,
 | 
			
		||||
): TootEnv {
 | 
			
		||||
  return {
 | 
			
		||||
    async bookmark(status: mastodon.v1.Status) {
 | 
			
		||||
      const c = client();
 | 
			
		||||
      if (!c) return;
 | 
			
		||||
 | 
			
		||||
      const result = await (status.bookmarked
 | 
			
		||||
        ? c.v1.statuses.$select(status.id).unbookmark()
 | 
			
		||||
        : c.v1.statuses.$select(status.id).bookmark());
 | 
			
		||||
 | 
			
		||||
      setToot(result.id, result);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async boost(status: mastodon.v1.Status) {
 | 
			
		||||
      const c = client();
 | 
			
		||||
      if (!c) return;
 | 
			
		||||
 | 
			
		||||
      vibrate(50);
 | 
			
		||||
      const rootStatus = status.reblog ? status.reblog : status;
 | 
			
		||||
      const reblogged = rootStatus.reblogged;
 | 
			
		||||
      if (status.reblog) {
 | 
			
		||||
        setToot(status.id, {
 | 
			
		||||
          ...status,
 | 
			
		||||
          reblog: { ...status.reblog!, reblogged: !reblogged },
 | 
			
		||||
          reblogged: !reblogged,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        setToot(status.id, {
 | 
			
		||||
          ...status,
 | 
			
		||||
          reblogged: !reblogged,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      // modified the original
 | 
			
		||||
 | 
			
		||||
      const result = reblogged
 | 
			
		||||
        ? await c.v1.statuses.$select(status.id).unreblog()
 | 
			
		||||
        : (await c.v1.statuses.$select(status.id).reblog());
 | 
			
		||||
 | 
			
		||||
      if (status.reblog && !reblogged) {
 | 
			
		||||
        // When calling /reblog, the result is the boost object (the actor
 | 
			
		||||
        // is the calling account); for /unreblog, the result is the original
 | 
			
		||||
        // toot. So we only do this trick only on the reblogging.
 | 
			
		||||
        setToot(status.id, {
 | 
			
		||||
          ...status,
 | 
			
		||||
          reblog: result.reblog,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        setToot(status.id, result);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async favourite(status: mastodon.v1.Status) {
 | 
			
		||||
      const c = client();
 | 
			
		||||
      if (!c) return;
 | 
			
		||||
 | 
			
		||||
      const ovalue = status.favourited;
 | 
			
		||||
      setToot(status.id, { ...status, favourited: !ovalue });
 | 
			
		||||
 | 
			
		||||
      const result = ovalue
 | 
			
		||||
        ? await c.v1.statuses.$select(status.id).unfavourite()
 | 
			
		||||
        : await c.v1.statuses.$select(status.id).favourite();
 | 
			
		||||
      setToot(status.id, result);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async vote(status: mastodon.v1.Status, votes: readonly number[]) {
 | 
			
		||||
      const c = client();
 | 
			
		||||
      if (!c) return;
 | 
			
		||||
 | 
			
		||||
      const toot = status.reblog ?? status;
 | 
			
		||||
      if (!toot.poll) return;
 | 
			
		||||
 | 
			
		||||
      const npoll = await c.v1.polls.$select(toot.poll.id).votes.create({
 | 
			
		||||
        choices: votes,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      if (status.reblog) {
 | 
			
		||||
        setToot(status.id, {
 | 
			
		||||
          ...status,
 | 
			
		||||
          reblog: {
 | 
			
		||||
            ...status.reblog,
 | 
			
		||||
            poll: npoll,
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        setToot(status.id, {
 | 
			
		||||
          ...status,
 | 
			
		||||
          poll: npoll,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegularTootProps = {
 | 
			
		||||
  status: mastodon.v1.Status;
 | 
			
		||||
  actionable?: boolean;
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +305,7 @@ const RegularToot: Component<RegularTootProps> = (oprops) => {
 | 
			
		|||
            class={cardStyle.cardNoPad}
 | 
			
		||||
            style={{ "margin-top": "8px" }}
 | 
			
		||||
          />
 | 
			
		||||
          <TootActionGroup value={toot()} class={cardStyle.cardGutSkip} />
 | 
			
		||||
          <TootActionGroup value={status()} class={cardStyle.cardGutSkip} />
 | 
			
		||||
        </Show>
 | 
			
		||||
      </article>
 | 
			
		||||
    </>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,23 +1,17 @@
 | 
			
		|||
import { useParams } from "@solidjs/router";
 | 
			
		||||
import {
 | 
			
		||||
  catchError,
 | 
			
		||||
  createResource,
 | 
			
		||||
  Show,
 | 
			
		||||
  type Component,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { catchError, createResource, Show, type Component } from "solid-js";
 | 
			
		||||
import Scaffold from "~material/Scaffold";
 | 
			
		||||
import { CircularProgress } from "@suid/material";
 | 
			
		||||
import { Title } from "~material/typography";
 | 
			
		||||
import { useSessionForAcctStr } from "../masto/clients";
 | 
			
		||||
import { resolveCustomEmoji } from "../masto/toot";
 | 
			
		||||
import RegularToot, {
 | 
			
		||||
  createDefaultTootEnv,
 | 
			
		||||
  findElementActionable,
 | 
			
		||||
  TootEnvProvider,
 | 
			
		||||
} from "./RegularToot";
 | 
			
		||||
import type { mastodon } from "masto";
 | 
			
		||||
import cards from "~material/cards.module.css";
 | 
			
		||||
import { css } from "solid-styled";
 | 
			
		||||
import { vibrate } from "~platform/hardware";
 | 
			
		||||
import { createTimeSource, TimeSourceProvider } from "~platform/timesrc";
 | 
			
		||||
import TootComposer from "./TootComposer";
 | 
			
		||||
import { useDocumentTitle } from "../utils";
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +47,7 @@ const TootBottomSheet: Component = (props) => {
 | 
			
		|||
 | 
			
		||||
  const [tootContextErrorUncaught, { refetch: refetchContext }] =
 | 
			
		||||
    createResource(
 | 
			
		||||
      () => [session().client, params.id] as const,
 | 
			
		||||
      () => [session().client, toot()?.reblog?.id ?? params.id] as const,
 | 
			
		||||
      async ([client, id]) => {
 | 
			
		||||
        return await client.v1.statuses.$select(id).context.fetch();
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -89,49 +83,10 @@ const TootBottomSheet: Component = (props) => {
 | 
			
		|||
    return s.account ? s : undefined;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const onBookmark = async () => {
 | 
			
		||||
    const status = remoteToot()!;
 | 
			
		||||
    const client = actSession()!.client;
 | 
			
		||||
    setRemoteToot(
 | 
			
		||||
      Object.assign({}, status, {
 | 
			
		||||
        bookmarked: !status.bookmarked,
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    const result = await (status.bookmarked
 | 
			
		||||
      ? client.v1.statuses.$select(status.id).unbookmark()
 | 
			
		||||
      : client.v1.statuses.$select(status.id).bookmark());
 | 
			
		||||
    setRemoteToot(result);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const onBoost = async () => {
 | 
			
		||||
    const status = remoteToot()!;
 | 
			
		||||
    const client = actSession()!.client;
 | 
			
		||||
    vibrate(50);
 | 
			
		||||
    setRemoteToot(
 | 
			
		||||
      Object.assign({}, status, {
 | 
			
		||||
        reblogged: !status.reblogged,
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    const result = await (status.reblogged
 | 
			
		||||
      ? client.v1.statuses.$select(status.id).unreblog()
 | 
			
		||||
      : client.v1.statuses.$select(status.id).reblog());
 | 
			
		||||
    vibrate([20, 30]);
 | 
			
		||||
    setRemoteToot(result.reblog!);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const onFav = async () => {
 | 
			
		||||
    const status = remoteToot()!;
 | 
			
		||||
    const client = actSession()!.client;
 | 
			
		||||
    setRemoteToot(
 | 
			
		||||
      Object.assign({}, status, {
 | 
			
		||||
        favourited: !status.favourited,
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    const result = await (status.favourited
 | 
			
		||||
      ? client.v1.statuses.$select(status.id).favourite()
 | 
			
		||||
      : client.v1.statuses.$select(status.id).unfavourite());
 | 
			
		||||
    setRemoteToot(result);
 | 
			
		||||
  };
 | 
			
		||||
  const mainTootEnv = createDefaultTootEnv(
 | 
			
		||||
    () => actSession()?.client,
 | 
			
		||||
    (_, status) => setRemoteToot(status),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const defaultMentions = () => {
 | 
			
		||||
    const tootAcct = remoteToot()?.reblog?.account ?? remoteToot()?.account;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,33 +100,6 @@ const TootBottomSheet: Component = (props) => {
 | 
			
		|||
    return Array.from(new Set(values).keys());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const vote = async (status: mastodon.v1.Status, votes: readonly number[]) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
 | 
			
		||||
    const toot = status.reblog ?? status;
 | 
			
		||||
    if (!toot.poll) return;
 | 
			
		||||
 | 
			
		||||
    const npoll = await client.v1.polls.$select(toot.poll.id).votes.create({
 | 
			
		||||
      choices: votes,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (status.reblog) {
 | 
			
		||||
      setRemoteToot({
 | 
			
		||||
        ...status,
 | 
			
		||||
        reblog: {
 | 
			
		||||
          ...status.reblog,
 | 
			
		||||
          poll: npoll,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      setRemoteToot({
 | 
			
		||||
        ...status,
 | 
			
		||||
        poll: npoll,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleMainTootClick = (
 | 
			
		||||
    event: MouseEvent & { currentTarget: HTMLElement },
 | 
			
		||||
  ) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -237,58 +165,51 @@ const TootBottomSheet: Component = (props) => {
 | 
			
		|||
    >
 | 
			
		||||
      <div class="Scrollable">
 | 
			
		||||
        <TimeSourceProvider value={time}>
 | 
			
		||||
          <TootList
 | 
			
		||||
            threads={ancestors.list}
 | 
			
		||||
            onUnknownThread={ancestors.getPath}
 | 
			
		||||
            onChangeToot={ancestors.set}
 | 
			
		||||
          />
 | 
			
		||||
 | 
			
		||||
          <article>
 | 
			
		||||
            <Show when={toot()}>
 | 
			
		||||
              <TootEnvProvider
 | 
			
		||||
                value={{
 | 
			
		||||
                  bookmark: onBookmark,
 | 
			
		||||
                  boost: onBoost,
 | 
			
		||||
                  favourite: onFav,
 | 
			
		||||
                  vote,
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <RegularToot
 | 
			
		||||
                  id={`toot-${toot()!.id}`}
 | 
			
		||||
                  class={cards.card}
 | 
			
		||||
                  style={{
 | 
			
		||||
                    "scroll-margin-top":
 | 
			
		||||
                      "calc(var(--scaffold-topbar-height) + 20px)",
 | 
			
		||||
                    cursor: "auto",
 | 
			
		||||
                    "user-select": "auto",
 | 
			
		||||
                  }}
 | 
			
		||||
                  status={toot()!}
 | 
			
		||||
                  actionable={!!actSession()}
 | 
			
		||||
                  evaluated={true}
 | 
			
		||||
                  onClick={handleMainTootClick}
 | 
			
		||||
                ></RegularToot>
 | 
			
		||||
              </TootEnvProvider>
 | 
			
		||||
            </Show>
 | 
			
		||||
          </article>
 | 
			
		||||
 | 
			
		||||
          <Show when={(session().account as Account).inf}>
 | 
			
		||||
            <TootComposer
 | 
			
		||||
              mentions={defaultMentions()}
 | 
			
		||||
              profile={(session().account! as Account).inf}
 | 
			
		||||
              replyToDisplayName={toot()?.account?.displayName || ""}
 | 
			
		||||
              client={session().client}
 | 
			
		||||
              onSent={() => refetchContext()}
 | 
			
		||||
              inReplyToId={remoteToot()?.reblog?.id ?? remoteToot()?.id}
 | 
			
		||||
            />
 | 
			
		||||
          </Show>
 | 
			
		||||
 | 
			
		||||
          <Show when={tootContextErrorUncaught.loading}>
 | 
			
		||||
            <div class="progress-line">
 | 
			
		||||
              <CircularProgress style="width: 1.5em; height: 1.5em;" />
 | 
			
		||||
            </div>
 | 
			
		||||
          </Show>
 | 
			
		||||
 | 
			
		||||
          <ItemSelectionProvider value={selectionState}>
 | 
			
		||||
            <TootList
 | 
			
		||||
              threads={ancestors.list}
 | 
			
		||||
              onUnknownThread={ancestors.getPath}
 | 
			
		||||
              onChangeToot={ancestors.set}
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <article>
 | 
			
		||||
              <Show when={toot()}>
 | 
			
		||||
                <TootEnvProvider value={mainTootEnv}>
 | 
			
		||||
                  <RegularToot
 | 
			
		||||
                    id={`toot-${toot()!.id}`}
 | 
			
		||||
                    class={cards.card}
 | 
			
		||||
                    style={{
 | 
			
		||||
                      "scroll-margin-top":
 | 
			
		||||
                        "calc(var(--scaffold-topbar-height) + 20px)",
 | 
			
		||||
                      cursor: "auto",
 | 
			
		||||
                      "user-select": "auto",
 | 
			
		||||
                    }}
 | 
			
		||||
                    status={toot()!}
 | 
			
		||||
                    actionable={!!actSession()}
 | 
			
		||||
                    evaluated={true}
 | 
			
		||||
                    onClick={handleMainTootClick}
 | 
			
		||||
                  ></RegularToot>
 | 
			
		||||
                </TootEnvProvider>
 | 
			
		||||
              </Show>
 | 
			
		||||
            </article>
 | 
			
		||||
 | 
			
		||||
            <Show when={(session().account as Account).inf}>
 | 
			
		||||
              <TootComposer
 | 
			
		||||
                mentions={defaultMentions()}
 | 
			
		||||
                profile={(session().account! as Account).inf}
 | 
			
		||||
                replyToDisplayName={toot()?.account?.displayName || ""}
 | 
			
		||||
                client={session().client}
 | 
			
		||||
                onSent={() => refetchContext()}
 | 
			
		||||
                inReplyToId={remoteToot()?.reblog?.id ?? remoteToot()?.id}
 | 
			
		||||
              />
 | 
			
		||||
            </Show>
 | 
			
		||||
 | 
			
		||||
            <Show when={tootContextErrorUncaught.loading}>
 | 
			
		||||
              <div class="progress-line">
 | 
			
		||||
                <CircularProgress style="width: 1.5em; height: 1.5em;" />
 | 
			
		||||
              </div>
 | 
			
		||||
            </Show>
 | 
			
		||||
 | 
			
		||||
            <TootList
 | 
			
		||||
              threads={descendants.list}
 | 
			
		||||
              onUnknownThread={descendants.getPath}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,16 @@
 | 
			
		|||
import {
 | 
			
		||||
  Component,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  ErrorBoundary,
 | 
			
		||||
  type Ref,
 | 
			
		||||
  createSelector,
 | 
			
		||||
  Index,
 | 
			
		||||
  createMemo,
 | 
			
		||||
  For,
 | 
			
		||||
  createUniqueId,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { type mastodon } from "masto";
 | 
			
		||||
import { vibrate } from "~platform/hardware";
 | 
			
		||||
import { useDefaultSession } from "../masto/clients";
 | 
			
		||||
import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
 | 
			
		||||
import RegularToot, {
 | 
			
		||||
  createDefaultTootEnv,
 | 
			
		||||
  findElementActionable,
 | 
			
		||||
  findRootToot,
 | 
			
		||||
  TootEnvProvider,
 | 
			
		||||
| 
						 | 
				
			
			@ -62,62 +59,12 @@ const TootList: Component<{
 | 
			
		|||
  const [isExpanded, setExpanded] = useItemSelection();
 | 
			
		||||
  const { push } = useNavigator();
 | 
			
		||||
 | 
			
		||||
  const onBookmark = async (status: mastodon.v1.Status) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
  const tootEnv = createDefaultTootEnv(
 | 
			
		||||
    () => session()?.client,
 | 
			
		||||
    (...args) => props.onChangeToot(...args),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
    const result = await (status.bookmarked
 | 
			
		||||
      ? client.v1.statuses.$select(status.id).unbookmark()
 | 
			
		||||
      : client.v1.statuses.$select(status.id).bookmark());
 | 
			
		||||
    props.onChangeToot(result.id, result);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const toggleBoost = async (status: mastodon.v1.Status) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
 | 
			
		||||
    vibrate(50);
 | 
			
		||||
    const rootStatus = status.reblog ? status.reblog : status;
 | 
			
		||||
    const reblogged = rootStatus.reblogged;
 | 
			
		||||
    if (status.reblog) {
 | 
			
		||||
      props.onChangeToot(status.id, {
 | 
			
		||||
        ...status,
 | 
			
		||||
        reblog: { ...status.reblog, reblogged: !reblogged },
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      props.onChangeToot(status.id, {
 | 
			
		||||
        ...status,
 | 
			
		||||
        reblogged: !reblogged,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const result = reblogged
 | 
			
		||||
      ? await client.v1.statuses.$select(status.id).unreblog()
 | 
			
		||||
      : (await client.v1.statuses.$select(status.id).reblog()).reblog!;
 | 
			
		||||
 | 
			
		||||
    if (status.reblog) {
 | 
			
		||||
      props.onChangeToot(status.id, {
 | 
			
		||||
        ...status,
 | 
			
		||||
        reblog: result,
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      props.onChangeToot(status.id, result);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const toggleFavourite = async (status: mastodon.v1.Status) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
    const ovalue = status.favourited;
 | 
			
		||||
    props.onChangeToot(status.id, { ...status, favourited: !ovalue });
 | 
			
		||||
 | 
			
		||||
    const result = ovalue
 | 
			
		||||
      ? await client.v1.statuses.$select(status.id).unfavourite()
 | 
			
		||||
      : await client.v1.statuses.$select(status.id).favourite();
 | 
			
		||||
    props.onChangeToot(status.id, result);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const openFullScreenToot = (
 | 
			
		||||
  const openFullScreenToot = async (
 | 
			
		||||
    toot: mastodon.v1.Status,
 | 
			
		||||
    srcElement: HTMLElement,
 | 
			
		||||
    reply?: boolean,
 | 
			
		||||
| 
						 | 
				
			
			@ -235,33 +182,6 @@ const TootList: Component<{
 | 
			
		|||
    openFullScreenToot(status, element, true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const vote = async (status: mastodon.v1.Status, votes: readonly number[]) => {
 | 
			
		||||
    const client = session()?.client;
 | 
			
		||||
    if (!client) return;
 | 
			
		||||
 | 
			
		||||
    const toot = status.reblog ?? status;
 | 
			
		||||
    if (!toot.poll) return;
 | 
			
		||||
 | 
			
		||||
    const npoll = await client.v1.polls.$select(toot.poll.id).votes.create({
 | 
			
		||||
      choices: votes,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (status.reblog) {
 | 
			
		||||
      props.onChangeToot(status.id, {
 | 
			
		||||
        ...status,
 | 
			
		||||
        reblog: {
 | 
			
		||||
          ...status.reblog,
 | 
			
		||||
          poll: npoll,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      props.onChangeToot(status.id, {
 | 
			
		||||
        ...status,
 | 
			
		||||
        poll: npoll,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ErrorBoundary
 | 
			
		||||
      fallback={(err, reset) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -271,11 +191,8 @@ const TootList: Component<{
 | 
			
		|||
    >
 | 
			
		||||
      <TootEnvProvider
 | 
			
		||||
        value={{
 | 
			
		||||
          boost: toggleBoost,
 | 
			
		||||
          bookmark: onBookmark,
 | 
			
		||||
          favourite: toggleFavourite,
 | 
			
		||||
          ...tootEnv,
 | 
			
		||||
          reply: reply,
 | 
			
		||||
          vote: vote,
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <div ref={props.ref} id={props.id} class="toot-list">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,13 +24,19 @@ function isolatedCallback(e: MouseEvent) {
 | 
			
		|||
  e.stopPropagation();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The actions of the toot card.
 | 
			
		||||
 *
 | 
			
		||||
 * The `value` must be the original toot (contains `reblog` if
 | 
			
		||||
 * it's a boost), since the value will be passed to the callbacks.
 | 
			
		||||
 */
 | 
			
		||||
function TootActionGroup<T extends mastodon.v1.Status>(props: {
 | 
			
		||||
  value: T;
 | 
			
		||||
  class?: string;
 | 
			
		||||
}) {
 | 
			
		||||
  const { reply, boost, favourite, bookmark } = useTootEnv();
 | 
			
		||||
  let actGrpElement: HTMLDivElement;
 | 
			
		||||
  const toot = () => props.value;
 | 
			
		||||
  const toot = () => props.value.reblog ?? props.value;
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      ref={actGrpElement!}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue