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; |   inf?: mastodon.v1.AccountCredentials; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export function isAccount(object: AccountKey) { | export function isAccount(object: RemoteServer) { | ||||||
|   return !!(object as Record<string, unknown>)["tokenType"]; |   return isAccountKey(object) && !!(object as Record<string, unknown>)["tokenType"]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const $accounts = persistentAtom<Account[]>("accounts", [], { | export const $accounts = persistentAtom<Account[]>("accounts", [], { | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ import { | ||||||
|   untrack, |   untrack, | ||||||
|   useContext, |   useContext, | ||||||
| } from "solid-js"; | } from "solid-js"; | ||||||
| import { Account } from "../accounts/stores"; | import { Account, type RemoteServer } from "../accounts/stores"; | ||||||
| import { createRestAPIClient, mastodon } from "masto"; | import { createRestAPIClient, mastodon } from "masto"; | ||||||
| import { useLocation } from "@solidjs/router"; | import { useLocation } from "@solidjs/router"; | ||||||
| import { useNavigator } from "~platform/StackedRouter"; | import { useNavigator } from "~platform/StackedRouter"; | ||||||
|  | @ -131,8 +131,8 @@ export function useSessionForAcctStr(acct: Accessor<string>) { | ||||||
|     return ( |     return ( | ||||||
|       authedSession ?? { |       authedSession ?? { | ||||||
|         client: createUnauthorizedClient(inputSite), |         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 { | import { | ||||||
|   catchError, |   catchError, | ||||||
|   createRenderEffect, |  | ||||||
|   createResource, |   createResource, | ||||||
|   createSignal, |   createSignal, | ||||||
|   createUniqueId, |   createUniqueId, | ||||||
|  | @ -14,7 +13,6 @@ import { | ||||||
| } from "solid-js"; | } from "solid-js"; | ||||||
| import Scaffold from "~material/Scaffold"; | import Scaffold from "~material/Scaffold"; | ||||||
| import { | import { | ||||||
|   AppBar, |  | ||||||
|   Avatar, |   Avatar, | ||||||
|   Button, |   Button, | ||||||
|   Checkbox, |   Checkbox, | ||||||
|  | @ -26,7 +24,6 @@ import { | ||||||
|   ListItemSecondaryAction, |   ListItemSecondaryAction, | ||||||
|   ListItemText, |   ListItemText, | ||||||
|   MenuItem, |   MenuItem, | ||||||
|   Toolbar, |  | ||||||
| } from "@suid/material"; | } from "@suid/material"; | ||||||
| import { | import { | ||||||
|   Close, |   Close, | ||||||
|  | @ -63,6 +60,7 @@ import { | ||||||
|   default as ItemSelectionProvider, |   default as ItemSelectionProvider, | ||||||
| } from "../timelines/toots/ItemSelectionProvider"; | } from "../timelines/toots/ItemSelectionProvider"; | ||||||
| import AppTopBar from "~material/AppTopBar"; | import AppTopBar from "~material/AppTopBar"; | ||||||
|  | import type { Account } from "../accounts/stores"; | ||||||
| 
 | 
 | ||||||
| const Profile: Component = () => { | const Profile: Component = () => { | ||||||
|   const { pop } = useNavigator(); |   const { pop } = useNavigator(); | ||||||
|  | @ -117,7 +115,7 @@ const Profile: Component = () => { | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const isCurrentSessionProfile = () => { |   const isCurrentSessionProfile = () => { | ||||||
|     return session().account?.inf?.url === profile()?.url; |     return (session().account as Account).inf?.url === profile()?.url; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const [recentTootFilter, setRecentTootFilter] = createSignal({ |   const [recentTootFilter, setRecentTootFilter] = createSignal({ | ||||||
|  | @ -172,8 +170,8 @@ const Profile: Component = () => { | ||||||
| 
 | 
 | ||||||
|   const sessionDisplayName = createMemo(() => |   const sessionDisplayName = createMemo(() => | ||||||
|     resolveCustomEmoji( |     resolveCustomEmoji( | ||||||
|       session().account?.inf?.displayName || "", |       (session().account as Account).inf?.displayName || "", | ||||||
|       session().account?.inf?.emojis ?? [], |       (session().account as Account).inf?.emojis ?? [], | ||||||
|     ), |     ), | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|  | @ -244,7 +242,7 @@ const Profile: Component = () => { | ||||||
|           <Show when={session().account}> |           <Show when={session().account}> | ||||||
|             <MenuItem> |             <MenuItem> | ||||||
|               <ListItemAvatar> |               <ListItemAvatar> | ||||||
|                 <Avatar src={session().account?.inf?.avatar} /> |                 <Avatar src={(session().account as Account).inf?.avatar} /> | ||||||
|               </ListItemAvatar> |               </ListItemAvatar> | ||||||
|               <ListItemText secondary={"Default account"}> |               <ListItemText secondary={"Default account"}> | ||||||
|                 <span innerHTML={sessionDisplayName()}></span> |                 <span innerHTML={sessionDisplayName()}></span> | ||||||
|  | @ -367,7 +365,7 @@ const Profile: Component = () => { | ||||||
|             aria-label={`${relationship()?.following ? "Unfollow" : "Follow"} on your home timeline`} |             aria-label={`${relationship()?.following ? "Unfollow" : "Follow"} on your home timeline`} | ||||||
|           > |           > | ||||||
|             <ListItemAvatar> |             <ListItemAvatar> | ||||||
|               <Avatar src={session().account?.inf?.avatar}></Avatar> |               <Avatar src={(session().account as Account).inf?.avatar}></Avatar> | ||||||
|             </ListItemAvatar> |             </ListItemAvatar> | ||||||
|             <ListItemText |             <ListItemText | ||||||
|               secondary={ |               secondary={ | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ import TootPoll from "./toots/TootPoll"; | ||||||
| import TootActionGroup from "./toots/TootActionGroup.js"; | import TootActionGroup from "./toots/TootActionGroup.js"; | ||||||
| import TootAuthorGroup from "./toots/TootAuthorGroup.js"; | import TootAuthorGroup from "./toots/TootAuthorGroup.js"; | ||||||
| import "./RegularToot.css"; | import "./RegularToot.css"; | ||||||
|  | import { vibrate } from "~platform/hardware.js"; | ||||||
| 
 | 
 | ||||||
| export type TootEnv = { | export type TootEnv = { | ||||||
|   boost: (value: mastodon.v1.Status) => void; |   boost: (value: mastodon.v1.Status) => void; | ||||||
|  | @ -52,6 +53,107 @@ export function useTootEnv() { | ||||||
|   return env; |   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 = { | type RegularTootProps = { | ||||||
|   status: mastodon.v1.Status; |   status: mastodon.v1.Status; | ||||||
|   actionable?: boolean; |   actionable?: boolean; | ||||||
|  | @ -203,7 +305,7 @@ const RegularToot: Component<RegularTootProps> = (oprops) => { | ||||||
|             class={cardStyle.cardNoPad} |             class={cardStyle.cardNoPad} | ||||||
|             style={{ "margin-top": "8px" }} |             style={{ "margin-top": "8px" }} | ||||||
|           /> |           /> | ||||||
|           <TootActionGroup value={toot()} class={cardStyle.cardGutSkip} /> |           <TootActionGroup value={status()} class={cardStyle.cardGutSkip} /> | ||||||
|         </Show> |         </Show> | ||||||
|       </article> |       </article> | ||||||
|     </> |     </> | ||||||
|  |  | ||||||
|  | @ -1,23 +1,17 @@ | ||||||
| import { useParams } from "@solidjs/router"; | import { useParams } from "@solidjs/router"; | ||||||
| import { | import { catchError, createResource, Show, type Component } from "solid-js"; | ||||||
|   catchError, |  | ||||||
|   createResource, |  | ||||||
|   Show, |  | ||||||
|   type Component, |  | ||||||
| } from "solid-js"; |  | ||||||
| import Scaffold from "~material/Scaffold"; | import Scaffold from "~material/Scaffold"; | ||||||
| import { CircularProgress } from "@suid/material"; | import { CircularProgress } from "@suid/material"; | ||||||
| import { Title } from "~material/typography"; | import { Title } from "~material/typography"; | ||||||
| import { useSessionForAcctStr } from "../masto/clients"; | import { useSessionForAcctStr } from "../masto/clients"; | ||||||
| import { resolveCustomEmoji } from "../masto/toot"; | import { resolveCustomEmoji } from "../masto/toot"; | ||||||
| import RegularToot, { | import RegularToot, { | ||||||
|  |   createDefaultTootEnv, | ||||||
|   findElementActionable, |   findElementActionable, | ||||||
|   TootEnvProvider, |   TootEnvProvider, | ||||||
| } from "./RegularToot"; | } from "./RegularToot"; | ||||||
| import type { mastodon } from "masto"; |  | ||||||
| import cards from "~material/cards.module.css"; | import cards from "~material/cards.module.css"; | ||||||
| import { css } from "solid-styled"; | import { css } from "solid-styled"; | ||||||
| import { vibrate } from "~platform/hardware"; |  | ||||||
| import { createTimeSource, TimeSourceProvider } from "~platform/timesrc"; | import { createTimeSource, TimeSourceProvider } from "~platform/timesrc"; | ||||||
| import TootComposer from "./TootComposer"; | import TootComposer from "./TootComposer"; | ||||||
| import { useDocumentTitle } from "../utils"; | import { useDocumentTitle } from "../utils"; | ||||||
|  | @ -53,7 +47,7 @@ const TootBottomSheet: Component = (props) => { | ||||||
| 
 | 
 | ||||||
|   const [tootContextErrorUncaught, { refetch: refetchContext }] = |   const [tootContextErrorUncaught, { refetch: refetchContext }] = | ||||||
|     createResource( |     createResource( | ||||||
|       () => [session().client, params.id] as const, |       () => [session().client, toot()?.reblog?.id ?? params.id] as const, | ||||||
|       async ([client, id]) => { |       async ([client, id]) => { | ||||||
|         return await client.v1.statuses.$select(id).context.fetch(); |         return await client.v1.statuses.$select(id).context.fetch(); | ||||||
|       }, |       }, | ||||||
|  | @ -89,49 +83,10 @@ const TootBottomSheet: Component = (props) => { | ||||||
|     return s.account ? s : undefined; |     return s.account ? s : undefined; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const onBookmark = async () => { |   const mainTootEnv = createDefaultTootEnv( | ||||||
|     const status = remoteToot()!; |     () => actSession()?.client, | ||||||
|     const client = actSession()!.client; |     (_, status) => setRemoteToot(status), | ||||||
|     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 defaultMentions = () => { |   const defaultMentions = () => { | ||||||
|     const tootAcct = remoteToot()?.reblog?.account ?? remoteToot()?.account; |     const tootAcct = remoteToot()?.reblog?.account ?? remoteToot()?.account; | ||||||
|  | @ -145,33 +100,6 @@ const TootBottomSheet: Component = (props) => { | ||||||
|     return Array.from(new Set(values).keys()); |     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 = ( |   const handleMainTootClick = ( | ||||||
|     event: MouseEvent & { currentTarget: HTMLElement }, |     event: MouseEvent & { currentTarget: HTMLElement }, | ||||||
|   ) => { |   ) => { | ||||||
|  | @ -237,6 +165,7 @@ const TootBottomSheet: Component = (props) => { | ||||||
|     > |     > | ||||||
|       <div class="Scrollable"> |       <div class="Scrollable"> | ||||||
|         <TimeSourceProvider value={time}> |         <TimeSourceProvider value={time}> | ||||||
|  |           <ItemSelectionProvider value={selectionState}> | ||||||
|             <TootList |             <TootList | ||||||
|               threads={ancestors.list} |               threads={ancestors.list} | ||||||
|               onUnknownThread={ancestors.getPath} |               onUnknownThread={ancestors.getPath} | ||||||
|  | @ -245,14 +174,7 @@ const TootBottomSheet: Component = (props) => { | ||||||
| 
 | 
 | ||||||
|             <article> |             <article> | ||||||
|               <Show when={toot()}> |               <Show when={toot()}> | ||||||
|               <TootEnvProvider |                 <TootEnvProvider value={mainTootEnv}> | ||||||
|                 value={{ |  | ||||||
|                   bookmark: onBookmark, |  | ||||||
|                   boost: onBoost, |  | ||||||
|                   favourite: onFav, |  | ||||||
|                   vote, |  | ||||||
|                 }} |  | ||||||
|               > |  | ||||||
|                   <RegularToot |                   <RegularToot | ||||||
|                     id={`toot-${toot()!.id}`} |                     id={`toot-${toot()!.id}`} | ||||||
|                     class={cards.card} |                     class={cards.card} | ||||||
|  | @ -288,7 +210,6 @@ const TootBottomSheet: Component = (props) => { | ||||||
|               </div> |               </div> | ||||||
|             </Show> |             </Show> | ||||||
| 
 | 
 | ||||||
|           <ItemSelectionProvider value={selectionState}> |  | ||||||
|             <TootList |             <TootList | ||||||
|               threads={descendants.list} |               threads={descendants.list} | ||||||
|               onUnknownThread={descendants.getPath} |               onUnknownThread={descendants.getPath} | ||||||
|  |  | ||||||
|  | @ -1,19 +1,16 @@ | ||||||
| import { | import { | ||||||
|   Component, |   Component, | ||||||
|   createSignal, |  | ||||||
|   ErrorBoundary, |   ErrorBoundary, | ||||||
|   type Ref, |   type Ref, | ||||||
|   createSelector, |  | ||||||
|   Index, |   Index, | ||||||
|   createMemo, |   createMemo, | ||||||
|   For, |   For, | ||||||
|   createUniqueId, |   createUniqueId, | ||||||
| } from "solid-js"; | } from "solid-js"; | ||||||
| import { type mastodon } from "masto"; | import { type mastodon } from "masto"; | ||||||
| import { vibrate } from "~platform/hardware"; |  | ||||||
| import { useDefaultSession } from "../masto/clients"; | import { useDefaultSession } from "../masto/clients"; | ||||||
| import { setCache as setTootBottomSheetCache } from "./TootBottomSheet"; |  | ||||||
| import RegularToot, { | import RegularToot, { | ||||||
|  |   createDefaultTootEnv, | ||||||
|   findElementActionable, |   findElementActionable, | ||||||
|   findRootToot, |   findRootToot, | ||||||
|   TootEnvProvider, |   TootEnvProvider, | ||||||
|  | @ -62,62 +59,12 @@ const TootList: Component<{ | ||||||
|   const [isExpanded, setExpanded] = useItemSelection(); |   const [isExpanded, setExpanded] = useItemSelection(); | ||||||
|   const { push } = useNavigator(); |   const { push } = useNavigator(); | ||||||
| 
 | 
 | ||||||
|   const onBookmark = async (status: mastodon.v1.Status) => { |   const tootEnv = createDefaultTootEnv( | ||||||
|     const client = session()?.client; |     () => session()?.client, | ||||||
|     if (!client) return; |     (...args) => props.onChangeToot(...args), | ||||||
|  |   ); | ||||||
| 
 | 
 | ||||||
|     const result = await (status.bookmarked |   const openFullScreenToot = async ( | ||||||
|       ? 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 = ( |  | ||||||
|     toot: mastodon.v1.Status, |     toot: mastodon.v1.Status, | ||||||
|     srcElement: HTMLElement, |     srcElement: HTMLElement, | ||||||
|     reply?: boolean, |     reply?: boolean, | ||||||
|  | @ -235,33 +182,6 @@ const TootList: Component<{ | ||||||
|     openFullScreenToot(status, element, true); |     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 ( |   return ( | ||||||
|     <ErrorBoundary |     <ErrorBoundary | ||||||
|       fallback={(err, reset) => { |       fallback={(err, reset) => { | ||||||
|  | @ -271,11 +191,8 @@ const TootList: Component<{ | ||||||
|     > |     > | ||||||
|       <TootEnvProvider |       <TootEnvProvider | ||||||
|         value={{ |         value={{ | ||||||
|           boost: toggleBoost, |           ...tootEnv, | ||||||
|           bookmark: onBookmark, |  | ||||||
|           favourite: toggleFavourite, |  | ||||||
|           reply: reply, |           reply: reply, | ||||||
|           vote: vote, |  | ||||||
|         }} |         }} | ||||||
|       > |       > | ||||||
|         <div ref={props.ref} id={props.id} class="toot-list"> |         <div ref={props.ref} id={props.id} class="toot-list"> | ||||||
|  |  | ||||||
|  | @ -24,13 +24,19 @@ function isolatedCallback(e: MouseEvent) { | ||||||
|   e.stopPropagation(); |   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: { | function TootActionGroup<T extends mastodon.v1.Status>(props: { | ||||||
|   value: T; |   value: T; | ||||||
|   class?: string; |   class?: string; | ||||||
| }) { | }) { | ||||||
|   const { reply, boost, favourite, bookmark } = useTootEnv(); |   const { reply, boost, favourite, bookmark } = useTootEnv(); | ||||||
|   let actGrpElement: HTMLDivElement; |   let actGrpElement: HTMLDivElement; | ||||||
|   const toot = () => props.value; |   const toot = () => props.value.reblog ?? props.value; | ||||||
|   return ( |   return ( | ||||||
|     <div |     <div | ||||||
|       ref={actGrpElement!} |       ref={actGrpElement!} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue