Skip to content

Commit

Permalink
Merge pull request #14 from CPlusPatch/feat/ui-fixes-and-add-typing-i…
Browse files Browse the repository at this point in the history
…ndicator

UI fixes, add Typing indicator, add read receipts
  • Loading branch information
CPlusPatch committed Aug 3, 2023
2 parents f826123 + a5df26c commit 9940597
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 22 deletions.
2 changes: 0 additions & 2 deletions app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ await indexedDBStore.startup();
const isLoggedIn = ref(isUserLoggedIn());
console.error(isLoggedIn.value);
const store = useStore();
store.state.loaded = false;
Expand Down
25 changes: 22 additions & 3 deletions components/input/FvMessageSender.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<script setup lang="ts">
// Thanks https://github.com/cinnyapp/cinny/blob/f14d70ea3508a8467c0a27b9d61c8ab6661054ab/src/client/state/RoomsInput.js for some code
import { encryptAttachment } from "matrix-encrypt-attachment";
import { UploadProgress } from "matrix-js-sdk";
import { MatrixClient, UploadProgress } from "matrix-js-sdk";
import emojis from "emoji.json";
import parse from "snarkdown";
import { MatrixRoom } from "~/classes/Room";
import { useStore } from "~/utils/store";
import { getBlobSafeMimeType } from "~/utils/mime";
import { encodeBlurhash } from "~/utils/blurhash";
import { getVideoThumbnail, loadVideo } from "~/utils/video";
import { MatrixUser } from "~/classes/User";
const props = defineProps<{
room: MatrixRoom;
typing: Set<string>;
}>();
const emit = defineEmits<{
Expand Down Expand Up @@ -291,7 +293,7 @@ const eventReplyingTo = computed(
</script>

<template>
<form class="w-full px-3 pb-7" @submit.prevent="send">
<form class="w-full px-3" @submit.prevent="send">
<input
ref="fileInput"
multiple
Expand Down Expand Up @@ -360,7 +362,7 @@ const eventReplyingTo = computed(
<img
v-if="file.type.includes('image')"
:src="fileToURL(file)"
class="h-full" />
class="h-full w-full object-cover" />
<Icon
v-else
name="ic:round-insert-drive-file"
Expand Down Expand Up @@ -435,5 +437,22 @@ const eventReplyingTo = computed(
</button>
</div>
</div>

<div
class="h-7 text-xs flex flex-row gap-1 text-gray-300 p-1 items-center">
<span v-if="[...typing].length > 0">
<strong>{{
[...typing]
.map(t =>
new MatrixUser(
t,
store.client as MatrixClient
).getDisplayName()
)
.join(", ")
}}</strong>
{{ [...typing].length === 1 ? "is" : "are" }} typing...
</span>
</div>
</form>
</template>
1 change: 1 addition & 0 deletions components/login/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const submit = async (e: Event) => {
};
flowStage.value = FlowStage.Login;
error.value = null;
loading.value = false;
} else if (flowStage.value === FlowStage.Login) {
if (!homeserverData.value) return;
Expand Down
18 changes: 17 additions & 1 deletion components/messages/FvMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const reply = room.room.findEventById(event.value.event.replyEventId ?? "");
const log = console.error;
const body: string = props.message.getContent().body;
const body: string = props.message.getContent().body ?? "";
const bodyHtml = document.createElement("div");
const replyBody = document.createElement("div");
Expand Down Expand Up @@ -108,6 +108,21 @@ const setReply = () => {
text: "",
};
};
// Mark as read on visible
const messageRef = ref(null);
useIntersectionObserver(messageRef, ([{ isIntersecting }]) => {
if (isIntersecting) {
if (
!room.room.hasUserReadEvent(
store.client?.getUserId() ?? "",
event.value.event.getId() ?? ""
)
) {
store.client?.sendReadReceipt(event.value.event as MatrixEvent);
}
}
});
</script>

<template>
Expand All @@ -117,6 +132,7 @@ const setReply = () => {
enter-to-class="opacity-100 translate-x-0">
<div
v-if="message"
ref="messageRef"
:class="[
'flex flex-col px-6 py-1 gap-1 hover:bg-dark-700 relative group duration-200',
showHeader && 'mt-2',
Expand Down
2 changes: 1 addition & 1 deletion components/messages/FvMessageSkeleton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const amountOfSubMessages = Math.ceil(Math.random() * 3);
<div
v-for="index in amountOfSubMessages"
:key="index"
:class="['mb-3', index === 1 && 'mt-3']">
:class="['mb-3 px-6', index === 1 && 'mt-3']">
<div class="flex flex-row gap-2 w-full max-w-full">
<div v-if="index > 1" class="w-10 shrink-0"></div>
<div
Expand Down
4 changes: 2 additions & 2 deletions components/previews/FvRoomPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ try {
// Is "online" or "offline"
const presence = dmUser && dmUser.getPresenceStatus();
const unreadCount = props.room.room.getUnreadNotificationCount();
const unreadCount = props.room.room.getRoomUnreadNotificationCount();
</script>

<template>
<NuxtLink
:to="`/room/${room.id}`"
class="flex flex-row gap-2 duration-200 hover:bg-dark-700 p-2 rounded">
class="flex flex-row gap-2 duration-200 hover:bg-dark-800 p-2 rounded">
<div
class="h-8 w-8 relative rounded-full shrink-0 flex items-center justify-center shrink-0 shadow">
<img
Expand Down
2 changes: 1 addition & 1 deletion components/users/FvUser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const presence = props.user.getPresenceStatus();
</script>
<template>
<div
class="flex flex-row gap-2 duration-200 hover:bg-dark-700 p-2 rounded items-center">
class="flex flex-row gap-2 duration-200 hover:bg-dark-800 p-2 rounded items-center">
<div
class="h-8 w-8 relative rounded-full shrink-0 flex items-center justify-center shrink-0 shadow">
<img
Expand Down
26 changes: 17 additions & 9 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ const timelineChange = async () => {
};
store.client?.on(RoomEvent.Timeline, timelineChange);
store.client?.on(RoomEvent.Receipt, timelineChange);
onUnmounted(() => {
store.client?.off(RoomEvent.Timeline, timelineChange);
store.client?.off(RoomEvent.Receipt, timelineChange);
});
await timelineChange();
Expand All @@ -58,7 +60,7 @@ onMounted(() => {

<template>
<div
class="max-w-full w-full h-screen bg-dark-800 flex flex-row divide-gray-400 p-0 overflow-hidden font-inter">
class="max-w-full w-full h-screen bg-dark-800 flex flex-row divide-gray-400 p-0 overflow-hidden font-['Inter']">
<div
class="w-16 bg-dark-950 shrink-0 md:flex flex-col items-center py-2 gap-3 hidden">
<div
Expand All @@ -81,14 +83,20 @@ onMounted(() => {
</TransitionGroup>
</div>
<div
class="bg-dark-900 p-1 md:flex flex-col gap-1 overflow-x-hidden no-scrollbar overflow-y-scroll relative w-60 shrink-0 hidden">
<TransitionGroup move-class="duration-200 transition-all">
<PreviewsFvRoomPreview
v-for="{ room, lastMessage } of roomList"
:key="room.id"
:room="(room as any)"
:last-message="(lastMessage as any)" />
</TransitionGroup>
class="bg-dark-900 md:flex flex-col gap-1 overflow-hidden relative w-70 shrink-0 hidden">
<div class="w-full py-3 px-3 border-b border-dark-800">
<h1 class="font-semibold text-lg text-white">Conversations</h1>
</div>
<div
class="p-1 flex-col gap-1 flex no-scrollbar overflow-y-scroll overflow-x-hidden">
<TransitionGroup move-class="duration-200 transition-all">
<PreviewsFvRoomPreview
v-for="{ room, lastMessage } of roomList"
:key="room.id"
:room="(room as any)"
:last-message="(lastMessage as any)" />
</TransitionGroup>
</div>
</div>
<slot />
</div>
Expand Down
8 changes: 8 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineNuxtConfig({
"@vueuse/nuxt",
"@pinia/nuxt",
"nuxt-twemoji",
"@nuxtjs/google-fonts",
],
spaLoadingTemplate: false,
ssr: false,
Expand All @@ -26,6 +27,13 @@ export default defineNuxtConfig({
wasm(),
],
},
googleFonts: {
families: {
Inter: true,
},
subsets: "latin",
download: true,
},
runtimeConfig: {
public: {
TOKEN: process.env.TOKEN,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"devDependencies": {
"@nuxt/devtools": "latest",
"@nuxtjs/eslint-config-typescript": "^12.0.0",
"@nuxtjs/google-fonts": "^3.0.2",
"@types/node": "^18",
"@typescript-eslint/parser": "^6.2.1",
"eslint": "^8.43.0",
Expand Down
4 changes: 3 additions & 1 deletion pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<template>
<div>No content</div>
<div class="w-full h-full flex flex-col p-4">
<h1 class="text-gray-200 font-bold">Select a conversation to begin</h1>
</div>
</template>
16 changes: 14 additions & 2 deletions pages/room/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,28 @@ const ready = () => {
timeline.value = roomTimeline.timeline;
};
const typingMembers = ref<Set<string>>(new Set());
const updateTypingMembers = (members: Set<string>) => {
typingMembers.value = members;
};
// Add event listeners for timeline updates
roomTimeline
.on(events.events.timeline.EVENT, newEvent)
.on(events.events.timeline.READY, ready);
.on(events.events.timeline.READY, ready)
.on(events.events.timeline.TYPING_MEMBERS_UPDATED, updateTypingMembers);
// Remove event listeners on route leave or unmount
function removeListeners() {
roomTimeline.removeInternalListeners();
roomTimeline
.off(events.events.timeline.EVENT, newEvent)
.off(events.events.timeline.READY, ready);
.off(events.events.timeline.READY, ready)
.off(
events.events.timeline.TYPING_MEMBERS_UPDATED,
updateTypingMembers
);
}
onBeforeRouteLeave(removeListeners);
onUnmounted(removeListeners);
Expand Down Expand Up @@ -167,6 +178,7 @@ useHead({
</button>
</Transition>
<InputFvMessageSender
:typing="typingMembers"
:room="(room as MatrixRoom)"
@send="event_id => {}" />
</div>
Expand Down
23 changes: 23 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9940597

Please sign in to comment.