Add roster screen

This allows you to view and start new conversations with contacts,
although it doesn't let implement a sliding window or allow you to
search through then.
This commit is contained in:
Badri Sunderarajan 2024-03-23 17:33:03 +05:30
parent 1f7ad1408c
commit c8f5240332
Signed by: badrihippo
GPG key ID: 9F594532AD60DE03
4 changed files with 130 additions and 3 deletions

View file

@ -7,6 +7,7 @@
import Home from './routes/Home.svelte'
import Login from './routes/Login.svelte'
import Messages from './routes/Messages.svelte'
import Contacts from './routes/Contacts.svelte'
import Chat from './routes/Chat.svelte'
import Redirect from './routes/Redirect.svelte'
@ -23,6 +24,7 @@
'/': Home,
'/login': Login,
'/messages': Messages,
'/contacts': Contacts,
'/chat/:chatID': Chat,
'*': Redirect,
}

122
src/routes/Contacts.svelte Normal file
View file

@ -0,0 +1,122 @@
<script lang="ts">
import Text from '../components/Text.svelte'
import ListItem from '../components/ListItem.svelte'
import { push, replace } from 'svelte-spa-router'
import { _converse } from '@converse/headless/core'
import {
titleStore,
softkeysStore,
xmppConnected,
} from '../stores.ts'
titleStore.update(() => 'Contacts')
softkeysStore.update((k) => {
k.left.label = 'Search'
k.left.callback = () => {}
k.center.label = 'Chat'
k.center.callback = () => {
document.activeElement.click()
}
k.right.label = 'Options'
k.right.callback = () => {}
return k
})
// Main function for this view: get a conversation going!
function createChat(contactJID) {
_converse.api.listen.on('chatBoxInitialized', model => {
replace(`/chat/${model.id}`)
})
_converse.api.chats.create(contactJID)
}
// Run this and unsubscribe after one
// second. (The xmppConnected.subscribe function
// returns the unsubscribe callback, which we
// then call with setTimeout after 1000 ms)
setTimeout(xmppConnected.subscribe(value => {
if (!value) {
push('/redirect') // redirects to home
}
}), 1000)
// Stores information on the rendered contacts
let contacts = []
let contactsRenderedAt = 0 // a very, very long time ago
let contactsRendering = false // is a rendering scheduled?
// TODO: use a sliding window so that only the contacts
// that are in view get rendered
// Helper function to convert contacts list into
// (exceedingly lightweight) object array for
// final rendering
function contactsToArray(contacts) {
return contacts.map(c => ({
jid: c.attributes.jid,
name: c.attributes.nickname || c.attributes.user_id,
}))
}
function renderContacts() {
// If there are no contacts, just render an empty array
if (!_converse?.roster?.models) {
contacts = []
return
}
// If the contacts were updated more than 5 seconds ago,
// render them again immediately
if (new Date() - contactsRenderedAt > 5000) {
contacts = contactsToArray(_converse?.roster?.models)
} else {
// If they were updated less than 5 seconds ago, check
// if a re-render has been scheduled
if (contactsRendering) {
return
} else {
contactsRendering = true
// Render them after a gap
setTimeout(function () {
contactsRendering = false
contactsRenderedAt = new Date()
renderContacts()
}, 5000)
}
}
}
// Render them once
renderContacts()
_converse.on('rosterContactsFetched', () => {
renderContacts()
})
_converse.on('presence', () => {
renderContacts()
})
</script>
{#if !contacts.length}
<Text>
<p>You have no contacts. How about adding one?</p>
</Text>
{:else}
{#each contacts as contact, index (contact.jid)}
<ListItem
text={contact.name}
subtext={contact.jid}
tabindex={index}
onclick={() => createChat(contact.jid)}
/>
{/each}
{/if}

View file

@ -54,7 +54,8 @@
forward_messages: false,
enable_smacks: true,
allow_chat_pending_contacts: true,
allow_non_roster_messaging: true,
allow_non_roster_messaging: false,
roster_groups: false,
// Special optimisations to reduce memory usage on KaiOS
mam_request_all_pages: false,

View file

@ -14,8 +14,10 @@
titleStore.update(() => 'Convo')
softkeysStore.update((k) => {
k.left.label = 'new'
k.left.callback = () => {}
k.left.label = 'New'
k.left.callback = () => {
push('/contacts')
}
k.center.label = 'Open'
k.center.callback = () => {