petpet headpat init
This commit is contained in:
@@ -153,6 +153,7 @@
|
||||
userStatus={getFriendStatus(userId)}
|
||||
{doll}
|
||||
{isInteractive}
|
||||
senderDoll={getUserDoll()}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import type { UserBasicDto } from "../../../types/bindings/UserBasicDto";
|
||||
import type { PresenceStatus } from "../../../types/bindings/PresenceStatus";
|
||||
import type { UserStatus } from "../../../events/user-status";
|
||||
import type { InteractionPayloadDto } from "../../../types/bindings/InteractionPayloadDto";
|
||||
|
||||
export let id = "";
|
||||
export let targetX = 0;
|
||||
@@ -22,6 +23,7 @@
|
||||
export let userStatus: UserStatus | undefined = undefined;
|
||||
export let doll: DollDto | undefined = undefined;
|
||||
export let isInteractive = false;
|
||||
export let senderDoll: DollDto | undefined = undefined;
|
||||
|
||||
const { position, currentSprite, updatePosition, setPosition } = usePetState(
|
||||
32,
|
||||
@@ -33,17 +35,14 @@
|
||||
let spriteSheetUrl = onekoGif;
|
||||
|
||||
let isPetMenuOpen = false;
|
||||
let receivedMessage: string | undefined = undefined;
|
||||
let receivedInteraction: InteractionPayloadDto | undefined = undefined;
|
||||
let messageTimer: number | undefined = undefined;
|
||||
|
||||
// Watch for received interactions for this user
|
||||
$: {
|
||||
const interaction = $receivedInteractions.get(user.id);
|
||||
if (interaction && interaction.content !== receivedMessage) {
|
||||
console.log(
|
||||
`Received interaction for ${user.id}: ${interaction.content}`,
|
||||
);
|
||||
receivedMessage = interaction.content;
|
||||
if (interaction && interaction !== receivedInteraction) {
|
||||
receivedInteraction = interaction;
|
||||
isPetMenuOpen = true;
|
||||
|
||||
// Make scene interactive so user can see it
|
||||
@@ -58,7 +57,7 @@
|
||||
// Auto-close and clear after 8 seconds
|
||||
messageTimer = setTimeout(() => {
|
||||
isPetMenuOpen = false;
|
||||
receivedMessage = undefined;
|
||||
receivedInteraction = undefined;
|
||||
clearInteraction(user.id);
|
||||
// We probably shouldn't disable interactivity globally here as other pets might be active,
|
||||
// but 'set_pet_menu_state' in backend handles the window transparency logic per pet/menu.
|
||||
@@ -85,7 +84,7 @@
|
||||
// Actually, `isInteractive` is a prop passed from +page.svelte probably based on hover state.
|
||||
// If we want the menu to stay open during the message, we should probably ignore this auto-close behavior if a message is present.
|
||||
|
||||
$: if (!receivedMessage && !isInteractive) {
|
||||
$: if (!receivedInteraction && !isInteractive) {
|
||||
isPetMenuOpen = false;
|
||||
}
|
||||
|
||||
@@ -154,7 +153,13 @@
|
||||
aria-label="Pet Menu"
|
||||
>
|
||||
{#if doll}
|
||||
<PetMenu {doll} {user} {userStatus} {receivedMessage} />
|
||||
<PetMenu
|
||||
{doll}
|
||||
{user}
|
||||
{userStatus}
|
||||
{receivedInteraction}
|
||||
{senderDoll}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -176,7 +181,7 @@
|
||||
isPetMenuOpen = !isPetMenuOpen;
|
||||
if (!isPetMenuOpen) {
|
||||
// Clear message when closing menu manually
|
||||
receivedMessage = undefined;
|
||||
receivedInteraction = undefined;
|
||||
clearInteraction(user.id);
|
||||
if (messageTimer) clearTimeout(messageTimer);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
import type { UserBasicDto } from "../../../types/bindings/UserBasicDto";
|
||||
import type { SendInteractionDto } from "../../../types/bindings/SendInteractionDto";
|
||||
import type { UserStatus } from "../../../events/user-status";
|
||||
import type { InteractionPayloadDto } from "../../../types/bindings/InteractionPayloadDto";
|
||||
|
||||
export let doll: DollDto;
|
||||
export let user: UserBasicDto;
|
||||
export let userStatus: UserStatus | undefined = undefined;
|
||||
export let receivedMessage: string | undefined = undefined;
|
||||
export let receivedInteraction: InteractionPayloadDto | undefined = undefined;
|
||||
export let senderDoll: DollDto | undefined = undefined;
|
||||
|
||||
let showMessageInput = false;
|
||||
let messageContent = "";
|
||||
@@ -32,6 +34,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function sendHeadpat() {
|
||||
if (!senderDoll) return;
|
||||
|
||||
try {
|
||||
const gifBase64 = await invoke("encode_pet_doll_gif_base64", { doll: senderDoll }) as string;
|
||||
const dto: SendInteractionDto = {
|
||||
recipientUserId: user.id,
|
||||
content: gifBase64,
|
||||
type: "headpat",
|
||||
};
|
||||
|
||||
await invoke("send_interaction_cmd", { dto });
|
||||
messageContent = "";
|
||||
showMessageInput = false;
|
||||
} catch (e) {
|
||||
console.error("Failed to send interaction:", e);
|
||||
alert("Failed to send headpat: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "Enter") {
|
||||
sendMessage();
|
||||
@@ -62,11 +84,19 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if receivedMessage}
|
||||
{#if receivedInteraction}
|
||||
<div class="">
|
||||
<div class="text-sm max-w-[140px]">
|
||||
{receivedMessage}
|
||||
</div>
|
||||
{#if receivedInteraction.type === "headpat"}
|
||||
<img
|
||||
src={`data:image/gif;base64,${receivedInteraction.content}`}
|
||||
alt="Headpat GIF"
|
||||
class="max-w-[140px] h-auto"
|
||||
/>
|
||||
{:else}
|
||||
<div class="text-sm max-w-[140px]">
|
||||
{receivedInteraction.content}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if showMessageInput}
|
||||
<div class="flex flex-col gap-1">
|
||||
@@ -89,7 +119,7 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row gap-1 w-full *:flex-1 *:btn *:btn-sm">
|
||||
<button disabled>Headpat</button>
|
||||
<button onclick={sendHeadpat}>Headpat</button>
|
||||
<button onclick={() => (showMessageInput = true)}>Message</button>
|
||||
</div>
|
||||
<div class="flex flex-row gap-1 w-full *:flex-1 *:btn *:btn-sm">
|
||||
|
||||
Reference in New Issue
Block a user